org.apache.jetspeed.velocity.JetspeedPowerToolImpl Maven / Gradle / Ivy
Show all versions of jetspeed-portal Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.velocity;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.security.Principal;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.portlet.PortletConfig;
import javax.portlet.PortletMode;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import javax.security.auth.Subject;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.jetspeed.Jetspeed;
import org.apache.jetspeed.PortalReservedParameters;
import org.apache.jetspeed.aggregator.PortletRenderer;
import org.apache.jetspeed.capabilities.CapabilityMap;
import org.apache.jetspeed.container.PortletWindow;
import org.apache.jetspeed.container.url.BasePortalURL;
import org.apache.jetspeed.locator.LocatorDescriptor;
import org.apache.jetspeed.locator.TemplateDescriptor;
import org.apache.jetspeed.locator.TemplateLocator;
import org.apache.jetspeed.locator.TemplateLocatorException;
import org.apache.jetspeed.om.page.ContentFragment;
import org.apache.jetspeed.om.page.Page;
import org.apache.jetspeed.portlet.HeaderPhaseSupportConstants;
import org.apache.jetspeed.request.RequestContext;
import org.apache.jetspeed.util.ArgUtil;
import org.apache.jetspeed.util.DOMUtils;
import org.apache.jetspeed.util.KeyValue;
import org.apache.jetspeed.util.Path;
import org.apache.velocity.context.Context;
import org.w3c.dom.Element;
/**
*
* JetspeedPowerTool
*
*
* The JetspeedPowerTool is meant to be used by template designers to build
* templates for internal Jetspeed portlet applications. It hides the
* implementation details of the more common template actions so that future
* changes to said implementation have minimal effect on template.
*
*
* Where applicable, methods have been marked with a BEST PRATICES
* meaning that this method should be used instead the synonymous code
* listed within the method docuementation.
*
*
* @author Scott T. Weaver
* @version $Id: JetspeedPowerToolImpl.java 767444 2009-04-22 10:08:53Z ate $
*
*/
public class JetspeedPowerToolImpl implements JetspeedVelocityPowerTool
{
private static final String DECORATOR_ID_ATTR = "decoratorId";
private static final String ACTION_IMAGE_EXTENSION_ATTR = "actionImageExtension";
protected static final String PORTLET_CONFIG_ATTR = "javax.portlet.config";
protected static final String RENDER_RESPONSE_ATTR = "javax.portlet.response";
protected static final String RENDER_REQUEST_ATTR = "javax.portlet.request";
protected static final String COLUMNS_ATTR = "columns";
protected static final String COLUMN_SIZES = "columnSizes";
protected RenderRequest renderRequest;
protected RenderResponse renderResponse;
protected PortletConfig portletConfig;
protected Writer templateWriter;
protected static final Logger log = LoggerFactory.getLogger(JetspeedPowerToolImpl.class);
protected CapabilityMap capabilityMap;
protected Locale locale;
protected LocatorDescriptor templateLocatorDescriptor;
protected TemplateLocator templateLocator;
protected TemplateLocator decorationLocator;
protected LocatorDescriptor decorationLocatorDescriptor;
protected RequestContext requestContext;
protected Context velocityContext;
private BasePortalURL baseUrlAccess;
private PortletRenderer renderer;
public JetspeedPowerToolImpl(RequestContext requestContext, PortletConfig portletConfig, RenderRequest renderRequest, RenderResponse renderResponse, PortletRenderer renderer) throws Exception
{
HttpServletRequest request = requestContext.getRequest();
this.requestContext = requestContext;
try
{
baseUrlAccess = (BasePortalURL) getComponent("BasePortalURL");
}
catch (Exception e)
{
// BasePortalURL is optional: ignore (org.springframework.beans.factory.NoSuchBeanDefinitionException)
}
this.portletConfig = portletConfig;
this.renderRequest = renderRequest;
this.renderResponse = renderResponse;
templateLocator = (TemplateLocator) getComponent("TemplateLocator");
decorationLocator = (TemplateLocator) getComponent("DecorationLocator");
// By using null, we create a re-useable locator
capabilityMap = requestContext.getCapabilityMap();
locale = requestContext.getLocale();
templateLocatorDescriptor = templateLocator.createLocatorDescriptor(null);
templateLocatorDescriptor.setMediaType(capabilityMap.getPreferredMediaType().getName());
templateLocatorDescriptor.setCountry(locale.getCountry());
templateLocatorDescriptor.setLanguage(locale.getLanguage());
decorationLocatorDescriptor = decorationLocator.createLocatorDescriptor(null);
decorationLocatorDescriptor.setMediaType(capabilityMap.getPreferredMediaType().getName());
decorationLocatorDescriptor.setCountry(locale.getCountry());
decorationLocatorDescriptor.setLanguage(locale.getLanguage());
this.renderer = renderer;
}
/**
*
* getRequestContext
*
*
* @return
*/
protected final RequestContext getRequestContext()
{
return requestContext;
}
/**
* Gets the window state for the current portlet window (fragment)
*
* @return The window state for the current window
* @throws Exception
*/
public WindowState getWindowState() throws Exception
{
try
{
PortletWindow window = getPortletWindow(getCurrentFragment());
if (!window.isValid())
{
// return a sensible default value to allow a mimimum level of processing to continue
return WindowState.NORMAL;
}
return getRequestContext().getPortalURL().getNavigationalState().getState(window);
}
catch (Exception e)
{
handleError(e, e.toString(), getCurrentFragment());
// return a sensible default value to allow a mimimum level of processing to continue
return WindowState.NORMAL;
}
}
/**
* Gets the internal (portal) window state for the current portlet window (fragment)
*
* @return The window state for the current window
* @throws Exception
*/
public WindowState getMappedWindowState() throws Exception
{
try
{
PortletWindow window = getPortletWindow(getCurrentFragment());
if (!window.isValid())
{
// return a sensible default value to allow a mimimum level of processing to continue
return WindowState.NORMAL;
}
return getRequestContext().getPortalURL().getNavigationalState().getMappedState(window);
}
catch (Exception e)
{
handleError(e, e.toString(), getCurrentFragment());
// return a sensible default value to allow a mimimum level of processing to continue
return WindowState.NORMAL;
}
}
/**
* Gets the portlet mode for a current portlet window (fragment)
*
* @return The portlet mode of the current window
* @throws Exception
*/
public PortletMode getPortletMode() throws Exception
{
try
{
PortletWindow window = getPortletWindow(getCurrentFragment());
if (!window.isValid())
{
// return a sensible default value to allow a mimimum level of processing to continue
return PortletMode.VIEW;
}
return getRequestContext().getPortalURL().getNavigationalState().getMode(window);
}
catch (Exception e)
{
handleError(e, e.toString(), getCurrentFragment());
// return a sensible default value to allow a mimimum level of processing to continue
return PortletMode.VIEW;
}
}
/**
* Gets the internal (portal) portlet mode for a current portlet window (fragment)
*
* @return The portlet mode of the current window
* @throws Exception
*/
public PortletMode getMappedPortletMode() throws Exception
{
try
{
PortletWindow window = getPortletWindow(getCurrentFragment());
if (!window.isValid())
{
// return a sensible default value to allow a mimimum level of processing to continue
return PortletMode.VIEW;
}
return getRequestContext().getPortalURL().getNavigationalState().getMappedMode(window);
}
catch (Exception e)
{
handleError(e, e.toString(), getCurrentFragment());
// return a sensible default value to allow a mimimum level of processing to continue
return PortletMode.VIEW;
}
}
/**
*
* @return
*/
public ContentFragment getCurrentFragment()
{
checkState();
return (ContentFragment) renderRequest.getAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE);
}
/**
*
* @param f
*/
public void setCurrentFragment(ContentFragment f)
{
checkState();
setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, f);
}
public void setCurrentLayout()
{
checkState();
ContentFragment f = (ContentFragment) getRequestContext().getRequest().getAttribute(LAYOUT_ATTR);
setAttribute(LAYOUT_ATTR, f);
}
/**
*
* @return
*/
public ContentFragment getCurrentLayout()
{
checkState();
return (ContentFragment) renderRequest.getAttribute(LAYOUT_ATTR);
}
/**
*
* @return
*/
public Page getPage()
{
checkState();
// return (Page)
// renderRequest.getAttribute(PortalReservedParameters.PAGE_ATTRIBUTE_KEY);
return requestContext.getPage();
}
/**
*
* @return
*/
public List[] getColumns()
{
checkState();
return (List[]) renderRequest.getAttribute(COLUMNS_ATTR);
}
public List getColumnSizes()
{
checkState();
Object o = renderRequest.getAttribute(COLUMN_SIZES);
if (o == null)
return null;
return (List) renderRequest.getAttribute(COLUMN_SIZES);
}
/**
*
* @param f
* Fragment whose PortletWindow
we want to
* retrieve.
* @return The PortletWindow represented by the current fragment.
* @throws Exception
*/
public PortletWindow getPortletWindow(ContentFragment f) throws Exception
{
return getRequestContext().getPortletWindow(f);
}
/**
* Checks the the visibilty of this fragment with respect to the current
* RenderReqeust.
*
* @param f
* Fragment
* @return whether or not the Fragment in question should be considered
* visible during rendering.
*/
public boolean isHidden(ContentFragment f)
{
checkState();
if (f == null)
{
throw new IllegalArgumentException("Fragment cannot be null for isHidden(Fragment)");
}
return f.getState() != null && f.getState().equals(HIDDEN);
}
/**
* Retreives a template using Jetspeed's
*
* @see org.apache.jetspeed.locator.TemplateLocator
*
*
* @param path
* Expected to the template. This may actually be changed by the
* TL service based the capability and localization information
* provided by the client.
* @param templateType
* Type off template we are interested in.
* @return Template object containng the pertinent information required to
* inlcude the request template path in the current response
* @throws TemplateLocatorException
* if the path
does not exist.
*/
public TemplateDescriptor getTemplate(String path, String templateType) throws TemplateLocatorException
{
checkState();
return getTemplate(path, templateType, templateLocator, templateLocatorDescriptor);
}
public Configuration getTypeConfiguration(String type, String name, String location) throws Exception
{
ArgUtil.assertNotNull(String.class, type, this, "getTypeConfiguration(String type, String name)");
ArgUtil.assertNotNull(String.class, name, this, "getTypeConfiguration(String type, String name)");
try
{
TemplateDescriptor locator = null;
if (location.equals("templates"))
{
locator = getTemplate(name + "/" + type + ".properties", type);
}
else if (location.equals("decorations"))
{
locator = getDecoration(name + "/decorator.properties", type);
}
else
{
throw new IllegalArgumentException("Location type " + location
+ " is not supported by getTypeConfiguration().");
}
return new PropertiesConfiguration(locator.getAbsolutePath());
}
catch (TemplateLocatorException e)
{
log.warn(e.toString(), e);
return null;
}
}
public TemplateDescriptor getDecoration(String path, String templateType) throws TemplateLocatorException
{
checkState();
return getTemplate(path, templateType, decorationLocator, decorationLocatorDescriptor);
}
public String includeTemplate(String template, String templateType) throws IOException
{
checkState();
try
{
TemplateDescriptor useLocator = getTemplate(template, templateType);
return useLocator.getAppRelativePath();
}
catch (Exception e)
{
PrintWriter directError = new PrintWriter(renderResponse.getWriter());
directError.write("Error occured process includeTemplate(): " + e.toString() + "\n\n");
e.printStackTrace(directError);
directError.close();
return "";
}
}
public String includeDecoration(String template, String templateType) throws IOException
{
checkState();
try
{
return getDecoration(template, templateType).getAppRelativePath();
}
catch (Exception e)
{
PrintWriter directError = new PrintWriter(renderResponse.getWriter());
directError.write("Error occured process includeDecoration(): " + e.toString() + "\n\n");
e.printStackTrace(directError);
directError.close();
return "";
}
}
/**
*
* Decorate and include fragment content.
*
*
* @param f
* Fragment to include and decorate
* @throws Exception
* @return String path to the decorator.
*/
public String decorateAndInclude(ContentFragment f) throws Exception
{
// makes sure that any previous content has been written to
// preserve natural HTML rendering order
setCurrentFragment(f);
setCurrentLayout();
// include decorated layout or portlet fragment
try
{
return decorateAndIncludePortlet(f);
}
catch (Exception e)
{
renderResponse.getWriter().write(e.toString());
return "";
}
}
/**
*
* The decorator template itself is responsible for including the content of
* the target Fragment which is easily acheived like so:
* in Velocity:
*
*
*
* $jetspeed.include($jetspeed.currentFragment)
*
*
*
* In JSP:
*
*
*
*
* <%
* JetspeedPowerTool jetspeed = new JetspeedPowerTool(renderRequest, renderResponse, portletConfig);
* jetspeed.include(jetspeed.getCurrentFragment());
* %>
*
*
*
*
*
* @param f
* Portlet fragment to "decorate"
* @throws Exception
*/
protected String decorateAndIncludePortlet(ContentFragment f) throws Exception
{
// make sure that any previous content has been written to
// preserve natural HTML rendering order
// get fragment decorator; fallback to the default decorator
// if the current fragment is not specifically decorated
String fragmentType = f.getType();
String decorator = f.getDecorator();
if (decorator == null)
{
decorator = getPage().getEffectiveDefaultDecorator(fragmentType);
}
// get fragment properties for fragmentType or generic
TemplateDescriptor propsTemp = getTemplate(decorator + "/" + DECORATOR_TYPE + ".properties", fragmentType,
decorationLocator, decorationLocatorDescriptor);
if (propsTemp == null)
{
fragmentType = GENERIC_TEMPLATE_TYPE;
propsTemp = getTemplate(decorator + "/" + DECORATOR_TYPE + ".properties", fragmentType, decorationLocator,
decorationLocatorDescriptor);
}
// get decorator template
Configuration decoConf = new PropertiesConfiguration(propsTemp.getAbsolutePath());
String ext = decoConf.getString("template.extension");
String decoratorPath = decorator + "/" + DECORATOR_TYPE + ext;
TemplateDescriptor template = null;
try
{
template = getDecoration(decoratorPath, fragmentType);
}
catch (TemplateLocatorException e)
{
String parent = decoConf.getString("extends");
if (parent != null)
{
template = getDecoration(parent + "/" + DECORATOR_TYPE + ext, fragmentType);
}
}
setAttribute(DECORATOR_ID_ATTR, decoConf.getString("id"));
setAttribute(ACTION_IMAGE_EXTENSION_ATTR, decoConf.getString("action.image.extension", ".gif"));
return template.getAppRelativePath();
}
/**
*
*
* @throws java.lang.IllegalStateException
* if the PortletConfig
,
* RenderRequest
or RenderReponse
* is null.
*/
protected void checkState()
{
if (portletConfig == null || renderRequest == null || renderResponse == null)
{
throw new IllegalStateException("JetspeedPowerTool has not been properly initialized. " + ""
+ "The JetspeedPowerTool generally only usuable during the rendering phase of "
+ "internal portlet applications.");
}
}
protected TemplateDescriptor getTemplate(String path, String templateType, TemplateLocator locator,
LocatorDescriptor descriptor) throws TemplateLocatorException
{
checkState();
if (templateType == null)
{
templateType = GENERIC_TEMPLATE_TYPE;
}
try
{
descriptor.setName(path);
descriptor.setType(templateType);
TemplateDescriptor template = locator.locateTemplate(descriptor);
// Check for defaults above the currently specified root
if (template == null)
{
Path pathObject = new Path(path);
if (pathObject.length() > 1)
{
template = getTemplate(pathObject.getSegment(1).toString(), templateType, locator, descriptor);
}
}
return template;
}
catch (TemplateLocatorException e)
{
log.error("Unable to locate template: " + path, e);
throw e;
}
}
/**
*
* handleError
*
*
* @param e
* @param msg
*/
@SuppressWarnings("unchecked")
protected void handleError(Exception e, String msg, ContentFragment fragment)
{
log.error(msg, e);
Set exceptions = (Set) renderRequest.getAttribute(FRAGMENT_PROCESSING_ERROR_PREFIX + fragment.getId());
if (exceptions == null)
{
exceptions = new HashSet();
setAttribute(FRAGMENT_PROCESSING_ERROR_PREFIX + fragment.getId(), exceptions);
}
exceptions.add(e);
}
/**
* Gets the list of decorator actions for a window. Each window (on each
* page) has its own collection of actionAccess flags associated with it.
*
* @return A list of actions available to the current window, filtered by
* securty access and current state.
* @throws Exception
* @deprecated
*/
public List getDecoratorActions()
{
return getCurrentFragment().getDecoration().getActions();
}
/**
* Gets the list of decorator actions for a page. Each layout fragment on a
* page has its own collection of actionAccess flags associated with it.
*
* @return A list of actions available to the current window, filtered by
* securty access and current state.
* @throws Exception
* @deprecated
*/
public List getPageDecoratorActions() throws Exception
{
return getCurrentFragment().getDecoration().getActions();
}
/**
*
*
* getTitle
*
* Returns the appropriate for the title based on locale prferences
*
* @param entity
* @return
*/
public String getTitle(ContentFragment f)
{
String title = null;
if (f != null)
{
title = f.getTitle();
if (title == null && f.getPortletContent() != null)
{
title = f.getPortletContent().getTitle();
}
else
{
title = f.getName();
if (title != null && title.indexOf("::") > -1)
{
title = title.substring(title.indexOf("::")+2);
}
}
}
return title;
}
/**
*
*
* getTitle
*
* Returns the appropriate for the title based on locale prferences
*
* @return
*/
public String getTitle()
{
return getTitle(getCurrentFragment());
}
public Object getComponent(String name)
{
return Jetspeed.getComponentManager().getComponent(name);
}
public String getAbsoluteUrl(String relativePath)
{
// only rewrite a non-absolute url
if (relativePath != null && relativePath.indexOf("://") == -1 && relativePath.indexOf("mailto:") == -1)
{
HttpServletRequest request = getRequestContext().getRequest();
StringBuffer path = new StringBuffer();
if ( !getRequestContext().getPortalURL().isRelativeOnly() )
{
if (this.baseUrlAccess == null)
{
path.append(request.getScheme()).append("://").append(request.getServerName()).append(":").append(request.getServerPort());
}
else
{
path.append(baseUrlAccess.getServerScheme()).append("://").append(baseUrlAccess.getServerName()).append(":").append(baseUrlAccess.getServerPort());
}
}
return renderResponse.encodeURL(path.append(request.getContextPath()).append(request.getServletPath()).append(relativePath).toString());
}
else
{
return relativePath;
}
}
public Subject getSubject()
{
return requestContext.getSubject();
}
public boolean getLoggedOn()
{
Principal principal = requestContext.getRequest().getUserPrincipal();
return (principal != null);
}
public String getBasePath()
{
return getRequestContext().getPortalURL().getBasePath();
}
public String getPageBasePath()
{
return getRequestContext().getPortalURL().getPageBasePath();
}
public void setVelocityContext(Context velocityContext)
{
this.velocityContext = velocityContext;
}
/**
* Sets an attribute for use within your layout and decoration templates.
* The value is always stored within the current
* javax.portlet.Renderrequest
and is also stored within the
* current org.apache.velocity.Context
if it is available.
*
* @param name
* to store the attribute under.
* @param obj
* object to set.
*/
protected void setAttribute(String name, Object object)
{
renderRequest.setAttribute(name, object);
if (velocityContext != null)
{
velocityContext.put(name, object);
}
}
public String renderPortletWindow(String windowId, String portletUniqueName)
{
try
{
if (windowId == null || portletUniqueName == null)
{
throw new IllegalArgumentException("Parameter windowId and portletUniqueName are both required");
}
RequestContext context = getRequestContext();
PortletWindow window = context.getInstantlyCreatedPortletWindow(windowId, portletUniqueName);
if (window.isValid())
{
PortletWindow currentPortletWindow = context.getCurrentPortletWindow();
try
{
context.setCurrentPortletWindow(window);
renderer.renderNow(window.getFragment(), context);
return window.getFragment().getRenderedContent();
}
finally
{
context.setCurrentPortletWindow(currentPortletWindow);
}
}
else
{
return "";
}
}
catch (Exception e)
{
handleError(e, e.toString(), getCurrentFragment());
return "";
}
}
public String getElementHtmlString(Element element)
{
return DOMUtils.stringifyElementToHtml(element);
}
public List> getHeadElements(ContentFragment f) throws Exception
{
return getPortletWindow(f).getHeadElements();
}
public List> getHeadElements() throws Exception
{
return getHeadElements(getCurrentFragment());
}
public boolean isDojoEnabled(List> headElements)
{
for (KeyValue kvPair : headElements)
{
if (HeaderPhaseSupportConstants.HEAD_ELEMENT_CONTRIBUTION_ELEMENT_ID_DOJO_LIBRARY_INCLUDE.equals(kvPair.getKey()))
{
return true;
}
}
return false;
}
}