1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 if (log.isDebugEnabled())
101 {
102 log.debug( "BaseDecoration basePath: " + basePath.toString() );
103 log.debug( "BaseDecoration baseClientPath: " + baseClientPath.toString() );
104 }
105 }
106
107 public void init(Properties config, ResourceValidator validator, PathResolverCache cache)
108 {
109 this.config = config;
110 this.validator = validator;
111 this.cache = cache;
112 }
113
114 public String getName()
115 {
116 return name;
117 }
118
119 public String getBasePath()
120 {
121 return basePath.toString();
122 }
123
124 public String getBasePath( String relativePath )
125 {
126 if ( relativePath == null )
127 {
128 return basePath.toString();
129 }
130 return basePath.addSegment( relativePath ).toString();
131 }
132
133 public String getResource( String path )
134 {
135 Path workingPath = baseClientPath.getChild( path );
136
137 String hit = cache.getPath( workingPath.toString());
138 if( hit != null )
139 {
140 return hit;
141 }
142 else
143 {
144 String locatedPath = getResource( baseClientPath, new Path( path ) );
145 if( ! locatedPath.startsWith( NO_SUCH_RESOURCE ) )
146 {
147 if( ! path.startsWith( "/" ) )
148 {
149 locatedPath = locatedPath.substring( 1 );
150 }
151 cache.addPath( workingPath.toString(), locatedPath );
152 return locatedPath;
153 }
154 }
155 return null;
156 }
157
158 /***
159 * Recursively tries to locate a resource.
160 *
161 * @param rootPath initial path to start looking for the <code>searchPath.</code>
162 * The "pruning" of the rootPath of subsequest recursive calls follows the logic
163 * detailed in the {@link Decoration#getResource(String)} method.
164 * @param searchPath relative path to the resource we wish to locate.
165 * @return
166 *
167 * @see Decoration
168 */
169 protected String getResource( Path rootPath, Path searchPath )
170 {
171 String pathString = rootPath.getChild( searchPath ).toString();
172 if( validator.resourceExists( pathString ) )
173 {
174 return pathString;
175 }
176 else if( rootPath.length() > 0 )
177 {
178
179 return getResource( rootPath.removeLastPathSegment(), searchPath );
180 }
181 else
182 {
183 return NO_SUCH_RESOURCE + searchPath.getFileExtension();
184 }
185 }
186
187 public String getStyleSheet()
188 {
189 if ( this.commonStylesheet != null )
190 {
191 return getResource( this.commonStylesheet );
192 }
193 return null;
194 }
195 public String getStyleSheetPortal()
196 {
197 if ( this.portalStylesheet != null )
198 {
199 return getResource( this.portalStylesheet );
200 }
201 return null;
202 }
203 public String getStyleSheetDesktop()
204 {
205 if ( this.desktopStylesheet != null )
206 {
207 return getResource( this.desktopStylesheet );
208 }
209 return null;
210 }
211
212 public List getActions()
213 {
214 if(actions != null)
215 {
216 return actions;
217 }
218 else
219 {
220 return Collections.EMPTY_LIST;
221 }
222 }
223
224 public void setActions( List actions )
225 {
226 this.actions = actions;
227 }
228
229 public String getProperty( String name )
230 {
231 return config.getProperty( name );
232 }
233
234 public String getBaseCSSClass()
235 {
236 return config.getProperty( Decoration.BASE_CSS_CLASS_PROP, getName() );
237 }
238
239 public String getCurrentModeAction()
240 {
241 return this.currentModeAction;
242 }
243 public void setCurrentModeAction( String currentModeAction )
244 {
245 this.currentModeAction = currentModeAction;
246 }
247
248 public String getCurrentStateAction()
249 {
250 return this.currentStateAction;
251 }
252 public void setCurrentStateAction( String currentStateAction )
253 {
254 this.currentStateAction = currentStateAction;
255 }
256
257 public String getResourceBundleName()
258 {
259 return config.getProperty( Decoration.RESOURCE_BUNDLE_PROP );
260 }
261
262 public ResourceBundle getResourceBundle( Locale locale, org.apache.jetspeed.request.RequestContext context )
263 {
264 String resourceDirName = context.getConfig().getServletContext()
265 .getRealPath( getResource( RESOURCES_DIRECTORY_NAME ) );
266 File resourceDir = new File( resourceDirName );
267 String resourceName = getResourceBundleName();
268 if ( resourceName == null )
269 {
270 throw new NullPointerException( "Decoration cannot get ResourceBundle due to null value for decoration property " + Decoration.RESOURCE_BUNDLE_PROP + "." );
271 }
272 if ( !resourceDir.isDirectory() )
273 {
274 throw new MissingResourceException(
275 "Can't find the resource directory: " + resourceDirName,
276 resourceName + "_" + locale, "" );
277 }
278 URL[] urls = new URL[1];
279 try
280 {
281 urls[0] = resourceDir.toURL();
282 }
283 catch ( MalformedURLException e )
284 {
285 throw new MissingResourceException(
286 "The resource directory cannot be parsed as a URL: "
287 + resourceDirName, resourceName + "_" + locale, "");
288 }
289 return ResourceBundle.getBundle( resourceName, locale, new URLClassLoader( urls ) );
290 }
291
292 public boolean supportsDesktop()
293 {
294 return this.supportsDesktop;
295 }
296 }