1/*2 * Copyright 2000-2001,2004 The Apache Software Foundation.3 * 4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 */1617packageorg.apache.jetspeed.util.template;
1819import org.apache.ecs.ConcreteElement;
20import org.apache.ecs.StringElement;
2122import org.apache.turbine.util.RunData;
23import org.apache.turbine.services.pull.ApplicationTool;
24import org.apache.turbine.services.localization.Localization;
2526import org.apache.jetspeed.portal.Portlet;
27import org.apache.jetspeed.portal.PortletSet;
28import org.apache.jetspeed.portal.PortletControl;
29import org.apache.jetspeed.services.PortalToolkit;
30import org.apache.jetspeed.services.PortletFactory;
31import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
32import org.apache.jetspeed.services.logging.JetspeedLogger;
33import org.apache.jetspeed.services.resources.JetspeedResources;
34import org.apache.jetspeed.services.Profiler;
35import org.apache.jetspeed.services.rundata.JetspeedRunData;
36import org.apache.jetspeed.om.SecurityReference;
37import org.apache.jetspeed.om.profile.PSMLDocument;
38import org.apache.jetspeed.om.profile.Profile;
39import org.apache.jetspeed.om.profile.ProfileException;
40import org.apache.jetspeed.om.profile.Entry;
41import org.apache.jetspeed.modules.ParameterLoader;
42import org.apache.jetspeed.services.security.PortalResource;
43import org.apache.jetspeed.om.registry.Parameter;
44import org.apache.jetspeed.om.registry.PortletEntry;
45import org.apache.jetspeed.om.security.JetspeedUser;
46import org.apache.jetspeed.services.Registry;
47import org.apache.jetspeed.services.JetspeedSecurity;
48import org.apache.jetspeed.portal.security.portlets.PortletWrapper;
49import org.apache.jetspeed.util.JetspeedClearElement;
5051import java.util.Enumeration;
52import java.util.Stack;
53import java.util.Map;
54import java.util.Hashtable;
55import java.util.StringTokenizer;
5657/***58 * Utility class for accessing Jetspeed in a "pull" mode59 *60 * <strong>Since the tool stores a RunData object, it may not be61 * shared between threads and/or requests</strong>62 *63 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>64 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>65 * @author <a href="mark_orciuch@ngsltd.com">Mark Orciuch</a>66 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>67 *68 * @version $Id: JetspeedTool.java,v 1.38 2004/03/29 21:38:43 taylor Exp $69 */70publicclassJetspeedTool implements ApplicationTool
71 {
72/***73 * Static initialization of the logger for this class74 */75privatestaticfinalJetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedTool.class.getName());
7677/*** RunData object for this request */78protectedJetspeedRunData rundata = null;
7980/*** Empty constructor used by introspection81 */82publicJetspeedTool()
83 {
84 }
8586/*** The Tool constructor87 *88 * @param data the RunData object for the current request89 */90publicJetspeedTool(RunData data)
91 {
92this.rundata = (JetspeedRunData)data;
93 }
9495/***96 * This will initialise a JetspeedTool object that was97 * constructed with the default constructor (ApplicationTool98 * method).99 *100 * @param data assumed to be a RunData object101 */102publicvoid init(Object data)
103 {
104this.rundata = (JetspeedRunData)data;
105 }
106107/***108 * Refresh method - does nothing109 */110publicvoid refresh()
111 {
112// empty113 }
114115/*** 116 * Returns the portlet content customized for the current user.117 * Currently, the layout engine does not handle panes, so the 118 * panes are mapped to real PSML files.119 * If the pane name is null or "default", the profiler will automatically120 * chose the PSML content, else the tool will try to load the PSML121 * file with the specified name122 *123 * @param name the name of the pane to render124 * @return the rendered content of the pane125 */126public ConcreteElement getPane(String name)
127 {
128 ConcreteElement result = null;
129 String msg = "";
130131if (null != rundata)
132 {
133Profile profile = rundata.getProfile();
134try135 {
136if (null == profile)
137 {
138 profile = Profiler.getProfile(rundata);
139if (profile == null)
140 {
141thrownewProfileException("Profile not found.");
142 }
143 rundata.setProfile(profile);
144 }
145146if ((name == null) || Profiler.DEFAULT_PROFILE.equals(name) || "".equals(name))
147 ;
148else149 profile.setName(name);
150151PSMLDocument doc = profile.getDocument();
152if (null != doc)
153 {
154 result = PortalToolkit.getSet(doc.getPortlets()).getContent(rundata);
155 }
156 }
157catch (Exception e)
158 {
159 logger.warn("JetspeedTool.getPane: problem getting: "160 + name + " from current request's profile: " + e.toString());
161 msg = e.getMessage();
162 }
163164 }
165166if (result == null)
167 {
168 result = new StringElement("Error retrieving Portal Page: " + msg);
169 }
170171return result;
172 }
173174/***175 * Return the content of a named portlet. This portlet is sought in176 * the current PSML resource.177 *178 * If a control is attached to the portlet description, returns the defined179 * portlet and control, otherwise use the default control.180 *181 * Note: This will return the FIRST portlet with a name = name. Use getPortletById().182 *183 * @param name the name of the portlet to render184 * @return the rendered content of the portlet185 *186 * @deprecated Use getPortletById()187 */188public ConcreteElement getPortlet(String name)
189 {
190 ConcreteElement result = null;
191Portlet found = null;
192 Stack sets = new Stack();
193 sets.push(rundata.getProfile().getRootSet());
194195while ((sets.size() > 0) && (found==null))
196 {
197PortletSet set = (PortletSet)sets.pop();
198199if (set.getName().equals(name))
200 {
201 found = set;
202 }
203else204 {
205 Enumeration en = set.getPortlets();
206while((found==null) && en.hasMoreElements())
207 {
208Portlet p = (Portlet)en.nextElement();
209210// unstack the controls to find the real PortletSets211Portlet real = p;
212while (real instanceof PortletControl)
213 {
214 real = ((PortletControl)p).getPortlet();
215 }
216217if (real instanceof PortletSet)
218 {
219// we'll explore this set afterwards220 sets.push(real);
221 }
222elseif (p.getName().equals(name))
223 {
224 found = p;
225 }
226 }
227 }
228 }
229230if (found!=null)
231 {
232 result = found.getContent(rundata);
233 }
234235if (result==null)
236 {
237//the customizer already streamed its content, return a stub238 result = new ConcreteElement();
239 }
240241return result;
242 }
243244/*** This method retrieves the appropriate customizer portlet for the 245 * current portlet246 *247 * @param p the portlet to customize248 * @param data the RunData for this request249 * @return the portlet object of the appropriate customizer250 */251publicstaticPortlet getCustomizer(Portlet p)
252 {
253Portlet customizer = p;
254255while (p instanceof PortletControl)
256 {
257 p = ((PortletControl)p).getPortlet();
258 }
259260// if the portlet cannot customize itself...261if ( !p.providesCustomization() )
262 {
263264//look for the customizer name in the portlet265//config (from Registry definition)266267 String name = p.getPortletConfig().getInitParameter("_customizer");
268269if (name == null)
270 {
271 String key = (p instanceof PortletSet)?"PortletSet":"Portlet";
272273 name = JetspeedResources.getString("customizer."+key,key+"Customizer");
274 }
275276try277 {
278 customizer = PortletFactory.getPortlet(name, p.getID()+"customize");
279 customizer.getPortletConfig()
280 .setPortletSkin(p.getPortletConfig().getPortletSkin());
281PortletControl control = PortalToolkit.getControl((String)null);
282if (control!=null)
283 {
284 control.setPortlet(customizer);
285 control.init();
286return control;
287 }
288 }
289catch (Exception e)
290 {
291 logger.error("Exception", e);
292 }
293 }
294295return customizer;
296 }
297298/*** This method retrieves the appropriate information portlet for the 299 * current portlet300 *301 * @param p the portlet to display information about302 * @param data the RunData for this request303 * @return the portlet object of the appropriate customizer304 */305publicstaticPortlet getPortletInfoPortlet(RunData data)
306 {
307Portlet info = null;
308309 String name = JetspeedResources.getString("PortletInfoPortlet.name", "PortletInfoPortlet");
310311try {
312313if (null != data)
314 {
315JetspeedRunData jdata = (JetspeedRunData)data;
316Profile profile = jdata.getProfile();
317318if (null == profile)
319 {
320 logger.warn("JetspeedTool: profile is null");
321 profile = Profiler.getProfile(jdata);
322 jdata.setProfile(profile);
323 }
324325Portlet source = findPortlet(data);
326if (source != null) {
327 jdata.setPortlet(source.getName());
328 info = PortletFactory.getPortlet(name, "PortletInfoPortlet");
329 info.getPortletConfig().setPortletSkin(source.getPortletConfig().getPortletSkin());
330PortletControl control = PortalToolkit.getControl((String)null);
331if (control != null)
332 {
333 control.setPortlet(info);
334 control.init();
335return control;
336 }
337 }
338 }
339 } catch (Exception e) {
340 logger.error("Exception", e);
341 }
342343return info;
344 }
345346/***347 * Finds portlet identified by js_peid in the current user's profile348 * 349 * @param rundata for this request350 * @return portlet identified by js_peid351 */352privatestaticPortlet findPortlet(RunData rundata) {
353354Portlet found = null;
355JetspeedRunData jdata = (JetspeedRunData)rundata;
356 String peid = jdata.getJs_peid();
357if (peid != null)
358 {
359 Stack sets = new Stack();
360 sets.push(jdata.getProfile().getRootSet());
361362while ((found==null) && (sets.size() > 0))
363 {
364PortletSet set = (PortletSet)sets.pop();
365366if (set.getID().equals(peid))
367 {
368 found = set;
369 }
370else371 {
372 Enumeration en = set.getPortlets();
373while((found==null) && en.hasMoreElements())
374 {
375Portlet p = (Portlet)en.nextElement();
376377// unstack the controls to find the real PortletSets378Portlet real = p;
379while (real instanceof PortletControl)
380 {
381 real = ((PortletControl)p).getPortlet();
382 }
383384if (real instanceof PortletSet)
385 {
386if (real.getID().equals(peid))
387 {
388 found=real;
389 }
390else391 {
392// we'll explore this set afterwards393 sets.push(real);
394 }
395 }
396elseif (p.getID().equals(peid))
397 {
398 found = p;
399 }
400 }
401 }
402 }
403 }
404405return found;
406 }
407408409/*** 410 * Return the content of a portal element given the id of the element. 411 *412 * @param id The portlet id413 * @return the rendered content of the portlet414 */415public ConcreteElement getPortalElement(String id)
416 {
417 ConcreteElement result = null;
418419if (null != rundata)
420 {
421Profile profile = rundata.getProfile();
422try423 {
424if (null == profile)
425 {
426 System.out.println("profile is null");
427 profile = Profiler.getProfile(rundata);
428 rundata.setProfile(profile);
429 }
430431PSMLDocument doc = profile.getDocument();
432if (null != doc)
433 {
434Entry entry = doc.getEntryById(id);
435if (null == entry)
436 {
437// FIXME: need to write this function438// Portlets ps = doc.getPortletsById(id);439 result = new StringElement("not implemented - PortletElement");
440 }
441else442 {
443Portlet p = PortletFactory.getPortlet( entry );
444if (p != null)
445 {
446 result = p.getContent(rundata);
447 }
448else449 result = new StringElement("Error retrieving PortletElement");
450451 }
452 }
453 }
454catch (Exception e)
455 {
456 logger.error("Exception", e);
457 }
458 }
459460if (result == null)
461 {
462 result = new StringElement("Error fetching pane");
463 }
464465return result;
466467 }
468469/***470 * Return the content of a portlet using the portlet's id (PEID). This portlet is sought in471 * the current PSML resource.472 *473 * If a control is attached to the portlet description, returns the defined474 * portlet and control, otherwise use the default control.475 *476 * @param peid the peid of the portlet to render477 * @return the rendered content of the portlet478 */479public ConcreteElement getPortletById(String peid)
480 {
481 ConcreteElement result = null;
482Portlet found = null;
483 Stack sets = new Stack();
484 sets.push(rundata.getProfile().getRootSet());
485486while ((sets.size() > 0) && (found==null))
487 {
488PortletSet set = (PortletSet)sets.pop();
489490if (set.getID().equals(peid))
491 {
492 found = set;
493 }
494else495 {
496 Enumeration en = set.getPortlets();
497while((found==null) && en.hasMoreElements())
498 {
499Portlet p = (Portlet)en.nextElement();
500501// unstack the controls to find the real PortletSets502Portlet real = p;
503while (real instanceof PortletControl)
504 {
505 real = ((PortletControl)p).getPortlet();
506 }
507508if (real instanceof PortletSet)
509 {
510// we'll explore this set afterwards511 sets.push(real);
512 }
513elseif (p.getID().equals(peid))
514 {
515 found = p;
516 }
517 }
518 }
519 }
520521if (found!=null)
522 {
523// Return portlet's content checking the security first524 result = PortletWrapper.wrap(found).getContent(rundata);
525 }
526527if (result==null)
528 {
529//the customizer already streamed its content, return a stub530 result = new ConcreteElement();
531 }
532533return result;
534 }
535536/***537 * Return the content of a portlet using the portlet's name. This portlet is sought in538 * the registry. This is useful when you want to get portlet's content without539 * actually having the portlet in user's profile (for example, to preview a portlet540 * before adding it to the profile).541 * <P>542 * If a control name is specified to the portlet description, returns the defined543 * portlet and control, otherwise use the default control.544 * <P>545 * Issues to resolve:546 * <UL>547 * <LI>is new portlet instance created everytime someone previews the same portlet?</LI>548 * <LI>should use the same skin as the current pane</LI>549 * <LI>if TitlePortletControl is used, the action icons (max, min, etc) are not functional.550 * Also, customize icon should not be present.</LI>551 * <LI> interactive portlets (such as DatabaseBrowser) lose functionality (such as sorting552 * in DatabaseBrowser).</LI>553 * </UL>554 * 555 * @param portletName556 * Name of the portlet as defined in registry557 * @param controlName558 * Optional control name to use in displaying the portlet559 * @return the rendered content of the portlet560 */561public ConcreteElement getPortletFromRegistry(RunData data)
562 {
563564 ConcreteElement result = null;
565Portlet p = null;
566 String portletName = data.getParameters().getString("p");
567 String controlName = data.getParameters().getString("c");
568569try570 {
571572// Retrieve registry entry573PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portletName);
574575// Verify security for the parameter576boolean canAccess = JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(),
577newPortalResource(entry),
578 JetspeedSecurity.PERMISSION_CUSTOMIZE);
579580if (canAccess)
581 {
582// Always set portlet id to "preview" so each preview request gets it from the cache.583// At least, I think that's how it works.584 p = PortletFactory.getPortlet(portletName, "preview");
585PortletControl control = controlName == null ? PortalToolkit.getControl((String) null)
586 : PortalToolkit.getControl(controlName);
587if (control != null)
588 {
589JetspeedRunData jdata = (JetspeedRunData) rundata;
590// Use the profile's skin591 p.getPortletConfig().setPortletSkin(PortalToolkit.getSkin(jdata.getProfile().getDocument().getPortlets().getSkin()));
592 control.setPortlet(p);
593 control.init();
594 result = control.getContent(rundata);
595 }
596elseif (p != null)
597 {
598 result = p.getContent(rundata);
599 }
600 }
601else602 {
603 result = newJetspeedClearElement(Localization.getString(data, "SECURITY_NO_ACCESS_TO_PORTLET"));
604 }
605 }
606catch (Exception e)
607 {
608 logger.error("Exception", e);
609 result = new ConcreteElement();
610 }
611612if (result == null)
613 {
614//the customizer already streamed its content, return a stub615 result = new ConcreteElement();
616 }
617618return result;
619 }
620621/***622 * Return the content of a portlet using the portlet's name. This portlet is sought in623 * the registry. This is useful when you want to get portlet's content without624 * actually having the portlet in user's profile (for example, to preview a portlet625 * before adding it to the profile).626 * <P>627 * If a control name is specified to the portlet description, returns the defined628 * portlet and control, otherwise use the default control.629 * <P>630 * Issues to resolve:631 * <UL>632 * <LI>is new portlet instance created everytime someone previews the same portlet?</LI>633 * <LI>should use the same skin as the current pane</LI>634 * <LI>if TitlePortletControl is used, the action icons (max, min, etc) are not functional.635 * Also, customize icon should not be present.</LI>636 * <LI> interactive portlets (such as DatabaseBrowser) lose functionality (such as sorting637 * in DatabaseBrowser).</LI>638 * </UL>639 * 640 * @param portletName641 * Name of the portlet as defined in registry642 * @param controlName643 * Optional control name to use in displaying the portlet644 * @return the rendered content of the portlet645 * @deprecated Do not use this method because it's not secure. It will be removed after Beta 5.646 */647public ConcreteElement getPortletFromRegistry(String portletName, String controlName)
648 {
649650 ConcreteElement result = null;
651Portlet p = null;
652653try654 {
655// Always set portlet id to "preview" so each preview request gets it from the cache.656// At least, I think that's how it works.657 p = PortletFactory.getPortlet(portletName, "preview");
658PortletControl control = controlName == null ? PortalToolkit.getControl((String) null)
659 : PortalToolkit.getControl(controlName);
660if (control != null)
661 {
662JetspeedRunData jdata = (JetspeedRunData) rundata;
663// Use the profile's skin664 p.getPortletConfig().setPortletSkin(PortalToolkit.getSkin(jdata.getProfile().getDocument().getPortlets().getSkin()));
665 control.setPortlet(p);
666 control.init();
667 result = control.getContent(rundata);
668 }
669elseif (p != null)
670 {
671 result = p.getContent(rundata);
672 }
673 }
674catch (Exception e)
675 {
676 logger.error("Exception", e);
677 result = new ConcreteElement();
678 }
679680if (result == null)
681 {
682//the customizer already streamed its content, return a stub683 result = new ConcreteElement();
684 }
685686return result;
687 }
688689/***690 * Returns a parameter in its defined parameter style691 * 692 * @param data for this request693 * @param portlet portlet instance694 * @param parmName parameter name695 * @return current parameter value using specified presentation style696 */697publicstatic String getPortletParameter(RunData data, Portlet portlet, String parmName)
698 {
699700if (portlet != null && parmName != null)
701 {
702 String parmValue = portlet.getPortletConfig().getInitParameter(parmName, "");
703return getPortletParameter(data, portlet, parmName, parmValue);
704 }
705706return"";
707 }
708709/***710 * Returns a parameter in its defined parameter style711 * 712 * @param data for this request713 * @param portlet portlet instance714 * @param parmName parameter name715 * @param parmValue current parameter value716 * @return current parameter value using specified presentation style717 */718publicstatic String getPortletParameter(RunData data, Portlet portlet, String parmName, String parmValue)
719 {
720 String result = null;
721try722 {
723if (portlet != null && parmName != null)
724 {
725// Retrieve registry entry and its parameter726PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portlet.getName());
727Parameter param = entry.getParameter(parmName);
728729// Verify security for the parameter730boolean canAccess = JetspeedSecurity.checkPermission((JetspeedUser) data.getUser(),
731newPortalResource(entry, param),
732 JetspeedSecurity.PERMISSION_CUSTOMIZE);
733 Map portletParms = portlet.getPortletConfig().getInitParameters();
734 String parmStyle = portlet.getPortletConfig().getInitParameter(parmName + ".style");
735736// Add portlet reference737 portletParms.put(parmName.concat(".style.portlet"), portlet);
738739if (canAccess)
740 {
741if (parmStyle != null)
742 {
743 result = ParameterLoader.getInstance().eval(data,
744 parmStyle,
745 parmName,
746 parmValue,
747 portletParms);
748 }
749else750 {
751 result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\"";
752 }
753 }
754else755 {
756// If security does not allow access to specific parameter, allow to provide a fallback parameter757 String parmNameNoAccess = portlet.getPortletConfig().getInitParameter(parmName + ".style.no-access");
758if (parmNameNoAccess != null)
759 {
760if (logger.isDebugEnabled())
761 {
762 logger.debug("JetspeedTool: access to parm [" + parmName + "] disallowed, redirecting to parm [" +
763 parmNameNoAccess + "]");
764 }
765 String parmStyleNoAccess = portlet.getPortletConfig().getInitParameter(parmNameNoAccess + ".style");
766 result = ParameterLoader.getInstance().eval(data,
767 parmStyleNoAccess,
768 parmNameNoAccess,
769 parmValue,
770 portletParms);
771 }
772 }
773 }
774 }
775catch (Exception e)
776 {
777 logger.error("Exception", e);
778 }
779780return result;
781 }
782783/***784 * Returns a parameter rendered in specific parameter style785 * 786 * @param data for this request787 * @param parmStyle parameter style788 * @param parmName parameter name789 * @param parmValue current parameter value790 * @param options optional style parameters in delimited format (option1=value1;option2=value2)791 * @return current parameter value using specified presentation style792 */793publicstatic String getParameter(RunData data, String parmStyle, String parmName, String parmValue, String parmOptions)
794 {
795 String result = null;
796try797 {
798if (parmName != null)
799 {
800if (parmStyle != null)
801 {
802 Map options = null;
803if (parmOptions != null && parmOptions.length() > 0)
804 {
805 options = new Hashtable();
806807 StringTokenizer st = new StringTokenizer(parmOptions, ";");
808 String prefix = parmName + ".style.";
809while (st.hasMoreTokens())
810 {
811 StringTokenizer pair = new StringTokenizer(st.nextToken(), "=");
812if (pair.countTokens() == 2)
813 {
814 options.put(prefix + pair.nextToken().trim(), pair.nextToken().trim());
815 }
816 }
817818 }
819 result = ParameterLoader.getInstance().eval(data,
820 parmStyle,
821 parmName,
822 parmValue,
823 options);
824 }
825else826 {
827 result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\"";
828 }
829 }
830 }
831catch (Exception e)
832 {
833 logger.error("Exception", e);
834 result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\"";
835 }
836837return result;
838 }
839840/***841 * Retreives the correct SecurityReference for the portlet based on the current842 * profile and the request.843 */844publicSecurityReference getSecurityReference(Entry entry)
845 {
846return JetspeedSecurity.getSecurityReference(entry, rundata);
847 }
848849publicint getSecuritySource(Entry entry)
850 {
851return JetspeedSecurity.getSecuritySource(entry, rundata);
852 }
853854/***855 * Retreives the Entry object for current portlet based on the 856 * "js_peid" parameter857 */858publicEntry getEntryFromRequest() throws Exception
859 {
860 String jsPeid = rundata.getParameters().getString("js_peid");
861Profile profile = Profiler.getProfile(rundata);
862PSMLDocument doc = profile.getDocument();
863return doc.getEntryById(jsPeid);
864 }
865866 }