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  import java.util.Set;
23  import java.util.Random;
24  
25  import javax.servlet.RequestDispatcher;
26  import javax.servlet.ServletContext;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.jetspeed.Jetspeed;
31  import org.apache.jetspeed.cache.CacheElement;
32  import org.apache.jetspeed.cache.JetspeedCache;
33  import org.apache.jetspeed.container.url.BasePortalURL;
34  import org.apache.jetspeed.decoration.DecorationFactory;
35  import org.apache.jetspeed.decoration.LayoutDecoration;
36  import org.apache.jetspeed.decoration.PortletDecoration;
37  import org.apache.jetspeed.decoration.Theme;
38  import org.apache.jetspeed.desktop.JetspeedDesktop;
39  import org.apache.jetspeed.desktop.JetspeedDesktopContext;
40  import org.apache.jetspeed.headerresource.HeaderResource;
41  import org.apache.jetspeed.headerresource.HeaderResourceFactory;
42  import org.apache.jetspeed.headerresource.HeaderResourceLib;
43  import org.apache.jetspeed.om.page.Page;
44  import org.apache.jetspeed.request.RequestContext;
45  import org.springframework.web.context.ServletContextAware;
46  
47  /***
48   * Desktop Valve
49   *
50   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
51   * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
52   * @version $Id: JetspeedDesktopImpl.java $
53   */
54  public class JetspeedDesktopImpl implements JetspeedDesktop, ServletContextAware
55  {
56  	private static final Log log = LogFactory.getLog( JetspeedDesktopImpl.class );
57  	
58      private final static String EOL = "\r\n";   // html eol
59      private final static String DOJO_CONFIG_LAYOUT_DECORATION_PATH_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".layoutDecorationPath";
60      private final static String DOJO_CONFIG_LAYOUT_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".layoutName";
61      private final static String DOJO_CONFIG_PORTLET_DECORATIONS_PATH_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".portletDecorationsPath";
62      private final static String DOJO_CONFIG_PORTLET_DECORATIONS_ALLOWED_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".portletDecorationsAllowed";
63      private final static String DOJO_CONFIG_PORTLET_DECORATIONS_CONFIG_VAR_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".portletDecorationsProperties";    
64      private final static String DOJO_CONFIG_ACTION_LABELS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".desktopActionLabels";
65      private final static String DOJO_CONFIG_LOADING_IMGPROPS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".loadingImgProps";
66      private final static String DOJO_CONFIG_PAGEEDITOR_LABELS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".pageEditorLabels";
67      private final static String DOJO_CONFIG_PAGEEDITOR_DIALOG_LABELS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".pageEditorDialogLabels";
68      private final static String DOJO_CONFIG_PAGEEDITOR_SETTINGS_NAME = HeaderResource.HEADER_INTERNAL_DOJO_CONFIG_JETSPEED_VAR_NAME + ".pec";
69      
70      private final static String[] DESKTOP_LOADING_PROPERTY_NAMES = new String[] 
71                                                                   { "dir", "animated", "stepprefix", "stepextension", "steps"
72                                                                   };
73      private final static String[] DESKTOP_LOADING_OUTPUT_PROPERTY_NAMES = new String[] 
74                                                                   { "imgdir", "imganimated", "imgstepprefix", "imgstepextension", "imgsteps"
75                                                                   };
76      private final static String[] DESKTOP_ACTION_RESOURCE_NAMES = new String[] 
77                                                                   { "menu", "tile", "untile", "heightexpand", "heightnormal",
78      															   "restore", "removeportlet", "minimized", "maximized", "normal",
79      															   "help", "edit", "view", "print", "config", "edit_defaults", "about",
80      															   "addportlet", "editpage", 
81      															   "movetiled", "moveuntiled", "loadpage", "loadpageeditor",
82      															   "loadportletrender", "loadportletaction", "loadportletupdate"
83      															 };
84      private final static String[] DESKTOP_PAGEEDITOR_RESOURCE_NAMES = new String[]
85                                                                   { "title", "changelayout", "changepagelayouttheme", "changepageportlettheme",
86      	                                                           "newpage", "deletepage", "addlayout", "addportlet", "columnsizes",
87      	                                                           "deletelayout", "movemode", "movemode_exit", "changeportlettheme"
88      	                                                         };
89      private final static String[] DESKTOP_PAGEEDITOR_DIALOG_RESOURCE_NAMES = new String[]
90                                                                   { "columnsizes", "columnsizes_column1", "columnsizes_column2", "columnsizes_column3",
91      	                                                           "columnsizes_column4", "columnsizes_column5", "newpage", "newpage_name",
92      	                                                           "newpage_title", "newpage_titleshort", "deletepage", "deletelayout",
93      	                                                           "removeportlet", "ok", "cancel", "yes", "no"
94                                                                   };
95      
96      private final static String DESKTOP_LOADING_NAME_PREFIX = "desktop.loading.";
97      private final static String DESKTOP_ACTION_NAME_PREFIX = "desktop.action.";
98      private final static String DESKTOP_PAGEEDITOR_NAME_PREFIX = "desktop.pageeditor.";
99      
100     private final static String DESKTOP_LOADING_IMG_NAME_PREFIX = DESKTOP_LOADING_NAME_PREFIX + "img.";
101     private final static String DESKTOP_ACTION_RESOURCE_NAME_PREFIX = DESKTOP_ACTION_NAME_PREFIX + "labels.";
102     private final static String DESKTOP_PAGEEDITOR_RESOURCE_NAME_PREFIX = DESKTOP_PAGEEDITOR_NAME_PREFIX + "labels.";
103     private final static String DESKTOP_PAGEEDITOR_DIALOG_RESOURCE_NAME_PREFIX = DESKTOP_PAGEEDITOR_NAME_PREFIX + "dialog.labels.";
104     
105     private final static String DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "page.layout.decorator.editable";
106     private final static String DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE_DEFAULT = "true";
107     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.name.editable";
108     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE_DEFAULT = "true";
109     
110     private final static String DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.columnsize.editable";
111     private final static String DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE_DEFAULT = "true";
112     
113     private final static String DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED = DESKTOP_PAGEEDITOR_NAME_PREFIX + "page.add.enabled";
114     private final static String DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED_DEFAULT = "true";
115     private final static String DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED = DESKTOP_PAGEEDITOR_NAME_PREFIX + "portlet.add.enabled";
116     private final static String DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED_DEFAULT = "true";
117     private final static String DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "page.portlet.decorator.editable";
118     private final static String DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE_DEFAULT = "true";
119     private final static String DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "portlet.decorator.editable";
120     private final static String DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE_DEFAULT = "true";
121     
122     private final static String DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT = DESKTOP_PAGEEDITOR_NAME_PREFIX + "movemode.isdefault";
123     private final static String DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT_DEFAULT = "true";
124     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.noactions.editable";
125     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE_DEFAULT = "false";
126     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.noactions.toplevel.moveable";
127     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE_DEFAULT = "false";
128     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.noactions.columnsize.editable";
129     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE_DEFAULT = "false";
130     
131     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITOR_ROLE = DESKTOP_PAGEEDITOR_NAME_PREFIX + "layout.noactions.editor.role";
132     private final static String DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITOR_ROLE_DEFAULT = null;
133     
134     private final static String DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX = DESKTOP_PAGEEDITOR_NAME_PREFIX + "page.layout.depth.max";
135     private final static int DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX_DEFAULT = 2;                     // allowed range is 0-15
136 
137     private final static int DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX_RESERVED =              0x000F;  // max layout depth (0-15) is first 4 bits
138     private final static int DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE_TRUE =         0x0010;
139     private final static int DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE_TRUE =                   0x0020;
140     private final static int DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE_TRUE =             0x0040;
141     private final static int DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED_TRUE =                       0x0080;
142     private final static int DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED_TRUE =                    0x0100;
143     private final static int DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE_TRUE =        0x0200;
144     private final static int DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE_TRUE =             0x0400;
145     private final static int DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT_TRUE =                     0x0800;
146     private final static int DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE_TRUE =              0x1000;
147     private final static int DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE_TRUE =     0x2000;
148     private final static int DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE_TRUE =   0x4000;
149     // algorithm used below and on client-size doesn't allow for further expansion (i.e. allows for expansion up to 0x4000)
150     //   (i.e. use of 0x8000 would break algorithm - because it would introduce the possibility of values close to 0xFFFF)
151     //   - if needed, add another variable for a fresh set of flags (and adjust the dependencies)
152             
153     private DecorationFactory decorationFactory;
154         
155     /*** desktop pipeline servlet path */
156     private String desktopServletPath;
157     
158     /*** default extension for layout templates */
159     private String defaultLayoutTemplateExtension;
160     
161     /*** spring-fed servlet context property */
162     private ServletContext servletContext;
163     
164     /*** tool for directing output to html &lt;head&gt; */
165     private HeaderResourceFactory headerResourceFactory;
166     
167     /*** cache to minimize production of generated desktop configuration content **/
168     private JetspeedCache desktopContentCache;
169         
170     /*** base portal URL to override default URL server info from servlet */
171     private BasePortalURL baseUrlAccess = null;
172     
173     public JetspeedDesktopImpl( DecorationFactory decorationFactory,
174     						    HeaderResourceFactory headerResourceFactory,
175     						    JetspeedCache desktopContentCache,
176     						    String desktopServletPath,
177     						    String defaultLayoutTemplateExtension )
178     {
179         this( decorationFactory, headerResourceFactory, desktopContentCache, desktopServletPath, defaultLayoutTemplateExtension, null, null, null );
180     }
181     public JetspeedDesktopImpl( DecorationFactory decorationFactory,
182                                 HeaderResourceFactory headerResourceFactory,
183                                 JetspeedCache desktopContentCache,
184                                 String desktopServletPath,
185                                 String defaultLayoutTemplateExtension,
186                                 String defaultDesktopLayoutDecoration,
187                                 String defaultDesktopPortletDecoration )
188     {
189     	this( decorationFactory, headerResourceFactory, desktopContentCache, desktopServletPath, defaultLayoutTemplateExtension, defaultDesktopLayoutDecoration, defaultDesktopPortletDecoration, null );
190     }
191     public JetspeedDesktopImpl( DecorationFactory decorationFactory,
192     		                    HeaderResourceFactory headerResourceFactory,
193     		                    JetspeedCache desktopContentCache,
194     		                    String desktopServletPath,
195     		                    String defaultLayoutTemplateExtension,
196     		                    String defaultDesktopLayoutDecoration,
197     		                    String defaultDesktopPortletDecoration,
198     		                    BasePortalURL baseUrlAccess )
199     {
200         this.decorationFactory = decorationFactory;
201         this.headerResourceFactory = headerResourceFactory;
202         this.desktopContentCache = desktopContentCache;
203         
204         if ( desktopServletPath != null && desktopServletPath.length() > 0 )
205         {
206             if ( desktopServletPath.charAt( 0 ) != '/' )
207                 desktopServletPath = "/" + desktopServletPath;
208         }
209         this.desktopServletPath = desktopServletPath;
210         if ( this.desktopServletPath == null || this.desktopServletPath.length() == 0 )
211         {
212             log.warn( "JetspeedDesktopImpl initialization is incomplete due to undefined desktop servlet path." );
213             this.desktopServletPath = null;
214         }
215         
216         this.defaultLayoutTemplateExtension = defaultLayoutTemplateExtension;
217         
218         // set default layout and portlet decorations only if they are not currently undefined
219         if ( defaultDesktopLayoutDecoration != null && defaultDesktopLayoutDecoration.length() > 0 )
220         {
221             String existingDefaultDesktopLayoutDecoration = decorationFactory.getDefaultDesktopLayoutDecoration();
222             if ( existingDefaultDesktopLayoutDecoration == null || existingDefaultDesktopLayoutDecoration.length() == 0 )
223             {
224                 decorationFactory.setDefaultDesktopLayoutDecoration( defaultDesktopLayoutDecoration );
225             }
226         }
227         if ( defaultDesktopPortletDecoration != null && defaultDesktopPortletDecoration.length() > 0 )
228         {
229             String existingDefaultDesktopPortletDecoration = decorationFactory.getDefaultDesktopPortletDecoration();
230             if ( existingDefaultDesktopPortletDecoration == null || existingDefaultDesktopPortletDecoration.length() == 0 )
231             {
232                 decorationFactory.setDefaultDesktopPortletDecoration( defaultDesktopPortletDecoration );
233             }
234         }
235                 
236         this.baseUrlAccess = baseUrlAccess;
237     }
238 
239     public void render( RequestContext request )    
240     {
241         String layoutDecorationTemplatePath = null;
242         boolean layoutDecorationTemplatePathWasAssigned = false;
243         try
244         {
245             Page page = request.getPage();
246             
247             // enable desktop
248             request.setAttribute( JetspeedDesktop.DESKTOP_ENABLED_REQUEST_ATTRIBUTE, Boolean.TRUE );
249             
250             // get decorations
251             Theme theme = decorationFactory.getTheme( page, request );
252             
253             HeaderResource hr = getHeaderResourceFactory().getHeaderResouce( request );
254             JetspeedDesktopContext desktopContext = new JetspeedDesktopContextImpl( request, this.baseUrlAccess, theme, hr, defaultLayoutTemplateExtension );
255             
256             String layoutTemplateIdPropertyName = null;
257             if ( "true".equals( request.getRequest().getParameter( "jsprintmode" ) ) )
258                 layoutTemplateIdPropertyName = JetspeedDesktopContext.LAYOUT_PRINT_TEMPLATE_ID_PROP;
259             
260             layoutDecorationTemplatePath = desktopContext.getLayoutTemplatePath( layoutTemplateIdPropertyName );
261             layoutDecorationTemplatePathWasAssigned = true;
262             
263             RequestDispatcher dispatcher = request.getRequest().getRequestDispatcher( layoutDecorationTemplatePath );
264             
265             hr.dojoEnable();
266             
267             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_CONTEXT_ATTRIBUTE, desktopContext );
268             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_REQUEST_CONTEXT_ATTRIBUTE, request );
269             request.getRequest().setAttribute( JetspeedDesktopContext.DESKTOP_COMPONENT_MANAGER_ATTRIBUTE, Jetspeed.getComponentManager() );
270             
271             String layoutDecorationName = desktopContext.getLayoutDecorationName();
272             boolean inclStyleLayout = hr.isHeaderSectionIncluded( HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT );
273             String dojoConfigContentCacheKey = DOJO_CONFIG_LAYOUT_VAR_NAME + "." + layoutDecorationName;
274             String dojoConfigContent = getCachedContent( dojoConfigContentCacheKey );
275             
276             if ( dojoConfigContent == null )
277             {
278 	            String portletDecorationsBasePath = decorationFactory.getPortletDecorationsBasePath();
279 	            StringBuffer dojoConfigAddOn = new StringBuffer();
280 	            dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_LAYOUT_DECORATION_PATH_VAR_NAME ).append( " = \"" ).append( desktopContext.getLayoutBasePath() ).append( "\";" ).append( EOL );
281 	            dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_LAYOUT_VAR_NAME ).append( " = \"" ).append( layoutDecorationName ).append( "\";" ).append( EOL );
282 	            dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_PORTLET_DECORATIONS_PATH_VAR_NAME ).append( " = \"" ).append( portletDecorationsBasePath ).append( "\";" ).append( EOL );
283 
284 	            LayoutDecoration desktopLayoutDecoration = decorationFactory.getLayoutDecoration( layoutDecorationName, request );
285 	            if ( desktopLayoutDecoration != null )
286 	            {
287 	            	boolean atLeastOneFound = false;
288 	            	StringBuffer loadingPropsBuffer = new StringBuffer();
289 	                loadingPropsBuffer.append( "    " ).append( DOJO_CONFIG_LOADING_IMGPROPS_NAME ).append( " = { " );
290 	                for ( int i = 0 ; i < DESKTOP_LOADING_PROPERTY_NAMES.length ; i++ )
291 	                {
292 	                    String propValue = desktopLayoutDecoration.getProperty( DESKTOP_LOADING_IMG_NAME_PREFIX + DESKTOP_LOADING_PROPERTY_NAMES[ i ] );
293 	                    if ( propValue != null )
294 	                    {
295 	                        if ( atLeastOneFound )
296 	                        {
297 	                            loadingPropsBuffer.append( ", " );
298 	                        }
299 	                        else
300 	                        {
301 	                        	atLeastOneFound = true;
302 	                        }
303 	                        String usePropertyName = DESKTOP_LOADING_PROPERTY_NAMES[ i ];
304 	                        if ( DESKTOP_LOADING_OUTPUT_PROPERTY_NAMES != null && DESKTOP_LOADING_OUTPUT_PROPERTY_NAMES.length > i && DESKTOP_LOADING_OUTPUT_PROPERTY_NAMES[i] != null )
305 	                        	usePropertyName = DESKTOP_LOADING_OUTPUT_PROPERTY_NAMES[i];
306 	                        	
307 	                        loadingPropsBuffer.append( usePropertyName ).append( ": " ).append( propValue );
308 	                    }
309 	                }
310 	                loadingPropsBuffer.append( " };" );
311 	                if ( atLeastOneFound )
312 	                	dojoConfigAddOn.append( loadingPropsBuffer.toString() ).append( EOL );
313 	                
314 	                addPageEditorSettings( dojoConfigAddOn, desktopLayoutDecoration );
315 	            }
316 	            else
317 	            {
318 	            	log.error( "Failed to find desktop layout decoration " + layoutDecorationName + " - layout decoration properties cannot be added to content." );
319 	            }
320 	            
321 	            Set desktopPortletDecorationsNames = decorationFactory.getDesktopPortletDecorations( request );
322 	            String portletDecorationNamesContent = HeaderResourceLib.makeJSONStringArray( desktopPortletDecorationsNames );
323 	            dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_PORTLET_DECORATIONS_ALLOWED_VAR_NAME ).append( " = " ).append( portletDecorationNamesContent ).append( ";" );
324 
325 	            StringBuffer pDecsOut = new StringBuffer();
326 	            Iterator desktopPortletDecorationsNamesIter = desktopPortletDecorationsNames.iterator();
327 	            while ( desktopPortletDecorationsNamesIter.hasNext() )
328 	            {
329 	                String desktopPortletDecorationName = (String)desktopPortletDecorationsNamesIter.next();
330 	            
331 	                PortletDecoration desktopPortletDecoration = decorationFactory.getPortletDecoration( desktopPortletDecorationName, request );
332 	                
333 	                StringBuffer pOut = new StringBuffer();
334 	                
335 	                String actionButtonOrderContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ACTION_BUTTON_ORDER );
336 	                if ( actionButtonOrderContent != null && actionButtonOrderContent.length() > 0 )
337 	                {
338 	                    pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ACTION_BUTTON_ORDER ).append( ": " ).append( actionButtonOrderContent );
339 	                }
340 	                
341 	                String actionNoImageContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ACTION_NOIMAGE );
342 	                if ( actionNoImageContent != null && actionNoImageContent.length() > 0 )
343 	                {
344 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ACTION_NOIMAGE ).append( ": " ).append( actionNoImageContent );
345 	                }
346 	                
347 	                String actionMenuOrderContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ACTION_MENU_ORDER );
348 	                if ( actionMenuOrderContent != null && actionMenuOrderContent.length() > 0 )
349 	                {
350 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ACTION_MENU_ORDER ).append( ": " ).append( actionMenuOrderContent );
351 	                }
352 	                
353 	                String windowActionButtonTooltip = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ACTION_BUTTON_TOOLTIP );
354 	                if ( windowActionButtonTooltip != null && windowActionButtonTooltip.length() > 0 )
355 	                {
356 	                    pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ACTION_BUTTON_TOOLTIP ).append( ": " ).append( windowActionButtonTooltip );
357 	                }
358 
359 	                String windowActionButtonMax = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ACTION_BUTTON_MAX );
360 	                if ( windowActionButtonMax != null && windowActionButtonMax.length() > 0 )
361 	                {
362 	                    pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ACTION_BUTTON_MAX ).append( ": " ).append( windowActionButtonMax );
363 	                }
364 	                
365 	                String iconEnabledContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ICON_ENABLED );
366 	                if ( iconEnabledContent != null && iconEnabledContent.length() > 0 )
367 	                {
368 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ICON_ENABLED ).append( ": " ).append( iconEnabledContent );
369 	                }
370 	                
371 	                String iconPathContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_ICON_PATH );
372 	                if ( iconPathContent != null && iconPathContent.length() > 0 )
373 	                {
374 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_ICON_PATH ).append( ": " ).append( iconPathContent ).append( ";" ).append( EOL );
375 	                }
376 	                
377 	                String titlebarEnabledContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_TITLEBAR_ENABLED );
378 	                if ( titlebarEnabledContent != null && titlebarEnabledContent.length() > 0 )
379 	                {
380 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_TITLEBAR_ENABLED ).append( ": " ).append( titlebarEnabledContent );
381 	                }
382 	                
383 	                String resizebarEnabledContent = desktopPortletDecoration.getProperty( HeaderResource.HEADER_CONFIG_DESKTOP_WINDOW_RESIZEBAR_ENABLED );
384 	                if ( resizebarEnabledContent != null && resizebarEnabledContent.length() > 0 )
385 	                {
386 	                	pOut.append( ( pOut.length() > 0 ) ? ", " : "" ).append( HeaderResource.DESKTOP_JSON_WINDOW_RESIZEBAR_ENABLED ).append( ": " ).append( resizebarEnabledContent );
387 	                }
388 	                
389 	                if ( pOut.length() > 0 )
390 	                {
391 	                	if ( pDecsOut.length() == 0 )
392 	                	{
393 	                		pDecsOut.append( DOJO_CONFIG_PORTLET_DECORATIONS_CONFIG_VAR_NAME ).append( " = { " );
394 	                	}
395 	                	else
396 	                	{
397 	                		pDecsOut.append( ", " );
398 	                	}
399 	                	pDecsOut.append( "\"" ).append( desktopPortletDecorationName ).append( "\": { " ).append( pOut.toString() ).append( " }" ).append( EOL );
400 	                }
401 	            }   // while ( desktopPortletDecorationsNamesIter.hasNext() )
402 	            if ( pDecsOut.length() > 0 )
403 	            {
404 	            	pDecsOut.append( " }" );
405 		            dojoConfigAddOn.append( EOL ).append( "    " ).append( pDecsOut.toString() ).append( ";" );
406 	            }
407 	            
408 	            dojoConfigContent = dojoConfigAddOn.toString();
409 	            setCachedContent( dojoConfigContentCacheKey, dojoConfigContent );		            
410             }            
411             
412             if ( dojoConfigContent != null )
413             {
414             	hr.addHeaderSectionFragment( DOJO_CONFIG_LAYOUT_VAR_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, dojoConfigContent );
415             }
416             
417             if ( inclStyleLayout )
418             {
419             	String contextPath = request.getRequest().getContextPath();
420             	String styleLayoutContentCacheKey = (HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT + "." + layoutDecorationName + "." + contextPath);
421             	String styleLayoutContent = getCachedContent( styleLayoutContentCacheKey );
422             	if ( styleLayoutContent == null )
423                 {
424             		String portletDecorationsBasePath = decorationFactory.getPortletDecorationsBasePath();
425     	            String portletDecorationsBaseRelative = portletDecorationsBasePath;
426     	            if ( portletDecorationsBaseRelative != null && portletDecorationsBaseRelative.length() > 1 && portletDecorationsBaseRelative.indexOf( '/' ) == 0 )
427     	            {
428     	                portletDecorationsBaseRelative = portletDecorationsBaseRelative.substring( 1 );
429     	            }
430 	                StringBuffer desktopThemeStyleLink = new StringBuffer();
431 	                
432 	                int stylesheetCount = 0;
433 	                Iterator stylesheetIter = theme.getStyleSheets().iterator();
434 	                while ( stylesheetIter.hasNext() )
435 	                {
436 	                    String stylesheetHref = (String)stylesheetIter.next();
437 	                    if ( stylesheetHref != null && stylesheetHref.length() > 0 )
438 	                    {
439 	                        if ( ! stylesheetHref.startsWith( portletDecorationsBaseRelative ) )
440 	                        {   // exclude portlet decorations - in desktop these are loaded via javascript
441 	                            if ( stylesheetCount > 0 )
442 	                            {
443 	                                desktopThemeStyleLink.append( EOL );
444 	                            }
445 	                            
446 	                            desktopThemeStyleLink.append( "<link rel=\"stylesheet\" type=\"text/css\" media=\"screen, projection\" href=\"" );
447 	                            //desktopThemeStyleLink.append( desktopContext.getPortalResourceUrl( stylesheetHref ) ).append( "\"/>" );
448 	                            desktopThemeStyleLink.append( contextPath + "/" + stylesheetHref ).append( "\"/>" );
449 	                            
450 	                            stylesheetCount++;
451 	                        }
452 	                    }
453 	                }
454 	                styleLayoutContent = desktopThemeStyleLink.toString();
455 		            setCachedContent( styleLayoutContentCacheKey, styleLayoutContent );
456                 }
457                 if ( styleLayoutContent != null && styleLayoutContent.length() > 0 )
458                 {
459                 	hr.setHeaderSectionType( HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT, HeaderResource.HEADER_TYPE_LINK_TAG );
460                 	hr.addHeaderSectionFragment( "desktop.style.layout", HeaderResource.HEADER_SECTION_DESKTOP_STYLE_LAYOUT, styleLayoutContent );            	
461                 }
462             }
463             
464             String layoutDecorationLocaleSuffix = "." + layoutDecorationName + "." + request.getLocale().toString();
465             String desktopActionLabelsCacheKey = DOJO_CONFIG_ACTION_LABELS_NAME + layoutDecorationLocaleSuffix;
466             String pageEditorLabelsCacheKey = DOJO_CONFIG_PAGEEDITOR_LABELS_NAME + layoutDecorationLocaleSuffix;
467             String pageEditorDialogLabelsCacheKey = DOJO_CONFIG_PAGEEDITOR_DIALOG_LABELS_NAME + layoutDecorationLocaleSuffix;
468             
469             String desktopActionLabelsContent = getCachedContent( desktopActionLabelsCacheKey );
470             String pageEditorLabelsContent = getCachedContent( pageEditorLabelsCacheKey );
471             String pageEditorDialogLabelsContent = getCachedContent( pageEditorDialogLabelsCacheKey );
472             if ( desktopActionLabelsContent == null || pageEditorLabelsContent == null || pageEditorDialogLabelsContent == null )
473             {
474             	ResourceBundle messages = desktopContext.getLayoutResourceBundle( request.getLocale() );            	
475             	if ( desktopActionLabelsContent == null )
476             	{
477             		desktopActionLabelsContent = getResourcesAsJavascriptObject( DESKTOP_ACTION_RESOURCE_NAME_PREFIX, DESKTOP_ACTION_RESOURCE_NAMES, messages, DOJO_CONFIG_ACTION_LABELS_NAME, "    ", true );
478             		setCachedContent( desktopActionLabelsCacheKey, desktopActionLabelsContent );
479             	}
480             	if ( pageEditorLabelsContent == null )
481             	{
482             		pageEditorLabelsContent = getResourcesAsJavascriptObject( DESKTOP_PAGEEDITOR_RESOURCE_NAME_PREFIX, DESKTOP_PAGEEDITOR_RESOURCE_NAMES, messages, DOJO_CONFIG_PAGEEDITOR_LABELS_NAME, "    ", true );
483             		setCachedContent( pageEditorLabelsCacheKey, pageEditorLabelsContent );
484             	}
485             	if ( pageEditorDialogLabelsContent == null )
486             	{
487             		pageEditorDialogLabelsContent = getResourcesAsJavascriptObject( DESKTOP_PAGEEDITOR_DIALOG_RESOURCE_NAME_PREFIX, DESKTOP_PAGEEDITOR_DIALOG_RESOURCE_NAMES, messages, DOJO_CONFIG_PAGEEDITOR_DIALOG_LABELS_NAME, "    ", true );
488             		setCachedContent( pageEditorDialogLabelsCacheKey, pageEditorDialogLabelsContent );
489             	}
490             }
491             if ( desktopActionLabelsContent != null && desktopActionLabelsContent.length() > 0 )
492             {
493                 hr.addHeaderSectionFragment( DOJO_CONFIG_ACTION_LABELS_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, desktopActionLabelsContent );
494             }
495             if ( pageEditorLabelsContent != null && pageEditorLabelsContent.length() > 0 )
496             {
497                 hr.addHeaderSectionFragment( DOJO_CONFIG_PAGEEDITOR_LABELS_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, pageEditorLabelsContent );
498             }
499             if ( pageEditorDialogLabelsContent != null && pageEditorDialogLabelsContent.length() > 0 )
500             {
501                 hr.addHeaderSectionFragment( DOJO_CONFIG_PAGEEDITOR_DIALOG_LABELS_NAME, HeaderResource.HEADER_SECTION_DOJO_CONFIG, pageEditorDialogLabelsContent );
502             }
503             
504             dispatcher.include( request.getRequest(), request.getResponse() );
505         }
506         catch ( Exception e )
507         {
508             try
509             {
510                 if ( layoutDecorationTemplatePathWasAssigned )
511                 {
512                     layoutDecorationTemplatePath = ( layoutDecorationTemplatePath == null || layoutDecorationTemplatePath.length() == 0 ? "null" : layoutDecorationTemplatePath );
513                     log.error( "Failed to include desktop layout decoration at path " + layoutDecorationTemplatePath, e );
514                     request.getResponse().getWriter().println( "Desktop layout decoration " + layoutDecorationTemplatePath + " is not available" );
515                 }
516                 else
517                 {
518                     log.error( "Failed to initialize for inclusion of desktop layout decoration", e );
519                     request.getResponse().getWriter().println( "Failed to initialize for inclusion of desktop layout decoration" );
520                 }
521             }
522             catch ( IOException ioe )
523             {
524                 log.error( "Failed to write desktop layout decoration exception information to servlet output writer", ioe );
525             }
526         }
527     }
528     
529     private void addPageEditorSettings( StringBuffer dojoConfigAddOn, LayoutDecoration desktopLayoutDecoration )
530     {
531     	int[] pageEditorConfigFlags = new int[] { 0 };
532     	String propValue;
533 
534     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE );
535     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DECORATOR_EDITABLE_TRUE );
536     	
537     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE );
538     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_LAYOUT_NAME_EDITABLE_TRUE );
539     	
540     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE );
541     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_LAYOUT_COLUMNSIZE_EDITABLE_TRUE );
542     	
543     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED );
544     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED_DEFAULT, DESKTOP_PAGEEDITOR_PAGE_ADD_ENABLED_TRUE );
545     	
546     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED );
547     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED_DEFAULT, DESKTOP_PAGEEDITOR_PORTLET_ADD_ENABLED_TRUE );
548     	
549     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE );
550     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_PAGE_PORTLET_DECORATOR_EDITABLE_TRUE );
551 
552     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE );
553     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_PORTLET_DECORATOR_EDITABLE_TRUE );
554 
555     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE );
556     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITABLE_TRUE );
557     	
558     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE );
559     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE_DEFAULT, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_TOPLEVEL_MOVEABLE_TRUE );
560     	
561     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE );
562     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE_DEFAULT, DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_COLUMNSIZE_EDITABLE_TRUE );
563 
564     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT );
565     	processBooleanFlagProperty( pageEditorConfigFlags, propValue, DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT_DEFAULT, DESKTOP_PAGEEDITOR_MOVEMODE_ISDEFAULT_TRUE );
566     	
567     	propValue = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX );
568     	Integer maxLayoutNestingObj = null;
569     	try
570     	{
571     		maxLayoutNestingObj = new Integer( propValue );
572     	}
573     	catch ( NumberFormatException ex )
574     	{
575     		maxLayoutNestingObj = new Integer( DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX_DEFAULT );
576     	}
577     	int maxLayoutNesting = maxLayoutNestingObj.intValue();
578     	if ( maxLayoutNesting < 0 )
579     		maxLayoutNesting = 0;
580     	if ( maxLayoutNesting > DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX_RESERVED )
581     		maxLayoutNesting = DESKTOP_PAGEEDITOR_PAGE_LAYOUT_DEPTH_MAX_RESERVED;
582     	pageEditorConfigFlags[0] += maxLayoutNesting;
583     	    	
584     	String allowEditNoactionsRole = desktopLayoutDecoration.getProperty( DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITOR_ROLE );
585     	if ( allowEditNoactionsRole == null )
586     		allowEditNoactionsRole = DESKTOP_PAGEEDITOR_LAYOUT_NOACTIONS_EDITOR_ROLE_DEFAULT;
587     	if ( allowEditNoactionsRole == null )
588     		allowEditNoactionsRole = "";
589     	char[] allowEditNoactionsRoleChars = allowEditNoactionsRole.toCharArray();
590     	int allowEditNoactionsRoleCharsLen = ( ( allowEditNoactionsRoleChars == null ) ? 0 : allowEditNoactionsRoleChars.length );
591     	Random rnd = new Random();
592     	int extrasCount = ( allowEditNoactionsRoleCharsLen > 0 ? getRandom( rnd, 2, 5 ) : getRandom( rnd, 5, 8 ) );
593     	int hexLen = 1 + extrasCount + allowEditNoactionsRoleCharsLen;
594     	int addedExtras = 0;
595     	int nextRoleChar = 0;
596     	StringBuffer pageEditorSettings = new StringBuffer();
597     	for ( int i = 0 ; i < hexLen ; i++ )
598     	{   // here we "mix-up" (obfuscate) the way this information is provided to the client-side
599     		//    this is done to avoid obvious display of certain strings in content, like "manager" or "admin"
600     		int rndVal = getRandom( rnd, 0x1000, 0xFFFD );
601     		boolean isRndValEven = ( (rndVal % 2) == 0 );
602     		int rndValTens = (int)Math.floor( rndVal / 10 );
603     		int rndValTensEven = ( ( ( rndValTens % 2 ) == 1 ) ? Math.max( rndValTens - 1, 2 ) : rndValTens );
604     		int valToHex;
605     		if ( i == 0 )
606     		{
607     			valToHex = pageEditorConfigFlags[0];
608     		}
609     		else if ( addedExtras < extrasCount && ( ( ( i % 2 ) == 1 ) || nextRoleChar >= allowEditNoactionsRoleCharsLen ) )
610     		{
611     			if ( ! isRndValEven )
612     				rndVal++;
613     			valToHex = getRandom( rnd, 0x0A00, 0xDFFF );
614     			if ( (valToHex % 2) == 1 )
615     				valToHex = valToHex + 1;
616     			pageEditorSettings.append( ", " );
617     			addedExtras++;
618     		}
619     		else
620     		{
621     			//log.info( "char '" + allowEditNoactionsRoleChars[nextRoleChar] + "' numericval=" + (int)allowEditNoactionsRoleChars[nextRoleChar] + " hex=" + Integer.toHexString( (int)allowEditNoactionsRoleChars[nextRoleChar] ) + " hexLshift4=" + Integer.toHexString( (int)allowEditNoactionsRoleChars[nextRoleChar] << 4 ) + " hexLshift4+1=" + Integer.toHexString( ((int)allowEditNoactionsRoleChars[nextRoleChar] << 4 ) | 0x0001 ) );
622     			valToHex = ( ((int)allowEditNoactionsRoleChars[nextRoleChar] << 4 ) | 0x0001 );
623     			pageEditorSettings.append( ", " );
624     			nextRoleChar++;
625     		}
626     		String rndValHex = Integer.toHexString( 0x10000 | rndVal ).substring( 1 );
627     		
628     		String realValHex = Integer.toHexString( 0x10000 | ( valToHex + rndValTensEven ) ).substring( 1 );
629     		if ( isRndValEven && i > 0 )
630     			pageEditorSettings.append( "0x" ).append( realValHex ).append( rndValHex );
631     		else
632     			pageEditorSettings.append( "0x" ).append( rndValHex ).append( realValHex );
633     	}
634     	dojoConfigAddOn.append( "    " ).append( DOJO_CONFIG_PAGEEDITOR_SETTINGS_NAME ).append( " = [ " ).append( pageEditorSettings.toString() ).append( " ];" ).append( EOL );
635     }
636     private int getRandom( Random rnd, int minValueInclusive, int maxValueExclusive )
637     {
638     	if ( minValueInclusive > maxValueExclusive )
639     		throw new IllegalArgumentException( "minValueInclusive (" + minValueInclusive + ") cannot be greater than maxValueExclusive (" + maxValueExclusive + ")" );
640 
641     	int diff = (int)( maxValueExclusive - minValueInclusive );
642     	if ( diff == 0 )
643     		return minValueInclusive;
644 
645     	double sample = rnd.nextDouble();
646     	int result = (int)( sample * diff + minValueInclusive );
647     	result = ( ( result != maxValueExclusive ) ? result : ( result - 1 ) );
648     	return result;
649     }
650     
651     private void processBooleanFlagProperty( int[] flags, Object propVal, Object propValDefault, int propIsTrueBit )
652     {
653         String boolStr = ( ( propVal == null ) ? ( ( propValDefault == null ) ? (String)null : propValDefault.toString() ) : propVal.toString() );
654         if ( boolStr != null && boolStr.toLowerCase().equals( "true" ) )
655         	flags[0] |= propIsTrueBit;
656     }
657 
658     private String getCachedContent( String cacheKey )
659     {
660     	CacheElement cachedElement = desktopContentCache.get(cacheKey);
661         if (cachedElement != null)
662          return (String)cachedElement.getContent();  
663         return null;
664     }
665     private void setCachedContent( String cacheKey, String content )
666     {
667     	CacheElement cachedElement = desktopContentCache.createElement( cacheKey, content );
668     	cachedElement.setTimeToIdleSeconds(desktopContentCache.getTimeToIdleSeconds());
669     	cachedElement.setTimeToLiveSeconds(desktopContentCache.getTimeToLiveSeconds());
670     	desktopContentCache.put( cachedElement );
671     }
672 
673     private String getResourcesAsJavascriptObject( String resourceNamePrefix, String[] resourceNames, ResourceBundle messages, String varName, String indent, boolean ifEmptyReturnEmptyString )
674     {
675     	StringBuffer jsObjBuffer = new StringBuffer();
676         boolean atLeastOneFound = false;
677         if ( indent != null )
678         	jsObjBuffer.append( indent );
679         if ( varName != null )
680         	jsObjBuffer.append( varName ).append( " = " );
681         jsObjBuffer.append( "{ " );
682         for ( int i = 0 ; i < resourceNames.length ; i++ )
683         {
684             String resourceValue = null;
685         	try
686         	{
687         		resourceValue = messages.getString( resourceNamePrefix + resourceNames[ i ] );
688         	}
689         	catch ( java.util.MissingResourceException ex ) { }
690             if ( resourceValue != null )
691             {
692                 if ( atLeastOneFound )
693                 {
694                     jsObjBuffer.append( ", " );
695                 }
696                 else
697                 {
698                 	atLeastOneFound = true;
699                 }
700                 jsObjBuffer.append( resourceNames[ i ] ).append( ": \"" ).append( resourceValue ).append( "\"" );
701             }
702         }
703         jsObjBuffer.append( " };" );
704         if ( ! atLeastOneFound && ifEmptyReturnEmptyString )
705         	return "";
706         return jsObjBuffer.toString();
707     }
708     
709     public boolean isDesktopEnabled( RequestContext requestContext )
710     {
711         return this.decorationFactory.isDesktopEnabled( requestContext );
712     }
713     
714     public ServletContext getServletContext()
715     {
716         return servletContext;
717     }
718 
719     public void setServletContext(ServletContext servletContext)
720     {
721         this.servletContext = servletContext;
722     }
723     
724     public HeaderResourceFactory getHeaderResourceFactory()
725     {
726         return this.headerResourceFactory;
727     }
728     
729     // get portal urls - each of these methods is copied from HeaderResourceImpl.java
730  
731     /***
732      * Desktop servlet path ( e.g. /desktop )
733      * 
734      * @return portal base url
735      */
736     public String getDesktopServletPath()
737     {
738         return this.desktopServletPath;
739     }
740     
741     /***
742      * Portal base url ( e.g. http://localhost:8080/jetspeed )
743      * 
744      * @return portal base url
745      */
746     public String getPortalBaseUrl( RequestContext context )
747     {
748         return HeaderResourceLib.getPortalBaseUrl( context, this.baseUrlAccess );
749     }
750     
751     /***
752      * Portal base url ( e.g. http://localhost:8080/jetspeed )
753      * 
754      * @return portal base url
755      */
756     public String getPortalBaseUrl( RequestContext context, boolean encode )
757     {
758         String baseurl = getPortalBaseUrl( context );
759         if ( ! encode )
760         {
761             return baseurl;
762         }
763         else
764         {
765             return context.getResponse().encodeURL( baseurl );
766         }
767     }
768     
769     /***
770      * Portal base url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/javascript/dojo/ )
771      * 
772      * @return portal base url with relativePath argument appended
773      */
774     public String getPortalResourceUrl( RequestContext context, String relativePath )
775     {
776         return getPortalResourceUrl( context, relativePath, false );
777     }
778     
779     /***
780      * Portal base url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/javascript/dojo/ )
781      * 
782      * @return portal base url with relativePath argument appended
783      */
784     public String getPortalResourceUrl( RequestContext context, String relativePath, boolean encode )
785     {
786         return HeaderResourceLib.getPortalResourceUrl( relativePath, getPortalBaseUrl( context ), encode, context );
787     }
788     
789     /***
790      * Portal base servlet url ( e.g. http://localhost:8080/jetspeed/desktop/ )
791      * 
792      * @return portal base servlet url
793      */
794     public String getPortalUrl( RequestContext context )
795     {
796         return HeaderResourceLib.getPortalUrl( getPortalBaseUrl( context ), context, getDesktopServletPath() );
797     }
798     
799     /***
800      * Portal base servlet url ( e.g. http://localhost:8080/jetspeed/desktop/ )
801      * 
802      * @return portal base servlet url
803      */
804     public String getPortalUrl( RequestContext context, boolean encode )
805     {
806         return getPortalUrl( context, null, encode );
807     }
808     
809     /***
810      * Portal base servlet url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/desktop/default-page.psml )
811      * 
812      * @return portal base servlet url with relativePath argument appended
813      */
814     public String getPortalUrl( RequestContext context, String relativePath )
815     {
816         return getPortalUrl( context, relativePath, false );
817     }
818     
819     /***
820      * Portal base servlet url with relativePath argument appended ( e.g. http://localhost:8080/jetspeed/desktop/default-page.psml )
821      * 
822      * @return portal base servlet url with relativePath argument appended
823      */
824     public String getPortalUrl( RequestContext context, String relativePath, boolean encode )
825     {
826         return HeaderResourceLib.getPortalResourceUrl( relativePath, getPortalUrl( context ), encode, context );
827     }
828 }
829