/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.portletbridge.bridge.controller;
import com.sun.faces.context.StateContext;
import org.jboss.portletbridge.bridge.config.BridgeConfig;
import org.jboss.portletbridge.bridge.context.BridgeContext;
import org.jboss.portletbridge.bridge.event.BridgePostConstructFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.event.BridgePreReleaseFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.logger.BridgeLogger.Level;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScope;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScopeManager;
import org.jboss.portletbridge.context.AbstractExternalContext;
import org.jboss.portletbridge.context.flash.PortletFlash;
import org.jboss.portletbridge.lifecycle.PortalPhaseListener;
import org.jboss.portletbridge.lifecycle.PublicParameterPhaseListener;
import org.jboss.portletbridge.lifecycle.RenderResponsePhaseListener;
import org.jboss.portletbridge.util.BeanWrapper;
import org.jboss.portletbridge.util.FacesMessageWrapper;
import org.jboss.portletbridge.util.ParameterFunction;
import org.jboss.portletbridge.util.PublicParameterUtil;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.FacesMessage;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.event.PostAddToViewEvent;
import javax.faces.event.PreRemoveFromViewEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.render.ResponseStateManager;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.StateAwareResponse;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.BridgeException;
import javax.portlet.faces.event.EventNavigationResult;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a>
*/
public class Jsf20ControllerImpl implements BridgeController {
protected BridgeConfig bridgeConfig = null;
protected FacesContextFactory facesContextFactory = null;
protected static final String RENDER_REDIRECT_VIEW_PARAMS = "org.jboss.portletbridge.renderRedirectViewParams";
protected static final String RENDER_REDIRECT_PUBLIC_PARAM_MAP = "org.jboss.portletbridge.renderRedirectPublicParamMap";
private static final String FACES_MESSAGES_WRAPPER = "org.jboss.portletbridge.facesMessagesHolder";
private static final String MANAGED_BEANS_WRAPPER = "org.jboss.portletbridge.managedBeansHolder";
private static final String REQUEST_SCOPE_ID = "__pbrReqScopeId";
private static final String FACES_EXECUTED_DURING_ACTION_REQUEST = "facesDuringAction";
private static final String AUTOMATIC_RESOURCE_DISPATCHING = "javax.portlet.automaticResourceDispatching";
public Jsf20ControllerImpl(BridgeConfig bridgeConfig) {
this.bridgeConfig = bridgeConfig;
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#destroy()
*/
public void destroy() {
bridgeConfig = null;
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#processPortletAction(org.jboss.portletbridge.bridge.context.BridgeContext)
*/
public void processPortletAction(BridgeContext bridgeContext) throws BridgeException {
FacesContext facesContext = null;
Lifecycle facesLifecycle = null;
PublicParameterPhaseListener ppPhaseListener = null;
// Remove any lingering BridgeRequestScopes. Not required by spec, but prevents issues
bridgeContext.getBridgeRequestScopeManager().removeRequestScope(bridgeContext, bridgeContext.getFacesViewId(true));
try {
facesLifecycle = getFacesLifecycle();
facesContext = getFacesContext(bridgeContext, facesLifecycle);
ppPhaseListener = new PublicParameterPhaseListener(bridgeConfig, bridgeContext.getPortletRequest());
facesLifecycle.addPhaseListener(ppPhaseListener);
performPreExecuteTasks(facesContext, facesLifecycle);
facesLifecycle.execute(facesContext);
if (!facesContext.getResponseComplete()) {
encodeStateAware(bridgeContext, facesContext);
}
} catch (Exception e) {
throwBridgeException(e);
} finally {
if (null != facesLifecycle && null != ppPhaseListener) {
facesLifecycle.removePhaseListener(ppPhaseListener);
}
if (null != facesContext) {
releaseFacesContext(bridgeContext, facesContext);
}
}
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#handlePortletEvent(org.jboss.portletbridge.bridge.context.BridgeContext)
*/
public void handlePortletEvent(BridgeContext bridgeContext) throws BridgeException {
FacesContext facesContext = null;
Lifecycle facesLifecycle = null;
PublicParameterPhaseListener ppPhaseListener = null;
boolean removeScope = false;
// Carry forward current render parameters
((EventResponse) bridgeContext.getPortletResponse()).setRenderParameters((EventRequest) bridgeContext
.getPortletRequest());
// As per spec 5.2.5
if (null == bridgeConfig.getEventHandler()) {
bridgeConfig.getLogger().log(
Level.ERROR,
"The EventHandler is null for " + bridgeConfig.getPortletConfig().getPortletName()
+ ". Ensure your portlet.xml settings are correct and that you have implemented the "
+ "BridgeEventHandler in your application. The event has not been processed.");
return;
}
BridgeRequestScope scope = getBridgeRequestScope(bridgeContext);
try {
facesLifecycle = getFacesLifecycle();
facesContext = getFacesContext(bridgeContext, facesLifecycle);
if (null != scope) {
restoreScopeData(bridgeContext, facesContext, scope);
}
ppPhaseListener = new PublicParameterPhaseListener(bridgeConfig, bridgeContext.getPortletRequest());
facesLifecycle.addPhaseListener(ppPhaseListener);
performPreExecuteTasks(facesContext, facesLifecycle);
facesLifecycle.execute(facesContext);
EventNavigationResult eventResult = bridgeConfig.getEventHandler().handleEvent(facesContext,
((EventRequest) bridgeContext.getPortletRequest()).getEvent());
if (facesContext.getResponseComplete()) {
// Redirected during event handling
removeScope = true;
} else if (null != eventResult) {
facesContext.getApplication().getNavigationHandler()
.handleNavigation(facesContext, eventResult.getFromAction(), eventResult.getOutcome());
if (facesContext.getResponseComplete()) {
// Redirected due to navigation rule
removeScope = true;
}
}
BridgeRequestScope currentScope = encodeStateAware(bridgeContext, facesContext);
if (null != currentScope && !currentScope.equals(scope)) {
removeScope = true;
}
} catch (Exception e) {
throwBridgeException(e);
} finally {
if (removeScope) {
if (null != scope) {
bridgeContext.getBridgeRequestScopeManager().removeRequestScope(bridgeContext, scope);
}
}
if (null != facesLifecycle && null != ppPhaseListener) {
facesLifecycle.removePhaseListener(ppPhaseListener);
}
if (null != facesContext) {
releaseFacesContext(bridgeContext, facesContext);
}
}
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#renderPortletHead(org.jboss.portletbridge.bridge.context.BridgeContext)
*/
public void renderPortletHead(BridgeContext bridgeContext) throws BridgeException {
// Do Nothing
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#renderPortletBody(org.jboss.portletbridge.bridge.context.BridgeContext)
*/
public void renderPortletBody(BridgeContext bridgeContext) throws BridgeException {
FacesContext facesContext = null;
Lifecycle facesLifecycle = null;
BridgeRequestScope scope = getBridgeRequestScope(bridgeContext);
try {
facesLifecycle = getFacesLifecycle();
facesContext = getFacesContext(bridgeContext, facesLifecycle);
// Restore scope if present and mode not changed
if (null != scope) {
if (scope.getPortletMode().equals(bridgeContext.getPortletRequest().getPortletMode().toString())) {
restoreScopeData(bridgeContext, facesContext, scope);
} else {
clearBridgeRequestScope(bridgeContext);
}
}
if (facesContext.getExternalContext().getRequestParameterValuesMap()
.containsKey(ResponseStateManager.VIEW_STATE_PARAM)) {
facesContext.getExternalContext().getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE);
}
renderFaces(bridgeContext, facesContext, facesLifecycle, scope, null);
} catch (Exception e) {
throwBridgeException(e);
} finally {
// PBR-499 Clear Bridge Scope after Render unless config says to retain it
if (!bridgeConfig.isBridgeScopePreservedPostRender()) {
clearBridgeRequestScope(bridgeContext);
}
if (null != facesContext) {
releaseFacesContext(bridgeContext, facesContext);
}
}
}
/**
* @see org.jboss.portletbridge.bridge.controller.BridgeController#renderResource(org.jboss.portletbridge.bridge.context.BridgeContext)
*/
public void renderResource(BridgeContext bridgeContext) throws BridgeException {
FacesContext facesContext = null;
Lifecycle facesLifecycle = null;
try {
facesLifecycle = getFacesLifecycle();
facesContext = getFacesContext(bridgeContext, facesLifecycle);
ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
ResourceRequest resourceRequest = (ResourceRequest) bridgeContext.getPortletRequest();
String resourceId = resourceRequest.getResourceID();
if (resourceHandler.isResourceRequest(facesContext)) {
// JSF2 Resource
resourceHandler.handleResourceRequest(facesContext);
} else if (null != resourceId) {
if (isAutomaticResourceDispatchingEnabled(bridgeContext)) {
renderNonFacesResource(bridgeContext, resourceId);
}
} else {
renderFacesResource(bridgeContext, facesContext, facesLifecycle);
}
} catch (Exception e) {
throwBridgeException(e);
} finally {
if (null != facesContext) {
releaseFacesContext(bridgeContext, facesContext);
}
}
}
protected BridgeRequestScope encodeStateAware(BridgeContext bridgeContext, FacesContext facesContext) {
BridgeRequestScope scope = null;
String viewId = facesContext.getViewRoot().getViewId();
String queryString = bridgeContext.getNavigationalQueryString();
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
String viewUrl = viewHandler.getActionURL(facesContext, viewId);
if (null != queryString && queryString.length() > 1) {
if (viewUrl.indexOf('?') > 0) {
viewUrl += "&" + queryString.substring(1);
} else {
viewUrl = viewUrl.concat("?").concat(queryString);
}
}
facesContext.getExternalContext().encodeActionURL(viewUrl);
// Process Public Parameter changes
processOutgoingParameters(facesContext, bridgeContext.getPortletRequest(),
(StateAwareResponse) bridgeContext.getPortletResponse());
if (bridgeContext.isBridgeRequestScopePreserved()) {
scope = bridgeContext.getBridgeScope();
if (null == scope) {
// Action starts new lifecycle
scope = newBridgeRequestScope(bridgeContext);
}
// Remove StateContext from FacesContext to prevent issues with Dynamic Actions being retained between Renders
facesContext.getAttributes().remove(StateContext.class.getName() + "_KEY");
// Unregister PostAddToViewEvent listener if it's StateContext.AddRemoveListener
List<SystemEventListener> postAddListeners = facesContext.getViewRoot().getViewListenersForEventClass(PostAddToViewEvent.class);
if (null != postAddListeners && !postAddListeners.isEmpty()) {
for (SystemEventListener listener : postAddListeners) {
if (listener.getClass().getName().equals(stateContextListenerClassname())) {
facesContext.getViewRoot().unsubscribeFromViewEvent(PostAddToViewEvent.class, listener);
}
}
}
// Unregister PreRemoveFromViewEvent listener if it's StateContext.AddRemoveListener
List<SystemEventListener> preRemoveListeners = facesContext.getViewRoot().getViewListenersForEventClass(PreRemoveFromViewEvent.class);
if (null != preRemoveListeners && !preRemoveListeners.isEmpty()) {
for (SystemEventListener listener : preRemoveListeners) {
if (listener.getClass().getName().equals(stateContextListenerClassname())) {
facesContext.getViewRoot().unsubscribeFromViewEvent(PreRemoveFromViewEvent.class, listener);
}
}
}
saveFacesView(scope, facesContext);
saveMessages(facesContext);
if (Bridge.PortletPhase.ACTION_PHASE == bridgeContext.getPortletRequestPhase()) {
// Save View State Param
String viewState = facesContext.getExternalContext().getRequestParameterMap()
.get(ResponseStateManager.VIEW_STATE_PARAM);
if (null != viewState) {
scope.put(AbstractExternalContext.FACES_VIEW_STATE, viewState);
}
saveActionParams(bridgeContext, facesContext);
// Save parameter to let us know Faces Lifecycle was executed
scope.put(FACES_EXECUTED_DURING_ACTION_REQUEST, "true");
}
saveBeans(bridgeContext, facesContext);
scope.putAll(facesContext.getExternalContext().getRequestMap());
((StateAwareResponse) bridgeContext.getPortletResponse()).setRenderParameter(REQUEST_SCOPE_ID, scope.getId());
}
return scope;
}
protected BridgeRequestScope newBridgeRequestScope(BridgeContext bridgeContext) {
BridgeRequestScopeManager scopeManager = bridgeContext.getBridgeRequestScopeManager();
BridgeRequestScope scope = scopeManager.createRequestScope(bridgeContext, bridgeContext.getFacesViewId(true));
// Add excludes
scope.setExcludedEntries(bridgeConfig.getExcludedRequestAttributes());
scope.addExcludedEntries(bridgeContext.getPreFacesRequestAttrNames());
return scope;
}
protected void renderFaces(BridgeContext bridgeContext, FacesContext facesContext, Lifecycle facesLifecycle,
BridgeRequestScope scope, String redirectViewId) throws BridgeException, NullPointerException {
PublicParameterPhaseListener ppPhaseListener = null;
PortalPhaseListener portalPhaseListener = null;
RenderResponsePhaseListener renderResponsePhaseListener = null;
if (!bridgeContext.hasRenderRedirect()) {
try {
ppPhaseListener = new PublicParameterPhaseListener(bridgeConfig, bridgeContext.getPortletRequest());
portalPhaseListener = new PortalPhaseListener();
facesLifecycle.addPhaseListener(ppPhaseListener);
facesLifecycle.addPhaseListener(portalPhaseListener);
performPreExecuteTasks(facesContext, facesLifecycle);
if (scope != null && Boolean.parseBoolean((String) scope.get(FACES_EXECUTED_DURING_ACTION_REQUEST))) {
scope.remove(FACES_EXECUTED_DURING_ACTION_REQUEST);
PhaseEvent fakeRestoreViewEvent = new PhaseEvent(facesContext, PhaseId.RESTORE_VIEW, facesLifecycle);
ppPhaseListener.afterPhase(fakeRestoreViewEvent);
// PBR-558 Trigger RESTORE_VIEW event for WeldPhaseListener to activate Conversation context
for (PhaseListener listener : facesLifecycle.getPhaseListeners()) {
if ("WeldPhaseListener".equals(listener.getClass().getSimpleName())) {
listener.beforePhase(fakeRestoreViewEvent);
break;
}
}
} else {
// PBR-510 - Only end facesLifecycle.execute() after RESTORE_VIEW if we don't want f:viewParam to work
if (bridgeConfig.isViewParamHandlingDisabled()) {
renderResponsePhaseListener = new RenderResponsePhaseListener();
facesLifecycle.addPhaseListener(renderResponsePhaseListener);
}
facesLifecycle.execute(facesContext);
}
} finally {
if (null != facesLifecycle) {
if (null != ppPhaseListener) {
facesLifecycle.removePhaseListener(ppPhaseListener);
}
if (null != portalPhaseListener) {
facesLifecycle.removePhaseListener(portalPhaseListener);
}
if (null != renderResponsePhaseListener) {
facesLifecycle.removePhaseListener(renderResponsePhaseListener);
}
}
}
if (!facesContext.getResponseComplete()) {
facesLifecycle.render(facesContext);
bridgeContext.setViewHistory(bridgeContext.getPortletRequest().getPortletMode().toString(), facesContext
.getViewRoot().getViewId(), true);
}
}
if (bridgeContext.hasRenderRedirect()) {
redirectViewId = bridgeContext.getRedirectViewId();
renderRedirect(bridgeContext, facesContext, facesLifecycle, scope, redirectViewId);
facesContext = FacesContext.getCurrentInstance();
} else {
encodeMarkupResponse(bridgeContext, facesContext, scope);
}
}
protected void renderRedirect(BridgeContext bridgeContext, FacesContext facesContext, Lifecycle facesLifecycle,
BridgeRequestScope scope, String redirectViewId) {
bridgeContext.setRedirectViewId(redirectViewId);
releaseFacesContext(bridgeContext, facesContext);
bridgeContext.setRenderRedirect(false);
if (null != scope) {
bridgeContext.getBridgeRequestScopeManager().removeRequestScope(bridgeContext, scope);
}
facesContext = getFacesContext(bridgeContext, facesLifecycle);
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
UIViewRoot uiViewRoot = viewHandler.createView(facesContext, redirectViewId);
facesContext.setViewRoot(uiViewRoot);
renderFaces(bridgeContext, facesContext, facesLifecycle, null, null);
facesContext = FacesContext.getCurrentInstance();
}
protected void encodeMarkupResponse(BridgeContext bridgeContext, FacesContext facesContext, BridgeRequestScope scope) {
if (Bridge.PortletPhase.RENDER_PHASE == bridgeContext.getPortletRequestPhase()) {
if (null == scope) {
return;
}
saveFacesView(scope, facesContext);
} else {
// We're in Resource Request
if (isBridgeScopeAjaxEnabled()) {
if (null == scope) {
scope = newBridgeRequestScope(bridgeContext);
}
saveFacesView(scope, facesContext);
if (isFacesMessagesStoredOnAjax()) {
saveMessages(facesContext);
}
scope.putAll(facesContext.getExternalContext().getRequestMap());
}
}
}
protected boolean isBridgeScopeAjaxEnabled() {
return bridgeConfig.isBridgeScopeEnabledOnAjaxRequest();
}
protected boolean isFacesMessagesStoredOnAjax() {
return bridgeConfig.isFacesMessagesStoredOnAjaxRequest();
}
protected void restoreScopeData(BridgeContext bridgeContext, FacesContext facesContext, BridgeRequestScope scope) {
if (null == scope) {
return;
}
restoreFacesViewFromScope(facesContext, scope);
restoreMessages(facesContext, scope);
restoreBeans(bridgeContext, scope);
Set<Map.Entry<String, Object>> keys = scope.entrySet();
for (Entry<String, Object> entry : keys) {
bridgeContext.getPortletRequest().setAttribute(entry.getKey(), entry.getValue());
}
}
protected void restoreFacesViewFromScope(FacesContext facesContext, BridgeRequestScope scope) {
UIViewRoot viewRoot = null;
viewRoot = (UIViewRoot) scope.remove(VIEW_ROOT);
if (null != viewRoot) {
facesContext.setViewRoot(viewRoot);
}
}
protected void restoreMessages(FacesContext facesContext, BridgeRequestScope scope) {
if (facesContext.getExternalContext().getRequest() instanceof RenderRequest) {
FacesMessageWrapper messageWrapper = (FacesMessageWrapper) scope.remove(FACES_MESSAGES_WRAPPER);
if (null != messageWrapper) {
for (String clientId : messageWrapper.getClientIds()) {
for (FacesMessage msg : messageWrapper.getMessages(clientId)) {
facesContext.addMessage(clientId, msg);
}
}
}
}
}
protected void restoreBeans(BridgeContext bridgeContext, BridgeRequestScope scope) {
BeanWrapper beanWrapper = (BeanWrapper) scope.remove(MANAGED_BEANS_WRAPPER);
if (null != beanWrapper) {
PortletRequest request = bridgeContext.getPortletRequest();
for (String name : beanWrapper.getBeanNames()) {
request.setAttribute(name, beanWrapper.getBean(name));
}
}
}
protected void saveFacesView(BridgeRequestScope scope, FacesContext facesContext) {
scope.put(VIEW_ROOT, facesContext.getViewRoot());
}
protected void saveMessages(FacesContext facesContext) {
Iterator<String> idsWithMessages = facesContext.getClientIdsWithMessages();
Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
if (idsWithMessages.hasNext()) {
FacesMessageWrapper messageWrapper = new FacesMessageWrapper();
while (idsWithMessages.hasNext()) {
String id = idsWithMessages.next();
Iterator<FacesMessage> messages = facesContext.getMessages(id);
while (messages.hasNext()) {
FacesMessage message = messages.next();
messageWrapper.addMessage(id, message);
}
}
requestMap.put(FACES_MESSAGES_WRAPPER, messageWrapper);
} else {
requestMap.remove(FACES_MESSAGES_WRAPPER);
}
}
protected void saveBeans(BridgeContext bridgeContext, FacesContext facesContext) {
ExternalContext externalContext = facesContext.getExternalContext();
List<String> existingAttributes = null;
if (null != bridgeContext) {
existingAttributes = bridgeContext.getPreFacesRequestAttrNames();
}
if (null == existingAttributes) {
existingAttributes = new ArrayList<String>();
} else {
// Create local copy for merge with initial parameters.
existingAttributes = new ArrayList<String>(existingAttributes);
}
Map<String, Object> requestMap = externalContext.getRequestMap();
BeanWrapper beanWrapper = new BeanWrapper();
for (Iterator<Entry<String, Object>> iterator = requestMap.entrySet().iterator(); iterator.hasNext();) {
Entry<String, Object> entry = iterator.next();
String attributeName = entry.getKey();
if (!existingAttributes.contains(attributeName)) {
Object bean = entry.getValue();
if (null != bean && !bridgeContext.getBridgeScope().isExcluded(attributeName, bean)) {
beanWrapper.addBean(attributeName, bean);
}
}
}
if (beanWrapper.getBeanNames().size() > 0) {
requestMap.put(MANAGED_BEANS_WRAPPER, beanWrapper);
}
}
protected void saveActionParams(BridgeContext bridgeContext, FacesContext facesContext) {
ExternalContext externalContext = facesContext.getExternalContext();
if (bridgeConfig.hasPreserveActionParameters()) {
BridgeRequestScope scope = bridgeContext.getBridgeScope();
Map<String, String[]> params = new HashMap<String, String[]>(externalContext.getRequestParameterValuesMap());
params.remove(ResponseStateManager.VIEW_STATE_PARAM);
scope.put(ACTION_PARAMETERS, params);
}
}
protected void renderFacesResource(BridgeContext bridgeContext, FacesContext facesContext, Lifecycle facesLifecycle)
throws BridgeException {
BridgeRequestScope scope = getBridgeRequestScope(bridgeContext);
renderFaces(bridgeContext, facesContext, facesLifecycle, scope, null);
}
protected void renderNonFacesResource(BridgeContext bridgeContext, String resourceId) throws BridgeException,
PortletException, IOException {
if (null != resourceId) {
try {
resourceId = new URI(resourceId).normalize().getPath();
} catch (URISyntaxException e) {
throw new IOException("Unable to normalize the path to the resourceId");
}
PortletContext portletContext = bridgeContext.getPortletContext();
PortletRequestDispatcher dispatcher = portletContext.getRequestDispatcher(resourceId);
if (null != dispatcher) {
String mimeType = portletContext.getMimeType(resourceId);
if (null == mimeType) {
int lastIndexOfSlash = resourceId.lastIndexOf('/');
if (lastIndexOfSlash >= 0) {
resourceId = resourceId.substring(lastIndexOfSlash + 1);
}
int indexOfQuestion = resourceId.indexOf('?');
if (indexOfQuestion >= 0) {
resourceId = resourceId.substring(0, indexOfQuestion);
}
mimeType = portletContext.getMimeType(resourceId);
}
if (null != mimeType) {
((ResourceResponse) bridgeContext.getPortletResponse()).setContentType(mimeType);
}
// some security checks
String excludedResources = portletContext.getInitParameter(ResourceHandler.RESOURCE_EXCLUDES_PARAM_NAME);
if (null == excludedResources || excludedResources.isEmpty()) {
excludedResources = ResourceHandler.RESOURCE_EXCLUDES_DEFAULT_VALUE;
}
if (isProtectedResource(resourceId) || isExcludedResource(excludedResources, resourceId)) {
FacesContext context = FacesContext.getCurrentInstance();
if (null != context) {
throw new IOException("The requested resource is protected.");
}
return;
}
dispatcher.forward(bridgeContext.getPortletRequest(), bridgeContext.getPortletResponse());
}
}
}
private boolean isExcludedResource(String excludedResources, String resourceId) {
String extension = resourceId.substring(resourceId.indexOf('.'));
return Arrays.asList(excludedResources.split(",")).contains(extension);
}
private boolean isProtectedResource(String resourceId) {
String resourceIdCleaned = resourceId.toUpperCase();
return resourceIdCleaned.startsWith("/WEB-INF/") ||
resourceIdCleaned.startsWith("/META-INF/") ||
resourceIdCleaned.startsWith("WEB-INF/") ||
resourceIdCleaned.startsWith("META-INF/");
}
protected FacesContext getFacesContext(BridgeContext bridgeContext, Lifecycle facesLifecycle) throws FacesException {
FacesContext facesContext = getFacesContextFactory().getFacesContext(bridgeContext.getPortletContext(),
bridgeContext.getPortletRequest(), bridgeContext.getPortletResponse(), facesLifecycle);
// Fire Post Construct FacesContext system event
fireFacesSystemEvent(bridgeContext, BridgePostConstructFacesContextSystemEvent.class);
return facesContext;
}
protected FacesContextFactory getFacesContextFactory() throws FacesException {
if (null == facesContextFactory) {
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
}
return facesContextFactory;
}
protected Lifecycle getFacesLifecycle() throws FacesException {
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
return lifecycleFactory.getLifecycle(bridgeConfig.getLifecycleId());
}
protected void releaseFacesContext(BridgeContext bridgeContext, FacesContext facesContext) {
fireFacesSystemEvent(bridgeContext, BridgePreReleaseFacesContextSystemEvent.class);
PortletFlash.needHttpResponse.remove();
facesContext.release();
}
protected void fireFacesSystemEvent(BridgeContext bridgeContext, Class<? extends SystemEvent> eventClass) {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getApplication().publishEvent(facesContext, eventClass, bridgeContext);
}
protected BridgeRequestScope getBridgeRequestScope(BridgeContext bridgeContext) {
BridgeRequestScope scope = null;
if (Bridge.PortletPhase.RENDER_PHASE == bridgeContext.getPortletRequestPhase()) {
String bridgeRequestScopeId = bridgeContext.getPortletRequest().getParameter(REQUEST_SCOPE_ID);
if (null != bridgeRequestScopeId) {
scope = bridgeContext.getBridgeRequestScopeManager().getRequestScopeById(bridgeContext, bridgeRequestScopeId);
}
}
if (null == scope) {
scope = bridgeContext.getBridgeScope();
}
return scope;
}
protected void clearBridgeRequestScope(BridgeContext bridgeContext) {
BridgeRequestScope scope = bridgeContext.getBridgeScope();
if (null != scope) {
scope.clear();
bridgeContext.getBridgeRequestScopeManager().removeRequestScope(bridgeContext, scope);
}
}
protected void throwBridgeException(Exception e) throws BridgeException {
if (!(e instanceof BridgeException)) {
e = new BridgeException(e);
}
throw (BridgeException) e;
}
protected void processOutgoingParameters(FacesContext facesContext, PortletRequest request,
final StateAwareResponse response) {
Map<String, String> publicParameterMapping = bridgeConfig.getPublicRenderParameterMappings();
Enumeration<String> parameterNames = bridgeConfig.getPortletConfig().getPublicRenderParameterNames();
if (null != publicParameterMapping && publicParameterMapping.size() > 0 && parameterNames.hasMoreElements()) {
ParameterFunction outgoingFunction = new ParameterFunction() {
public boolean processParameter(ELContext elContext, Map<String, String[]> publicParameters, String name,
ValueExpression valueExpression) {
boolean valueChanged = false;
String modelValue = (String) valueExpression.getValue(elContext);
if (null != modelValue) {
String[] values = publicParameters.get(name);
String parameterValue = (null != values && values.length > 0) ? values[0] : null;
if (null == parameterValue || !modelValue.equals(parameterValue)) {
response.setRenderParameter(name, modelValue);
valueChanged = true;
}
} else if (publicParameters.containsKey(name)) {
response.removePublicRenderParameter(name);
valueChanged = true;
}
return valueChanged;
}
};
PublicParameterUtil.processPublicParameters(facesContext, request, publicParameterMapping, parameterNames,
outgoingFunction, bridgeConfig.getPortletConfig().getPortletName());
}
}
/**
* Perform any tasks that need to be completed before calling <code>Lifecycle.execute()</code>. For JSF 2.0, nothing
* is required.
*
* @param facesContext Faces Context for the current portlet request.
* @param facesLifecycle Lifecycle for the current portlet request.
*/
protected void performPreExecuteTasks(FacesContext facesContext, Lifecycle facesLifecycle) {
// Do Nothing for JSF 2.0
}
protected String stateContextListenerClassname() {
return "com.sun.faces.context.StateContext$AddRemoveListener";
}
private boolean isAutomaticResourceDispatchingEnabled(BridgeContext bridgeContext) {
Object o = bridgeContext.getPortletRequest().getAttribute("javax.portlet.config");
if (o instanceof PortletConfig) {
PortletConfig portletConfig = (PortletConfig) o;
String autoDispatch = portletConfig.getInitParameter(AUTOMATIC_RESOURCE_DISPATCHING);
return "true".equalsIgnoreCase(autoDispatch);
}
return false;
}
}