KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > portal > generic > PortletServlet


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution, if
19  * any, must include the following acknowlegement:
20  * "This product includes software developed by the
21  * Caucho Technology (http://www.caucho.com/)."
22  * Alternately, this acknowlegement may appear in the software itself,
23  * if and wherever such third-party acknowlegements normally appear.
24  *
25  * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * info@caucho.com.
29  *
30  * 5. Products derived from this software may not be called "Resin"
31  * nor may "Resin" appear in their names without prior written
32  * permission of Caucho Technology.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37  * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  *
46  * @author Sam
47  */

48
49 package com.caucho.portal.generic;
50
51 import javax.portlet.*;
52 import javax.servlet.ServletConfig JavaDoc;
53 import javax.servlet.ServletException JavaDoc;
54 import javax.servlet.http.HttpServlet JavaDoc;
55 import javax.servlet.http.HttpServletRequest JavaDoc;
56 import javax.servlet.http.HttpServletResponse JavaDoc;
57 import java.io.IOException JavaDoc;
58 import java.lang.reflect.Constructor JavaDoc;
59 import java.lang.reflect.Modifier JavaDoc;
60 import java.util.*;
61 import java.util.logging.Logger JavaDoc;
62
63 /**
64  * A servlet that uses a class implementing javax.portlet.Portlet.
65  *
66  * This servlet supports the following configuration items.
67  * Items marked with a * can be set as init-param.
68  *
69  * <dl>
70  * <dd>portal
71  * <dt>an instance of {@link Portal}, default is an instance of
72  * {@link GenericPortal}.
73  * <dt>portal-class*
74  * <dd>a class name, an alternative to <code>portal</code>
75  * <dt>portal-ref*
76  * <dd>an attribute name to use for a lookup for a {@link Portal} as
77  * an application attribute. This is an alternative to using
78  * <code>portal</code> and is useful when more than one portlet
79  * servlet share a Portal.
80  * <dt>portlet
81  * <dd>an instance of {@link javax.portlet.Portlet}, required
82  * <dt>portlet-class*
83  * <dd>a class name, an alternative to <code>portlet</code>
84  * <dt>portlet-name*
85  * <dd>a name for the value of
86  * {@link javax.portlet.PortletConfig#getPortletName()},
87  * the default is ServletConfig.getServletName()
88  * <dt>portlet-preferences
89  * <dd>Set the default preferences for the portlet
90  * (see <a HREF="#portlet-preferences">"Portlet Preferences"</a>)
91  * <dt>expiration-cache*
92  * <dd>an integer, a cache time in seconds for the portlet, 0 (the default)
93  * disables and -1 means forever
94  * <dt>private*
95  * <dd>"true" or "false", if true the response is marked as private for
96  * the client, no cache will share the response with other users
97  * <dt>supported-locales*
98  * A comma-separated list of locales of the form "en-us" or "en_us', the
99  * default is to support all locales.
100  * <dt>resource-bundle*
101  * <dd>the name of a resource bundle, the portlet may use the resource bundle
102  * with {@link javax.portlet.PortletConfig#getResourceBundle(Locale)}
103  * <dt>renderer
104  * <dd>an instance of {@link Renderer}, used to add decorations like headers
105  * footers and controls to the portlet, the default is no renderer. See
106  * {@link AbstractRenderer}.
107  * <dt>renderer-class*
108  * <dd>a class name, an alternative to <code>renderer</code>
109  * {@link #setRenderer(Renderer)}.
110  * </dl>
111  *
112  * <h3><a name="portlet-preferences">Portlet Preferences</a></h3>
113  *
114  * <pre>
115  * &lt;servlet servlet-name="portal"
116  * servlet-class="com.caucho.portal.generic.PortletServlet"&gt;
117  *
118  * &lt;init&gt;
119  *
120  * ...
121  *
122  * &lt;portlet-preferences&gt;
123  * &lt;preference name="colour" value="green" read-only="true"/&gt;
124  * or
125  * &lt;preference&gt;
126  * &lt;name&gt;colour&lt;/name&gt;
127  * &lt;value&gt;green&lt;/value&gt;
128  * &lt;read-only&gt;true&lt;/read-only&gt;
129  * &lt;/preference&gt;
130  * &lt;/portlet-preferences&gt;
131  *
132  * ...
133  * &lt;/init&gt;
134  * &lt;/servlet&gt;
135  * </pre>
136  */

137 public class PortletServlet
138   extends HttpServlet JavaDoc
139   implements Window, PortletConfig
140 {
141   static protected final Logger JavaDoc log =
142     Logger.getLogger(PortletServlet.class.getName());
143
144   private Portal _portal;
145   private HttpPortletContext _portletContext;
146
147   private Portlet _portlet;
148   private String JavaDoc _portletName;
149   private String JavaDoc _namespace = "";
150   private Map<String JavaDoc, String JavaDoc> _initParamMap;
151   private int _expirationCache;
152   private boolean _isPrivate;
153   private Renderer _renderer;
154   private int _bufferSize;
155   private Set<Locale> _supportedLocales;
156   private GenericPortletPreferences _defaultPreferences;
157   private ResourceBundleFactory _resourceBundleFactory;
158
159   /**
160    * Default is an instance of {@link GenericPortal}.
161    */

162   public void setPortal(Portal portal)
163   {
164     if (_portal != null)
165       throw new IllegalArgumentException JavaDoc("`portal' already set");
166
167     _portal = portal;
168   }
169
170   /**
171    * An alternative to {@link #setPortal(Portal)}, specify the class
172    * name of an object to instantiate
173    */

174   public void setPortalClass(String JavaDoc className)
175   {
176     setPortal( (Portal) newInstance(Portal.class, className) );
177   }
178
179   /**
180    * An alternative to {@link #setPortal(Portal)}, specify the name
181    * of an attribute to lookup in the ServletContext. This is useful
182    * for sharing a Portal amongst different servlets.
183    */

184   public void setPortalRef(String JavaDoc attributeName)
185   {
186     Portal portal = (Portal) getServletContext().getAttribute(attributeName);
187
188     if (portal == null)
189       throw new IllegalArgumentException JavaDoc(
190           "Portal not found with ServletContext attribute name `"
191           + attributeName + "'");
192
193     setPortal(portal);
194   }
195
196   /**
197    * The namespace is used to uniquely identify this usage of the portlet,
198    * the default is "" (the empty string).
199    *
200    * The namespace is important when using a portlet preferences store,
201    * and also has an effect on the encoding of parameters.
202    */

203   public void setNamespace(String JavaDoc namespace)
204   {
205     _namespace = namespace;
206   }
207
208   /**
209    * The portlet, required. This method can be called in derived classes,
210    * or through the use of depndency injection on containers that support it,
211    * or indirectly using the init param `portlet-class'.
212    */

213   public void setPortlet(Portlet portlet)
214   {
215     if (_portlet != null)
216       throw new IllegalArgumentException JavaDoc("`portlet' is already set");
217
218     _portlet = portlet;
219   }
220
221
222   /**
223    * An alternative to {@link #setPortlet(Portlet)}, specify the class
224    * name of an object to instantiate
225    */

226   public void setPortletClass(String JavaDoc className)
227   {
228     setPortlet( (Portlet) newInstance(Portlet.class, className) );
229   }
230
231   /**
232    * The default is the value of ServletConfig.getServletName()
233    */

234   public void setPortletName(String JavaDoc portletName)
235   {
236     _portletName = portletName;
237   }
238
239   /**
240    * Add an init-param for the portlet. If no init-param are added, the
241    * default behaviour is to expose the Servlet's init-param to the portlet.
242    * If this method is called at least once, the Servlet's init-param are not
243    * exposed to the portlet.
244    */

245   public void addInitParam(String JavaDoc name, String JavaDoc value)
246   {
247     if (_initParamMap == null)
248       _initParamMap = new LinkedHashMap<String JavaDoc, String JavaDoc>();
249
250     _initParamMap.put(name, value);
251   }
252
253   public void addInitParam(NameValuePair nameValuePair)
254   {
255     addInitParam(nameValuePair.getName(), nameValuePair.getValue());
256   }
257
258   /**
259    * Set the default preferences.
260    */

261   public void setPortletPreferences(GenericPortletPreferences defaultPreferences)
262   {
263     _defaultPreferences = defaultPreferences;
264   }
265
266   /**
267    * Enable caching of the response and set the expiration time in seconds. 0
268    * (the default) means do not cache, -1 means unlimited cach time, any other
269    * number is the number of seconds for which the response can be cached.
270    *
271    * Can also be specified with
272    * <a HREF="#init-param">init-param</a> `expiration-cache'.
273    */

274   public void setExpirationCache(int expirationCache)
275   {
276     _expirationCache = expirationCache;
277   }
278
279   /**
280    * If true then the response is private, indicating that it contains
281    * information that should only be provided to the current client, default is
282    * false. Setting this to true has an effect on caching, if true then a
283    * cached value
284    * cannot be shared amongst different users and the effectiveness of caching
285    * is greatly reduced.
286    *
287    * Can also be specified with
288    * <a HREF="#init-param">init-param</a> `private'.
289    */

290   public void setPrivate(boolean isPrivate)
291   {
292     _isPrivate = isPrivate;
293   }
294
295   /**
296    * Add a supported locale, the default is to support all locales.
297    * This is an ordered list, those added first are more preferrable.
298    */

299   void addSupportedLocale(String JavaDoc locale)
300   {
301     String JavaDoc language = "";
302     String JavaDoc country = "";
303     String JavaDoc variant = "";
304
305     String JavaDoc[] split = locale.split("_", 3);
306     int len = split.length;
307
308     if (len == 0) {
309       split = locale.split("-", 3);
310       len = split.length;
311     }
312
313     if (len == 0)
314       throw new IllegalArgumentException JavaDoc(locale);
315
316     language = split[0];
317     if (len > 0)
318       country = split[1];
319     if (len > 1)
320       country = split[2];
321     
322     if (_supportedLocales == null)
323       _supportedLocales = new LinkedHashSet<Locale>();
324
325     _supportedLocales.add(new Locale(language, country, variant));
326   }
327
328   /**
329    * Add supported locales with a comma separated list, the default is to
330    * support all locales. This is an ordered list, those added first are more
331    * preferrable.
332    */

333   void addSupportedLocales(String JavaDoc locales)
334   {
335     String JavaDoc[] split = locales.split("\\s*,\\s*");
336     for (int i = 0; i < split.length; i++)
337       addSupportedLocale(split[i]);
338   }
339
340   /**
341    * Set a resource bundle name, used to instantiate an instance of
342    * ResourceBundleFactory.
343    */

344   public void setResourceBundle(String JavaDoc name)
345   {
346     ResourceBundleFactory resourceBundleFactory =
347       new ResourceBundleFactory();
348
349     resourceBundleFactory.setName(name);
350
351     setResourceBundleFactory(resourceBundleFactory);
352   }
353
354   public void setResourceBundleFactory(ResourceBundleFactory factory)
355   {
356     if (_resourceBundleFactory != null)
357       throw new IllegalArgumentException JavaDoc("resource-bundle-factory already set");
358   }
359
360   /**
361    * A Renderer wraps decorations around the portlet, see
362    * {@link AbstractRenderer}.
363    */

364   public void setRenderer(Renderer renderer)
365   {
366     _renderer = renderer;
367   }
368
369   /**
370    * An alternative to {@link #setRenderer(Renderer)}, specify the class
371    * name of an object to instantiate
372    */

373   public void setRendererClass(String JavaDoc className)
374   {
375     setRenderer( (Renderer) newInstance(Renderer.class, className) );
376   }
377
378   /**
379    * Default is 0
380    */

381   public void setBufferSize(int bufferSize)
382   {
383     _bufferSize = bufferSize;
384   }
385
386   public void init(ServletConfig JavaDoc servletConfig)
387     throws ServletException JavaDoc
388   {
389     super.init(servletConfig);
390
391     String JavaDoc p;
392
393     p = super.getInitParameter("portal-class");
394     if (p != null)
395       setPortalClass( p );
396
397     p = super.getInitParameter("portal-ref");
398     if (p != null)
399       setPortalRef(p);
400
401     if (_portal == null)
402       _portal = new GenericPortal();
403
404     p = super.getInitParameter("portlet-class");
405     if (p != null)
406       setPortletClass( p );
407
408     if (_portlet == null)
409       throw new ServletException JavaDoc("`portlet' is required");
410
411     p = super.getInitParameter("portlet-name");
412     if (p != null)
413       setPortletName(p);
414
415     if (_portletName == null)
416       _portletName = servletConfig.getServletName();
417
418     p = super.getInitParameter("expiration-cache");
419     if (p != null)
420       setExpirationCache(Integer.parseInt(p));
421
422     p = super.getInitParameter("private");
423     if (p != null)
424       setPrivate(Boolean.valueOf(p).booleanValue());
425
426     p = super.getInitParameter("buffer-size");
427     if (p != null)
428       setBufferSize(Integer.parseInt(p));
429
430     p = super.getInitParameter("supported-locales");
431     if (p != null)
432       addSupportedLocales( p );
433
434     p = super.getInitParameter("resource-bundle");
435     if (p != null)
436       setResourceBundle( p );
437
438     p = super.getInitParameter("renderer-class");
439     if (p != null)
440       setRendererClass( p );
441
442     _portletContext = new HttpPortletContext(getServletContext());
443
444     try {
445       _portlet.init(this);
446     }
447     catch (PortletException ex) {
448       throw new ServletException JavaDoc(ex);
449     }
450   }
451
452   protected Object JavaDoc newInstance(Class JavaDoc targetClass, String JavaDoc className)
453     throws IllegalArgumentException JavaDoc
454   {
455     Class JavaDoc cl = null;
456
457     ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
458
459     try {
460       cl = Class.forName(className, false, loader);
461     } catch (ClassNotFoundException JavaDoc e) {
462     }
463
464     if (cl == null)
465       throw new IllegalArgumentException JavaDoc(
466           "`" + className + "' is not a known class");
467
468     if (!targetClass.isAssignableFrom(cl))
469       throw new IllegalArgumentException JavaDoc(
470           "'" + className + "' must implement " + targetClass.getName());
471
472     if (Modifier.isAbstract(cl.getModifiers()))
473       throw new IllegalArgumentException JavaDoc(
474           "'" + className + "' must not be abstract.");
475
476     if (!Modifier.isPublic(cl.getModifiers()))
477       throw new IllegalArgumentException JavaDoc(
478           "'" + className + "' must be public.");
479
480     Constructor JavaDoc []constructors = cl.getDeclaredConstructors();
481
482     Constructor JavaDoc zeroArg = null;
483     for (int i = 0; i < constructors.length; i++) {
484       if (constructors[i].getParameterTypes().length == 0) {
485         zeroArg = constructors[i];
486         break;
487       }
488     }
489
490     if (zeroArg == null || !Modifier.isPublic(zeroArg.getModifiers()))
491       throw new IllegalArgumentException JavaDoc(
492           "'" + className + "' must have a public zero arg constructor");
493
494     Object JavaDoc obj = null;
495
496     try {
497       obj = cl.newInstance();
498     }
499     catch (Exception JavaDoc ex) {
500       throw new IllegalArgumentException JavaDoc(
501           "error instantiating `" + className + "': " + ex.toString(), ex);
502     }
503
504     return obj;
505   }
506
507   public PortletConfig getPortletConfig()
508   {
509     return this;
510   }
511
512   public String JavaDoc getInitParameter(String JavaDoc name)
513   {
514     if (_initParamMap == null)
515       return super.getInitParameter(name);
516     else
517       return _initParamMap.get(name);
518   }
519
520   public Enumeration getInitParameterNames()
521   {
522     if (_initParamMap == null)
523       return super.getInitParameterNames();
524     else
525       return Collections.enumeration(_initParamMap.keySet());
526   }
527
528   /**
529    * {@inheritDoc}
530    */

531   public int getExpirationCache()
532   {
533     return _expirationCache;
534   }
535
536   /**
537    * {@inheritDoc}
538    */

539   public boolean isPrivate()
540   {
541     return _isPrivate;
542   }
543
544   /**
545    * {@inheritDoc}
546    *
547    * This implementation returns true.
548    */

549   public boolean isWindowStateAllowed(PortletRequest request,
550                                       WindowState windowState)
551   {
552     // XXX: todo: support a window-states init-param like
553
// normal, minimized
554
return true;
555   }
556
557   /**
558    * {@inheritDoc}
559    *
560    * This implementation returns true.
561    */

562   public boolean isPortletModeAllowed(PortletRequest request,
563                                       PortletMode portletMode)
564   {
565     // todo: see getSupportedContentTypes()
566
return true;
567   }
568
569   /**
570    * {@inheritDoc}
571    *
572    * This implementation returns null, which means that all content
573    * types are supported.
574    */

575   public Set<String JavaDoc> getSupportedContentTypes(PortletMode portletMode)
576   {
577     // XXX: todo: support a content-type init-param like
578
// edit(text/html), view(text/html, application/pdf)
579
return null;
580   }
581
582   /**
583    * {@inheritDoc}
584    *
585    * This implementation returns null, which means that all locales are
586    * supported.
587    */

588   public Set<Locale> getSupportedLocales()
589   {
590     return _supportedLocales;
591   }
592
593   /**
594    * {@inheritDoc}
595    *
596    * This implementation returns null.
597    */

598   public PortletPreferences getDefaultPreferences()
599   {
600     return _defaultPreferences;
601   }
602
603   /**
604    * {@inheritDoc}
605    */

606   public ArrayList<PreferencesValidator> getPreferencesValidators()
607   {
608     if (_defaultPreferences != null)
609       return _defaultPreferences.getPreferencesValidators();
610     else
611       return null;
612   }
613
614   /**
615    * {@inheritDoc}
616    *
617    * This implementation returns null.
618    */

619   public Map<String JavaDoc, String JavaDoc> getRoleRefMap()
620   {
621     return null;
622     // todo
623
}
624
625   /**
626    * {@inheritDoc}
627    *
628    * This implementation returns null.
629    */

630   public ArrayList<Constraint> getConstraints()
631   {
632     return null;
633     // todo
634
}
635
636   /**
637    * {@inheritDoc}
638    */

639   public Renderer getRenderer()
640   {
641     return _renderer;
642   }
643
644   /**
645    * {@inheritDoc}
646    *
647    * This implementation returns PortletMode.VIEW.
648    */

649   public PortletMode handlePortletModeFailure( PortletRequest request,
650                                                PortletMode notAllowed )
651   {
652     return PortletMode.VIEW;
653   }
654
655
656   /**
657    * {@inheritDoc}
658    *
659    * This implementation returns WindowState.NORMAL.
660    */

661   public WindowState handleWindowStateFailure( PortletRequest request,
662                                                WindowState notAllowed )
663   {
664     return WindowState.NORMAL;
665   }
666
667   /**
668    * {@inheritDoc}
669    *
670    * This implementation does nothing.
671    */

672   public void handleConstraintFailure(RenderRequest request,
673                                       RenderResponse response,
674                                       ConstraintFailureEvent event)
675   {
676   }
677
678
679   /**
680    * {@inheritDoc}
681    *
682    * This implementation does nothing.
683    */

684   public void handleException(RenderRequest request,
685                               RenderResponse response,
686                               ExceptionEvent event)
687   {
688     // XXX: todo: support error-page
689
}
690
691   /**
692    * {@inheritDoc}
693    */

694   public String JavaDoc getPortletName()
695   {
696     return _portletName;
697   }
698
699   /**
700    * {@inheritDoc}
701    */

702   public PortletContext getPortletContext()
703   {
704     return _portletContext;
705   }
706
707   /**
708    * {@inheritDoc}
709    */

710   public ResourceBundle getResourceBundle(Locale locale)
711   {
712     if (_resourceBundleFactory == null)
713       _resourceBundleFactory = new ResourceBundleFactory();
714
715     return _resourceBundleFactory.getResourceBundle(locale);
716   }
717
718   /**
719    * {@inheritDoc}
720    */

721   public int getBufferSize()
722   {
723     return _bufferSize;
724   }
725
726   protected void doGet(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
727     throws ServletException JavaDoc, IOException JavaDoc
728   {
729     doRequest(req, res);
730   }
731
732   protected void doPost(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
733     throws ServletException JavaDoc, IOException JavaDoc
734   {
735     doRequest(req, res);
736   }
737
738   protected void doRequest(HttpServletRequest JavaDoc httpRequest,
739                            HttpServletResponse JavaDoc httpResponse)
740     throws ServletException JavaDoc, IOException JavaDoc
741   {
742     HttpPortletConnection connection = new HttpPortletConnection();
743     connection.start(_portal, _portletContext, httpRequest, httpResponse, true);
744
745     try {
746       Action action = connection.getAction(this, _namespace);
747
748       if (action != null) {
749         try {
750           if (action.isTarget()) {
751             action.processAction(_portlet);
752           }
753         }
754         finally {
755           action.finish();
756         }
757       }
758
759       Render render = connection.getRender(this, _namespace);
760
761       if (render != null) {
762         try {
763           render.render(_portlet);
764         }
765         finally {
766           render.finish();
767         }
768       }
769
770       connection.checkForFailure();
771     }
772     catch (PortletException ex) {
773       throw new ServletException JavaDoc(ex);
774     }
775     finally {
776       connection.finish();
777     }
778   }
779
780   public void destroy()
781   {
782     if (_portlet != null)
783       _portlet.destroy();
784   }
785
786 }
787
788
Popular Tags