/* * Copyright 2000-2001,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jetspeed.util.template; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Stack; import java.util.StringTokenizer; import org.apache.ecs.ConcreteElement; import org.apache.ecs.StringElement; import org.apache.jetspeed.modules.ParameterLoader; import org.apache.jetspeed.om.SecurityReference; import org.apache.jetspeed.om.profile.Control; import org.apache.jetspeed.om.profile.Controller; import org.apache.jetspeed.om.profile.Entry; import org.apache.jetspeed.om.profile.PSMLDocument; import org.apache.jetspeed.om.profile.Portlets; import org.apache.jetspeed.om.profile.Profile; import org.apache.jetspeed.om.profile.ProfileException; import org.apache.jetspeed.om.profile.psml.PsmlControl; import org.apache.jetspeed.om.registry.ClientEntry; import org.apache.jetspeed.om.registry.ClientRegistry; import org.apache.jetspeed.om.registry.Parameter; import org.apache.jetspeed.om.registry.PortletEntry; import org.apache.jetspeed.om.security.JetspeedUser; import org.apache.jetspeed.portal.Portlet; import org.apache.jetspeed.portal.PortletControl; import org.apache.jetspeed.portal.PortletSet; import org.apache.jetspeed.portal.security.portlets.PortletWrapper; import org.apache.jetspeed.services.JetspeedSecurity; import org.apache.jetspeed.services.PortalToolkit; import org.apache.jetspeed.services.PortletFactory; import org.apache.jetspeed.services.Profiler; import org.apache.jetspeed.services.Registry; import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.jetspeed.services.resources.JetspeedResources; import org.apache.jetspeed.services.rundata.JetspeedRunData; import org.apache.jetspeed.services.security.PortalResource; import org.apache.jetspeed.util.JetspeedClearElement; import org.apache.turbine.services.localization.Localization; import org.apache.turbine.services.pull.ApplicationTool; import org.apache.turbine.util.RunData; /** * Utility class for accessing Jetspeed in a "pull" mode * * <strong>Since the tool stores a RunData object, it may not be shared between * threads and/or requests</strong> * * @author <a href="mailto:raphael@apache.org">Rapha�l Luta</a> * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a> * @author <a href="mark_orciuch@ngsltd.com">Mark Orciuch</a> * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a> * * @version $Id: JetspeedTool.java,v 1.38 2004/03/29 21:38:43 taylor Exp $ */ public class JetspeedTool implements ApplicationTool { /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService .getLogger(JetspeedTool.class.getName()); /** RunData object for this request */ protected JetspeedRunData rundata = null; /** * Empty constructor used by introspection */ public JetspeedTool() { } /** * The Tool constructor * * @param data * the RunData object for the current request */ public JetspeedTool(RunData data) { this.rundata = (JetspeedRunData) data; } /** * This will initialise a JetspeedTool object that was constructed with the * default constructor (ApplicationTool method). * * @param data * assumed to be a RunData object */ @Override public void init(Object data) { this.rundata = (JetspeedRunData) data; } /** * Refresh method - does nothing */ @Override public void refresh() { // empty } /** * Returns the portlet content customized for the current user. Currently, the * layout engine does not handle panes, so the panes are mapped to real PSML * files. If the pane name is null or "default", the profiler will * automatically chose the PSML content, else the tool will try to load the * PSML file with the specified name * * @param name * the name of the pane to render * @return the rendered content of the pane */ public ConcreteElement getPane(String name) { ConcreteElement result = null; String msg = ""; if (null != rundata) { Profile profile = rundata.getProfile(); try { if (null == profile) { profile = Profiler.getProfile(rundata); if (profile == null) { throw new ProfileException("Profile not found."); } rundata.setProfile(profile); } if ((name == null) || Profiler.DEFAULT_PROFILE.equals(name) || "".equals(name)) { ; } else { profile.setName(name); } PSMLDocument doc = profile.getDocument(); Portlets portlets = doc.getPortlets(); String useragent = rundata.getUserAgent(); useragent = useragent.trim(); ClientRegistry registry = (ClientRegistry) Registry.get(Registry.CLIENT); ClientEntry entry = registry.findEntry(useragent); if ("IPHONE".equals(entry == null ? null : entry.getManufacturer()) && !Boolean.parseBoolean((String) rundata.getSession().getAttribute( "changeToPc"))) { for (@SuppressWarnings("unchecked") Iterator<Portlets> it = portlets.getPortletsIterator(); it.hasNext();) { Portlets subset = it.next(); { // スケジュールがあればスケジュールを先頭にする。 Entry[] preentrylist = subset.getEntriesArray(); if (preentrylist.length > 0) { int scheduleindex = 0; for (int i = 0; i < preentrylist.length; i++) { if ("Schedule".equals(preentrylist[i].getParent()) || "AjaxScheduleWeekly".equals(preentrylist[i].getParent())) { scheduleindex = i; } subset.removeEntry(0); } subset.addEntry(preentrylist[scheduleindex]); for (int i = 0; i < preentrylist.length; i++) { if (scheduleindex != i) { subset.addEntry(preentrylist[i]); } } } // タイムラインがあればタイムラインを先頭にする。 Entry[] entrylist = subset.getEntriesArray(); if (entrylist.length > 0) { int timelineindex = 0; for (int i = 0; i < entrylist.length; i++) { if ("Timeline".equals(entrylist[i].getParent())) { timelineindex = i; } subset.removeEntry(0); } subset.addEntry(entrylist[timelineindex]); for (int i = 0; i < entrylist.length; i++) { if (timelineindex != i) { subset.addEntry(entrylist[i]); } } } } Controller ctl = subset.getController(); ctl.setName("MenuController"); Control c = subset.getControl(); if (c == null) { c = new PsmlControl(); } if (c.getName() != "MenuControl") { c.setName("MenuControl"); } subset.setControl(c); subset.setController(ctl); } } if (null != doc) { result = PortalToolkit.getSet(doc.getPortlets()).getContent(rundata); } } catch (Exception e) { logger.warn("JetspeedTool.getPane: problem getting: " + name + " from current request's profile: " + e.toString()); msg = e.getMessage(); } } if (result == null) { result = new StringElement("Error retrieving Portal Page: " + msg); } return result; } /** * Return the content of a named portlet. This portlet is sought in the * current PSML resource. * * If a control is attached to the portlet description, returns the defined * portlet and control, otherwise use the default control. * * Note: This will return the FIRST portlet with a name = name. Use * getPortletById(). * * @param name * the name of the portlet to render * @return the rendered content of the portlet * * @deprecated Use getPortletById() */ @Deprecated public ConcreteElement getPortlet(String name) { ConcreteElement result = null; Portlet found = null; Stack sets = new Stack(); sets.push(rundata.getProfile().getRootSet()); while ((sets.size() > 0) && (found == null)) { PortletSet set = (PortletSet) sets.pop(); if (set.getName().equals(name)) { found = set; } else { Enumeration en = set.getPortlets(); while ((found == null) && en.hasMoreElements()) { Portlet p = (Portlet) en.nextElement(); // unstack the controls to find the real PortletSets Portlet real = p; while (real instanceof PortletControl) { real = ((PortletControl) p).getPortlet(); } if (real instanceof PortletSet) { // we'll explore this set afterwards sets.push(real); } else if (p.getName().equals(name)) { found = p; } } } } if (found != null) { result = found.getContent(rundata); } if (result == null) { // the customizer already streamed its content, return a stub result = new ConcreteElement(); } return result; } /** * This method retrieves the appropriate customizer portlet for the current * portlet * * @param p * the portlet to customize * @param data * the RunData for this request * @return the portlet object of the appropriate customizer */ public static Portlet getCustomizer(Portlet p) { Portlet customizer = p; while (p instanceof PortletControl) { p = ((PortletControl) p).getPortlet(); } // if the portlet cannot customize itself... if (!p.providesCustomization()) { // look for the customizer name in the portlet // config (from Registry definition) String name = p.getPortletConfig().getInitParameter("_customizer"); if (name == null) { String key = (p instanceof PortletSet) ? "PortletSet" : "Portlet"; name = JetspeedResources.getString("customizer." + key, key + "Customizer"); } try { customizer = PortletFactory.getPortlet(name, p.getID() + "customize"); customizer.getPortletConfig().setPortletSkin( p.getPortletConfig().getPortletSkin()); PortletControl control = PortalToolkit.getControl((String) null); if (control != null) { control.setPortlet(customizer); control.init(); return control; } } catch (Exception e) { logger.error("Exception", e); } } return customizer; } /** * This method retrieves the appropriate information portlet for the current * portlet * * @param p * the portlet to display information about * @param data * the RunData for this request * @return the portlet object of the appropriate customizer */ public static Portlet getPortletInfoPortlet(RunData data) { Portlet info = null; String name = JetspeedResources.getString( "PortletInfoPortlet.name", "PortletInfoPortlet"); try { if (null != data) { JetspeedRunData jdata = (JetspeedRunData) data; Profile profile = jdata.getProfile(); if (null == profile) { logger.warn("JetspeedTool: profile is null"); profile = Profiler.getProfile(jdata); jdata.setProfile(profile); } Portlet source = findPortlet(data); if (source != null) { jdata.setPortlet(source.getName()); info = PortletFactory.getPortlet(name, "PortletInfoPortlet"); info.getPortletConfig().setPortletSkin( source.getPortletConfig().getPortletSkin()); PortletControl control = PortalToolkit.getControl((String) null); if (control != null) { control.setPortlet(info); control.init(); return control; } } } } catch (Exception e) { logger.error("Exception", e); } return info; } /** * Finds portlet identified by js_peid in the current user's profile * * @param rundata * for this request * @return portlet identified by js_peid */ private static Portlet findPortlet(RunData rundata) { Portlet found = null; JetspeedRunData jdata = (JetspeedRunData) rundata; String peid = jdata.getJs_peid(); if (peid != null) { Stack sets = new Stack(); sets.push(jdata.getProfile().getRootSet()); while ((found == null) && (sets.size() > 0)) { PortletSet set = (PortletSet) sets.pop(); if (set.getID().equals(peid)) { found = set; } else { Enumeration en = set.getPortlets(); while ((found == null) && en.hasMoreElements()) { Portlet p = (Portlet) en.nextElement(); // unstack the controls to find the real PortletSets Portlet real = p; while (real instanceof PortletControl) { real = ((PortletControl) p).getPortlet(); } if (real instanceof PortletSet) { if (real.getID().equals(peid)) { found = real; } else { // we'll explore this set afterwards sets.push(real); } } else if (p.getID().equals(peid)) { found = p; } } } } } return found; } /** * Return the content of a portal element given the id of the element. * * @param id * The portlet id * @return the rendered content of the portlet */ public ConcreteElement getPortalElement(String id) { ConcreteElement result = null; if (null != rundata) { Profile profile = rundata.getProfile(); try { if (null == profile) { System.out.println("profile is null"); profile = Profiler.getProfile(rundata); rundata.setProfile(profile); } PSMLDocument doc = profile.getDocument(); if (null != doc) { Entry entry = doc.getEntryById(id); if (null == entry) { // FIXME: need to write this function // Portlets ps = doc.getPortletsById(id); result = new StringElement("not implemented - PortletElement"); } else { Portlet p = PortletFactory.getPortlet(entry); if (p != null) { result = p.getContent(rundata); } else { result = new StringElement("Error retrieving PortletElement"); } } } } catch (Exception e) { logger.error("Exception", e); } } if (result == null) { result = new StringElement("Error fetching pane"); } return result; } /** * Return the content of a portlet using the portlet's id (PEID). This portlet * is sought in the current PSML resource. * * If a control is attached to the portlet description, returns the defined * portlet and control, otherwise use the default control. * * @param peid * the peid of the portlet to render * @return the rendered content of the portlet */ public ConcreteElement getPortletById(String peid) { ConcreteElement result = null; Portlet found = null; Stack sets = new Stack(); sets.push(rundata.getProfile().getRootSet()); while ((sets.size() > 0) && (found == null)) { PortletSet set = (PortletSet) sets.pop(); if (set.getID().equals(peid)) { found = set; } else { Enumeration en = set.getPortlets(); while ((found == null) && en.hasMoreElements()) { Portlet p = (Portlet) en.nextElement(); // unstack the controls to find the real PortletSets Portlet real = p; while (real instanceof PortletControl) { real = ((PortletControl) p).getPortlet(); } if (real instanceof PortletSet) { // we'll explore this set afterwards sets.push(real); } else if (p.getID().equals(peid)) { found = p; } } } } if (found != null) { // Return portlet's content checking the security first result = PortletWrapper.wrap(found).getContent(rundata); } if (result == null) { // the customizer already streamed its content, return a stub result = new ConcreteElement(); } return result; } /** * Return the content of a portlet using the portlet's name. This portlet is * sought in the registry. This is useful when you want to get portlet's * content without actually having the portlet in user's profile (for example, * to preview a portlet before adding it to the profile). * <P> * If a control name is specified to the portlet description, returns the * defined portlet and control, otherwise use the default control. * <P> * Issues to resolve: * <UL> * <LI>is new portlet instance created everytime someone previews the same * portlet?</LI> * <LI>should use the same skin as the current pane</LI> * <LI>if TitlePortletControl is used, the action icons (max, min, etc) are * not functional. Also, customize icon should not be present.</LI> * <LI>interactive portlets (such as DatabaseBrowser) lose functionality (such * as sorting in DatabaseBrowser).</LI> * </UL> * * @param portletName * Name of the portlet as defined in registry * @param controlName * Optional control name to use in displaying the portlet * @return the rendered content of the portlet */ public ConcreteElement getPortletFromRegistry(RunData data) { ConcreteElement result = null; Portlet p = null; String portletName = data.getParameters().getString("p"); String controlName = data.getParameters().getString("c"); try { // Retrieve registry entry PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portletName); // Verify security for the parameter boolean canAccess = JetspeedSecurity.checkPermission( (JetspeedUser) data.getUser(), new PortalResource(entry), JetspeedSecurity.PERMISSION_CUSTOMIZE); if (canAccess) { // Always set portlet id to "preview" so each preview request gets it // from the cache. // At least, I think that's how it works. p = PortletFactory.getPortlet(portletName, "preview"); PortletControl control = controlName == null ? PortalToolkit.getControl((String) null) : PortalToolkit.getControl(controlName); if (control != null) { JetspeedRunData jdata = rundata; // Use the profile's skin p.getPortletConfig().setPortletSkin( PortalToolkit.getSkin(jdata .getProfile() .getDocument() .getPortlets() .getSkin())); control.setPortlet(p); control.init(); result = control.getContent(rundata); } else if (p != null) { result = p.getContent(rundata); } } else { result = new JetspeedClearElement(Localization.getString( data, "SECURITY_NO_ACCESS_TO_PORTLET")); } } catch (Exception e) { logger.error("Exception", e); result = new ConcreteElement(); } if (result == null) { // the customizer already streamed its content, return a stub result = new ConcreteElement(); } return result; } /** * Return the content of a portlet using the portlet's name. This portlet is * sought in the registry. This is useful when you want to get portlet's * content without actually having the portlet in user's profile (for example, * to preview a portlet before adding it to the profile). * <P> * If a control name is specified to the portlet description, returns the * defined portlet and control, otherwise use the default control. * <P> * Issues to resolve: * <UL> * <LI>is new portlet instance created everytime someone previews the same * portlet?</LI> * <LI>should use the same skin as the current pane</LI> * <LI>if TitlePortletControl is used, the action icons (max, min, etc) are * not functional. Also, customize icon should not be present.</LI> * <LI>interactive portlets (such as DatabaseBrowser) lose functionality (such * as sorting in DatabaseBrowser).</LI> * </UL> * * @param portletName * Name of the portlet as defined in registry * @param controlName * Optional control name to use in displaying the portlet * @return the rendered content of the portlet * @deprecated Do not use this method because it's not secure. It will be * removed after Beta 5. */ @Deprecated public ConcreteElement getPortletFromRegistry(String portletName, String controlName) { ConcreteElement result = null; Portlet p = null; try { // Always set portlet id to "preview" so each preview request gets it from // the cache. // At least, I think that's how it works. p = PortletFactory.getPortlet(portletName, "preview"); PortletControl control = controlName == null ? PortalToolkit.getControl((String) null) : PortalToolkit.getControl(controlName); if (control != null) { JetspeedRunData jdata = rundata; // Use the profile's skin p.getPortletConfig().setPortletSkin( PortalToolkit.getSkin(jdata .getProfile() .getDocument() .getPortlets() .getSkin())); control.setPortlet(p); control.init(); result = control.getContent(rundata); } else if (p != null) { result = p.getContent(rundata); } } catch (Exception e) { logger.error("Exception", e); result = new ConcreteElement(); } if (result == null) { // the customizer already streamed its content, return a stub result = new ConcreteElement(); } return result; } /** * Returns a parameter in its defined parameter style * * @param data * for this request * @param portlet * portlet instance * @param parmName * parameter name * @return current parameter value using specified presentation style */ public static String getPortletParameter(RunData data, Portlet portlet, String parmName) { if (portlet != null && parmName != null) { String parmValue = portlet.getPortletConfig().getInitParameter(parmName, ""); return getPortletParameter(data, portlet, parmName, parmValue); } return ""; } /** * Returns a parameter in its defined parameter style * * @param data * for this request * @param portlet * portlet instance * @param parmName * parameter name * @param parmValue * current parameter value * @return current parameter value using specified presentation style */ public static String getPortletParameter(RunData data, Portlet portlet, String parmName, String parmValue) { String result = null; try { if (portlet != null && parmName != null) { // Retrieve registry entry and its parameter PortletEntry entry = (PortletEntry) Registry.getEntry(Registry.PORTLET, portlet.getName()); Parameter param = entry.getParameter(parmName); // Verify security for the parameter boolean canAccess = JetspeedSecurity.checkPermission( (JetspeedUser) data.getUser(), new PortalResource(entry, param), JetspeedSecurity.PERMISSION_CUSTOMIZE); Map portletParms = portlet.getPortletConfig().getInitParameters(); String parmStyle = portlet.getPortletConfig().getInitParameter(parmName + ".style"); // Add portlet reference portletParms.put(parmName.concat(".style.portlet"), portlet); if (canAccess) { if (parmStyle != null) { result = ParameterLoader.getInstance().eval( data, parmStyle, parmName, parmValue, portletParms); } else { result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\""; } } else { // If security does not allow access to specific parameter, allow to // provide a fallback parameter String parmNameNoAccess = portlet.getPortletConfig().getInitParameter( parmName + ".style.no-access"); if (parmNameNoAccess != null) { if (logger.isDebugEnabled()) { logger.debug("JetspeedTool: access to parm [" + parmName + "] disallowed, redirecting to parm [" + parmNameNoAccess + "]"); } String parmStyleNoAccess = portlet.getPortletConfig().getInitParameter( parmNameNoAccess + ".style"); result = ParameterLoader.getInstance().eval( data, parmStyleNoAccess, parmNameNoAccess, parmValue, portletParms); } } } } catch (Exception e) { logger.error("Exception", e); } return result; } /** * Returns a parameter rendered in specific parameter style * * @param data * for this request * @param parmStyle * parameter style * @param parmName * parameter name * @param parmValue * current parameter value * @param options * optional style parameters in delimited format * (option1=value1;option2=value2) * @return current parameter value using specified presentation style */ public static String getParameter(RunData data, String parmStyle, String parmName, String parmValue, String parmOptions) { String result = null; try { if (parmName != null) { if (parmStyle != null) { Map options = null; if (parmOptions != null && parmOptions.length() > 0) { options = new Hashtable(); StringTokenizer st = new StringTokenizer(parmOptions, ";"); String prefix = parmName + ".style."; while (st.hasMoreTokens()) { StringTokenizer pair = new StringTokenizer(st.nextToken(), "="); if (pair.countTokens() == 2) { options.put(prefix + pair.nextToken().trim(), pair .nextToken() .trim()); } } } result = ParameterLoader.getInstance().eval( data, parmStyle, parmName, parmValue, options); } else { result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\""; } } } catch (Exception e) { logger.error("Exception", e); result = "<input type=\"text\" name=\"" + parmName + "\" value=\"" + parmValue + "\""; } return result; } /** * Retreives the correct SecurityReference for the portlet based on the * current profile and the request. */ public SecurityReference getSecurityReference(Entry entry) { return JetspeedSecurity.getSecurityReference(entry, rundata); } public int getSecuritySource(Entry entry) { return JetspeedSecurity.getSecuritySource(entry, rundata); } /** * Retreives the Entry object for current portlet based on the "js_peid" * parameter */ public Entry getEntryFromRequest() throws Exception { String jsPeid = rundata.getParameters().getString("js_peid"); Profile profile = Profiler.getProfile(rundata); PSMLDocument doc = profile.getDocument(); return doc.getEntryById(jsPeid); } }