View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.decoration;
18  
19  import java.io.File;
20  import java.io.Serializable;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.net.URLClassLoader;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.MissingResourceException;
28  import java.util.Properties;
29  import java.util.ResourceBundle;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.jetspeed.util.Path;
34  
35  /***
36   * Base class implementing the most common methods shared between
37   * LayoutDecorations and PortletDecorations.
38   * 
39   * 
40   * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
41   * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
42   * 
43   * @see org.apache.jetspeed.decoration.Decoration
44   * @see org.apache.jetspeed.decoration.LayoutDecoration
45   * @see org.apache.jetspeed.decoration.PortletDecoration
46   * 
47   */
48  public class BaseDecoration implements Decoration, Serializable
49  {
50      private static final Log log = LogFactory.getLog(BaseDecoration.class);
51      
52      protected static final String NO_SUCH_RESOURCE = "no_such_resource";
53      protected transient Properties config;
54      private transient ResourceValidator validator;        
55      private final String name;
56      private final Path basePath;
57      private final Path baseClientPath;
58      private transient PathResolverCache cache;
59      private final String commonStylesheet;
60      private final String portalStylesheet;
61      private final String desktopStylesheet;
62      private List actions;
63      private String currentModeAction;
64      private String currentStateAction;
65      private boolean supportsDesktop;
66      
67      /***
68       * 
69       * @param config <code>java.util.Properties</code> object containing configuration infomation
70       * for this Decoration.
71       * @param validator The ResourceValidator to be used in looking up fully-qualified resource pathes
72       * @param baseClientPath The "root" of the decroation hierarchy.
73       * 
74       * @throws InvalidDecorationConfigurationException
75       */
76      public BaseDecoration( Properties config, ResourceValidator validator, Path basePath, Path baseClientPath, PathResolverCache cache ) 
77      {        
78          this.config = config;
79          this.validator = validator;
80          this.basePath = basePath;
81          this.baseClientPath= baseClientPath;
82          this.cache = cache;
83          
84          this.name = config.getProperty( "name" );      
85          
86          this.commonStylesheet = config.getProperty( "stylesheet", DEFAULT_COMMON_STYLE_SHEET );
87          
88          this.supportsDesktop = "true".equalsIgnoreCase( config.getProperty( Decoration.DESKTOP_SUPPORTED_PROPERTY ) );
89          if ( this.supportsDesktop )
90          {
91              this.portalStylesheet = config.getProperty( "stylesheet.portal", DEFAULT_PORTAL_STYLE_SHEET );
92              this.desktopStylesheet = config.getProperty( "stylesheet.desktop", DEFAULT_DESKTOP_STYLE_SHEET );
93          }
94          else
95          {
96              this.portalStylesheet = null;
97              this.desktopStylesheet = null;
98          }
99          
100         log.info( "BaseDecoration basePath: " + basePath.toString() );
101         log.info( "BaseDecoration baseClientPath: " + baseClientPath.toString() );
102         
103     }
104     
105     public void init(Properties config, ResourceValidator validator, PathResolverCache cache)
106     {
107         this.config = config;
108         this.validator = validator;
109         this.cache = cache;
110     }    
111 
112     public String getName()
113     {        
114         return name;
115     }
116     
117     public String getBasePath()
118     {
119         return basePath.toString();
120     }
121     
122     public String getBasePath( String relativePath )
123     {
124         if ( relativePath == null )
125         {
126             return basePath.toString();
127         }
128         return basePath.addSegment( relativePath ).toString();
129     }
130         
131     public String getResource( String path )
132     {        
133         Path workingPath = baseClientPath.getChild( path );
134         
135         String hit = cache.getPath( workingPath.toString()); 
136         if(  hit != null )
137         {
138             return hit;
139         }
140         else
141         {
142             String locatedPath = getResource( baseClientPath, new Path( path ) );
143             if( ! locatedPath.startsWith( NO_SUCH_RESOURCE ) )
144             {
145                 if( ! path.startsWith( "/" ) )
146                 {
147                     locatedPath = locatedPath.substring( 1 );
148                 }
149                 cache.addPath( workingPath.toString(), locatedPath );
150                 return locatedPath;
151             }
152         }
153 	    return null;
154     }
155     
156     /***
157      * Recursively tries to locate a resource.
158      * 
159      * @param rootPath initial path to start looking for the <code>searchPath.</code>
160      * The "pruning" of the rootPath of subsequest recursive calls follows the logic
161      * detailed in the {@link Decoration#getResource(String)} method.
162      * @param searchPath relative path to the resource we wish to locate.
163      * @return
164      * 
165      * @see Decoration
166      */
167     protected String getResource( Path rootPath, Path searchPath )
168     {
169         String pathString = rootPath.getChild( searchPath ).toString();
170         if( validator.resourceExists( pathString ) )
171         {
172             return pathString;
173         }
174         else if( rootPath.length() > 0 )
175         {
176             
177             return getResource( rootPath.removeLastPathSegment(), searchPath );
178         }
179         else
180         {
181             return NO_SUCH_RESOURCE + searchPath.getFileExtension();
182         }
183     }
184 
185     public String getStyleSheet()
186     {
187         if ( this.commonStylesheet != null )
188         {
189             return getResource( this.commonStylesheet );
190         }
191         return null;
192     }
193     public String getStyleSheetPortal()
194     {
195         if ( this.portalStylesheet != null )
196         {
197             return getResource( this.portalStylesheet );
198         }
199         return null;
200     }
201     public String getStyleSheetDesktop()
202     {
203         if ( this.desktopStylesheet != null )
204         {
205             return getResource( this.desktopStylesheet );
206         }
207         return null;
208     }
209 
210     public List getActions()
211     {
212        if(actions != null)
213        {
214            return actions;
215        }
216        else
217        {
218            return Collections.EMPTY_LIST;
219        }
220     }
221 
222     public void setActions( List actions )
223     {
224         this.actions = actions;
225     }
226 
227     public String getProperty( String name )
228     {
229         return config.getProperty( name );
230     }
231 
232     public String getBaseCSSClass()
233     {
234         return config.getProperty( Decoration.BASE_CSS_CLASS_PROP, getName() );
235     }
236 
237     public String getCurrentModeAction()
238     {
239         return this.currentModeAction;
240     }
241     public void setCurrentModeAction( String currentModeAction )
242     {
243         this.currentModeAction = currentModeAction;
244     }
245 
246     public String getCurrentStateAction()
247     {
248         return this.currentStateAction;
249     }
250     public void setCurrentStateAction( String currentStateAction )
251     {
252         this.currentStateAction = currentStateAction;
253     }
254     
255     public String getResourceBundleName()
256     {
257         return config.getProperty( Decoration.RESOURCE_BUNDLE_PROP );
258     }
259     
260     public ResourceBundle getResourceBundle( Locale locale, org.apache.jetspeed.request.RequestContext context )
261     {
262         String resourceDirName = context.getConfig().getServletContext()
263                 .getRealPath( getResource( RESOURCES_DIRECTORY_NAME ) );
264         File resourceDir = new File( resourceDirName );
265         String resourceName = getResourceBundleName();
266         if ( resourceName == null )
267         {
268             throw new NullPointerException( "Decoration cannot get ResourceBundle due to null value for decoration property " + Decoration.RESOURCE_BUNDLE_PROP + "." );
269         }
270         if ( !resourceDir.isDirectory() )
271         {
272             throw new MissingResourceException(
273                     "Can't find the resource directory: " + resourceDirName,
274                     resourceName + "_" + locale, "" );
275         }
276         URL[] urls = new URL[1];
277         try
278         {
279             urls[0] = resourceDir.toURL();
280         }
281         catch ( MalformedURLException e )
282         {
283             throw new MissingResourceException(
284                     "The resource directory cannot be parsed as a URL: "
285                             + resourceDirName, resourceName + "_" + locale, "");
286         }
287         return ResourceBundle.getBundle( resourceName, locale, new URLClassLoader( urls ) );
288     }
289     
290     public boolean supportsDesktop()
291     {
292         return this.supportsDesktop;
293     }
294 }