*/
@Override
public String encodeActionURL(String url)
{
String viewId = null, path = null;
QueryString queryStr = null;
int queryStart = -1;
boolean isPortletURL = false;
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
// path based resource).
if (isPortletURL(url))
{
isPortletURL = true;
//URL is of the form scheme:urlType?queryString
// remove the scheme
path = url.substring(url.indexOf(":")+ 1);
queryStart = path.indexOf('?');
if (queryStart != -1)
{
// Get the query string
queryStr = new QueryString(path.substring(queryStart + 1), "UTF8");
path = path.substring(0, queryStart);
}
if (path.equalsIgnoreCase("render"))
{
urlType = Bridge.PortletPhase.RENDER_PHASE;
}
else if (path.equalsIgnoreCase("action"))
{
urlType = Bridge.PortletPhase.ACTION_PHASE;
}
else if (path.equalsIgnoreCase("resource"))
{
urlType = Bridge.PortletPhase.RESOURCE_PHASE;
}
else
{
log("PortletExternalContextImpl.encodeActionURL: malformed portlet url "
+ 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 (s1 != 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("#") || isAbsoluteURL(url))
{
return url;
}
else if (isDirectLink(url))
{
// its not an absolute URL (or would have been handled in previous if) convert it into one.
return getAbsoluteUrlFromPath(url);
}
else
{
// Its a Path encoded URL
// url might contain DirectLink=false parameter -- spec says remove if
// it does.
url = removeDirectLink(url);
// Now determine the target viewId
// First: split URL into path and query string
// Hold onto QueryString for later processing
queryStart = url.indexOf('?');
if (queryStart != -1)
{
// Get the query string
queryStr = new QueryString(url.substring(queryStart + 1), "UTF8");
path = url.substring(0, queryStart);
}
else
{
path = url;
// construct an empty queryString to hold the viewId
queryStr = new QueryString("UTF8");
}
// Convert relative path to context path
if (isRelativePath(path))
{
path = getPathFromRelativePath(path);
}
// Now se if this is a Faces URL
viewId = getViewIdFromPath(path);
if (viewId != null)
{
encodeFacesActionTarget(queryStr, viewId);
}
else
{
// URL points at non-Faces action
// Non-JSF actions are renderURLs as we merely dispatch to them
urlType = Bridge.PortletPhase.RENDER_PHASE;
encodeNonFacesActionTarget(queryStr, path);
}
}
if (getPortletPhase() == Bridge.PortletPhase.RENDER_PHASE ||
getPortletPhase() == Bridge.PortletPhase.RESOURCE_PHASE)
{ // render - write
// the viewId into
// the response
// (interaction
// state)
MimeResponse mimeResponse = (MimeResponse) getResponse();
PortletURL actionURL = null;
ResourceURL resourceURL = null;
BaseURL baseURL = null;
// Non-JSF actions are renderURLs as we merely dispatch to them
if (urlType == Bridge.PortletPhase.ACTION_PHASE)
{
baseURL = actionURL = mimeResponse.createActionURL();
}
else if (urlType == Bridge.PortletPhase.RESOURCE_PHASE)
{
baseURL = resourceURL = mimeResponse.createResourceURL();
}
else
{
baseURL = actionURL = mimeResponse.createRenderURL();
}
// Add parameters so they don't get lost
Enumeration<String> list = queryStr.getParameterNames();
while (list.hasMoreElements())
{
String param = list.nextElement().toString();
if (actionURL != null && param.equals(Bridge.PORTLET_MODE_PARAMETER))
{
try
{
actionURL.setPortletMode(new PortletMode(queryStr.getParameter(param)));
}
catch (Exception e)
{
; // do nothing -- just ignore
}
}
else if (actionURL != null && param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
{
try
{
actionURL.setWindowState(new WindowState(queryStr.getParameter(param)));
}
catch (Exception e)
{
; // do nothing -- just ignore
}
}
else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
{
try
{
baseURL.setSecure(Boolean.getBoolean(queryStr.getParameter(param)));
}
catch (Exception e)
{
; // do nothing -- just ignore
}
}
else
{
baseURL.setParameter(param, queryStr.getParameter(param));
}
}
// Carry forward render parameters if this is a portlet:url that references the current view
if (isPortletURLSelfReference)
{
Map<String, String[]> addedActionParams = (Map<String, String[]>) getRequestMap().get(BridgeImpl.REQUEST_PARAMETERS);
if (addedActionParams == null)
{
addedActionParams = Collections.EMPTY_MAP;
}
carryForwardRenderParameters(baseURL, mPortletRequest.getPrivateParameterMap(), queryStr, addedActionParams);
carryForwardRenderParameters(baseURL, mPortletRequest.getPublicParameterMap(), queryStr, addedActionParams);
}
// JSF expects encodeActionURL to not perturb any XML encoding (or lack thereof) of the url.
// I.e. the caller is responsible for either pre or post XML escaping the string sent/returned
// by encodeActionURL. As Portlet 2.0 provides specific apis for xml encoding/escaping the url (or not),
// use the right form based on what we saw in the incoming url
url = portletURLToString(baseURL, isStrictXhtmlEncoded);
}
else if (getPortletPhase() == Bridge.PortletPhase.ACTION_PHASE ||
getPortletPhase() == Bridge.PortletPhase.EVENT_PHASE)
{ // action - write the viewId to navigational state
StateAwareResponse stateResponse = (StateAwareResponse) getResponse();
// set request params into navigational states
Enumeration<String> list = queryStr.getParameterNames();
while (list.hasMoreElements())
{
String param = list.nextElement();
if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
{
try
{
stateResponse.setPortletMode(new PortletMode(queryStr.getParameter(param)));
}
catch (Exception e)
{
//TODO: Ignoring is probably dangerous here as it means that we are
// EITHER using exceptions for flow control (which is extreemly
// inefficient) or we should log a message saying what the issue
// is. According to the Javadocs an exception is thrown here if the
// portlet mode is not allowed or if sendRedirect has already been
// called. In either case we should log an information type message
// here.
; // do nothing -- just ignore
}
}
else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
{
try
{
stateResponse.setWindowState(new WindowState(queryStr.getParameter(param)));
}
catch (Exception e)
{
; // do nothing -- just ignore
}
}
else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
{
; // ignore -- do nothing as can't encode into an actionResponse
}
else
{
stateResponse.setRenderParameter(param, queryStr.getParameter(param));
}
}
}
// Because we want to support translating a redirect that occurs
// during a render as an in place navigation AND we can't reverse