You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by so...@apache.org on 2010/03/17 10:59:27 UTC
svn commit: r924205 -
/myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
Author: sobryan
Date: Wed Mar 17 09:59:26 2010
New Revision: 924205
URL: http://svn.apache.org/viewvc?rev=924205&view=rev
Log:
Updates to the ExternalContextImpl
Modified:
myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
Modified: myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=924205&r1=924204&r2=924205&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan_portlet-bridge-3.0.0/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Wed Mar 17 09:59:26 2010
@@ -23,14 +23,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-
import java.io.Writer;
-
import java.net.MalformedURLException;
import java.net.URL;
-
import java.security.Principal;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -45,10 +41,7 @@ import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
-
-import javax.faces.context.Flash;
import javax.faces.render.ResponseStateManager;
-
import javax.portlet.ActionResponse;
import javax.portlet.BaseURL;
import javax.portlet.ClientDataRequest;
@@ -61,14 +54,12 @@ import javax.portlet.PortletRequestDispa
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.PortletURL;
-import javax.portlet.RenderResponse;
import javax.portlet.ResourceURL;
import javax.portlet.StateAwareResponse;
import javax.portlet.WindowState;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
import javax.portlet.faces.BridgeInvalidViewPathException;
-
import javax.servlet.http.Cookie;
import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
@@ -338,11 +329,12 @@ public class PortletExternalContextImpl
public String encodeActionURL(String url)
{
String viewId = null, path = null;
- boolean nonFacesAction = false;
QueryString queryStr = null;
int queryStart = -1;
boolean isPortletURL = false;
- Bridge.PortletPhase urlType = getPortletPhase();
+ boolean isPortletURLSelfReference = false;
+ boolean isStrictXhtmlEncoded = isStrictXhtmlEncoded(url);
+ Bridge.PortletPhase urlType = Bridge.PortletPhase.ACTION_PHASE;
// First check to see if the special URI indicating we should encode
// a Nonfaces target to just the current portlet (without an associated
@@ -350,7 +342,6 @@ public class PortletExternalContextImpl
if (isPortletURL(url))
{
isPortletURL = true;
- nonFacesAction = true;
//URL is of the form scheme:urlType?queryString
// remove the scheme
path = url.substring(url.indexOf(":")+ 1);
@@ -381,6 +372,27 @@ public class PortletExternalContextImpl
+ url);
return url;
}
+
+ // We allow use of this syntax to reference another (or this) jsf page --
+ // For example if one wants to create a redisplay link for this page
+ // we recognize its a JSF page because it includes a QS parameter
+ // that references either the viewId or viewPath
+ String s = queryStr.getParameter(Bridge.FACES_VIEW_ID_PARAMETER);
+ String s1 = queryStr.getParameter(Bridge.FACES_VIEW_PATH_PARAMETER);
+ if (s != null && s.equals(Bridge.FACES_USE_CURRENT_VIEW_PARAMETER))
+ {
+ isPortletURLSelfReference = true;
+ // by removing the parameter we will rely on retaining the current view info based on \
+ // the current render params
+ queryStr.removeParameter(Bridge.FACES_VIEW_ID_PARAMETER);
+ }
+ else if (s != null && s1.equals(Bridge.FACES_USE_CURRENT_VIEW_PARAMETER))
+ {
+ isPortletURLSelfReference = true;
+ // by removing the parameter we will rely on retaining the current view info based on \
+ // the current render params
+ queryStr.removeParameter(Bridge.FACES_VIEW_PATH_PARAMETER);
+ }
}
else if (url.startsWith("#") || isExternalURL(url) || isDirectLink(url))
{
@@ -429,7 +441,6 @@ public class PortletExternalContextImpl
else
{
// URL points at non-Faces action
- nonFacesAction = true;
encodeNonFacesActionTarget(queryStr, path);
}
}
@@ -446,24 +457,17 @@ public class PortletExternalContextImpl
ResourceURL resourceURL = null;
BaseURL baseURL = null;
// Non-JSF actions are renderURLs as we merely dispatch to them
- if (nonFacesAction)
+ if (urlType == Bridge.PortletPhase.ACTION_PHASE)
{
- if (isPortletURL && urlType == Bridge.PortletPhase.ACTION_PHASE)
- {
- baseURL = actionURL = mimeResponse.createActionURL();
- }
- else if (isPortletURL && urlType == Bridge.PortletPhase.RESOURCE_PHASE)
- {
- baseURL = resourceURL = mimeResponse.createResourceURL();
- }
- else
- {
- baseURL = actionURL = mimeResponse.createRenderURL();
- }
- }
+ baseURL = actionURL = mimeResponse.createActionURL();
+ }
+ else if (urlType == Bridge.PortletPhase.RESOURCE_PHASE)
+ {
+ baseURL = resourceURL = mimeResponse.createResourceURL();
+ }
else
{
- baseURL = actionURL = mimeResponse.createActionURL();
+ baseURL = actionURL = mimeResponse.createRenderURL();
}
// Add parameters so they don't get lost
@@ -509,14 +513,23 @@ public class PortletExternalContextImpl
baseURL.setParameter(param, queryStr.getParameter(param));
}
}
+
+ // Carry forward render parameters if this is a portlet:url that references the current view
+ if (isPortletURLSelfReference)
+ {
+ carryForwardRenderParameters(baseURL, mPortletRequest.getPrivateParameterMap(), queryStr);
+ carryForwardRenderParameters(baseURL, mPortletRequest.getPublicParameterMap(), queryStr);
+ }
- // Some portlet containers implementing wsrp choose to separate the
- // consumer rewrite string that represents this URL using & as the
- // spec allows for either that or &. If the container has chosen to
- // to do such -- undo it (use & instead) as faces renderkits/response writers
- // may reencode when writing XMl content.
- url = baseURL.toString();
- url = url.replaceAll("\\&\\;", "&");
+ // If we weren't already Xhtml encoded (used &) then renderkit will likely
+ // do it after us if it needs to do such encoding -- so undo any xml encoding the portlet URL might
+ // have done to avoid double encoding -- Otherwise if the string passed in was encoded the renderkit
+ // is unlikely to reencode after the call -- so don't undo any encoding.
+ if (!isStrictXhtmlEncoded)
+ {
+ url = actionURL.toString();
+ url = url.replaceAll("\\&\\;", "&");
+ }
}
else if (getPortletPhase() == Bridge.PortletPhase.ACTION_PHASE ||
getPortletPhase() == Bridge.PortletPhase.EVENT_PHASE)
@@ -579,6 +592,21 @@ public class PortletExternalContextImpl
return url;
}
+
+ private void carryForwardRenderParameters(BaseURL url, Map<String, String[]> m, QueryString queryStr)
+ {
+ Set<Map.Entry<String, String[]>> s = m.entrySet();
+ Iterator<Map.Entry<String, String[]>> i = s.iterator();
+ while (i.hasNext())
+ {
+ Map.Entry<String, String[]> entry = i.next();
+ // only add if not already added from above
+ if (queryStr.getParameter(entry.getKey()) == null)
+ {
+ url.setParameter(entry.getKey(), entry.getValue());
+ }
+ }
+ }
@Override
public void redirect(String url)
@@ -653,7 +681,51 @@ public class PortletExternalContextImpl
private void redirectDuringRender(String url)
throws IOException
{
- redirectFacesView(url);
+ // As this doesn't go back to the consumer -- we need to reencode the public render parameters so they are there
+ redirectFacesView(encodePublicRenderParameters(url));
+ }
+
+ private String encodePublicRenderParameters(String inUrl)
+ {
+ // If there are no Public Render Parameters just return the inUrl
+ Map<String, String[]> m = mPortletRequest.getPublicParameterMap();
+ if (m == null || m.isEmpty())
+ {
+ return inUrl;
+ }
+
+ // Otherwise -- there are public render parameters that need to be encoded
+ StringBuffer outUrl = null;
+ QueryString queryStr = null;
+ int queryStart = inUrl.indexOf('?');
+
+ if (queryStart != -1)
+ {
+ // Get the query string
+ queryStr = new QueryString(inUrl.substring(queryStart + 1), "UTF8");
+ outUrl = new StringBuffer(inUrl.substring(0, queryStart));
+ }
+ else
+ {
+ outUrl = new StringBuffer(inUrl);
+ // construct an empty queryString to hold the viewId
+ queryStr = new QueryString("UTF8");
+ }
+
+ for (Map.Entry<String, String[]> entry:m.entrySet())
+ {
+ String key = entry.getKey();
+
+ // Only add if not already reflected in the QS
+ if (queryStr.getParameter(key) == null)
+ {
+ for (String param:entry.getValue())
+ {
+ queryStr.addParameter(key, param);
+ }
+ }
+ }
+ return outUrl.append("?").append(queryStr.toString()).toString();
}
private void redirectFacesView(String url)
@@ -704,28 +776,39 @@ public class PortletExternalContextImpl
@Override
public String encodeResourceURL(String s)
{
- if (isOpaqueURL(s))
+ if (isPortletURL(s))
+ {
+ return urlEncode(encodeResourceAsViewNavigationURL(s));
+ }
+ else if (isOpaqueURL(s))
{
- return s;
+ // spec says return this unchanged
+ return s;
}
- if (isExternalURL(s))
+ else if (isExternalURL(s))
{
- return encodeResourceURL(s, false);
+ return urlEncode(encodeResourceURL(s, false));
}
- else if (isViewLink(s) || isPortletURL(s))
+ else if (isViewLink(s))
{
- return encodeResourceAsViewNavigationURL(s);
+ return urlEncode(encodeResourceAsViewNavigationURL(s));
}
else if (!isInProtocolResourceLink(s))
{
- return encodeResourceURL(s, true);
+ return urlEncode(encodeResourceURL(s, true));
}
else
{
- return encodePortletServedResourceURL(s);
+ return urlEncode(encodePortletServedResourceURL(s));
}
}
+ private String urlEncode(String s)
+ {
+ // replace all spaces in the url with %20 to avoid Faces from encoding with a +
+ return s.replace(" ", "%20");
+ }
+
private String encodeResourceURL(String s, boolean targetInApp)
{
if (targetInApp)
@@ -735,13 +818,25 @@ public class PortletExternalContextImpl
// Check for backlink and viewlink markers -- if they exist replace
s = replaceResourceQueryStringMarkers(s);
+
+ // If we weren't already Xhtml encoded (used &) then renderkit will likely
+ // do it after us if it needs to do such encoding -- so undo any xml encoding the portlet URL might
+ // have done to avoid double encoding -- Otherwise if the string passed in was encoded the renderkit
+ // is unlikely to reencode after the call -- so don't undo any encoding.
+ if (!isStrictXhtmlEncoded(s))
+ {
- // Some portlet containers implementing wsrp choose to separate the
- // consumer rewrite string that represents this URL using & as the
- // spec allows for either that or &. If the container has chosen to
- // to do such -- undo it (use & instead) as faces renderkits/response writers
- // may reencode when writing XMl content.
- return mPortletResponse.encodeURL(s).replaceAll("\\&\\;", "&");
+ // Some portlet containers implementing wsrp choose to separate the
+ // consumer rewrite string that represents this URL using & as the
+ // spec allows for either that or &. If the container has chosen to
+ // to do such -- undo it (use & instead) as faces renderkits/response writers
+ // may reencode when writing XMl content.
+ return mPortletResponse.encodeURL(s).replaceAll("\\&\\;", "&");
+ }
+ else
+ {
+ return mPortletResponse.encodeURL(s);
+ }
}
private String normalizeResourcePath(String s)
@@ -1542,6 +1637,17 @@ public class PortletExternalContextImpl
}
+ @Override
+ public Writer getResponseOutputWriter() throws IOException
+ {
+ if (mPortletResponse instanceof MimeResponse)
+ {
+ return ((MimeResponse)mPortletResponse).getWriter();
+ }
+
+ throw new IllegalStateException();
+ }
+
/**
* <p>
* Set the environment-specific response to be returned by subsequent calls to
@@ -1592,9 +1698,42 @@ public class PortletExternalContextImpl
{
// JSR 168 has no corresponding API.
}
+
+ @Override
+ public boolean isResponseCommitted()
+ {
+ if(mPortletResponse instanceof MimeResponse)
+ {
+ return ((MimeResponse)mPortletResponse).isCommitted();
+ }
+
+ //TODO: What should be returned here? False or Unsupported Operation?
+ throw new IllegalStateException();
+ }
- // End of JSF 1.2 API
+ @Override
+ public void responseReset()
+ {
+ if(mPortletResponse instanceof MimeResponse)
+ {
+ ((MimeResponse)mPortletResponse).reset();
+ }
+ else
+ {
+ //TODO: What should be done here? noop or UnsupportedOperationException?
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public void setResponseStatus(int statusCode)
+ {
+ //TODO: What should I do here. It would be cool to render out an
+ //error page to display in the portlet
+ System.out.println("*****Status Code: "+ statusCode);
+ }
+ // End of JSF 1.2 API
private Bridge.PortletPhase getPortletPhase()
{
return (Bridge.PortletPhase) getRequestMap().get(Bridge.PORTLET_LIFECYCLE_PHASE);
@@ -2067,6 +2206,33 @@ public class PortletExternalContextImpl
return url.toLowerCase().startsWith("portlet:");
}
+ private boolean isStrictXhtmlEncoded(String url)
+ {
+ // check for use of & in query string
+ int currentPos = url.indexOf('?');
+
+ if (currentPos == -1) return false;
+
+ boolean isStrict = false;
+ while (true)
+ {
+ int ampPos = url.indexOf('&', currentPos);
+ int xhtmlAmpPos = url.indexOf("\\&\\;", currentPos);
+ // no more & to process -- so return current value of isStrict
+ if (ampPos == -1)
+ {
+ return isStrict;
+ }
+ // if the amp we found doesn't start an & then its not strict
+ if (ampPos != xhtmlAmpPos)
+ {
+ return false;
+ }
+ isStrict = true;
+ currentPos = ampPos;
+ }
+ }
+
private boolean isAbsoluteURL(String url)
{
@@ -2110,8 +2276,8 @@ public class PortletExternalContextImpl
}
// Its opaque if it is absolute (contains a scheme) that isn't followed
- // by a '/'
- return (url.indexOf(':') != (url.indexOf('/') - 1));
+ // by a '/' or doesn't start with our special portlet: scheme
+ return (!isPortletURL(url) && (url.indexOf(':') != (url.indexOf('/') - 1)));
}
private boolean isExternalURL(String url)