/* | |
* 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 <security-role-ref> 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); | |
} | |
} |