/******************************************************************************
* JBoss, a division of Red Hat *
* Copyright 2006, Red Hat Middleware, LLC, and individual *
* contributors as indicated by the @authors tag. See the *
* copyright.txt in the distribution for a full listing of *
* individual contributors. *
* *
* This is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of *
* the License, or (at your option) any later version. *
* *
* This software is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this software; if not, write to the Free *
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
******************************************************************************/
package org.jboss.portletbridge.context;
import org.jboss.portletbridge.seam.PortletScope;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.lang.reflect.InvocationTargetException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContextFactory;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletModeException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.WindowState;
import javax.portlet.WindowStateException;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
/**
* Version of the {@link ExternalContext} for a Portlet request.
* {@link FacesContextFactory} will create instance of this class for a portal
* <code>action</code> phase.
*
* @author asmirnov
*
*/
public class PortletExternalContextImpl extends AbstractExternalContext {
public static final String SERVLET_PATH_ATTRIBUTE = "javax.servlet.include.servlet_path";
public static final String PATH_INFO_ATTRIBUTE = "javax.servlet.include.path_info";
public static final String ACTION_URL_DO_NOTHITG = "/JBossPortletBridge/actionUrl/do/nothing";
private String namespace;
public PortletExternalContextImpl(PortletContext context,
PortletRequest request, PortletResponse response) {
super(context, request, response);
portletBridgeContext = (PortletBridgeContext) request
.getAttribute(PortletBridgeContext.REQUEST_PARAMETER_NAME);
if (null == portletBridgeContext) {
throw new FacesException("No portlet bridge context");
}
windowState = portletBridgeContext.getWindowState();
// Calculate FacesServlet prefix.
calculateViewId();
}
public void setResponseCharacterEncoding(String encoding) {
// Do nothing
}
public String getResponseCharacterEncoding() {
return null;
}
public String getResponseContentType() {
return null;
}
public void setRequestCharacterEncoding(String encoding)
throws UnsupportedEncodingException {
try {
ActionRequest actionRequest = (ActionRequest) getPortletRequest();
actionRequest.setCharacterEncoding(encoding);
} catch (IllegalStateException e) {
// TODO: handle exception
}
}
public String getRequestCharacterEncoding() {
ActionRequest actionRequest = (ActionRequest) getPortletRequest();
return actionRequest.getCharacterEncoding();
}
public String getRequestContentType() {
return null;
}
protected PortletContext getPortletContext() {
return (PortletContext) getContext();
}
protected PortletRequest getPortletRequest() {
return (PortletRequest) getRequest();
}
protected PortletResponse getPortletResponse() {
return (PortletResponse) getResponse();
}
public String getInitParameter(String name) {
return getPortletContext().getInitParameter(name);
}
protected String getNamespace() {
if (null == namespace) {
namespace = (String) getRequestParameter(AbstractExternalContext.NAMESPACE_PARAMETER);
if (null == namespace) {
throw new IllegalStateException(
"Can not determine portletbridge namespace");
}
}
return namespace;
}
public URL getResource(String path) throws MalformedURLException {
return getPortletContext().getResource(path);
}
public InputStream getResourceAsStream(String path) {
return getPortletContext().getResourceAsStream(path);
}
@SuppressWarnings("unchecked")
public Set<String> getResourcePaths(String path) {
return getPortletContext().getResourcePaths(path);
}
@SuppressWarnings("unchecked")
protected Enumeration<String> enumerateRequestParameterNames() {
return getPortletRequest().getParameterNames();
}
protected Object getContextAttribute(String name) {
return getPortletContext().getAttribute(name);
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getContextAttributeNames() {
return getPortletContext().getAttributeNames();
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getInitParametersNames() {
return getPortletContext().getInitParameterNames();
}
protected Object getRequestAttribute(String name) {
if(PATH_INFO_ATTRIBUTE.equals(name)){
return getRequestPathInfo();
} else if (SERVLET_PATH_ATTRIBUTE.equals(name)) {
return getRequestServletPath();
} else {
return getPortletRequest().getAttribute(name);
}
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getRequestAttributeNames() {
return getPortletRequest().getAttributeNames();
}
@SuppressWarnings("unchecked")
public Map<String, String[]> getRequestParameterValuesMap() {
return getPortletRequest().getParameterMap();
}
protected String[] getRequestParameterValues(String name) {
return getPortletRequest().getParameterValues(name);
}
protected String getRequestHeader(String name) {
return getPortletRequest().getProperty(name);
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getRequestHeaderNames() {
return getPortletRequest().getPropertyNames();
}
@SuppressWarnings("unchecked")
protected String[] getRequestHeaderValues(String name) {
Enumeration<String> properties = getPortletRequest()
.getProperties(name);
List<String> values = new ArrayList<String>();
while (properties.hasMoreElements()) {
String value = properties.nextElement();
values.add(value);
}
return (String[]) values.toArray(EMPTY_STRING_ARRAY);
}
protected String getRequestParameter(String name) {
return getPortletRequest().getParameter(name);
}
protected Object getSessionAttribute(String name) {
return getSessionAttribute(name, getScopeForName(name));
}
protected Object getSessionAttribute(String name,int scope) {
return getPortletRequest().getPortletSession(true).getAttribute(name,
scope);
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getSessionAttributeNames() {
class AttributeEnumeration implements Enumeration<String> {
int scope;
Enumeration<String> attributes;
public AttributeEnumeration() {
scope = PortletSession.PORTLET_SCOPE;
attributes = getSessionAttributeNames(scope);
if (!attributes.hasMoreElements()) {
scope = PortletSession.APPLICATION_SCOPE;
attributes = getSessionAttributeNames(scope);
}
}
public boolean hasMoreElements() {
return attributes.hasMoreElements();
}
public String nextElement() {
final String result = attributes.nextElement();
if (!attributes.hasMoreElements()
&& scope == PortletSession.PORTLET_SCOPE) {
scope = PortletSession.APPLICATION_SCOPE;
attributes = getSessionAttributeNames(scope);
}
return result;
}
}
return new AttributeEnumeration();
//return getSessionAttributeNames(PortletSession.PORTLET_SCOPE);
}
@SuppressWarnings("unchecked")
protected Enumeration<String> getSessionAttributeNames(int scope) {
return getPortletRequest().getPortletSession(true).getAttributeNames(
scope);
}
protected void removeContextAttribute(String name) {
getPortletContext().removeAttribute(name);
}
protected void removeRequestAttribute(String name) {
getPortletRequest().removeAttribute(name);
}
protected void removeSessionAttribute(String name) {
removeSessionAttribute(name, getScopeForName(name));
}
protected void removeSessionAttribute(String name,int scope) {
getPortletRequest().getPortletSession(true).removeAttribute(name,
scope);
}
protected void setContextAttribute(String name, Object value) {
getPortletContext().setAttribute(name, value);
}
protected void setRequestAttribute(String name, Object value) {
getPortletRequest().setAttribute(name, value);
}
protected void setSessionAttribute(String name, Object value) {
setSessionAttribute(name, value, getScopeForName(name));
}
protected void setSessionAttribute(String name, Object value, int scope) {
getPortletRequest().getPortletSession(true).setAttribute(name, value,
PortletSession.PORTLET_SCOPE);
}
public void dispatch(String path) throws IOException {
if (null == path) {
throw new NullPointerException("Path to new view is null");
}
throw new IllegalStateException(
"Dispatch to new view not at render phase");
}
// private static final Pattern absoluteUrl = Pattern.compile("");
// private static final Pattern directLink = Pattern.compile("");
// private static final Pattern viewIdParam = Pattern.compile("");
/**
* @param url
* @return
*/
@Override
protected String createActionUrl(PortalActionURL actionUrl) {
String viewIdFromUrl = getViewIdFromUrl(actionUrl);
actionUrl.setPath(getRequestContextPath() + ACTION_URL_DO_NOTHITG);
actionUrl.setParameter(VIEW_ID_PARAMETER, viewIdFromUrl);
// Determine mode, window state or secure changes.
String modeParameter = actionUrl
.getParameter(Bridge.PORTLET_MODE_PARAMETER);
if (null != modeParameter) {
PortletMode mode = new PortletMode(modeParameter);
try {
((ActionResponse) getResponse()).setPortletMode(mode);
} catch (PortletModeException e) {
// only valid modes supported.
}
}
String windowStateParameter = actionUrl
.getParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
if (null != windowStateParameter) {
try {
WindowState state = new WindowState(windowStateParameter);
((ActionResponse) getResponse()).setWindowState(state);
} catch (WindowStateException e) {
// only valid modes supported.
}
}
return actionUrl.toString();
}
/**
* @param url
* @return
*/
protected String encodeURL(String url) {
return getPortletResponse().encodeURL(url);
}
public String getAuthType() {
return getPortletRequest().getAuthType();
}
public String getRemoteUser() {
String user = getPortletRequest().getRemoteUser();
if (user == null) {
Principal userPrincipal = getUserPrincipal();
if (null != userPrincipal) {
user = userPrincipal.getName();
}
}
return user;
}
public String getRequestContextPath() {
return getPortletRequest().getContextPath();
}
public Locale getRequestLocale() {
return getPortletRequest().getLocale();
}
public Iterator<Locale> getRequestLocales() {
return new EnumerationIterator<Locale>(getPortletRequest().getLocales());
}
private String _pathInfo = null;
public String getRequestPathInfo() {
return _pathInfo;
}
private String _servletPath = null;
private String servletMappingSuffix;
private String defaultJsfSuffix;
private String servletMappingPrefix;
private String viewId;
public String getRequestServletPath() {
return _servletPath;
}
public Object getSession(boolean create) {
return getPortletRequest().getPortletSession(create);
}
public Principal getUserPrincipal() {
return getPortletRequest().getUserPrincipal();
}
public boolean isUserInRole(String role) {
return getPortletRequest().isUserInRole(role);
}
public void log(String message) {
getPortletContext().log(message);
}
public void log(String message, Throwable exception) {
getPortletContext().log(message, exception);
}
public void redirect(String url) throws IOException {
if (null == url || url.length() < 0) {
throw new NullPointerException("Path to redirect is null");
}
PortalActionURL actionURL = new PortalActionURL(url);
if (url.startsWith("#")
|| (!actionURL.isInContext(getRequestContextPath()))
|| "true".equalsIgnoreCase(actionURL
.getParameter(Bridge.DIRECT_LINK))) {
((ActionResponse) getResponse()).sendRedirect(url);
} else {
internalRedirect(actionURL);
}
}
protected void calculateViewId() {
viewId = getPortletRequest().getParameter(VIEW_ID_PARAMETER);
// Get stored ViewId from window state
if (null == viewId) {
viewId = windowState.getViewId();
if (null == viewId) {
// Try to get viewId from stored session attribute
String portletModeName = getPortletRequest().getPortletMode()
.toString();
PortletSession portletSession = getPortletRequest()
.getPortletSession(false);
if (null != portletSession) {
String historyViewId = (String) portletSession
.getAttribute(Bridge.VIEWID_HISTORY + "."
+ portletModeName);
try {
PortalActionURL viewIdUrl = new PortalActionURL(
historyViewId);
viewId = viewIdUrl.getPath();
} catch (MalformedURLException e) {
// Ignore it.
}
}
if (null == viewId) {
viewId = windowState.getBridgeConfig()
.getDefaultViewIdMap().get(portletModeName);
}
if (null == viewId) {
throw new BridgeDefaultViewNotSpecifiedException();
}
}
}
// TODO - detect mapping and convert viewId into appropriate url
List<String> servletMappings = windowState.getBridgeConfig()
.getFacesServletMappings();
calculateServletPath(viewId, servletMappings);
}
protected void calculateServletPath(String viewId,
List<String> servletMappings) {
if (null != servletMappings && servletMappings.size() > 0) {
String mapping = servletMappings.get(0);
if (mapping.startsWith("*")) {
// Suffix Mapping
servletMappingSuffix = mapping.substring(mapping.indexOf('.'));
defaultJsfSuffix = getPortletContext().getInitParameter(
ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
if (null == defaultJsfSuffix) {
defaultJsfSuffix = ViewHandler.DEFAULT_SUFFIX;
}
int i = viewId.lastIndexOf(defaultJsfSuffix);
if (i < 0) {
i = viewId.lastIndexOf('.');
}
if (i >= 0) {
viewId = viewId.substring(0, i) + servletMappingSuffix;
}
_servletPath = viewId;
getPortletRequest().setAttribute(
SERVLET_PATH_ATTRIBUTE, viewId);
getPortletRequest().setAttribute(
"com.sun.faces.INVOCATION_PATH", servletMappingSuffix);
_pathInfo = null;
} else if (mapping.endsWith("*")) {
mapping = mapping.substring(0, mapping.length() - 1);
if (mapping.endsWith("/")) {
mapping = mapping.substring(0, mapping.length() - 1);
}
servletMappingPrefix = _servletPath = mapping;
getPortletRequest().setAttribute(
"com.sun.faces.INVOCATION_PATH", mapping);
_pathInfo = viewId;
} else {
_servletPath = null;
_pathInfo = viewId;
}
} else {
_servletPath = null;
_pathInfo = viewId;
}
}
/**
* @param actionURL
*/
protected void internalRedirect(PortalActionURL actionURL) {
// Detect ViewId from URL and create new view for them.
String viewId = actionURL.getParameter(VIEW_ID_PARAMETER);
if (null != viewId) {
try {
viewId = URLDecoder.decode(viewId, "UTF8");
// Save new viewId to restore after redirect.
portletBridgeContext.setRedirectViewId(viewId);
// FacesContext facesContext =
// FacesContext.getCurrentInstance();
// ViewHandler viewHandler = facesContext.getApplication()
// .getViewHandler();
// facesContext.setViewRoot(viewHandler.createView(facesContext,
// viewId));
// setHasNavigationRedirect(true);
Map<String, String[]> requestParameters = actionURL
.getParameters();
if (requestParameters.size() > 0) {
portletBridgeContext
.setRedirectRequestParameters(requestParameters);
}
} catch (UnsupportedEncodingException e) {
// Do nothing - UTF-8 encoding is a default.
}
}
}
/**
* @return the servletMappingSuffix
*/
public String getServletMappingSuffix() {
return servletMappingSuffix;
}
/**
* @return the defaultJsfSuffix
*/
public String getDefaultJsfSuffix() {
return defaultJsfSuffix;
}
/**
* @return the defaultJsfPrefix
*/
public String getServletMappingPrefix() {
return servletMappingPrefix;
}
protected String getViewIdFromUrl(PortalActionURL url) {
String viewId;
viewId = url.getParameter(VIEW_ID_PARAMETER);
if (null == viewId) {
viewId = url.getPath();
if (viewId.startsWith(getRequestContextPath())) {
viewId = viewId.substring(getRequestContextPath().length());
}
if (null != getServletMappingPrefix()) {
if (viewId.startsWith(getServletMappingPrefix())) {
viewId = viewId.substring(getServletMappingPrefix()
.length());
}
} else if (null != getServletMappingSuffix()) {
int i = viewId.lastIndexOf(getServletMappingSuffix());
if (i >= 0) {
viewId = viewId.substring(0, i) + getDefaultJsfSuffix();
}
}
}
return viewId;
}
public static Class classForName(String name) throws ClassNotFoundException
{
try
{
return Thread.currentThread().getContextClassLoader().loadClass(name);
}
catch (Exception e)
{
return Class.forName(name);
}
}
protected int getScopeForName(String name) {
try {
Class c = classForName("org.jboss.seam.Component");
if (c != null){
org.jboss.seam.Component component = org.jboss.seam.Component.forName(name);
if (null == component) {
return PortletSession.PORTLET_SCOPE;
}
final PortletScope portletScope =
component.getBeanClass().getAnnotation(PortletScope.class);
return null != portletScope
? portletScope.value().getScopeType()
: PortletSession.PORTLET_SCOPE;
}else{
return PortletSession.PORTLET_SCOPE;
}
} catch (IllegalStateException e) {
// not handled by seam at all?
return PortletSession.PORTLET_SCOPE;
} catch (ClassNotFoundException e) {
return PortletSession.PORTLET_SCOPE;
}
}
}