blob: d6bf7ad1ebeeb85a05b3bf2fc8977645cae5057f [file] [log] [blame]
/*
* Copyright 2003,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.pluto.internal.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pluto.PortletContainer;
import org.apache.pluto.descriptors.common.SecurityRoleRefDD;
import org.apache.pluto.descriptors.portlet.PortletDD;
import org.apache.pluto.descriptors.portlet.SupportsDD;
import org.apache.pluto.internal.InternalPortletRequest;
import org.apache.pluto.internal.InternalPortletWindow;
import org.apache.pluto.internal.PortletEntity;
import org.apache.pluto.util.ArgumentUtility;
import org.apache.pluto.util.Enumerator;
import org.apache.pluto.util.NamespaceMapper;
import org.apache.pluto.util.StringManager;
import org.apache.pluto.util.StringUtils;
import org.apache.pluto.util.impl.NamespaceMapperImpl;
import javax.portlet.PortalContext;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.WindowState;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.Locale;
import java.security.Principal;
/**
* Abstract <code>javax.portlet.PortletRequest</code> implementation.
* This class also implements InternalPortletRequest.
*
* @author <a href="mailto:ddewolf@apache.org">David H. DeWolf</a>
* @author <a href="mailto:zheng@apache.org">ZHENG Zhong</a>
*/
public abstract class PortletRequestImpl extends HttpServletRequestWrapper
implements PortletRequest, InternalPortletRequest {
/** Logger. */
private static final Log LOG = LogFactory.getLog(PortletRequestImpl.class);
private static final StringManager EXCEPTIONS =
StringManager.getManager(PortletRequestImpl.class.getPackage().getName());
// Private Member Variables ------------------------------------------------
/** The parent container within which this request was created. */
private PortletContainer container = null;
/** The portlet window which is the target of this portlet request. */
private InternalPortletWindow internalPortletWindow = null;
/**
* The PortletContext associated with this Request. This PortletContext must
* be initialized from within the <code>PortletServlet</code>.
*/
private PortletContext portletContext = null;
/** The PortalContext within which this request is occuring. */
private PortalContext portalContext = null;
/** The portlet session. */
private PortletSession portletSession = null;
/** Response content types. */
private Vector contentTypes = null;
/** TODO: javadoc */
private NamespaceMapper mapper = new NamespaceMapperImpl();
/** FIXME: do we really need this?
* Flag indicating if the HTTP-Body has been accessed. */
private boolean bodyAccessed = false;
// Constructors ------------------------------------------------------------
public PortletRequestImpl(InternalPortletRequest internalPortletRequest) {
this(internalPortletRequest.getPortletContainer(),
internalPortletRequest.getInternalPortletWindow(),
internalPortletRequest.getHttpServletRequest());
}
/**
* Creates a PortletRequestImpl instance.
* @param container the portlet container.
* @param internalPortletWindow the internal portlet window.
* @param servletRequest the underlying servlet request.
*/
public PortletRequestImpl(PortletContainer container,
InternalPortletWindow internalPortletWindow,
HttpServletRequest servletRequest) {
super(servletRequest);
this.container = container;
this.internalPortletWindow = internalPortletWindow;
this.portalContext = container.getRequiredContainerServices().getPortalContext();
}
// PortletRequest Impl -----------------------------------------------------
/**
* Determine whether or not the specified WindowState is allowed for this
* portlet.
*
* @param state the state in question
* @return true if the state is allowed.
*/
public boolean isWindowStateAllowed(WindowState state) {
for (Enumeration en = portalContext.getSupportedWindowStates();
en.hasMoreElements(); ) {
if (en.nextElement().toString().equals(state.toString())) {
return true;
}
}
return false;
}
public boolean isPortletModeAllowed(PortletMode mode) {
return (isPortletModeAllowedByPortlet(mode)
&& isPortletModeAllowedByPortal(mode));
}
public PortletMode getPortletMode() {
return internalPortletWindow.getPortletMode();
}
public WindowState getWindowState() {
return internalPortletWindow.getWindowState();
}
public PortletSession getPortletSession() {
return getPortletSession(true);
}
/**
* Returns the portlet session.
* <p>
* Note that since portlet request instance is created everytime the portlet
* container receives an incoming request, the portlet session instance held
* by the request instance is also re-created for each incoming request.
* </p>
*/
public PortletSession getPortletSession(boolean create) {
if (LOG.isDebugEnabled()) {
LOG.debug("Retreiving portlet session (create=" + create + ")");
}
//
// It is critical that we don't retrieve the portlet session until the
// cross context dispatch has been completed. If we do then we risk
// having a cached version which is invalid for the context within
// which it exists.
//
if (portletContext == null) {
throw new IllegalStateException(
EXCEPTIONS.getString("error.session.illegalState"));
}
//
// We must make sure that if the session has been invalidated (perhaps
// through setMaxIntervalTimeout()) and the underlying request
// returns null that we no longer use the cached version.
// We have to check (ourselves) if the session has exceeded its max
// inactive interval. If so, we should invalidate the underlying
// HttpSession and recreate a new one (if the create flag is set to
// true) -- We just cannot depend on the implementation of
// javax.servlet.http.HttpSession!
//
HttpSession httpSession = getHttpServletRequest().getSession(create);
if (httpSession != null) {
// HttpSession is not null does NOT mean that it is valid.
//START PATCH - Jira Issue PLUTO-242 contriuted by David Garcia
// long maxInactiveTime = httpSession.getMaxInactiveInterval() * 1000L;
// long currentInactiveTime = System.currentTimeMillis()
// - httpSession.getLastAccessedTime();
// if (currentInactiveTime > maxInactiveTime) {
// if (LOG.isDebugEnabled()) {
// LOG.debug("The underlying HttpSession is expired and "
// + "should be invalidated.");
int maxInactiveInterval = httpSession.getMaxInactiveInterval();
if (maxInactiveInterval >= 0) { // < 0 => Never expires.
long maxInactiveTime = httpSession.getMaxInactiveInterval() * 1000L;
long currentInactiveTime = System.currentTimeMillis()
- httpSession.getLastAccessedTime();
if (currentInactiveTime > maxInactiveTime) {
if (LOG.isDebugEnabled()) {
LOG.debug("The underlying HttpSession is expired and "
+ "should be invalidated.");
}
httpSession.invalidate();
httpSession = getHttpServletRequest().getSession(create);
}
// httpSession.invalidate();
// httpSession = getHttpServletRequest().getSession(create);
//END PATCH
}
}
if (httpSession == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("The underlying HttpSession is not available: "
+ "no session will be returned.");
}
return null;
}
//
// If we reach here, we are sure that the underlying HttpSession is
// available. If we haven't created and cached a portlet session
// instance, we will create and cache one now.
//
if (portletSession == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating new portlet session...");
}
portletSession = new PortletSessionImpl(
portletContext,
internalPortletWindow,
httpSession);
}
return portletSession;
}
public String getProperty(String name) throws IllegalArgumentException {
ArgumentUtility.validateNotNull("propertyName", name);
String property = this.getHttpServletRequest().getHeader(name);
if (property == null) {
Map propertyMap = container.getRequiredContainerServices()
.getPortalCallbackService()
.getRequestProperties(
getHttpServletRequest(),
internalPortletWindow);
if (propertyMap != null) {
String[] properties = (String[]) propertyMap.get(name);
if (properties != null && properties.length > 0) {
property = properties[0];
}
}
}
return property;
}
public Enumeration getProperties(String name) {
ArgumentUtility.validateNotNull("propertyName", name);
Set v = new HashSet();
Enumeration props = this.getHttpServletRequest().getHeaders(name);
if (props != null) {
while (props.hasMoreElements()) {
v.add(props.nextElement());
}
}
// get properties from PropertyManager
Map map = container.getRequiredContainerServices()
.getPortalCallbackService()
.getRequestProperties(
getHttpServletRequest(),
internalPortletWindow);
if (map != null) {
String[] properties = (String[]) map.get(name);
if (properties != null) {
// add properties to vector
for (int i = 0; i < properties.length; i++) {
v.add(properties[i]);
}
}
}
return new Enumerator(v.iterator());
}
public Enumeration getPropertyNames() {
Set v = new HashSet();
// get properties from PropertyManager
Map map = container.getRequiredContainerServices()
.getPortalCallbackService()
.getRequestProperties(getHttpServletRequest(), internalPortletWindow);
if (map != null) {
v.addAll(map.keySet());
}
// get properties from request header
Enumeration props = this.getHttpServletRequest().getHeaderNames();
if (props != null) {
while (props.hasMoreElements()) {
v.add(props.nextElement());
}
}
return new Enumerator(v.iterator());
}
public PortalContext getPortalContext() {
return container.getRequiredContainerServices().getPortalContext();
}
public String getAuthType() {
return this.getHttpServletRequest().getAuthType();
}
public String getContextPath() {
return this.internalPortletWindow.getContextPath();
//return ((HttpServletRequest)getRequest()).getContextPath();
}
public String getRemoteUser() {
return this.getHttpServletRequest().getRemoteUser();
}
public Principal getUserPrincipal() {
return this.getHttpServletRequest().getUserPrincipal();
}
/**
* Determines whether a user is mapped to the specified role. As specified
* in PLT-20-3, we must reference the &lt;security-role-ref&gt; mappings
* within the deployment descriptor. If no mapping is available, then, and
* only then, do we check use the actual role name specified against the web
* application deployment descriptor.
*
* @param roleName the name of the role
* @return true if it is determined the user has the given role.
*/
public boolean isUserInRole(String roleName) {
PortletEntity entity = internalPortletWindow.getPortletEntity();
PortletDD def = entity.getPortletDefinition();
SecurityRoleRefDD ref = null;
Iterator refs = def.getSecurityRoleRefs().iterator();
while (refs.hasNext()) {
SecurityRoleRefDD r = (SecurityRoleRefDD) refs.next();
if (r.getRoleName().equals(roleName)) {
ref = r;
break;
}
}
String link;
if (ref != null && ref.getRoleLink() != null) {
link = ref.getRoleLink();
} else {
link = roleName;
}
return this.getHttpServletRequest().isUserInRole(link);
}
public Object getAttribute(String name) {
ArgumentUtility.validateNotNull("attributeName", name);
String encodedName = isNameReserved(name) ?
name :
mapper.encode(internalPortletWindow.getId(), name);
Object attribute = getHttpServletRequest()
.getAttribute(encodedName);
if (attribute == null) {
attribute = getHttpServletRequest().getAttribute(name);
}
return attribute;
}
public Enumeration getAttributeNames() {
Enumeration attributes = this.getHttpServletRequest()
.getAttributeNames();
Vector portletAttributes = new Vector();
while (attributes.hasMoreElements()) {
String attribute = (String) attributes.nextElement();
String portletAttribute = mapper.decode(
internalPortletWindow.getId(), attribute);
if (portletAttribute != null) { // it is in the portlet's namespace
portletAttributes.add(portletAttribute);
}
}
return portletAttributes.elements();
}
public String getParameter(String name) {
ArgumentUtility.validateNotNull("parameterName", name);
String[] values = (String[]) baseGetParameterMap().get(name);
if (values != null && values.length > 0) {
return values[0];
} else {
return null;
}
}
public Enumeration getParameterNames() {
return Collections.enumeration(baseGetParameterMap().keySet());
}
public String[] getParameterValues(String name) {
ArgumentUtility.validateNotNull("parameterName", name);
String[] values = (String[]) baseGetParameterMap().get(name);
if (values != null) {
values = StringUtils.copy(values);
}
return values;
}
public Map getParameterMap() {
return StringUtils.copyParameters(baseGetParameterMap());
}
public boolean isSecure() {
return this.getHttpServletRequest().isSecure();
}
public void setAttribute(String name, Object value) {
ArgumentUtility.validateNotNull("attributeName", name);
String encodedName = isNameReserved(name) ?
name : mapper.encode(internalPortletWindow.getId(), name);
if (value == null) {
removeAttribute(name);
} else {
getHttpServletRequest().setAttribute(encodedName, value);
}
}
public void removeAttribute(String name) {
ArgumentUtility.validateNotNull("attributeName", name);
String encodedName = isNameReserved(name) ?
name : mapper.encode(internalPortletWindow.getId(), name);
getHttpServletRequest().removeAttribute(encodedName);
}
public String getRequestedSessionId() {
return this.getHttpServletRequest().getRequestedSessionId();
}
public boolean isRequestedSessionIdValid() {
if (LOG.isDebugEnabled()) {
LOG.debug(" ***** IsRequestedSessionIdValid? "+getHttpServletRequest().isRequestedSessionIdValid());
}
return getHttpServletRequest().isRequestedSessionIdValid();
}
public String getResponseContentType() {
Enumeration enumeration = getResponseContentTypes();
while (enumeration.hasMoreElements()) {
return (String) enumeration.nextElement();
}
return "text/html";
}
public Enumeration getResponseContentTypes() {
if (contentTypes == null) {
contentTypes = new Vector();
PortletDD dd = internalPortletWindow.getPortletEntity().getPortletDefinition();
Iterator supports = dd.getSupports().iterator();
while (supports.hasNext()) {
SupportsDD sup = (SupportsDD) supports.next();
contentTypes.add(sup.getMimeType());
}
if (contentTypes.size() < 1) {
contentTypes.add("text/html");
}
}
return contentTypes.elements();
}
public Locale getLocale() {
return this.getHttpServletRequest().getLocale();
}
public Enumeration getLocales() {
return this.getHttpServletRequest().getLocales();
}
public String getScheme() {
return this.getHttpServletRequest().getScheme();
}
public String getServerName() {
return this.getHttpServletRequest().getServerName();
}
public int getServerPort() {
return this.getHttpServletRequest().getServerPort();
}
// Protected Methods -------------------------------------------------------
/**
* The base method that returns the parameter map in this portlet request.
* All parameter-related methods call this base method. Subclasses may just
* overwrite this protected method to change behavior of all parameter-
* related methods.
* @return the base parameter map from which parameters are retrieved.
*/
protected Map baseGetParameterMap() {
bodyAccessed = true;
return this.getHttpServletRequest().getParameterMap();
}
protected void setBodyAccessed() {
bodyAccessed = true;
}
// InternalPortletRequest Impl ---------------------------------------------
public InternalPortletWindow getInternalPortletWindow() {
return internalPortletWindow;
}
public PortletContainer getPortletContainer() {
return container;
}
public HttpServletRequest getHttpServletRequest() {
return (HttpServletRequest) super.getRequest();
}
public void init(PortletContext portletContext, HttpServletRequest req) {
this.portletContext = portletContext;
setRequest(req);
}
/**
* TODO: Implement this properly. Not required now
*/
public void release() {
// TODO:
}
// TODO: Additional Methods of HttpServletRequestWrapper -------------------
public BufferedReader getReader()
throws UnsupportedEncodingException, IOException {
// the super class will ensure that a IllegalStateException is thrown
// if getInputStream() was called earlier
BufferedReader reader = getHttpServletRequest().getReader();
bodyAccessed = true;
return reader;
}
public ServletInputStream getInputStream() throws IOException {
ServletInputStream stream = getHttpServletRequest().getInputStream();
bodyAccessed = true;
return stream;
}
public RequestDispatcher getRequestDispatcher(String path) {
return getHttpServletRequest().getRequestDispatcher(path);
}
/**
* TODO: why check bodyAccessed?
*/
public void setCharacterEncoding(String encoding)
throws UnsupportedEncodingException {
if (bodyAccessed) {
throw new IllegalStateException("Cannot set character encoding "
+ "after HTTP body is accessed.");
}
super.setCharacterEncoding(encoding);
}
// Private Methods ---------------------------------------------------------
/**
* Is this attribute name a reserved name (by the J2EE spec)?. Reserved
* names begin with "java." or "javax.".
*/
private boolean isNameReserved(String name) {
return name.startsWith("java.") || name.startsWith("javax.");
}
private boolean isPortletModeAllowedByPortlet(PortletMode mode) {
if (isPortletModeMandatory(mode)) {
return true;
}
PortletDD dd = internalPortletWindow.getPortletEntity()
.getPortletDefinition();
Iterator mimes = dd.getSupports().iterator();
while (mimes.hasNext()) {
Iterator modes = ((SupportsDD) mimes.next()).getPortletModes().iterator();
while (modes.hasNext()) {
String m = (String) modes.next();
if (m.equals(mode.toString())) {
return true;
}
}
}
return false;
}
private boolean isPortletModeAllowedByPortal(PortletMode mode) {
Enumeration supportedModes = portalContext.getSupportedPortletModes();
while (supportedModes.hasMoreElements()) {
if (supportedModes.nextElement().toString().equals(
(mode.toString()))) {
return true;
}
}
return false;
}
private boolean isPortletModeMandatory(PortletMode mode) {
return PortletMode.VIEW.equals(mode) || PortletMode.EDIT.equals(mode) || PortletMode.HELP.equals(mode);
}
}