You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/10/25 15:38:13 UTC
svn commit: r588233 [3/5] - in /myfaces/portlet-bridge/trunk: ./ api/
api/src/ api/src/main/ api/src/main/java/ api/src/main/java/javax/
api/src/main/java/javax/portlet/ api/src/main/java/javax/portlet/faces/
api/src/main/java/javax/portlet/faces/compo...
Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=588233&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Thu Oct 25 06:38:05 2007
@@ -0,0 +1,1371 @@
+/* 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.myfaces.portlet.faces.context;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.security.Principal;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletContext;
+import javax.portlet.PortletException;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.PortletResponse;
+import javax.portlet.PortletURL;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+
+import org.apache.myfaces.portlet.faces.util.map.LocalesIterator;
+import org.apache.myfaces.portlet.faces.util.map.PortletApplicationMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletInitParameterMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestHeaderMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestHeaderValuesMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestHeaders;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestParameterMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletRequestParameterValuesMap;
+import org.apache.myfaces.portlet.faces.util.map.PortletSessionMap;
+import org.apache.myfaces.portlet.faces.util.QueryString;
+import org.apache.myfaces.portlet.faces.util.URLUtils;
+
+import java.util.Vector;
+
+import javax.faces.application.ViewHandler;
+
+import javax.portlet.faces.Bridge;
+
+import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
+
+/**
+ * This implementation of {@link ExternalContext} is specific to the portlet implementation.
+ *
+ * Methods of interests are: - encodeActionURL - redirect
+ */
+public class PortletExternalContextImpl extends ExternalContext
+{
+
+ public static final String FACES_MAPPING_ATTRIBUTE = "org.apache.myfaces.portlet.faces.context.facesMapping";
+
+ public static final String RENDER_POLICY_ATTRIBUTE = Bridge.BRIDGE_PACKAGE_PREFIX
+ + "." + Bridge.RENDER_POLICY;
+
+ // Query parameter to store the original viewId in the query string
+ public static final String VIEW_ID_QUERY_PARAMETER = "_VIEW_ID";
+
+ // Render parameter to store the viewId
+ public static final String ACTION_ID_PARAMETER_NAME = "_ACTION_ID";
+
+ public static final String RESOURCE_METHOD_QUERY_PARAMETER = "_xResourceMethod";
+ public static final String RESOURCE_URL_QUERY_PARAMETER = "_xResourceUrl";
+ public static final String FACES_RESOURCE_QUERY_PARAMETER = "_xFacesResource";
+ public static final String PROCESS_AS_RENDER_QUERY_PARAMETER = "_xProcessAsRender";
+ public static final String REQUIRES_REWRITE_PARAMETER = "_xRequiresRewrite";
+
+ private PortletContext mPortletContext;
+ private PortletConfig mPortletConfig;
+ private PortletRequest mPortletRequest;
+ private PortletResponse mPortletResponse;
+
+ // Needed for distpach() which requires the actual PortletRequest/Response
+ // objects not wrapped one's (since wrapping isn't official in 168)
+ private PortletRequest mOrigPortletRequest = null;
+ private PortletResponse mOrigPortletResponse = null;
+
+ // External context maps
+ private Map mApplicationMap = null;
+ private Map mSessionMap = null;
+ private Map mRequestMap = null;
+ private Map mRequestParameterMap = null;
+ private Map mRequestParameterValuesMap = null;
+ private Map mRequestHeaderMap = null;
+ private Map mRequestHeaderValuesMap = null;
+ private Map mInitParameterMap = null;
+
+ // maps for internal parameters (eg, those specified in query string of
+ // any defaultViewId)
+ private Map mInternalRequestParameterMap = Collections.EMPTY_MAP;
+ private Map mInternalRequestParameterValuesMap = Collections.EMPTY_MAP;
+
+ private PortletRequestHeaders mPortletRequestHeaders = null;
+
+ // Requested Faces view
+ private String mViewId = null;
+
+ // Reverse engineered serlvet paths from mappings
+ private Vector mFacesMappings = null;
+ private String mServletPath = null;
+ private String mPathInfo = null;
+
+ // Current Portlet phase
+ private Bridge.PortletPhase mPhase = null;
+
+ public PortletExternalContextImpl(PortletConfig portletConfig, PortletRequest portletRequest,
+ PortletResponse portletResponse) throws FacesException
+ {
+ mPortletConfig = portletConfig;
+ mPortletContext = mPortletConfig.getPortletContext();
+ mPortletRequest = mOrigPortletRequest = portletRequest;
+ mPortletResponse = mOrigPortletResponse = portletResponse;
+
+ mPhase = (Bridge.PortletPhase) mPortletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+
+ if (mPhase == Bridge.PortletPhase.RenderPhase)
+ {
+ log("PortletExternalContextImpl.<init>: RENDER");
+ System.out.println("=====RENDER====="); // TODO DEBUG
+ }
+ else
+ {
+ log("PortletExternalContextImpl.<init>: ACTION");
+ System.out.println("=====ACTION====="); // TODO DEBUG
+ }
+
+ mViewId = getViewId();
+
+ // Now reverse engineer the servlet paths from the mappings
+ mFacesMappings = (Vector) mPortletRequest.getAttribute(FACES_MAPPING_ATTRIBUTE);
+ mapPathsFromViewId(mViewId, mFacesMappings);
+
+ // Get the DelegateRender context parameter here and set as a request
+ // attribute
+ // so Bridge's ViewHandler has access to it. ViewHandler can't get from
+ // context
+ // itself because its a per portlet setting but without the config
+ // object
+ // the ViewHandler has no way to get the portlet's name.
+ Bridge.BridgeRenderPolicy renderPolicy = (Bridge.BridgeRenderPolicy) mPortletContext
+ .getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX
+ + mPortletConfig
+ .getPortletName()
+ + "."
+ + Bridge.RENDER_POLICY);
+ if (renderPolicy != null)
+ {
+ mPortletRequest.setAttribute(RENDER_POLICY_ATTRIBUTE, renderPolicy);
+ }
+
+ }
+
+ public void release()
+ {
+
+ mPortletConfig = null;
+ mPortletContext = null;
+ mPortletRequest = null;
+ mPortletResponse = null;
+ mOrigPortletRequest = null;
+ mOrigPortletResponse = null;
+
+ mApplicationMap = null;
+ mSessionMap = null;
+ mRequestMap = null;
+ mRequestParameterMap = null;
+ mRequestParameterValuesMap = null;
+ mRequestHeaderMap = null;
+ mRequestHeaderValuesMap = null;
+ mInitParameterMap = null;
+
+ mViewId = null;
+ }
+
+ /**
+ * This method is the gatekeeper for managing the viewId across action/render + subsequent
+ * renders.
+ *
+ * For the render case, when rendering the actionURL, we call this method to write the viewId in
+ * the interaction state when calling createActionURL() This allows us to get the viewId in action
+ * request. eg, /adf-faces-demo/componentDemos.jspx?_VIEW_ID=/componentDemos.jspx
+ *
+ * For the action with redirect case, we call this method when the redirect() is called and we
+ * encode the viewId in the navigational state so we can get the viewId in the subsequent render
+ * request eg, /adf-faces-demo/componentDemos.jspx?_VIEW_ID=/componentDemos.jspx
+ *
+ * We do the same as above for the action with non-redirect case as well by calling the redirect()
+ * method at the end of action lifecycle in ADFBridgePorttlet.process() by passing in an URL
+ * created by ViewHandler.getActionURL()
+ *
+ * A special case to handle direct call from the goLink/goButton component in render request (bug
+ * 5259313) eg, /components/goButton.jspx or http://www.oracle.com
+ */
+ @Override
+ public String encodeActionURL(String url)
+ {
+ String viewId = null;
+ QueryString queryStr = null;
+ int queryStart = -1;
+
+ if (url.startsWith("#") || isExternalURL(url) || isDirectLink(url))
+ {
+ return url;
+ }
+
+ // url might contain DirectLink=false parameter -- spec says remove if
+ // it does.
+ url = removeDirectLink(url);
+
+ // Now determine the target viewId
+
+ // First: if it looks this is a bridge encoded action url
+ // try and process as such
+ if (url.indexOf(VIEW_ID_QUERY_PARAMETER) > -1)
+ {
+ // First, parse and remove the viewId from the URL
+ queryStart = url.indexOf('?');
+
+ if (queryStart != -1)
+ {
+ // Get the query string
+ queryStr = new QueryString(url.substring(queryStart + 1), "UTF8");
+
+ // Now rebuild the URL without this parameter
+ viewId = queryStr.getParameter(VIEW_ID_QUERY_PARAMETER);
+ queryStr.removeParameter(VIEW_ID_QUERY_PARAMETER);
+
+ String query = queryStr.toString();
+ if (query != null && query.length() != 0)
+ {
+ url = url.substring(0, queryStart) + "?" + query;
+ }
+ else
+ {
+ url = url.substring(0, queryStart);
+ }
+ }
+ }
+
+ // Did we find the viewId? If not assume a native URL -- and hence
+ // cull the viewId by using servlet path matching rules
+ if (viewId == null)
+ {
+ if (!isRelativePath(url))
+ {
+ viewId = getViewIdFromPath(url);
+ }
+ else
+ {
+ viewId = getViewIdFromRelativePath(url);
+ }
+ }
+
+ if (viewId == null)
+ {
+ throw new FacesException("encodeActionURL: unable to recognize viewId");
+ }
+
+ if (mPhase == Bridge.PortletPhase.RenderPhase)
+ { // render - write
+ // the viewId into
+ // the response
+ // (interaction
+ // state)
+ RenderResponse renderResponse = (RenderResponse) getResponse();
+ PortletURL actionURL = renderResponse.createActionURL();
+ actionURL.setParameter(ACTION_ID_PARAMETER_NAME, viewId);
+
+ // Add extra parameters so they don't get lost
+ if (queryStr != null)
+ {
+ Enumeration list = queryStr.getParameterNames();
+ while (list.hasMoreElements())
+ {
+ String param = list.nextElement().toString();
+ actionURL.setParameter(param, queryStr.getParameter(param));
+ }
+ }
+
+ // TODO hack to workaround double encoding problem
+ String actionURLStr = actionURL.toString();
+ actionURLStr = actionURLStr.replaceAll("\\&\\;", "&");
+ log("PortletExternalContextImpl.encodeActionURL:end:RENDER(viewId=" + viewId
+ + "; actionURL=" + actionURLStr + ")");
+ return actionURLStr;
+ }
+ else
+ { // action - write the viewId to navigational state
+ ActionResponse actionResponse = (ActionResponse) getResponse();
+
+ actionResponse.setRenderParameter(ACTION_ID_PARAMETER_NAME, viewId);
+
+ // set other request params (if any) into navigational states
+ if (queryStr != null)
+ {
+ Enumeration list = queryStr.getParameterNames();
+ while (list.hasMoreElements())
+ {
+ String param = list.nextElement().toString();
+ actionResponse.setRenderParameter(param, queryStr.getParameter(param));
+ }
+ }
+
+ log("PortletExternalContextImpl.encodeActionURL:end:ACTION(" + viewId + ")");
+
+ // Since this is an action -- enocodeActionURL shouldn't be written
+ // into markup anywhere -- hence nothing of value to return.
+ // To distinguish between this case and when the path is absolute
+ // (and
+ // might be used for a redirect the spec says return something
+ // different
+ // then was passed in.
+
+ // ContextPath is added so still seen as a local URL and hence isn't
+ // processed by redirect
+ return getRequestContextPath()
+ + "/PortletFacesBridge/endcodeActionURL/encodeInActionPhase/doNothing";
+ }
+ }
+
+ @Override
+ public void redirect(String url) throws IOException
+ {
+ // Distinguish between redirects within this app and external links
+ // redirects within this app are dealt (elsewhere) as navigations
+ // so do nothing. External links are redirected
+
+ log("PortletExternalContextImpl.redirect(" + url + ")");
+ if (mPhase == Bridge.PortletPhase.ActionPhase
+ && (url.startsWith("#") || isExternalURL(url) || isDirectLink(url)))
+ {
+ ((ActionResponse) getResponse()).sendRedirect(url);
+ }
+
+ // TODO: Should we recognize a redirect during a rendere to an internal
+ // link and treat as a navigation?
+
+ }
+
+ @Override
+ public String encodeResourceURL(String s)
+ {
+
+ if (!isExternalURL(s) && !s.startsWith("/"))
+ {
+ // must be a relative path -- convert it to contextPath relative
+ // construct our cwd (servletPath + pathInfo);
+ String pi = null;
+ String path = getRequestServletPath();
+ if (path == null)
+ {
+ path = getRequestPathInfo();
+ }
+ else
+ {
+ pi = getRequestPathInfo();
+ }
+
+ if (pi != null)
+ {
+ path = path.concat(pi);
+ }
+
+ // remove target
+ path = path.substring(0, path.lastIndexOf("/"));
+ s = URLUtils.convertFromRelative(path, s);
+ }
+
+ String resourceURLStr = mPortletResponse.encodeURL(s);
+
+ // Avoid double encoding
+ resourceURLStr = resourceURLStr.replaceAll("\\&\\;", "&");
+ log("PortletExternalContextImpl.encodeResourceURL:end(" + resourceURLStr + ")");
+
+ return resourceURLStr;
+ }
+
+ @Override
+ public void dispatch(String requestURI) throws IOException, FacesException
+ {
+ if (requestURI == null)
+ {
+ throw new java.lang.NullPointerException();
+ }
+
+ if (mPhase == Bridge.PortletPhase.ActionPhase)
+ {
+ throw new IllegalStateException("Request cannot be an ActionRequest");
+ }
+
+ log("PortletExternalContextImpl.dispatch: response content type "
+ + ((RenderResponse) mPortletResponse).getContentType());
+
+ PortletRequestDispatcher prd = mPortletContext.getRequestDispatcher(requestURI);
+
+ if (prd == null)
+ {
+ throw new IllegalArgumentException(
+ "No request dispatcher can be created for the specified path: "
+ + requestURI);
+ }
+
+ try
+ {
+ prd.include((RenderRequest) mOrigPortletRequest, (RenderResponse) mOrigPortletResponse);
+ }
+ catch (PortletException e)
+ {
+ if (e.getMessage() != null)
+ {
+ throw new FacesException(e.getMessage(), e);
+ }
+ else
+ {
+ throw new FacesException(e);
+ }
+ }
+ }
+
+ @Override
+ public Object getSession(boolean create)
+ {
+ return mPortletRequest.getPortletSession(create);
+ }
+
+ @Override
+ public Object getContext()
+ {
+ return mPortletContext;
+ }
+
+ @Override
+ public Object getRequest()
+ {
+ return mPortletRequest;
+ }
+
+ @Override
+ public Object getResponse()
+ {
+ return mPortletResponse;
+ }
+
+ @Override
+ public Map getApplicationMap()
+ {
+ if (mApplicationMap == null)
+ {
+ log("PortletExternalContextImpl.getApplicationMap: creating PortletApplicationMap");
+ mApplicationMap = new PortletApplicationMap(mPortletContext);
+ }
+ return mApplicationMap;
+ }
+
+ @Override
+ public Map getSessionMap()
+ {
+ if (mSessionMap == null)
+ {
+ log("PortletExternalContextImpl.getSessionMap: creating PortletSessionMap");
+ mSessionMap = new PortletSessionMap(mPortletRequest);
+ }
+ return mSessionMap;
+ }
+
+ @Override
+ public Map getRequestMap()
+ {
+ if (mRequestMap == null)
+ {
+ log("PortletExternalContextImpl.getRequestMap: creating PortletRequestMap");
+ mRequestMap = new PortletRequestMap(mPortletRequest);
+ }
+ return mRequestMap;
+ }
+
+ @Override
+ public Map getRequestParameterMap()
+ {
+ if (mRequestParameterMap == null)
+ {
+ log("PortletExternalContextImpl.getRequestParameterMap: creating PortletRequestParameterMap");
+ mRequestParameterMap = Collections
+ .unmodifiableMap(new PortletRequestParameterMap(
+ mPortletRequest,
+ mInternalRequestParameterMap));
+ }
+ return mRequestParameterMap;
+ }
+
+ public Map getRequestParameterValuesMap()
+ {
+ if (mRequestParameterValuesMap == null)
+ {
+ log("PortletExternalContextImpl.getRequestParameterValuesMap: creating PortletRequestParameterValuesMap");
+ mRequestParameterValuesMap = Collections
+ .unmodifiableMap(new PortletRequestParameterValuesMap(
+ mPortletRequest,
+ mInternalRequestParameterValuesMap));
+ }
+ return mRequestParameterValuesMap;
+ }
+
+ public Iterator getRequestParameterNames()
+ {
+ Map requestParameters = getRequestParameterMap();
+ final Iterator i = requestParameters.entrySet().iterator();
+ Iterator it = new Iterator() {
+ public boolean hasNext()
+ {
+ return i.hasNext();
+ }
+
+ public Object next()
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ return entry.getKey();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ return it;
+ }
+
+ public Map getRequestHeaderMap()
+ {
+ if (mRequestHeaderMap == null)
+ {
+ log("PortletExternalContextImpl.getRequestHeaderMap: creating PortletRequestHeaderMap");
+ if (mPortletRequestHeaders == null)
+ {
+ mPortletRequestHeaders = new PortletRequestHeaders(mOrigPortletRequest);
+ }
+
+ mRequestHeaderMap = new PortletRequestHeaderMap(mPortletRequestHeaders);
+ }
+ return mRequestHeaderMap;
+ }
+
+ public Map getRequestHeaderValuesMap()
+ {
+ if (mRequestHeaderValuesMap == null)
+ {
+ log("PortletExternalContextImpl.getRequestHeaderValuesMap: creating PortletRequestHeaderValuesMap");
+ if (mPortletRequestHeaders == null)
+ {
+ mPortletRequestHeaders = new PortletRequestHeaders(mOrigPortletRequest);
+ }
+
+ mRequestHeaderValuesMap = new PortletRequestHeaderValuesMap(mPortletRequestHeaders);
+ }
+ return mRequestHeaderValuesMap;
+ }
+
+ public Map getRequestCookieMap()
+ {
+ return Collections.unmodifiableMap(Collections.EMPTY_MAP);
+ }
+
+ public Locale getRequestLocale()
+ {
+ return mPortletRequest.getLocale();
+ }
+
+ public String getRequestPathInfo()
+ {
+ return mPathInfo;
+ }
+
+ public String getRequestContextPath()
+ {
+ return mPortletRequest.getContextPath();
+ }
+
+ public String getInitParameter(String s)
+ {
+ return mPortletContext.getInitParameter(s);
+ }
+
+ public Map getInitParameterMap()
+ {
+ if (mInitParameterMap == null)
+ {
+ log("PortletExternalContextImpl.getInitParameterMap: creating PortletInitParameterMap");
+ mInitParameterMap = new PortletInitParameterMap(mPortletContext);
+ }
+ return mInitParameterMap;
+ }
+
+ public Set getResourcePaths(String s)
+ {
+ return mPortletContext.getResourcePaths(s);
+ }
+
+ public InputStream getResourceAsStream(String s)
+ {
+ return mPortletContext.getResourceAsStream(s);
+ }
+
+ public String encodeNamespace(String s)
+ {
+ if (!(mPortletResponse instanceof RenderResponse))
+ {
+ throw new IllegalStateException("Only RenderResponse can be used to encode a namespace");
+ }
+ else
+ {
+ return ((RenderResponse) mPortletResponse).getNamespace() + s;
+ }
+ }
+
+ public String getRequestServletPath()
+ {
+ return mServletPath;
+ }
+
+ public String getAuthType()
+ {
+ return mPortletRequest.getAuthType();
+ }
+
+ public String getRemoteUser()
+ {
+ return mPortletRequest.getRemoteUser();
+ }
+
+ public boolean isUserInRole(String role)
+ {
+ return mPortletRequest.isUserInRole(role);
+ }
+
+ public Principal getUserPrincipal()
+ {
+ return mPortletRequest.getUserPrincipal();
+ }
+
+ public void log(String message)
+ {
+ mPortletContext.log(message);
+ }
+
+ public void log(String message, Throwable t)
+ {
+ mPortletContext.log(message, t);
+ }
+
+ public Iterator getRequestLocales()
+ {
+ return new LocalesIterator(mPortletRequest.getLocales());
+ }
+
+ public URL getResource(String s) throws MalformedURLException
+ {
+ return mPortletContext.getResource(s);
+ }
+
+ // Start of JSF 1.2 API
+
+ /**
+ * <p>
+ * Set the environment-specific request to be returned by subsequent calls to {@link #getRequest}.
+ * This may be used to install a wrapper for the request.
+ * </p>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ *
+ * @since 1.2
+ */
+ public void setRequest(Object request)
+ {
+ mPortletRequest = (PortletRequest) request;
+
+ // clear out request based cached maps
+ mRequestMap = null;
+ mRequestParameterMap = null;
+ mRequestParameterValuesMap = null;
+ mRequestHeaderMap = null;
+ mRequestHeaderValuesMap = null;
+ }
+
+ /**
+ *
+ * <p>
+ * Overrides the name of the character encoding used in the body of this request.
+ * </p>
+ *
+ * <p>
+ * Calling this method after the request has been accessed will have no no effect, unless a
+ * <code>Reader</code> or <code>Stream</code> has been obtained from the request, in which
+ * case an <code>IllegalStateException</code> is thrown.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must call through to the <code>javax.servlet.ServletRequest</code>
+ * method <code>setCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This must call through to the <code>javax.portlet.ActionRequest</code>
+ * method <code>setCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @throws java.io.UnsupportedEncodingException
+ * if this is not a valid encoding
+ *
+ * @since 1.2
+ *
+ */
+ public void setRequestCharacterEncoding(String encoding) throws UnsupportedEncodingException,
+ IllegalStateException
+ {
+ if (mPhase != Bridge.PortletPhase.ActionPhase)
+ {
+ throw new IllegalStateException(
+ "PortletExternalContextImpl.setRequestCharacterEncoding(): Request must be an ActionRequest");
+ }
+
+ ((ActionRequest) mPortletRequest).setCharacterEncoding(encoding);
+ }
+
+ /**
+ *
+ * <p>
+ * Return the character encoding currently being used to interpret this request.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must return the value returned by the
+ * <code>javax.servlet.ServletRequest</code> method <code>getCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This must return the value returned by the
+ * <code>javax.portlet.ActionRequest</code> method <code>getCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @since 1.2
+ *
+ */
+ public String getRequestCharacterEncoding()
+ {
+ if (mPhase == Bridge.PortletPhase.RenderPhase)
+ {
+ throw new IllegalStateException(
+ "PortletExternalContextImpl.getRequestCharacterEncoding(): Request must be an ActionRequest");
+ }
+
+ return ((ActionRequest) mPortletRequest).getCharacterEncoding();
+ }
+
+ /**
+ *
+ * <p>
+ * Return the MIME Content-Type for this request. If not available, return <code>null</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must return the value returned by the
+ * <code>javax.servlet.ServletRequest</code> method <code>getContentType()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This must return <code>null</code>.
+ * </p>
+ *
+ * NOTE: We are deviating from the javadoc based on recommendation from JSR 301 expert group
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @since 1.2
+ */
+ public String getRequestContentType()
+ {
+ if (mPhase == Bridge.PortletPhase.RenderPhase)
+ {
+ throw new IllegalStateException(
+ "PortletExternalContextImpl.getRequestContentType(): Request must be an ActionRequest");
+ }
+
+ return ((ActionRequest) mPortletRequest).getContentType();
+ }
+
+ /**
+ *
+ * <p>
+ * Returns the name of the character encoding (MIME charset) used for the body sent in this
+ * response.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must return the value returned by the
+ * <code>javax.servlet.ServletResponse</code> method <code>getCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This must return <code>null</code>.
+ * </p>
+ *
+ * NOTE: We are deviating from the javadoc based on recommendation from JSR 301 expert group
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @since 1.2
+ */
+ public String getResponseCharacterEncoding()
+ {
+ if (mPhase == Bridge.PortletPhase.ActionPhase)
+ {
+ throw new IllegalStateException(
+ "PortletExternalContextImpl.getResponseCharacterEncoding(): Response must be a RenderRequest");
+ }
+
+ return ((RenderResponse) mPortletResponse).getCharacterEncoding();
+ }
+
+ /**
+ *
+ * <p>
+ * Return the MIME Content-Type for this response. If not available, return <code>null</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must return the value returned by the
+ * <code>javax.servlet.ServletResponse</code> method <code>getContentType()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This must return <code>null</code>.
+ * </p>
+ *
+ * NOTE: We are deviating from the javadoc based on recommendation from JSR 301 expert group
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @since 1.2
+ */
+ public String getResponseContentType()
+ {
+ if (mPhase == Bridge.PortletPhase.ActionPhase)
+ {
+ throw new IllegalStateException(
+ "PortletExternalContextImpl.getResponseContentType(): Response must be a RenderRequest");
+ }
+
+ return ((RenderResponse) mPortletResponse).getContentType();
+ }
+
+ /**
+ * <p>
+ * Set the environment-specific response to be returned by subsequent calls to
+ * {@link #getResponse}. This may be used to install a wrapper for the response.
+ * </p>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ *
+ * @since 1.2
+ */
+ public void setResponse(Object response)
+ {
+ mPortletResponse = (PortletResponse) response;
+ }
+
+ /**
+ *
+ * <p>
+ * Sets the character encoding (MIME charset) of the response being sent to the client, for
+ * example, to UTF-8.
+ * </p>
+ *
+ * <p>
+ * <em>Servlet:</em> This must call through to the <code>javax.servlet.ServletResponse</code>
+ * method <code>setCharacterEncoding()</code>.
+ * </p>
+ *
+ * <p>
+ * <em>Portlet:</em> This method must take no action.
+ * </p>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ *
+ * @since 1.2
+ *
+ */
+ public void setResponseCharacterEncoding(String encoding)
+ {
+ // JSR 168 has no corresponding API.
+ }
+
+ // End of JSF 1.2 API
+
+ /**
+ * Gets the view identifier we should use for this request.
+ */
+ private String getViewId() throws BridgeDefaultViewNotSpecifiedException
+ {
+ String viewId = (String) mPortletRequest.getParameter(ACTION_ID_PARAMETER_NAME);
+
+ log("PortletExternalContextImpl.getViewId: found action_id = " + viewId);
+
+ // If no defaultview then throw an exception
+ if (viewId == null)
+ {
+ viewId = (String) mPortletRequest.getAttribute(Bridge.DEFAULT_VIEWID);
+ if (viewId == null)
+ {
+ throw new BridgeDefaultViewNotSpecifiedException();
+ }
+ log("PortletExternalContextImpl.getViewId: action_id not found, defaulting to: " + viewId);
+ }
+
+ // Some viewId may have query string, so handle that here
+ // (e.g., TaskFlow has the following viewId:
+ // /adf.task-flow?_document=/WEB-INF/task-flow.xml&_id=task1
+
+ int queryStart = viewId.indexOf('?');
+ QueryString queryStr = null;
+
+ if (queryStart != -1)
+ {
+ // parse the query string and add the parameters to internal maps
+ // delay the creation of ParameterMap and ParameterValuesMap until
+ // they are needed/called by the client
+ queryStr = new QueryString(viewId.substring(queryStart + 1), "UTF8");
+
+ mInternalRequestParameterMap = new HashMap(5);
+ mInternalRequestParameterValuesMap = new HashMap(5);
+
+ Enumeration list = queryStr.getParameterNames();
+ while (list.hasMoreElements())
+ {
+ String param = (String) list.nextElement().toString();
+ mInternalRequestParameterMap.put(param, queryStr.getParameter(param));
+ mInternalRequestParameterValuesMap
+ .put(param, new String[] { queryStr.getParameter(param) });
+ }
+
+ viewId = viewId.substring(0, queryStart);
+ log("PortletExternalContextImpl.getViewId: special viewId: " + viewId);
+ }
+
+ return viewId;
+ }
+
+ private void mapPathsFromViewId(String viewId, Vector mappings)
+ {
+ if (viewId == null || mappings == null)
+ {
+ // Fail safe -- even if we didn't find a servlet mapping set path
+ // info
+ // as if we did as this value is all anything generally depends on
+ mPathInfo = viewId;
+ return;
+ }
+
+ // see if the viewId terminates with an extension
+ // if non-null value contains *.XXX where XXX is the extension
+ String ext = extensionMappingFromViewId(viewId);
+ if (ext != null && mappings.contains(ext))
+ {
+ // we are extension mapped
+ mServletPath = viewId;
+ mPathInfo = null;
+ return;
+ }
+
+ // Otherwise we must be servlet mapped. Use the first path defined
+ // in mappings that isn't extension mapped
+ for (int i = 0; i < mappings.size(); i++)
+ {
+ String mapping = (String) mappings.elementAt(i);
+ if (mapping.startsWith("/"))
+ {
+ int j = mapping.lastIndexOf("/*");
+ if (j != -1)
+ {
+ mServletPath = mapping.substring(0, j);
+ }
+ }
+ }
+ // Fail safe -- even if we didn't find a servlet mapping set path info
+ // as if we did as this value is all anything generally depends on
+ mPathInfo = viewId;
+ }
+
+ private String extensionMappingFromViewId(String viewId)
+ {
+ int extLoc = viewId.lastIndexOf('.');
+
+ if (extLoc != -1 && extLoc > viewId.lastIndexOf('/'))
+ {
+ StringBuffer sb = new StringBuffer("*");
+ sb.append(viewId.substring(extLoc));
+ return sb.toString();
+ }
+ return null;
+ }
+
+ private String getViewIdFromPath(String url)
+ {
+ // Get a string that holds the path after the Context-Path through the
+ // target
+
+ // First remove the query string
+ int i = url.indexOf("?");
+ if (i != -1)
+ {
+ url = url.substring(0, i);
+ }
+
+ // Now remove up through the ContextPath
+ String ctxPath = getRequestContextPath();
+ i = url.indexOf(ctxPath);
+ if (i != -1)
+ {
+ url = url.substring(i + ctxPath.length());
+ }
+
+ String viewId = null;
+ // Okay now figure out whether this is prefix or suffixed mapped
+ if (isSuffixedMapped(url, mFacesMappings))
+ {
+ viewId = viewIdFromSuffixMapping(
+ url,
+ mFacesMappings,
+ mPortletContext
+ .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
+ }
+ if (isPrefixedMapped(url, mFacesMappings))
+ {
+ viewId = viewIdFromPrefixMapping(url, mFacesMappings);
+ }
+ else
+ {
+ // Set to what follows the URL
+ viewId = url;
+ }
+ return viewId;
+ }
+
+ private boolean isSuffixedMapped(String url, Vector mappings)
+ {
+ // see if the viewId terminates with an extension
+ // if non-null value contains *.XXX where XXX is the extension
+ String ext = extensionMappingFromViewId(url);
+ return ext != null && mappings.contains(ext);
+ }
+
+ private String viewIdFromSuffixMapping(String url, Vector mappings, String ctxDefault)
+ {
+ // replace extension with the DEFAULT_SUFFIX
+ if (ctxDefault == null)
+ {
+ ctxDefault = ViewHandler.DEFAULT_SUFFIX;
+ }
+
+ int i = url.lastIndexOf(".");
+ if (ctxDefault != null && i != -1)
+ {
+ if (ctxDefault.startsWith("."))
+ {
+ url = url.substring(0, i) + ctxDefault;
+ }
+ else
+ {
+ // shouldn't happen
+ url = url.substring(0, i) + "." + ctxDefault;
+ }
+ }
+ return url;
+ }
+
+ private boolean isPrefixedMapped(String url, Vector mappings)
+ {
+ for (int i = 0; i < mappings.size(); i++)
+ {
+ String prefix = null;
+ String mapping = (String) mappings.elementAt(i);
+ if (mapping.startsWith("/"))
+ {
+ int j = mapping.lastIndexOf("/*");
+ if (j != -1)
+ {
+ prefix = mapping.substring(0, j);
+ }
+ }
+ if (prefix != null && url.startsWith(prefix))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String viewIdFromPrefixMapping(String url, Vector mappings)
+ {
+ for (int i = 0; i < mappings.size(); i++)
+ {
+ String prefix = null;
+ String mapping = (String) mappings.elementAt(i);
+ if (mapping.startsWith("/"))
+ {
+ int j = mapping.lastIndexOf("/*");
+ if (j != -1)
+ {
+ prefix = mapping.substring(0, j);
+ }
+ }
+ if (prefix != null && url.startsWith(prefix))
+ {
+ return url.substring(prefix.length());
+ }
+ }
+ return null;
+ }
+
+ private String viewIdWithPrefixMapping(String viewId, Vector mappings)
+ {
+ // use first prefix mapping found
+ for (int i = 0; i < mappings.size(); i++)
+ {
+ String prefix = null;
+ String mapping = (String) mappings.elementAt(i);
+ if (mapping.startsWith("/"))
+ {
+ int j = mapping.lastIndexOf("/*");
+ if (j != -1)
+ {
+ prefix = mapping.substring(0, j);
+ }
+ }
+ if (prefix != null)
+ {
+ if (viewId.startsWith("/"))
+ {
+ return prefix + viewId;
+ }
+ else
+ {
+ return prefix + "/" + viewId;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isAbsoluteURL(String url)
+ {
+ if (url.startsWith("http"))
+ {
+ return true;
+ }
+
+ // now deal with other possible protocols
+ int i = url.indexOf(":");
+ if (i == -1)
+ {
+ return false;
+ }
+ int j = url.indexOf("/");
+ if (j != -1 && j > i)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isExternalURL(String url)
+ {
+
+ if (!isAbsoluteURL(url))
+ {
+ return false;
+ }
+
+ // otherwise see if the URL contains the ContextPath
+
+ // Simple test is that the url doesn't contain
+ // the CONTEXT_PATH -- though ultimately may want to test
+ // if we are on the same server
+ String ctxPath = getRequestContextPath();
+ int i = url.indexOf(ctxPath);
+ int j = url.indexOf("?");
+ if (i != -1 && (j == -1 || i < j))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isDirectLink(String url)
+ {
+ int queryStart = url.indexOf('?');
+ QueryString queryStr = null;
+ String directLink = null;
+
+ if (queryStart != -1)
+ {
+ queryStr = new QueryString(url.substring(queryStart + 1), "UTF8");
+ directLink = queryStr.getParameter(Bridge.DIRECT_LINK);
+ return Boolean.parseBoolean(directLink);
+ }
+
+ return false;
+ }
+
+ private String removeDirectLink(String url)
+ {
+ int queryStart = url.indexOf('?');
+ QueryString queryStr = null;
+ String directLink = null;
+
+ if (queryStart != -1)
+ {
+ queryStr = new QueryString(url.substring(queryStart + 1), "UTF8");
+ directLink = queryStr.getParameter(Bridge.DIRECT_LINK);
+ if (!Boolean.parseBoolean(directLink))
+ {
+ queryStr.removeParameter(Bridge.DIRECT_LINK);
+ String query = queryStr.toString();
+ if (query != null && query.length() != 0)
+ {
+ url = url.substring(0, queryStart + 1) + query;
+ }
+ }
+ }
+
+ return url;
+ }
+
+ private String getViewIdFromRelativePath(String url)
+ {
+ String currentViewId = getViewId();
+ int i = currentViewId.indexOf('?');
+ if (i != -1)
+ {
+ currentViewId = currentViewId.substring(0, i);
+ }
+
+ String prefixURL = currentViewId.substring(0, currentViewId.lastIndexOf('/'));
+
+ if (prefixURL.length() != 0 && !prefixURL.startsWith("/"))
+ {
+ log("PortletExternalContextImpl.encodeActionURL:end:in(" + url + ")");
+ return null; // this shouldn't happen, if so just return
+ }
+
+ if (url.startsWith("./"))
+ {
+ url = url.substring(2);
+ }
+ while (url.startsWith("../") && prefixURL.length() != 0)
+ {
+ url = url.substring(3);
+ prefixURL = prefixURL.substring(0, prefixURL.lastIndexOf('/'));
+ }
+ url = prefixURL + "/" + url;
+
+ // Now check to see if suffix mapped because we need to do the extension
+ // mapping
+ if (isSuffixedMapped(url, mFacesMappings))
+ {
+ url = viewIdFromSuffixMapping(
+ url,
+ mFacesMappings,
+ mPortletContext
+ .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
+ }
+
+ return url;
+ }
+
+ private boolean isRelativePath(String url)
+ {
+ // relative path doesn't start with a '/'
+ if (url.startsWith("/"))
+ {
+ return false;
+ }
+
+ // relative path if starts with a '.' or doesn't contain a '/'
+ if (url.startsWith("."))
+ {
+ return true;
+ }
+
+ // neither obviously a relative path or not -- now discount protocol
+ int i = url.indexOf("://");
+ if (i == -1)
+ {
+ return true;
+ }
+
+ // make sure : isn't in querystring
+ int j = url.indexOf('?');
+ if (j != -1 && j < i)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+}
Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java?rev=588233&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java Thu Oct 25 06:38:05 2007
@@ -0,0 +1,340 @@
+/* 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.myfaces.portlet.faces.context;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIViewRoot;
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseStream;
+import javax.faces.context.ResponseWriter;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+
+import javax.portlet.PortletResponse;
+
+import javax.portlet.faces.Bridge;
+import javax.portlet.faces.component.PortletNamingContainer;
+
+import org.apache.myfaces.portlet.faces.el.PortletELContextImpl;
+
+/**
+ * Implementation of <code>FacesContext</code> for portlet environment
+ */
+public class PortletFacesContextImpl extends FacesContext
+{
+ private Application mApplication;
+ private RenderKitFactory mRenderKitFactory;
+ private ExternalContext mExternalContext;
+ private ResponseStream mResponseStream = null;
+ private ResponseWriter mResponseWriter = null;
+ private UIViewRoot mViewRoot;
+ private boolean mRenderResponse = false;
+ private boolean mResponseComplete = false;
+ private Map mMessages = new HashMap();
+ private FacesMessage.Severity mMaximumSeverity = FacesMessage.SEVERITY_INFO;
+ private ELContext mElContext = null;
+
+ public PortletFacesContextImpl(ExternalContext externalContext, Lifecycle lifecycle)
+ throws FacesException
+ {
+ mApplication = ((ApplicationFactory) FactoryFinder
+ .getFactory(FactoryFinder.APPLICATION_FACTORY))
+ .getApplication();
+ mRenderKitFactory = (RenderKitFactory) FactoryFinder
+ .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ mExternalContext = externalContext;
+
+ FacesContext.setCurrentInstance(this);
+ }
+
+ // Start of JSF 1.2 API
+
+ /**
+ * <p>
+ * Return the <code>ELContext</code> instance for this <code>FacesContext</code> instance.
+ * This <code>ELContext</code> instance has the same lifetime and scope as the
+ * <code>FacesContext</code> instance with which it is associated, and may be created lazily the
+ * first time this method is called for a given <code>FacesContext</code> instance. Upon
+ * creation of the ELContext instance, the implementation must take the following action:
+ * </p>
+ *
+ * <ul>
+ *
+ * <li>
+ * <p>
+ * Call the {@link ELContext#putContext} method on the instance, passing in
+ * <code>FacesContext.class</code> and the <code>this</code> reference for the
+ * <code>FacesContext</code> instance itself.
+ * </p>
+ * </li>
+ *
+ * <li>
+ * <p>
+ * If the <code>Collection</code> returned by {@link
+ * javax.faces.application.Application#getELContextListeners} is non-empty, create an instance of
+ * {@link javax.el.ELContextEvent} and pass it to each {@link javax.el.ELContextListener} instance
+ * in the <code>Collection</code> by calling the {@link
+ * javax.el.ELContextListener#contextCreated} method.
+ * </p>
+ * </li>
+ *
+ * </ul>
+ *
+ * <p>
+ * The default implementation throws <code>UnsupportedOperationException</code> and is provided
+ * for the sole purpose of not breaking existing applications that extend this class.
+ * </p>
+ *
+ * @throws IllegalStateException
+ * if this method is called after this instance has been released
+ *
+ * @since 1.2
+ */
+ @Override
+ public ELContext getELContext()
+ {
+ if (mElContext == null)
+ {
+ mElContext = new PortletELContextImpl(getApplication().getELResolver());
+ mElContext.putContext(FacesContext.class, this);
+ UIViewRoot root = getViewRoot();
+ if (null != root)
+ {
+ mElContext.setLocale(root.getLocale());
+ }
+ // TODO - The spec said that when an instance is created,
+ // implementation
+ // must call contextCreated() method of all the ELContextListener's,
+ // but the RI FacesContextImpl is not doing this, so not sure if
+ // it's
+ // necessary. We'll revisit this later
+ }
+ return mElContext;
+ }
+
+ // End of JSF 1.2 API
+
+ @Override
+ public ExternalContext getExternalContext()
+ {
+ return mExternalContext;
+ }
+
+ @Override
+ public FacesMessage.Severity getMaximumSeverity()
+ {
+ return mMaximumSeverity;
+ }
+
+ @Override
+ public Iterator getMessages()
+ {
+ List results = new ArrayList();
+ Iterator clientIds = mMessages.keySet().iterator();
+ while (clientIds.hasNext())
+ {
+ String clientId = (String) clientIds.next();
+ results.addAll((List) mMessages.get(clientId));
+ }
+ return results.iterator();
+ }
+
+ @Override
+ public Application getApplication()
+ {
+ return mApplication;
+ }
+
+ @Override
+ public Iterator getClientIdsWithMessages()
+ {
+ return mMessages.keySet().iterator();
+ }
+
+ @Override
+ public Iterator getMessages(String clientId)
+ {
+ List list = (List) mMessages.get(clientId);
+ if (list == null)
+ {
+ list = new ArrayList();
+ }
+ return list.iterator();
+ }
+
+ @Override
+ public RenderKit getRenderKit()
+ {
+ if (getViewRoot() == null)
+ {
+ return null;
+ }
+
+ String renderKitId = getViewRoot().getRenderKitId();
+
+ if (renderKitId == null)
+ {
+ return null;
+ }
+
+ return mRenderKitFactory.getRenderKit(this, renderKitId);
+
+ }
+
+ @Override
+ public boolean getRenderResponse()
+ {
+ return mRenderResponse;
+ }
+
+ @Override
+ public boolean getResponseComplete()
+ {
+ return mResponseComplete;
+ }
+
+ @Override
+ public void setResponseStream(ResponseStream responseStream)
+ {
+ if (responseStream == null)
+ {
+ throw new NullPointerException("setResponseStream(null)");
+ }
+ mResponseStream = responseStream;
+ }
+
+ @Override
+ public ResponseStream getResponseStream()
+ {
+ return mResponseStream;
+ }
+
+ @Override
+ public void setResponseWriter(ResponseWriter responseWriter)
+ {
+ if (responseWriter == null)
+ {
+ throw new NullPointerException("setResponseWriter(null)");
+ }
+ mResponseWriter = responseWriter;
+ }
+
+ @Override
+ public ResponseWriter getResponseWriter()
+ {
+ return mResponseWriter;
+ }
+
+ @Override
+ public void setViewRoot(UIViewRoot viewRoot)
+ {
+ if (viewRoot == null)
+ {
+ throw new NullPointerException("setViewRoot(null)");
+ }
+
+ mViewRoot = viewRoot;
+
+ if (mViewRoot instanceof PortletNamingContainer)
+ {
+ try
+ {
+ PortletResponse pr = (PortletResponse) mExternalContext.getResponse();
+ pr.addProperty(Bridge.PORTLET_ISNAMESPACED_PROPERTY, "true");
+ }
+ catch (Exception e)
+ {
+ // TODO: log message
+ ; // do nothing -- just forge ahead
+ }
+ }
+ }
+
+ @Override
+ public UIViewRoot getViewRoot()
+ {
+ return mViewRoot;
+ }
+
+ @Override
+ public void addMessage(String clientId, FacesMessage message)
+ {
+ if (message == null)
+ {
+ throw new NullPointerException();
+ }
+ List list = (List) mMessages.get(clientId);
+ if (list == null)
+ {
+ list = new ArrayList();
+ mMessages.put(clientId, list);
+ }
+ list.add(message);
+
+ FacesMessage.Severity severity = message.getSeverity();
+ if (severity != null && severity.compareTo(mMaximumSeverity) > 0)
+ {
+ mMaximumSeverity = severity;
+ }
+ }
+
+ @Override
+ public void release()
+ {
+ if (mExternalContext != null && mExternalContext instanceof PortletExternalContextImpl)
+ {
+ ((PortletExternalContextImpl) mExternalContext).release();
+ mExternalContext = null;
+ }
+
+ mApplication = null;
+ mResponseStream = null;
+ mResponseWriter = null;
+ mViewRoot = null;
+ mElContext = null;
+ FacesContext.setCurrentInstance(null);
+ }
+
+ @Override
+ public void renderResponse()
+ {
+ mRenderResponse = true;
+ }
+
+ @Override
+ public void responseComplete()
+ {
+ mResponseComplete = true;
+ }
+}
Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java?rev=588233&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java Thu Oct 25 06:38:05 2007
@@ -0,0 +1,76 @@
+/* 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.myfaces.portlet.faces.el;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.VariableMapper;
+
+/**
+ * Concrete implementation of {@link javax.el.ELContext}. ELContext's constructor is protected to
+ * control creation of ELContext objects through their appropriate factory methods. This version of
+ * ELContext forces construction through PortletFacesContextImpl.
+ *
+ */
+public class PortletELContextImpl extends ELContext
+{
+
+ private FunctionMapper mFunctionMapper;
+ private VariableMapper mVariableMapper;
+ private ELResolver mResolver;
+
+ /**
+ * Constructs a new ELContext associated with the given ELResolver.
+ */
+ public PortletELContextImpl(ELResolver resolver)
+ {
+ mResolver = resolver;
+ }
+
+ public void setFunctionMapper(FunctionMapper fnMapper)
+ {
+ mFunctionMapper = fnMapper;
+ }
+
+ @Override
+ public FunctionMapper getFunctionMapper()
+ {
+ return mFunctionMapper;
+ }
+
+ public void setVariableMapper(VariableMapper varMapper)
+ {
+ mVariableMapper = varMapper;
+ }
+
+ @Override
+ public VariableMapper getVariableMapper()
+ {
+ return mVariableMapper;
+ }
+
+ @Override
+ public ELResolver getELResolver()
+ {
+ return mResolver;
+ }
+
+}
Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java?rev=588233&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java Thu Oct 25 06:38:05 2007
@@ -0,0 +1,251 @@
+/* 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.myfaces.portlet.faces.el;
+
+import java.beans.FeatureDescriptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ExternalContext;
+
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletRequest;
+
+import javax.portlet.faces.Bridge;
+
+public class PortletELResolver extends ELResolver
+{
+
+ // Important preserve index (order) between array and constants
+ public static final String[] IMPLICIT_OBJECTS = new String[] { "portletConfig",
+ "sessionApplicationScope", "sessionPortletScope", "portletPreferenceValue",
+ "portletPreferenceValues" };
+
+ public static final int PORTLET_CONFIG = 0;
+ public static final int SESSION_APPLICATION_SCOPE = 1;
+ public static final int SESSION_PORTLET_SCOPE = 2;
+ public static final int PORTLET_PREFERENCE_VALUE = 3;
+ public static final int PORTLET_PREFERENCE_VALUES = 4;
+
+ public PortletELResolver()
+ {
+ }
+
+ @Override
+ public Object getValue(ELContext context, Object base, Object property) throws ELException
+ {
+ // variable resolution is a special case of property resolution
+ // where the base is null.
+ if (base != null)
+ {
+ return null;
+ }
+ if (property == null)
+ {
+ throw new PropertyNotFoundException("Null property");
+ }
+
+ FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext extCtx = facesContext.getExternalContext();
+
+ // only process if running in a portlet request
+ if (!(extCtx.getRequest() instanceof PortletRequest))
+ {
+ return null;
+ }
+
+ int index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
+ if (index < 0)
+ {
+ return null;
+ }
+ else
+ {
+ switch (index)
+ {
+ case PORTLET_CONFIG:
+ context.setPropertyResolved(true);
+ return context.getContext(PortletConfig.class);
+ case SESSION_APPLICATION_SCOPE:
+ context.setPropertyResolved(true);
+ return extCtx.getSessionMap().get(Bridge.APPLICATION_SCOPE_MAP);
+ case SESSION_PORTLET_SCOPE:
+ context.setPropertyResolved(true);
+ return extCtx.getSessionMap();
+ case PORTLET_PREFERENCE_VALUE:
+ context.setPropertyResolved(true);
+ return getPreferencesValueMap(extCtx);
+ case PORTLET_PREFERENCE_VALUES:
+ context.setPropertyResolved(true);
+ return ((PortletRequest) extCtx.getRequest()).getPreferences().getMap();
+ default:
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public void setValue(ELContext context, Object base, Object property, Object val)
+ throws ELException
+ {
+ if (base != null)
+ {
+ return;
+ }
+ if (property == null)
+ {
+ throw new PropertyNotFoundException("Null property");
+ }
+
+ int index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
+ if (index >= 0)
+ {
+ throw new PropertyNotWritableException((String) property);
+ }
+ }
+
+ @Override
+ public boolean isReadOnly(ELContext context, Object base, Object property) throws ELException
+ {
+ if (base != null)
+ {
+ return false;
+ }
+ if (property == null)
+ {
+ throw new PropertyNotFoundException("Null property");
+ }
+
+ int index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
+ if (index >= 0)
+ {
+ context.setPropertyResolved(true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Class<?> getType(ELContext context, Object base, Object property) throws ELException
+ {
+ if (base != null)
+ {
+ return null;
+ }
+ if (property == null)
+ {
+ throw new PropertyNotFoundException("Null property");
+ }
+
+ int index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
+ if (index >= 0)
+ {
+ context.setPropertyResolved(true);
+ }
+ return null;
+ }
+
+ @Override
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
+ {
+ if (base != null)
+ {
+ return null;
+ }
+ ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(14);
+ list.add(getFeatureDescriptor("portletConfig", "portletConfig", "portletConfig", false, false,
+ true, Object.class, Boolean.TRUE));
+ list.add(getFeatureDescriptor("sessionApplicationScope", "sessionApplicationScope",
+ "sessionApplicationScope", false, false, true, Map.class,
+ Boolean.TRUE));
+ list.add(getFeatureDescriptor("sessionPortletScope", "sessionPortletScope",
+ "sessionPortletScope", false, false, true, Map.class,
+ Boolean.TRUE));
+ list.add(getFeatureDescriptor("portletPreferenceValue", "portletPreferenceValue",
+ "portletPreferenceValue", false, false, true, Map.class,
+ Boolean.TRUE));
+ list.add(getFeatureDescriptor("portletPreferenceValues", "portletPreferenceValues",
+ "portletPreferenceValues", false, false, true, Map.class,
+ Boolean.TRUE));
+ return list.iterator();
+
+ }
+
+ @Override
+ public Class<?> getCommonPropertyType(ELContext context, Object base)
+ {
+ if (base != null)
+ {
+ return null;
+ }
+ return String.class;
+ }
+
+ private FeatureDescriptor getFeatureDescriptor(String name, String displayName, String desc,
+ boolean expert, boolean hidden, boolean preferred,
+ Object type, Boolean designTime)
+ {
+
+ FeatureDescriptor fd = new FeatureDescriptor();
+ fd.setName(name);
+ fd.setDisplayName(displayName);
+ fd.setShortDescription(desc);
+ fd.setExpert(expert);
+ fd.setHidden(hidden);
+ fd.setPreferred(preferred);
+ fd.setValue(ELResolver.TYPE, type);
+ fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, designTime);
+ return fd;
+ }
+
+ private Map getPreferencesValueMap(ExternalContext extCtx)
+ {
+ PortletRequest portletRequest = (PortletRequest) extCtx.getRequest();
+ Enumeration e = portletRequest.getPreferences().getNames();
+ Map m = null;
+
+ while (e.hasMoreElements())
+ {
+ if (m == null)
+ {
+ m = new HashMap();
+ }
+ String name = (String) e.nextElement();
+ String value = portletRequest.getPreferences().getValue(name, null);
+ if (value != null)
+ {
+ m.put(name, value);
+ }
+ }
+ return m;
+ }
+
+}