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.portals.gems.flash;
18  
19  import java.io.IOException;
20  import java.io.StringWriter;
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.StringTokenizer;
24  import java.util.Collections;
25  import java.util.Properties;
26  
27  import javax.portlet.ActionRequest;
28  import javax.portlet.ActionResponse;
29  import javax.portlet.PortletException;
30  import javax.portlet.PortletPreferences;
31  import javax.portlet.PortletRequest;
32  import javax.portlet.RenderRequest;
33  import javax.portlet.RenderResponse;
34  import javax.portlet.WindowState;
35  import javax.portlet.PortletConfig;
36  
37  import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
38  
39  import org.apache.velocity.context.Context;
40  import org.apache.velocity.app.VelocityEngine;
41  import org.apache.velocity.Template;
42  import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
43  
44  import org.apache.commons.logging.Log;
45  import org.apache.commons.logging.LogFactory;
46  
47  import org.apache.jetspeed.PortalReservedParameters;
48  import org.apache.jetspeed.desktop.JetspeedDesktop;
49  import org.apache.jetspeed.headerresource.HeaderResourceLib;
50  import org.apache.jetspeed.request.RequestContext;
51  
52  public class FlashPortlet extends GenericVelocityPortlet
53  {
54      public static final String HEIGHT_PREF = "HEIGHT";
55      public static final String WIDTH_PREF = "WIDTH";
56      public static final String SRC_PREF = "SRC";
57      public static final String MAX_SRC_PREF = "MAX-SRC";
58      public static final String MAX_HEIGHT_PREF = "MAX-HEIGHT";
59      public static final String MAX_WIDTH_PREF = "MAX-WIDTH";
60   
61      public static final String OBJECT_PARAMS_INITPARAM = "object-params";
62      public static final String OBJECT_ATTRIBUTES_INITPARAM = "object-attributes";
63      public static final String FLASHVARS_INITPARAM = "flashvars";
64      public static final String VIEW_PAGE_INITPARAM = "ViewPage";
65  
66      public static final String PARAM_VIEW_PAGE = "ViewPage";
67      public static final String PARAM_EDIT_PAGE = "EditPage";
68      public static final String PARAM_VIEW_PAGE_DEFAULT = "org/apache/portals/gems/flash/templates/flash-demo.vm";
69      public static final String PARAM_EDIT_PAGE_DEFAULT = "org/apache/portals/gems/flash/templates/edit-prefs.vm";
70      
71      public static final String CODEBASE = "codebase";
72      public static final String CLASSID = "classid";
73      public static final String NODEID = "id";
74      
75      public static final String SRC = "SRC";
76      public static final String WIDTH = "WIDTH";
77      public static final String HEIGHT = "HEIGHT";
78  
79      public static final String WIDTH_ACTUAL = "widthActual";
80      public static final String HEIGHT_ACTUAL = "heightActual";
81      public static final String HEIGHT_PERCENT = "heightPercent";
82      
83      public static final String OBJECT_PARAMS = "PARAMS";
84      public static final String OBJECT_ATTRIBUTES = "ATTRIBUTES";
85      public static final String FLASHVARS = "FLASHVARS";
86      public static final String EXTRA_SIZE_INFO = "EXTRA_SIZE_INFO";
87      
88      public static final String WINDOW_STATE = "windowState";
89      public static final String NAMESPACE = "NAMESPACE";
90      public static final String REPLACECONTENT_NODEID = "REPLACECONTENT_NODEID";
91      public static final String SWF_VERSION = "SWF_VERSION";
92      public static final String SWF_VERSION_DEFAULT = "9.0.0";
93      
94      public static final String SWFOBJECTS_LIB_URL = "SWFOBJECTS_URL";
95      public static final String EXPRESS_INSTALL_URL = "EXPRESS_INSTALL_URL";
96      
97      public static final String IS_DESKTOP = "IS_DESKTOP";
98  
99      protected Log log = LogFactory.getLog( FlashPortlet.class );
100     
101     protected String viewPage = null;
102     protected String editPage = null;
103 
104     private Map object_parameters = null;
105     private Map object_attributes = null;    
106     private Map flash_vars = null;
107 
108     private VelocityEngine engine;
109 
110 
111 	public void init( PortletConfig config ) throws PortletException
112     { 
113         super.init(config);
114 
115         String viewPage = config.getInitParameter( PARAM_VIEW_PAGE );
116         if ( viewPage == null || viewPage.length() == 0 )
117             viewPage = null;
118         this.viewPage = viewPage;
119 
120         String editPage = config.getInitParameter( PARAM_EDIT_PAGE );
121         if ( editPage == null || editPage.length() == 0 )
122             editPage = null;
123         this.editPage = editPage;
124                 
125         Map objParams = parseSemicolonEqualsDelimitedProps( config.getInitParameter( OBJECT_PARAMS_INITPARAM ) );
126         Map objAttrs = parseSemicolonEqualsDelimitedProps( config.getInitParameter( OBJECT_ATTRIBUTES_INITPARAM ) );
127         Map flashVars = parseSemicolonEqualsDelimitedProps( config.getInitParameter( FLASHVARS_INITPARAM ) );
128         
129         if ( objAttrs != null )
130         {
131         	objAttrs.remove( CODEBASE );
132         	objAttrs.remove( CLASSID );
133         	objAttrs.remove( NODEID );
134         	this.object_attributes = Collections.unmodifiableMap( objAttrs );
135         }
136         
137         if ( objParams != null )
138         {
139         	objParams.remove( CODEBASE );
140         	objParams.remove( CLASSID );
141         	objParams.remove( NODEID );
142         	this.object_parameters = Collections.unmodifiableMap( new HashMap( objParams ) );
143         }
144         
145         if ( flashVars != null )
146         	this.flash_vars = Collections.unmodifiableMap( flashVars );
147     }
148 	
149 	protected final Map getDefaultObjectParameters()
150 	{
151 		return this.object_parameters;
152 	}
153 	protected final Map getDefaultObjectAttributes()
154 	{
155 		return this.object_attributes;
156 	}
157 	protected final Map getDefaultFlashVars()
158 	{
159 		return this.flash_vars;
160 	}
161 	protected String getDefaultSwfVersion()
162 	{
163 		return SWF_VERSION_DEFAULT;
164 	}
165 	
166 	protected Map getObjectParameters( RenderRequest request, RenderResponse response, SWFContext swfContext )
167 	{
168 		return this.object_parameters;
169 	}
170 	protected Map getObjectAttributes( RenderRequest request, RenderResponse response, SWFContext swfContext )
171 	{
172 		return this.object_attributes;
173 	}
174 	protected Map getFlashVars( RenderRequest request, RenderResponse response, SWFContext swfContext )
175 	{
176 		return this.flash_vars;
177 	}
178 	
179 	protected void setContextVars( RenderRequest request, RenderResponse response, Context context, SWFContext swfContext )
180 	{
181 		setParameterContextVars( request, response, context, swfContext );
182 		readSwfFileInfo( request, response, context, swfContext );
183 		setSizeContextVars( request, response, context, swfContext );
184 		setFinalContextVars( request, response, context, swfContext );	
185 	}
186 	
187 	protected void setFinalContextVars( RenderRequest request, RenderResponse response, Context context, SWFContext swfContext )
188 	{
189 		String namespace = response.getNamespace();
190 		context.put( NAMESPACE, namespace );
191 		context.put( REPLACECONTENT_NODEID, namespace + "_flash_replace" );
192 		
193 		RequestContext requestContext = (RequestContext)request.getAttribute( PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE );
194 
195         String portalBaseUrl = HeaderResourceLib.getPortalBaseUrl( requestContext );
196 		context.put( SWFOBJECTS_LIB_URL, portalBaseUrl + "/javascript/swfobject/swfobject.js" );
197 		context.put( EXPRESS_INSTALL_URL, portalBaseUrl + "/javascript/swfobject/expressInstall.swf" );
198 		
199         Boolean desktopEnabled = (Boolean)requestContext.getAttribute( JetspeedDesktop.DESKTOP_ENABLED_REQUEST_ATTRIBUTE );
200 		context.put( IS_DESKTOP, ( (desktopEnabled == null) ? Boolean.FALSE : desktopEnabled ) );
201 		
202 		int swfVersion = ( swfContext.getHeader() != null ? swfContext.getHeader().getVersion() : -1 );
203 		if ( swfVersion > 0 )
204 		{
205 			context.put( SWF_VERSION, new Integer( swfVersion ).toString() + ".0.0" );
206 		}
207 		else
208 		{
209 			context.put( SWF_VERSION, getDefaultSwfVersion() );
210 		}
211 		context.put( SRC, swfContext.getSrc() );
212 	}
213 	
214 	protected void setParameterContextVars( RenderRequest request, RenderResponse response, Context context, SWFContext swfContext )
215 	{
216 		context.put( OBJECT_PARAMS, HeaderResourceLib.makeJSONObject( getObjectParameters( request, response, swfContext ), true ).toString() );
217 		
218 		Map objNodeIdMap = new HashMap();
219 		objNodeIdMap.put( "id", response.getNamespace() + "_objnode" );
220 		Map[] attrMaps = new Map[] { getObjectAttributes( request, response, swfContext ), objNodeIdMap };
221 		context.put( OBJECT_ATTRIBUTES, HeaderResourceLib.makeJSONObject( attrMaps, true ).toString() );
222 		
223 		context.put( FLASHVARS, HeaderResourceLib.makeJSONObject( getFlashVars( request, response, swfContext ), true ).toString() );
224 	}
225 	
226 	protected void readSwfFileInfo( RenderRequest request, RenderResponse response, Context context, SWFContext swfContext )
227 	{
228         String swfSrc = swfContext.getSrc();
229         int swfSrcLen = ( swfSrc != null ? swfSrc.length() : 0 );
230         if ( swfSrcLen > 0 )
231         {
232         	SWFHeader swfH = new SWFHeader();
233             String contextPath = request.getContextPath();
234             int contextPathLen = ( contextPath != null ? contextPath.length() : 0 );
235             if ( contextPathLen > 0 && swfSrcLen > contextPathLen && swfSrc.startsWith( contextPath ) )
236             {
237             	swfSrc = swfSrc.substring( contextPathLen );
238             }
239             if ( swfH.parseHeader( this.getPortletContext().getResourceAsStream( swfSrc ) ) )
240             {
241             	swfContext.setHeader( swfH );
242             }
243         }
244 	}
245 	
246 	protected void setSizeContextVars( RenderRequest request, RenderResponse response, Context context, SWFContext swfContext )
247 	{
248 		String swfHeight = swfContext.getHeight();
249 		String swfWidth = swfContext.getWidth();
250 		String swfHeightActual = null;
251 		String swfWidthActual = null;
252 		SWFHeader header = swfContext.getHeader();
253 		if ( header != null )
254 		{
255 			if ( header.getHeight() > 0 )
256 				swfHeightActual = new Integer( header.getHeight() ).toString();
257         	if ( header.getWidth() > 0 )
258         		swfWidthActual = new Integer( header.getWidth() ).toString();
259 		}
260 
261 		boolean isMaximized = swfContext.isMaximized();
262 		if ( swfHeight == null )
263 		{
264 			if ( swfHeightActual != null )
265 				swfHeight = swfHeightActual;
266 			else
267 				swfHeight = ( isMaximized ? "800" : "250" );
268 			swfContext.setHeight( swfHeight );
269 		}
270 		if ( swfWidth == null )
271 		{
272 			swfWidth = "100%";    // ( isMaximized ? "600" : "250" );
273 			swfContext.setWidth( swfWidth );
274 		}
275 		context.put( HEIGHT, swfHeight );
276         context.put( WIDTH, swfWidth );
277         
278         Map extraSizeVars = new HashMap();
279         if ( swfHeightActual != null )
280         	extraSizeVars.put( HEIGHT_ACTUAL, swfHeightActual );
281         if ( swfWidthActual != null )
282         	extraSizeVars.put( WIDTH_ACTUAL, swfWidthActual );
283         
284         String heightPercent = swfContext.getHeightPercentage();
285         if ( heightPercent != null )
286         	extraSizeVars.put( HEIGHT_PERCENT, heightPercent );
287         
288         context.put( EXTRA_SIZE_INFO, HeaderResourceLib.makeJSONObject( extraSizeVars, true ).toString() );
289 	}
290        
291     public void doView(RenderRequest request, RenderResponse response)
292         throws PortletException, IOException
293     {
294         Context context = super.getContext(request);
295         PortletPreferences prefs = request.getPreferences();
296         
297         String swfSrc = null;
298         String swfHeight = null;
299         String swfWidth = null;
300         boolean isMaximized = false;
301         
302         if ( request.getWindowState().toString().equals( WindowState.MAXIMIZED.toString() ) )
303         {
304         	isMaximized = true;
305         	swfHeight = prefs.getValue( MAX_HEIGHT_PREF, null );
306             swfWidth = prefs.getValue( MAX_WIDTH_PREF, null );
307             swfSrc = prefs.getValue( MAX_SRC_PREF, null );
308         }
309         
310         if ( swfHeight == null || swfHeight.length() == 0 )
311         	swfHeight = prefs.getValue( HEIGHT_PREF, null );
312         
313         if ( swfWidth == null || swfWidth.length() == 0 )
314         	swfWidth = prefs.getValue( WIDTH_PREF, null );
315         
316         if ( swfSrc == null || swfSrc.length() == 0 )
317         	swfSrc = prefs.getValue( SRC_PREF, null );
318 
319         context.put( WINDOW_STATE, ( (! isMaximized) ? "normal" : "max" ) );
320         
321         SWFContext swfContext = new SWFContext( swfSrc, swfHeight, swfWidth, isMaximized );
322         setContextVars( request, response, context, swfContext );
323         
324         if ( this.viewPage != null )
325         {
326             super.doView( request, response );
327         }
328         else
329         {
330             processClasspathTemplate( PARAM_VIEW_PAGE_DEFAULT, context, response );
331         }
332     }
333 
334     public void doEdit( RenderRequest request, RenderResponse response ) throws PortletException, IOException
335     {
336         if ( this.editPage != null )
337         {
338             response.setContentType("text/html");
339             doPreferencesEdit(request, response);
340         }
341         else
342         {
343             setupPreferencesEdit( request, response );
344             processClasspathTemplate( PARAM_EDIT_PAGE_DEFAULT, getContext( request ), response );
345         }
346     }
347 
348     protected void processClasspathTemplate( String classpathTemplate, Context context, RenderResponse response ) throws PortletException
349     {
350         response.setContentType("text/html");
351         VelocityEngine vEngine = null;
352         synchronized ( this )
353         {
354             vEngine = this.engine;
355             if ( vEngine == null )
356             {
357                 vEngine = new VelocityEngine();
358                 configureClasspathVelocityEngine( vEngine );
359                 this.engine = vEngine;
360             }
361         }
362 
363         try
364         {
365             Template template = vEngine.getTemplate( classpathTemplate );
366         
367             StringWriter writer = new StringWriter();
368             template.merge( context, writer );
369             writer.close();
370             
371             response.getPortletOutputStream().write( writer.getBuffer().toString().getBytes() );
372             response.getPortletOutputStream().flush();
373         }
374         catch ( Exception ex )
375         {
376             String errMsg = "Failed to generate content with classpath based VelocityEngine for " + this.getClass().getName() + " due to " + ex.getClass().getName() + " " + ex.getMessage();
377             log.error( errMsg );
378             throw new PortletException( errMsg );
379         }
380     }
381 
382     protected void configureClasspathVelocityEngine( VelocityEngine vEngine ) throws PortletException
383     {
384         try
385         {
386             Properties props = new Properties();
387             props.setProperty( VelocityEngine.RESOURCE_LOADER, "classpath" );
388             props.setProperty( "classpath." + VelocityEngine.RESOURCE_LOADER + ".class", ClasspathResourceLoader.class.getName() );
389             vEngine.init( props );
390         }
391         catch ( Exception ex )
392         {
393             String errMsg = "Failed to configure classpath based VelocityEngine for " + this.getClass().getName() + " due to " + ex.getClass().getName() + " " + ex.getMessage();
394             log.error( errMsg );
395             throw new PortletException( errMsg );
396         }
397     }
398 
399 
400     /* (non-Javadoc)
401      * @see org.apache.portals.bridges.velocity.GenericVelocityPortlet#processAction(javax.portlet.ActionRequest, javax.portlet.ActionResponse)
402      */
403     public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException
404     {
405         String source = request.getParameter(SRC_PREF);
406         String height = request.getParameter(HEIGHT_PREF);
407         String width = request.getParameter(WIDTH_PREF);
408         String maxSource = request.getParameter(MAX_SRC_PREF);
409         String maxHeight = request.getParameter(MAX_HEIGHT_PREF);
410         String maxWidth = request.getParameter(MAX_WIDTH_PREF);
411         
412         PortletPreferences prefs = request.getPreferences();
413         prefs.setValue(SRC_PREF, source);
414         prefs.setValue(HEIGHT_PREF, height);
415         prefs.setValue(WIDTH_PREF, width);
416         prefs.setValue(MAX_SRC_PREF, maxSource);
417         prefs.setValue(MAX_HEIGHT_PREF, maxHeight);
418         prefs.setValue(MAX_WIDTH_PREF, maxWidth);        
419         prefs.store();
420         super.processAction(request, response);
421     }
422     
423     public Map parseSemicolonEqualsDelimitedProps( String propsStr )
424     {
425         if ( propsStr == null || propsStr.length() == 0 )
426             return null;
427         Map props = new HashMap();
428         StringTokenizer parser = new StringTokenizer( propsStr, ";" );
429         String token, propNm, propVal;
430         int eqPos;
431         while ( parser.hasMoreTokens() )
432         {
433             token = parser.nextToken();
434             eqPos = token.indexOf( '=' );
435             if ( eqPos > 0 )
436             {
437             	propNm = token.substring( 0, eqPos );
438             	if ( eqPos < (token.length() -1) )
439             	{
440             		propVal = token.substring( eqPos + 1 );
441             		props.put( propNm.toLowerCase(), propVal );
442             	}
443             }
444         }
445         return props;
446     }
447     
448     protected class SWFContext
449     {
450     	private String src;
451     	private SWFHeader header;
452     	private String height;
453     	private String height_percentage;
454     	private String width;
455     	private boolean is_maximized;
456     	public SWFContext( String swfSrc, String swfHeight, String swfWidth, boolean isMaximized )
457     	{
458     		setSrc( swfSrc );
459     		setHeight( swfHeight );
460     		setWidth( swfWidth );
461     		this.is_maximized = isMaximized;
462     	}
463 		public String getSrc()
464 		{
465         	return src;
466         }
467 		public void setSrc( String src )
468 		{
469 			if ( src == null || src.length() == 0 )
470 				src = null;
471         	this.src = src;
472         }
473 		public SWFHeader getHeader()
474 		{
475         	return header;
476         }
477 		public void setHeader( SWFHeader swfHeader )
478 		{
479         	this.header = swfHeader;
480         }
481 		public String getHeight()
482 		{
483         	return height;
484         }
485 		public void setHeight( String height )
486 		{
487 			if ( height == null || height.length() == 0 )
488 				height = null;
489 			else
490 			{
491 				height = height.trim();
492 				if ( height.endsWith("%") )
493 				{
494 					if ( height.length() > 1 )
495 					{
496 						this.height_percentage = height;
497 					}
498 					height = null;
499 				}
500 			}
501         	this.height = height;
502         }
503 		public String getHeightPercentage()
504 		{
505         	return height_percentage;
506         }
507 		public String getWidth()
508 		{
509         	return width;
510         }
511 		public void setWidth( String width )
512 		{
513 			if ( width == null || width.length() == 0 )
514 				width = null;
515         	this.width = width;
516         }
517 		public boolean isMaximized()
518 		{
519         	return is_maximized;
520         }
521     }
522 }