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.IOException;
20 import java.io.InputStream;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.Properties;
30 import java.util.Set;
31
32 import javax.servlet.ServletContext;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.jetspeed.components.portletregistry.PortletRegistry;
37 import org.apache.jetspeed.decoration.caches.SessionPathResolverCache;
38 import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
39 import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
40 import org.apache.jetspeed.om.page.Fragment;
41 import org.apache.jetspeed.om.page.Page;
42 import org.apache.jetspeed.request.RequestContext;
43 import org.apache.jetspeed.util.Path;
44 import org.apache.jetspeed.desktop.JetspeedDesktop;
45 import org.springframework.web.context.ServletContextAware;
46
47 /***
48 *
49 * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
50 * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
51 * @see org.apache.jetspeed.decoration.DecorationFactory
52 */
53 public class DecorationFactoryImpl implements DecorationFactory, ServletContextAware
54 {
55 private static final Log log = LogFactory.getLog(DecorationFactoryImpl.class);
56
57 private final Path decorationsPath;
58 private final Path portletDecorationsPath;
59 private final Path layoutDecorationsPath;
60 private final String portletDecorationsPathStr;
61 private final String layoutDecorationsPathStr;
62
63 private final ResourceValidator validator;
64 private final PortletRegistry registry;
65
66 private ServletContext servletContext;
67
68 private String defaultDesktopLayoutDecoration = null;
69 private String defaultDesktopPortletDecoration = null;
70
71 private Set layoutDecorationsDir = Collections.EMPTY_SET;
72 private Set portletDecorationsDir = Collections.EMPTY_SET;
73 private Set desktopLayoutDecorationsDir = Collections.EMPTY_SET;
74 private Set desktopPortletDecorationsDir = Collections.EMPTY_SET;
75
76 private Set layoutDecorationsList = Collections.EMPTY_SET;
77 private Set portletDecorationsList = Collections.EMPTY_SET;
78 private Set desktopLayoutDecorationsList = Collections.EMPTY_SET;
79 private Set desktopPortletDecorationsList = Collections.EMPTY_SET;
80
81 private Map portletDecoratorProperties = new HashMap();
82 private Map layoutDecoratorProperties = new HashMap();
83
84 public DecorationFactoryImpl( String decorationsPath,
85 ResourceValidator validator )
86 {
87 this( null, decorationsPath, validator );
88 }
89
90 public DecorationFactoryImpl( PortletRegistry registry,
91 String decorationsPath,
92 ResourceValidator validator )
93 {
94 this.registry = registry;
95 this.decorationsPath = new Path( decorationsPath );
96 this.layoutDecorationsPath = getBasePath( Fragment.LAYOUT );
97 this.layoutDecorationsPathStr = this.layoutDecorationsPath.toString();
98 this.portletDecorationsPath = getBasePath( Fragment.PORTLET );
99 this.portletDecorationsPathStr = this.portletDecorationsPath.toString();
100 this.validator = validator;
101 }
102
103 public ResourceValidator getResourceValidator()
104 {
105 return validator;
106 }
107
108 public Theme getTheme( Page page, RequestContext requestContext )
109 {
110 return new PageTheme(page, this, requestContext);
111 }
112
113 public Decoration getDecoration( Page page, Fragment fragment, RequestContext requestContext )
114 {
115 String decorationName = getDefaultDecorationName( fragment, page );
116 Decoration decoration;
117
118
119
120 if ( fragment.getType().equals( Fragment.LAYOUT ) )
121 {
122 decoration = getLayoutDecoration( decorationName, requestContext );
123 }
124 else
125 {
126 decoration = getPortletDecoration( decorationName, requestContext );
127 }
128
129 if ( isDesktopEnabled( requestContext ) )
130 {
131
132 if ( decoration == null || ! decoration.supportsDesktop() )
133 {
134 String defaultDecoration = null;
135 if (fragment.getType().equals( Fragment.LAYOUT ) )
136 {
137 defaultDecoration = getDefaultDesktopLayoutDecoration();
138 decoration = getLayoutDecoration( defaultDecoration, requestContext );
139 }
140 else
141 {
142 defaultDecoration = getDefaultDesktopPortletDecoration();
143 decoration = getPortletDecoration( defaultDecoration, requestContext );
144 }
145 if ( decoration == null )
146 {
147 String errMsg = "Cannot locate default desktop " + fragment.getType() + " decoration " + ( defaultDecoration == null ? "null" : ("\"" + defaultDecoration + "\"") ) + " (decoration " + ( defaultDecoration == null ? "null" : ("\"" + decorationName + "\"") ) + " specified for page could either not be located or does not support desktop). No desktop compatible " + fragment.getType() + " decoration is available.";
148 log.warn( errMsg );
149 }
150 }
151 }
152 return decoration;
153 }
154
155 public PortletDecoration getPortletDecoration( String name, RequestContext requestContext )
156 {
157 Path basePath = getPortletDecorationBasePath( name );
158 Path baseClientPath = createClientPath( name, basePath, requestContext, Fragment.PORTLET );
159 Properties configuration = getConfiguration( name, Fragment.PORTLET );
160 SessionPathResolverCache sessionPathResolver = new SessionPathResolverCache( requestContext.getRequest().getSession() );
161 return new PortletDecorationImpl( configuration, validator, basePath, baseClientPath, sessionPathResolver );
162 }
163
164 public LayoutDecoration getLayoutDecoration( String name, RequestContext requestContext )
165 {
166 Path basePath = getLayoutDecorationBasePath( name );
167 Path baseClientPath = createClientPath( name, basePath, requestContext, Fragment.LAYOUT );
168 Properties configuration = getConfiguration( name, Fragment.LAYOUT );
169 SessionPathResolverCache sessionPathResolver = new SessionPathResolverCache( requestContext.getRequest().getSession() );
170 return new LayoutDecorationImpl( configuration, validator, basePath, baseClientPath, sessionPathResolver );
171 }
172
173 public boolean isDesktopEnabled( RequestContext requestContext )
174 {
175 Boolean desktopEnabled = (Boolean)requestContext.getAttribute( JetspeedDesktop.DESKTOP_ENABLED_REQUEST_ATTRIBUTE );
176 return ( desktopEnabled != null && desktopEnabled.booleanValue() ? true : false );
177 }
178
179 public void setServletContext(ServletContext servletContext)
180 {
181 this.servletContext = servletContext;
182
183 }
184
185 /***
186 * Gets the configuration (decorator.properties) object for the decoration.
187 * @param name Name of the Decoration.
188 * @return <code>java.util.Properties</code> representing the configuration
189 * object.
190 */
191 public Properties getConfiguration( String name, String type )
192 {
193 Properties props = null;
194 if ( type.equals( Fragment.PORTLET ) )
195 {
196 props = (Properties)this.portletDecoratorProperties.get( name );
197
198 }
199 else
200 {
201 props = (Properties)this.layoutDecoratorProperties.get( name );
202 }
203 if ( props != null )
204 {
205 return props;
206 }
207
208 props = new Properties();
209 InputStream is = null;
210
211
212 try
213 {
214 is = servletContext.getResourceAsStream( decorationsPath + "/" + type + "/" + name + "/" + Decoration.CONFIG_FILE_NAME );
215 if (is != null)
216 {
217 props.load( is );
218 }
219 else
220 {
221 log.warn( "Could not locate the " + Decoration.CONFIG_FILE_NAME + " configuration file for decoration \"" + name + "\". This decoration may not exist." );
222 props.setProperty( "id", name );
223 props.setProperty( "name", name );
224 }
225 }
226 catch ( Exception e )
227 {
228 log.warn( "Failed to load the " + Decoration.CONFIG_FILE_NAME + " configuration file for decoration \"" + name + "\".", e );
229 props.setProperty( "id", name );
230 props.setProperty( "name", name );
231 }
232 finally
233 {
234 if ( is != null )
235 {
236 try
237 {
238 is.close();
239 }
240 catch (IOException e)
241 {
242 log.warn("Failed to close decoration configuration.", e);
243 }
244 }
245 String decorationIdPropVal = props.getProperty( "id" );
246 String decorationNamePropVal = props.getProperty( "name" );
247 if ( decorationIdPropVal == null )
248 {
249 if ( decorationNamePropVal != null )
250 {
251 decorationIdPropVal = decorationNamePropVal;
252 }
253 else
254 {
255 decorationIdPropVal = name;
256 }
257 props.setProperty( "id", decorationIdPropVal );
258 }
259
260 if ( decorationNamePropVal == null )
261 {
262 props.setProperty( "name", decorationIdPropVal );
263 }
264 }
265
266
267 try
268 {
269 is = servletContext.getResourceAsStream( decorationsPath + "/" + type + "/" + name + "/" + Decoration.CONFIG_DESKTOP_FILE_NAME );
270 if ( is != null )
271 {
272 props.load( is );
273 if ( props.getProperty( Decoration.DESKTOP_SUPPORTED_PROPERTY ) == null )
274 {
275 props.setProperty( Decoration.DESKTOP_SUPPORTED_PROPERTY, "true" );
276 }
277 }
278 else
279 {
280 log.debug( "Could not locate the " + Decoration.CONFIG_DESKTOP_FILE_NAME + " configuration file for decoration \"" + name + "\". This decoration may not exist." );
281 }
282 }
283 catch ( Exception e )
284 {
285 log.warn( "Failed to load the " + Decoration.CONFIG_DESKTOP_FILE_NAME + " configuration file for decoration \"" + name + "\".", e );
286 }
287 finally
288 {
289 if ( is != null )
290 {
291 try
292 {
293 is.close();
294 }
295 catch ( IOException e )
296 {
297 log.warn( "Failed to close decoration desktop configuration.", e );
298 }
299 }
300 if ( props.getProperty( Decoration.DESKTOP_SUPPORTED_PROPERTY ) == null )
301 {
302 props.setProperty( Decoration.DESKTOP_SUPPORTED_PROPERTY, "false" );
303 }
304 }
305
306 if ( type.equals( Fragment.PORTLET ) )
307 {
308 this.portletDecoratorProperties.put( name, props );
309 }
310 else
311 {
312 this.layoutDecoratorProperties.put( name, props );
313 }
314 return props;
315 }
316
317 /***
318 * Creates a <code>org.apache.jetspeed.util.Path</code> object based
319 * off of the user's client browser and locale.
320 *
321 * @param name Decroator's name
322 * @param requestContext Current portal request.
323 * @param decorationType Type of decoration, either <code>layout</code>
324 * or <code>portlet</code>
325 * @return
326 *
327 * @see Path
328 * @see RequestContext
329 */
330 protected Path createClientPath( String name, RequestContext requestContext, String decorationType )
331 {
332 return createClientPath( name, null, requestContext, decorationType );
333 }
334
335 private Path createClientPath( String name, Path basePath, RequestContext requestContext, String decorationType )
336 {
337 if ( basePath == null )
338 basePath = getBasePath( name, decorationType );
339 String mediaType = requestContext.getMediaType();
340 Locale locale = requestContext.getLocale();
341 String language = locale.getLanguage();
342 String country = locale.getCountry();
343 String variant = locale.getVariant();
344
345 basePath.addSegment( mediaType ).addSegment( language );
346
347 if ( country != null )
348 {
349 basePath.addSegment( country );
350 }
351
352 if (variant != null)
353 {
354 basePath.addSegment( variant );
355 }
356 return basePath;
357 }
358
359 /***
360 * Returns a the default decoration name for the specific Fragment type.
361 *
362 * @param fragment Fragment whose default decroation has been requested
363 * @param page Page this fragment belongs to.
364 * @return Default decorator name.
365 *
366 * @see Page
367 * @see Fragment
368 */
369 protected String getDefaultDecorationName(Fragment fragment, Page page)
370 {
371
372 String decoration = fragment.getDecorator();
373 if (decoration == null)
374 {
375 if (fragment.getType().equals(Fragment.LAYOUT))
376 {
377 if (fragment.equals(page.getRootFragment()))
378 {
379
380 decoration = page.getEffectiveDefaultDecorator(Fragment.LAYOUT);
381 }
382 else
383 {
384
385 decoration = DEFAULT_NESTED_LAYOUT_PORTLET_DECORATOR;
386 }
387 }
388 else
389 {
390
391 decoration = page.getEffectiveDefaultDecorator(Fragment.PORTLET);
392 }
393 }
394
395 return decoration;
396 }
397
398 public void clearCache(RequestContext requestContext)
399 {
400 new SessionPathResolverCache(requestContext.getRequest().getSession()).clear();
401 }
402
403 protected Path getBasePath( String decorationType )
404 {
405 return decorationsPath.addSegment(decorationType);
406 }
407
408 protected Path getBasePath( String name, String decorationType )
409 {
410 return decorationsPath.addSegment(decorationType).addSegment(name);
411 }
412
413 protected Path getLayoutDecorationBasePath( String name )
414 {
415 return layoutDecorationsPath.addSegment(name);
416 }
417 protected Path getPortletDecorationBasePath( String name )
418 {
419 return portletDecorationsPath.addSegment(name);
420 }
421
422 public String getLayoutDecorationsBasePath()
423 {
424 return this.layoutDecorationsPathStr;
425 }
426
427 public String getPortletDecorationsBasePath()
428 {
429 return this.portletDecorationsPathStr;
430 }
431
432 /***
433 * Get the portal-wide list of page decorations.
434 *
435 * @return A list of page decorations of type <code>Decoration</code>
436 */
437 public Set getPageDecorations( RequestContext request )
438 {
439 Set decorations = servletContext.getResourcePaths( decorationsPath.toString() + "/layout" );
440 if( ! layoutDecorationsDir.equals( decorations ) )
441 {
442 layoutDecorationsList = getListing( decorations, Decoration.CONFIG_FILE_NAME );
443 layoutDecorationsDir = decorations;
444
445 }
446 return layoutDecorationsList;
447 }
448
449 /***
450 * Get the portal-wide list of available desktop page decorations.
451 *
452 * @return A list of desktop skins of type <code>String</code>
453 */
454 public Set getDesktopPageDecorations( RequestContext request )
455 {
456 Set decorations = servletContext.getResourcePaths( decorationsPath.toString() + "/layout" );
457 if( ! desktopLayoutDecorationsDir.equals( decorations ) )
458 {
459 desktopLayoutDecorationsList = getListing( decorations, Decoration.CONFIG_DESKTOP_FILE_NAME );
460 desktopLayoutDecorationsDir = decorations;
461
462 }
463 return desktopLayoutDecorationsList;
464 }
465
466 /***
467 * Get the portal-wide list of portlet decorations.
468 *
469 * @return A list of portlet decorations of type <code>String</code>
470 */
471 public Set getPortletDecorations( RequestContext request )
472 {
473 Set decorations = servletContext.getResourcePaths( decorationsPath.toString() + "/portlet" );
474 if( ! portletDecorationsDir.equals( decorations ) )
475 {
476 portletDecorationsList = getListing( decorations, Decoration.CONFIG_FILE_NAME );
477 portletDecorationsDir = decorations;
478
479 }
480 return portletDecorationsList;
481 }
482
483 /***
484 * Get the portal-wide list of desktop portlet decorations.
485 *
486 * @return A list of portlet decorations of type <code>String</code>
487 */
488 public Set getDesktopPortletDecorations( RequestContext request )
489 {
490 Set decorations = servletContext.getResourcePaths( decorationsPath.toString() + "/portlet" );
491 if( ! desktopPortletDecorationsDir.equals( decorations ) )
492 {
493 desktopPortletDecorationsList = getListing( decorations, Decoration.CONFIG_DESKTOP_FILE_NAME );
494 desktopPortletDecorationsDir = decorations;
495
496 }
497 return desktopPortletDecorationsList;
498 }
499
500 /***
501 * Get the portal-wide list of available layouts.
502 *
503 * @return A list of layout portlets of type <code>PortletDefinitionComposite</code>
504 */
505 public List getLayouts( RequestContext request )
506 {
507 List list = new LinkedList();
508 Iterator portlets = registry.getAllPortletDefinitions().iterator();
509 while ( portlets.hasNext() )
510 {
511 PortletDefinitionComposite portlet = (PortletDefinitionComposite)portlets.next();
512 MutablePortletApplication muta = (MutablePortletApplication)portlet.getPortletApplicationDefinition();
513 String appName = muta.getName();
514 if ( appName == null )
515 continue;
516 if ( ! appName.equals( "jetspeed-layouts" ) )
517 continue;
518
519 String uniqueName = appName + "::" + portlet.getName();
520 list.add( new LayoutInfoImpl( uniqueName,
521 portlet.getDisplayNameText( request.getLocale() ),
522 portlet.getDescriptionText( request.getLocale() ) ) );
523
524 }
525 return list;
526 }
527
528 protected Set getListing(Set rawList, String propsFile)
529 {
530 Iterator itr = rawList.iterator();
531 Set filteredList = new HashSet();
532 while(itr.hasNext())
533 {
534 Path path = new Path((String) itr.next());
535 if(path.getFileName() == null && validator.resourceExists(path.toString() + propsFile))
536 {
537 int offset = path.length() - 1;
538 filteredList.add(path.getSegment(offset));
539 }
540 }
541 return filteredList;
542 }
543
544 public String getDefaultDesktopLayoutDecoration()
545 {
546 synchronized ( this )
547 {
548 return this.defaultDesktopLayoutDecoration;
549 }
550 }
551 public void setDefaultDesktopLayoutDecoration( String newOne )
552 {
553 synchronized ( this )
554 {
555 this.defaultDesktopLayoutDecoration = newOne;
556 }
557 }
558 public String getDefaultDesktopPortletDecoration()
559 {
560 synchronized ( this )
561 {
562 return this.defaultDesktopPortletDecoration;
563 }
564 }
565 public void setDefaultDesktopPortletDecoration( String newOne )
566 {
567 synchronized ( this )
568 {
569 this.defaultDesktopPortletDecoration = newOne;
570 }
571 }
572 }