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.desktop.impl;
18  
19  import java.io.IOException;
20  import java.util.Iterator;
21  import java.util.ResourceBundle;
22  
23  
24  import javax.servlet.RequestDispatcher;
25  import javax.servlet.ServletContext;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.jetspeed.Jetspeed;
30  import org.apache.jetspeed.container.url.BasePortalURL;
31  import org.apache.jetspeed.decoration.DecorationFactory;
32  import org.apache.jetspeed.decoration.Theme;
33  import org.apache.jetspeed.desktop.JetspeedDesktop;
34  import org.apache.jetspeed.desktop.JetspeedDesktopContext;
35  import org.apache.jetspeed.headerresource.HeaderResource;
36  import org.apache.jetspeed.headerresource.HeaderResourceFactory;
37  import org.apache.jetspeed.headerresource.HeaderResourceLib;
38  import org.apache.jetspeed.om.page.Page;
39  import org.apache.jetspeed.request.RequestContext;
40  import org.springframework.web.context.ServletContextAware;
41  
42  /***
43   * Desktop Valve
44   *
45   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
46   * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
47   * @version $Id: JetspeedDesktopImpl.java $
48   */
49  public class JetspeedDesktopImpl implements JetspeedDesktop, ServletContextAware
50  {
51      private final static String EOL = "\r\n";   // html eol
52      private final static String DOJO_CONFIG_LAYOUT_DECORATION_PATH_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".layoutDecorationPath";
53      private final static String DOJO_CONFIG_LAYOUT_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".layoutName";
54      private final static String DOJO_CONFIG_PORTLET_DECORATIONS_PATH_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".portletDecorationsPath";
55      private final static String DOJO_CONFIG_PORTLET_DECORATIONS_ALLOWED_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".portletDecorationsAllowed";
56      private final static String DOJO_CONFIG_ACTION_LABELS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".desktopActionLabels";
57  
58      private final static String[] DESKTOP_ACTIONS = new String[] { "menu", "tile", "untile", "heightexpand", "heightnormal", "restore", "removeportlet", "loadportletrender", "loadportletaction", "loadportletupdate", "addportlet", "editpage", "loadpage", "loadpageeditor" };
59      private final static String DESKTOP_ACTION_RESOURCE_NAME_PREFIX = "desktop.action.";
60      
61      private static final Log log = LogFactory.getLog( JetspeedDesktopImpl.class );
62  
63      private DecorationFactory decorationFactory;
64          
65      /*** desktop pipeline servlet path */
66      private String desktopServletPath;
67      
68      /*** default extension for layout templates */
69      private String defaultLayoutTemplateExtension;
70      
71      /*** spring-fed servlet context property */
72      private ServletContext servletContext;
73      
74      /*** tool for directing output to html &lt;head&gt; */
75      private HeaderResourceFactory headerResourceFactory;
76      
77      /*** base portal URL to override default URL server info from servlet */
78      private BasePortalURL baseUrlAccess = null;
79      
80      public JetspeedDesktopImpl( DecorationFactory decorationFactory, HeaderResourceFactory headerResourceFactory, String desktopServletPath, String defaultLayoutTemplateExtension )
81      {
82          this( decorationFactory, headerResourceFactory, desktopServletPath, defaultLayoutTemplateExtension, null, null, null );
83      }
84      public JetspeedDesktopImpl( DecorationFactory decorationFactory, HeaderResourceFactory headerResourceFactory, String desktopServletPath, String defaultLayoutTemplateExtension, String defaultDesktopLayoutDecoration, String defaultDesktopPortletDecoration )
85      {
86          this( decorationFactory, headerResourceFactory, desktopServletPath, defaultLayoutTemplateExtension, defaultDesktopLayoutDecoration, defaultDesktopPortletDecoration, null );
87      }
88      public JetspeedDesktopImpl( DecorationFactory decorationFactory, HeaderResourceFactory headerResourceFactory, String desktopServletPath, String defaultLayoutTemplateExtension, String defaultDesktopLayoutDecoration, String defaultDesktopPortletDecoration, BasePortalURL baseUrlAccess )
89      {
90          this.decorationFactory = decorationFactory;
91          this.headerResourceFactory = headerResourceFactory;
92          
93          if ( desktopServletPath != null && desktopServletPath.length() > 0 )
94          {
95              if ( desktopServletPath.charAt( 0 ) != '/' )
96                  desktopServletPath = "/" + desktopServletPath;
97          }
98          this.desktopServletPath = desktopServletPath;
99          if ( this.desktopServletPath == null || this.desktopServletPath.length() == 0 )
100         {
101             log.warn( "JetspeedDesktopImpl initialization is incomplete due to undefined desktop servlet path." );
102             this.desktopServletPath = null;
103         }
104         
105         this.defaultLayoutTemplateExtension = defaultLayoutTemplateExtension;
106         
107         // set default layout and portlet decorations only if they are not currently undefined
108         if ( defaultDesktopLayoutDecoration != null && defaultDesktopLayoutDecoration.length() > 0 )
109         {
110             String existingDefaultDesktopLayoutDecoration = decorationFactory.getDefaultDesktopLayoutDecoration();
111             if ( existingDefaultDesktopLayoutDecoration == null || existingDefaultDesktopLayoutDecoration.length() == 0 )
112             {
113                 decorationFactory.setDefaultDesktopLayoutDecoration( defaultDesktopLayoutDecoration );
114             }
115         }
116         if ( defaultDesktopPortletDecoration != null && defaultDesktopPortletDecoration.length() > 0 )
117         {
118             String existingDefaultDesktopPortletDecoration = decorationFactory.getDefaultDesktopPortletDecoration();
119             if ( existingDefaultDesktopPortletDecoration == null || existingDefaultDesktopPortletDecoration.length() == 0 )
120             {
121                 decorationFactory.setDefaultDesktopPortletDecoration( defaultDesktopPortletDecoration );
122             }
123         }
124         
125         this.baseUrlAccess = baseUrlAccess;
126     }
127     
128     public void render( RequestContext request )    
129     {
130         String layoutDecorationTemplatePath = null;
131         boolean layoutDecorationTemplatePathWasAssigned = false;
132         try
133         {
134             Page page = request.getPage();
135             
136             // enable desktop
137             request.setAttribute( JetspeedDesktop.DESKTOP_ENABLED_REQUEST_ATTRIBUTE, Boolean.TRUE );
138             
139             // get decorations
140             Theme theme = decorationFactory.getTheme( page, request );
141             
142             HeaderResource hr = getHeaderResourceFactory().getHeaderResouce( request );
143             JetspeedDesktopContext desktopContext = new JetspeedDesktopContextImpl( request, this.baseUrlAccess, theme, hr, defaultLayoutTemplateExtension );
144             
145             String layoutTemplateIdPropertyName = null;
146             if ( "true".equals( request.getRequest().getParameter( "jsprintmode" ) ) )
147                 layoutTemplateIdPropertyName = JetspeedDesktopContext.LAYOUT_PRINT_TEMPLATE_ID_PROP;
148             
149             layoutDecorationTemplatePath = desktopContext.getLayoutTemplatePath( layoutTemplateIdPropertyName );
150             layoutDecorationTemplatePathWasAssigned = true;
151             
152             RequestDispatcher dispatcher = request.getRequest().getRequestDispatcher( layoutDecorationTemplatePath );
153             
154             hr.dojoEnable();
155             
156             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_CONTEXT_ATTRIBUTE, desktopContext );
157             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_REQUEST_CONTEXT_ATTRIBUTE, request );
158             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_COMPONENT_MANAGER_ATTRIBUTE, Jetspeed.getComponentManager() );
159             
160             String portletDecorationsBasePath = decorationFactory.getPortletDecorationsBasePath();
161             String portletDecorationsBaseRelative = portletDecorationsBasePath;
162             if ( portletDecorationsBaseRelative != null && portletDecorationsBaseRelative.length() > 1 && portletDecorationsBaseRelative.indexOf( '/' ) == 0 )
163             {
164                 portletDecorationsBaseRelative = portletDecorationsBaseRelative.substring( 1 );
165             }
166             StringBuffer dojoConfigAddOn = new StringBuffer();
167             dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_LAYOUT_DECORATION_PATH_VAR_NAME ).append( " = \"" ).append( desktopContext.getLayoutBasePath() ).append( "\";" ).append( EOL );
168             dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_LAYOUT_VAR_NAME ).append( " = \"" ).append( desktopContext.getLayoutDecorationName() ).append( "\";" ).append( EOL );
169             dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_PORTLET_DECORATIONS_PATH_VAR_NAME ).append( " = \"" ).append( portletDecorationsBasePath ).append( "\";" ).append( EOL );
170             String portletDecorationNamesContent = HeaderResourceLib.makeJSONStringArray( decorationFactory.getDesktopPortletDecorations( request ) );
171             dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_PORTLET_DECORATIONS_ALLOWED_VAR_NAME ).append( " = " ).append( portletDecorationNamesContent ).append( ";" );
172             hr.addHeaderSectionFragment( DOJO_CONFIG_LAYOUT_VAR_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, dojoConfigAddOn.toString() );
173             
174             if ( hr.isHeaderSectionIncluded( HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT ) )
175             {
176                 hr.setHeaderSectionType( HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT, HeaderResource.HEADER_TYPE_LINK_TAG );
177                 StringBuffer desktopThemeStyleLink = new StringBuffer();
178                 int stylesheetCount = 0;
179                 Iterator stylesheetIter = theme.getStyleSheets().iterator();
180                 while ( stylesheetIter.hasNext() )
181                 {
182                     String stylesheetHref = (String)stylesheetIter.next();
183                     if ( stylesheetHref != null && stylesheetHref.length() > 0 )
184                     {
185                         if ( ! stylesheetHref.startsWith( portletDecorationsBaseRelative ) )
186                         {   // exclude portlet decorations - in desktop these are loaded via javascript
187                             if ( stylesheetCount > 0 )
188                             {
189                                 desktopThemeStyleLink.append( EOL );
190                             }
191                             desktopThemeStyleLink.append( "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen, projection\" href=\"" );
192                             desktopThemeStyleLink.append( desktopContext.getPortalResourceUrl( stylesheetHref ) ).append( "\"/>" );
193                             stylesheetCount++;
194                         }
195                     }
196                 }
197                 hr.addHeaderSectionFragment( "desktop.style.layout", HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT, desktopThemeStyleLink.toString() );
198             }
199             
200             // desktop action labels
201             StringBuffer desktopActionLabels = new StringBuffer();
202             ResourceBundle messages = desktopContext.getLayoutResourceBundle( request.getLocale() );
203             for ( int i = 0 ; i < DESKTOP_ACTIONS.length ; i++ )
204             {
205                 String actionLabel = messages.getString( DESKTOP_ACTION_RESOURCE_NAME_PREFIX + DESKTOP_ACTIONS[ i ] );
206                 if ( actionLabel != null )
207                 {
208                     if ( desktopActionLabels.length() == 0 )
209                     {
210                         desktopActionLabels.append( "{ " );
211                     }
212                     else
213                     {
214                         desktopActionLabels.append( ", " );
215                     }
216                     desktopActionLabels.append( DESKTOP_ACTIONS[ i ] ).append( ": \"" ).append( actionLabel ).append( "\"" );
217                 }
218             }
219             if ( desktopActionLabels.length() > 0 )
220             {
221                 dojoConfigAddOn = new StringBuffer();
222                 dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_ACTION_LABELS_NAME ).append( " = " ).append( desktopActionLabels.toString() ).append( " };" ).append( EOL );
223                 hr.addHeaderSectionFragment( DOJO_CONFIG_ACTION_LABELS_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, dojoConfigAddOn.toString() );
224             }
225             
226             dispatcher.include( request.getRequest(), request.getResponse() );
227         }
228         catch ( Exception e )
229         {
230             try
231             {
232                 if ( layoutDecorationTemplatePathWasAssigned )
233                 {
234                     layoutDecorationTemplatePath = ( layoutDecorationTemplatePath == null || layoutDecorationTemplatePath.length() == 0 ? "null" : layoutDecorationTemplatePath );
235                     log.error( "Failed to include desktop layout decoration at path " + layoutDecorationTemplatePath, e );
236                     request.getResponse().getWriter().println( "Desktop layout decoration " + layoutDecorationTemplatePath + " is not available" );
237                 }
238                 else
239                 {
240                     log.error( "Failed to initialize for inclusion of desktop layout decoration", e );
241                     request.getResponse().getWriter().println( "Failed to initialize for inclusion of desktop layout decoration" );
242                 }
243             }
244             catch ( IOException ioe )
245             {
246                 log.error( "Failed to write desktop layout decoration exception information to servlet output writer", ioe );
247             }
248         }
249     }
250     
251     public boolean isDesktopEnabled( RequestContext requestContext )
252     {
253         return this.decorationFactory.isDesktopEnabled( requestContext );
254     }
255     
256     public ServletContext getServletContext()
257     {
258         return servletContext;
259     }
260 
261     public void setServletContext(ServletContext servletContext)
262     {
263         this.servletContext = servletContext;
264     }
265     
266     public HeaderResourceFactory getHeaderResourceFactory()
267     {
268         return this.headerResourceFactory;
269     }
270     
271     // get portal urls - each of these methods is copied from HeaderResourceImpl.java
272  
273     /***
274      * Desktop servlet path ( e.g. /desktop )
275      * 
276      * @return portal base url
277      */
278     public String getDesktopServletPath()
279     {
280         return this.desktopServletPath;
281     }
282     
283     /***
284      * Portal base url ( e.g. http://localhost:8080/jetspeed )
285      * 
286      * @return portal base url
287      */
288     public String getPortalBaseUrl( RequestContext context )
289     {
290         return HeaderResourceLib.getPortalBaseUrl( context, this.baseUrlAccess );
291     }
292     
293     /***
294      * Portal base url ( e.g. http://localhost:8080/jetspeed )
295      * 
296      * @return portal base url
297      */
298     public String getPortalBaseUrl( RequestContext context, boolean encode )
299     {
300         String baseurl = getPortalBaseUrl( context );
301         if ( ! encode )
302         {
303             return baseurl;
304         }
305         else
306         {
307             return context.getResponse().encodeURL( baseurl );
308         }
309     }
310     
311     /***
312      * Portal base url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/javascript/dojo/ )
313      * 
314      * @return portal base url with relativePath argument appended
315      */
316     public String getPortalResourceUrl( RequestContext context, String relativePath )
317     {
318         return getPortalResourceUrl( context, relativePath, false );
319     }
320     
321     /***
322      * Portal base url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/javascript/dojo/ )
323      * 
324      * @return portal base url with relativePath argument appended
325      */
326     public String getPortalResourceUrl( RequestContext context, String relativePath, boolean encode )
327     {
328         return HeaderResourceLib.getPortalResourceUrl( relativePath, getPortalBaseUrl( context ), encode, context );
329     }
330     
331     /***
332      * Portal base servlet url ( e.g. http://localhost:8080/jetspeed/desktop/ )
333      * 
334      * @return portal base servlet url
335      */
336     public String getPortalUrl( RequestContext context )
337     {
338         return HeaderResourceLib.getPortalUrl( getPortalBaseUrl( context ), context, getDesktopServletPath() );
339     }
340     
341     /***
342      * Portal base servlet url ( e.g. http://localhost:8080/jetspeed/desktop/ )
343      * 
344      * @return portal base servlet url
345      */
346     public String getPortalUrl( RequestContext context, boolean encode )
347     {
348         return getPortalUrl( context, null, encode );
349     }
350     
351     /***
352      * Portal base servlet url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/desktop/default-page.psml )
353      * 
354      * @return portal base servlet url with relativePath argument appended
355      */
356     public String getPortalUrl( RequestContext context, String relativePath )
357     {
358         return getPortalUrl( context, relativePath, false );
359     }
360     
361     /***
362      * Portal base servlet url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/desktop/default-page.psml )
363      * 
364      * @return portal base servlet url with relativePath argument appended
365      */
366     public String getPortalUrl( RequestContext context, String relativePath, boolean encode )
367     {
368         return HeaderResourceLib.getPortalResourceUrl( relativePath, getPortalUrl( context ), encode, context );
369     }
370 }
371