/** @author Neil Griffin */ public abstract class LiferayFacesContext extends FacesContext implements FacesContextHelper, PortletHelper, LiferayPortletHelper { // Logger private static final Logger logger = LoggerFactory.getLogger(LiferayFacesContext.class); // Singleton Instance private static transient LiferayFacesContext instance; /** Returns the implementation singleton instance. */ public static LiferayFacesContext getInstance() { if (instance == null) { logger.error("Instance not initialized -- caller might be static"); } return instance; } /** Sets the implementation singleton instance. */ public static void setInstance(LiferayFacesContext liferayFacesContext) { instance = liferayFacesContext; } /** Returns the Liferay build number. */ public abstract int getBuildNumber(); }
/** * This class wraps the Liferay {@link NamespaceServletRequest} class, so that calls to {@link * #setAttribute(String, Object)} do not cause attribute names to be prefixed with the response * namespace. This is necessary so that Liferay Portal JSP tag classes will be able to set request * attributes that can be picked up by JSPs. For example, the {@link InputEditorTag} sets attributes * that are picked up by the portal-web/docroot/html/js/editor/ckeditor.jsp page. * * @author Neil Griffin */ public class NonNamespacedHttpServletRequest extends HttpServletRequestWrapper { // Logger private static final Logger logger = LoggerFactory.getLogger(NonNamespacedHttpServletRequest.class); // Private Constants private static final String AUI_FORM_USE_NAMESPACE = "aui:form:useNamespace"; private static final String NAMESPACE_SERVLET_REQUEST_FQCN = "com.liferay.portal.servlet.NamespaceServletRequest"; public NonNamespacedHttpServletRequest(HttpServletRequest httpServletRequest) { super(httpServletRequest); } @Override public Object getAttribute(String name) { if (AUI_FORM_USE_NAMESPACE.equals(name)) { // Note: The portal-web/docroot/html/taglib/init.jsp file asks the value of this attribute. // Need to return // false in order to ensure that the portlet namespace is not prepended to method names and // element ids. return Boolean.FALSE.toString(); } else { return super.getAttribute(name); } } @Override public void setAttribute(String name, Object value) { Object wrappedRequest = getRequest(); if (wrappedRequest.getClass().getName().equals(NAMESPACE_SERVLET_REQUEST_FQCN)) { try { // Calling NameSpaceServletRequest.setAttribute(String, Object, false) instead of // NameSpaceServletRequest.setAttribute(String, Object) will prevent the attribute name from // getting // prefixed with the response namespace. The method must be called reflectively since the // NameSpaceServletRequest is packaged in portal-impl.jar and is not available at // compile-time. Method method = wrappedRequest .getClass() .getMethod("setAttribute", String.class, Object.class, boolean.class); method.invoke(wrappedRequest, name, value, false); } catch (Exception e) { logger.error(e); } } else { super.setAttribute(name, value); } } }
/** @author Neil Griffin */ public class LiferayThemeDisplayUtil { // Logger private static final Logger logger = LoggerFactory.getLogger(LiferayThemeDisplayUtil.class); // Private Constants private static final Method IS_ISOLATED_METHOD; private static final Method IS_STATE_EXCLUSIVE_METHOD; static { Method isIsolatedMethod = null; Method isStateExclusiveMethod = null; try { Class<?> portletClass = Class.forName("com.liferay.portal.theme.ThemeDisplay"); isIsolatedMethod = portletClass.getMethod("isIsolated", new Class[] {}); isStateExclusiveMethod = portletClass.getMethod("isStateExclusive", new Class[] {}); } catch (Exception e) { // ignore } IS_ISOLATED_METHOD = isIsolatedMethod; IS_STATE_EXCLUSIVE_METHOD = isStateExclusiveMethod; } public static boolean isIsolated(Object themeDisplay) { boolean isolated = false; if ((IS_ISOLATED_METHOD != null) && (themeDisplay != null)) { try { isolated = (Boolean) IS_ISOLATED_METHOD.invoke(themeDisplay, new Object[] {}); } catch (Exception e) { logger.error(e); } } return isolated; } public static boolean isStateExclusive(Object themeDisplay) { boolean stateExclusive = false; if ((IS_STATE_EXCLUSIVE_METHOD != null) && (themeDisplay != null)) { try { stateExclusive = (Boolean) IS_STATE_EXCLUSIVE_METHOD.invoke(themeDisplay, new Object[] {}); } catch (Exception e) { logger.error(e); } } return stateExclusive; } }
/** * Custom {@link ResponseWriter} that has the ability to write to the <head>...</head> section of * the portal page via the standard Portlet 2.0 MimeResponse.MARKUP_HEAD_ELEMENT mechanism. * * @author Neil Griffin */ public class HeadResponseWriterImpl extends HeadResponseWriter { // Logger private static final Logger logger = LoggerFactory.getLogger(HeadResponseWriterImpl.class); // Private Data Members private PortletResponse portletResponse; public HeadResponseWriterImpl( ResponseWriter wrappedResponseWriter, PortletResponse portletResponse) { super(wrappedResponseWriter); this.portletResponse = portletResponse; } @Override public Element createElement(String name) { return portletResponse.createElement(name); } @Override public void endElement(String name) throws IOException { try { ElementWriter elementWriter = elementWriterStack.pop(); Element element = elementWriter.getElement(); String nodeName = element.getNodeName(); logger.trace("POPPED element name=[{0}]", nodeName); if (!StringPool.HEAD.equals(nodeName)) { // NOTE: The Portlet 2.0 Javadocs for the addProperty method indicate that if the key // already exists, // then the element will be added to any existing elements under that key name. There is a // risk that // multiple portlet instances on the same portal page could cause multiple <script /> // elements to be // added to the <head>...</head> section of the rendered portal page. See: // http://portals.apache.org/pluto/portlet-2.0-apidocs/javax/portlet/PortletResponse.html#addProperty(java.lang.String, // org.w3c.dom.Element) portletResponse.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, element); logger.debug( "Added resource to portal's <head>...</head> section nodeName=[{0}]", nodeName); } } catch (EmptyStackException e) { throw new IOException(EmptyStackException.class.getSimpleName()); } } @Override public void startElement(String name, UIComponent component) throws IOException { Element element = createElement(name); ElementWriter elementWriter = new ElementWriter(element); elementWriterStack.push(elementWriter); } }
/** @author Kyle Stiemann */ @ManagedBean @RequestScoped public class FieldBackingBean { private static final Logger logger = LoggerFactory.getLogger(FieldBackingBean.class); @ManagedProperty(value = "#{fieldModelBean}") private FieldModelBean fieldModelBean; public void errorValidator(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException { FacesMessage facesMessage = new FacesMessage(); facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR); facesMessage.setDetail("This is an error message."); facesContext.addMessage(uiComponent.getClientId(), facesMessage); } public void infoValidator(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException { FacesMessage facesMessage = new FacesMessage(); facesMessage.setSeverity(FacesMessage.SEVERITY_INFO); facesMessage.setDetail("This is an info message."); facesContext.addMessage(uiComponent.getClientId(), facesMessage); } public void submit() { FacesMessage globalFacesMessage = new FacesMessage("Your request processed successfully."); FacesContext facesContext = FacesContext.getCurrentInstance(); facesContext.addMessage(null, globalFacesMessage); logger.info("submit: firstName = " + fieldModelBean.getFirstName()); } public void warningValidator(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException { FacesMessage facesMessage = new FacesMessage(); facesMessage.setSeverity(FacesMessage.SEVERITY_WARN); facesMessage.setDetail("This is a warning message."); facesContext.addMessage(uiComponent.getClientId(), facesMessage); } public void setFieldModelBean(FieldModelBean fieldModelBean) { this.fieldModelBean = fieldModelBean; } }
/** @author Neil Griffin */ @ManagedBean(name = "customersModelBean") @RequestScoped public class CustomersModelBean implements Serializable { // serialVersionUID private static final long serialVersionUID = 2241487919972557504L; // Logger private static final Logger logger = LoggerFactory.getLogger(CustomersModelBean.class); // Injections @ManagedProperty(name = "customerService", value = "#{customerService}") private CustomerService customerService; // Private Bean Properties private List<Customer> allCustomers; private String selectedCustomerId; @PostConstruct public void postConstruct() { logger.trace("@PostConstruct annotation worked"); allCustomers = customerService.getAllCustomers(); } @PreDestroy public void preDestroy() { logger.trace("@PreDestroy annotation worked"); } public List<Customer> getAllCustomers() { return allCustomers; } public void setCustomerService(CustomerService customerService) { // Injected via ManagedProperty annotation this.customerService = customerService; } public String getSelectedCustomerId() { return selectedCustomerId; } public void setSelectedCustomerId(String selectedCustomerId) { this.selectedCustomerId = selectedCustomerId; } }
public class AbstractGB { protected static final Logger logger = LoggerFactory.getLogger(AbstractGB.class); protected static final String UNEXPECTED_ERROR_MSG_ID = "an-unexpected-error-occurred"; protected static final String SUCCESS_INFO_MSG_ID = "your-request-processed-successfully"; public void addGlobalSuccessInfoMessage() { LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance(); liferayFacesContext.addGlobalSuccessInfoMessage(); } public void addGlobalUnexpectedErrorMessage() { LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance(); liferayFacesContext.addGlobalUnexpectedErrorMessage(); } }
/** @author Vernon Singleton */ @ManagedBean @RequestScoped public class SelectBooleanCheckboxBackingBean { private static final Logger logger = LoggerFactory.getLogger(SelectBooleanCheckboxBackingBean.class); @ManagedProperty( name = "selectBooleanCheckboxModelBean", value = "#{selectBooleanCheckboxModelBean}") private SelectBooleanCheckboxModelBean selectBooleanCheckboxModelBean; public void submit() { PhaseId phaseId = FacesContext.getCurrentInstance().getCurrentPhaseId(); logger.info( "submit: phaseId=[{0}] agree=[{1}]", phaseId.toString(), selectBooleanCheckboxModelBean.getAgree()); } public void valueChangeListener(ValueChangeEvent valueChangeEvent) { FacesContext facesContext = FacesContext.getCurrentInstance(); PhaseId phaseId = facesContext.getCurrentPhaseId(); logger.debug("valueChangeListener: phaseId=[{0}]", phaseId.toString()); String phaseName = phaseId.getName(); FacesMessage facesMessage = new FacesMessage( "The valueChangeListener method was called during the " + phaseName + " phase of the JSF lifecycle."); facesContext.addMessage(null, facesMessage); } public void setSelectBooleanCheckboxModelBean( SelectBooleanCheckboxModelBean selectBooleanCheckboxModelBean) { this.selectBooleanCheckboxModelBean = selectBooleanCheckboxModelBean; } }
/** @author Neil Griffin */ public abstract class BridgePhaseBaseImpl implements BridgePhase { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgePhaseBaseImpl.class); // Private Constants private static final String PARAM_BRIDGE_REQUEST_SCOPE_ID = "com.liferay.faces.bridge.bridgeRequestScopeId"; // Protected Data Members protected BridgeConfig bridgeConfig; protected BridgeRequestScope bridgeRequestScope; protected BridgeRequestScopeCache bridgeRequestScopeCache; protected boolean bridgeRequestScopePreserved; protected FacesContext facesContext; protected IncongruityContext incongruityContext; protected Lifecycle facesLifecycle; protected PortletConfig portletConfig; protected PortletContext portletContext; protected String portletName; // Private Data Members private FacesContextFactory facesContextFactory; public BridgePhaseBaseImpl(PortletConfig portletConfig, BridgeConfig bridgeConfig) { this.portletConfig = portletConfig; this.bridgeConfig = bridgeConfig; this.portletName = portletConfig.getPortletName(); this.bridgeRequestScopePreserved = PortletConfigParam.BridgeRequestScopePreserved.getBooleanValue(portletConfig); this.portletContext = BridgePortletContextFactory.getPortletContextInstance(portletConfig.getPortletContext()); // Initialize the incongruity context implementation. this.incongruityContext = IncongruityContextFactory.getIncongruityContextInstance(); // Get the bridge request scope cache from the factory. this.bridgeRequestScopeCache = BridgeRequestScopeCacheFactory.getBridgeRequestScopeCacheInstance(portletContext); // Get the default lifecycle instance from the factory. LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); String lifecycleId = this.portletContext.getInitParameter(Bridge.LIFECYCLE_ID); if (lifecycleId == null) { lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE; } this.facesLifecycle = lifecycleFactory.getLifecycle(lifecycleId); } protected abstract void removeBridgeContextAttribute(PortletRequest portletRequest); protected abstract void setBridgeContextAttribute(PortletRequest portletRequest); protected void cleanup(PortletRequest portletRequest) { if (facesContext != null) { facesContext.release(); } // Cleanup request attributes. if (portletRequest != null) { removeBridgeContextAttribute(portletRequest); portletRequest.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE); portletRequest.removeAttribute(PortletConfig.class.getName()); portletRequest.removeAttribute(BridgeConfig.class.getName()); portletRequest.removeAttribute(BridgeRequestScope.class.getName()); portletRequest.removeAttribute(IncongruityContext.class.getName()); } } protected FacesContext getFacesContext( PortletRequest portletRequest, PortletResponse portletResponse, Lifecycle lifecycle) { FacesContext newFacesContext = getFacesContextFactory() .getFacesContext(portletContext, portletRequest, portletResponse, lifecycle); // TCK TestPage203 (JSF_ELTest) ensure that the #{facesContext} implicit object is set to the // current instance. ELContext elContext = newFacesContext.getELContext(); elContext.putContext(FacesContext.class, newFacesContext); return newFacesContext; } protected FacesContextFactory getFacesContextFactory() { if (facesContextFactory == null) { facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); } return facesContextFactory; } protected String getFacesViewId(ExternalContext externalContext) { String viewId = externalContext.getRequestPathInfo(); if (viewId == null) { viewId = externalContext.getRequestServletPath(); } return viewId; } protected void indicateNamespacingToConsumers( UIViewRoot uiViewRoot, PortletResponse portletResponse) { if (uiViewRoot != null) { // This method helps satisfy the namespacing requirements of Section 6.6 of the specification. // It might be // the case that the consumer (portal engine / portlet container) needs to know if all of the // form fields // have been namespaced properly. If that's the case, then it can check for the existence of // the // "X-JAVAX-PORTLET-FACES-NAMESPACED-RESPONSE" property on the response, which will be set to // "true" if the // UIViewRoot is annotated with {@link PortletNamingContainer}. if (uiViewRoot.getClass().getAnnotation(PortletNamingContainer.class) != null) { portletResponse.addProperty( Bridge.PORTLET_NAMESPACED_RESPONSE_PROPERTY, Boolean.TRUE.toString()); } } else { // http://issues.liferay.com/browse/FACES-267 Sometimes there are requests that the bridge may // see as valid // ResourceRequests (e.g. related to Ajax Push) where a ViewRoot might not be available -- // this is not an // error. logger.debug("UIViewRoot is null -- might be push related"); } } protected void init( PortletRequest portletRequest, PortletResponse portletResponse, Bridge.PortletPhase portletPhase) { // Save the Bridge.PortletPhase as a request attribute so that it can be picked up by the // BridgeRequestAttributeListener. portletRequest.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, portletPhase); // Save the PortletConfig as a request attribute. portletRequest.setAttribute(PortletConfig.class.getName(), portletConfig); // Save the BridgeConfig as a request attribute. portletRequest.setAttribute(BridgeConfig.class.getName(), bridgeConfig); // Initialize the bridge request scope. initBridgeRequestScope(portletRequest, portletResponse, portletPhase); // Save the BridgeRequestScope as a request attribute. portletRequest.setAttribute(BridgeRequestScope.class.getName(), bridgeRequestScope); // Save the IncongruityContext as a request attribute. portletRequest.setAttribute(IncongruityContext.class.getName(), incongruityContext); // Save the BridgeContext as a request attribute for legacy versions of ICEfaces. setBridgeContextAttribute(portletRequest); // Get the FacesContext. facesContext = getFacesContext(portletRequest, portletResponse, facesLifecycle); // If not set by a previous request, then set the default viewIdHistory for the portlet modes. for (String portletMode : PortletModeHelper.PORTLET_MODE_NAMES) { String attributeName = Bridge.VIEWID_HISTORY + "." + portletMode; PortletSession portletSession = portletRequest.getPortletSession(); if (portletSession.getAttribute(attributeName) == null) { Map<String, String> defaultViewIdMap = ViewUtil.getDefaultViewIdMap(portletConfig); portletSession.setAttribute(attributeName, defaultViewIdMap.get(portletMode)); } } } protected void initBridgeRequestScope( PortletRequest portletRequest, PortletResponse portletResponse, Bridge.PortletPhase portletPhase) { boolean bridgeRequestScopeEnabled = true; if (portletPhase == Bridge.PortletPhase.RESOURCE_PHASE) { bridgeRequestScopeEnabled = PortletConfigParam.BridgeRequestScopeAjaxEnabled.getBooleanValue(portletConfig); } if (bridgeRequestScopeEnabled) { // Determine if there is a bridge request scope "id" saved as a render parameter. Note that in // order to // avoid collisions with bridge request scopes for other portlets, the render parameter name // has to be // namespaced with the portlet name. String portletName = portletConfig.getPortletName(); String bridgeRequestScopeKey = portletName + PARAM_BRIDGE_REQUEST_SCOPE_ID; // If there is a render parameter value found for the "id", then return the cached bridge // request scope // associated with the "id". String bridgeRequestScopeId = portletRequest.getParameter(bridgeRequestScopeKey); if (bridgeRequestScopeId != null) { bridgeRequestScope = bridgeRequestScopeCache.get(bridgeRequestScopeId); if (bridgeRequestScope != null) { logger.debug( "Found render parameter name=[{0}] value=[{1}] and cached bridgeRequestScope=[{2}]", bridgeRequestScopeKey, bridgeRequestScopeId, bridgeRequestScope); } else { if (bridgeRequestScopePreserved) { logger.error( "Found render parameter name=[{0}] value=[{1}] BUT bridgeRequestScope is NOT in the cache", bridgeRequestScopeKey, bridgeRequestScopeId); } } } // Otherwise, if there is a portlet session attribute found for the "id", then return the // cached bridge // request scope associated with the "id". Note: This occurs after an Ajax-based // ResourceRequest so that // non-excluded request attributes can be picked up by a subsequent RenderRequest. if (bridgeRequestScope == null) { // TCK TestPage071: nonFacesResourceTest // TCK TestPage073: scopeAfterRedisplayResourcePPRTest PortletSession portletSession = portletRequest.getPortletSession(); bridgeRequestScopeId = (String) portletSession.getAttribute(bridgeRequestScopeKey); if (bridgeRequestScopeId != null) { portletSession.removeAttribute(bridgeRequestScopeKey); bridgeRequestScope = bridgeRequestScopeCache.get(bridgeRequestScopeId); if (bridgeRequestScope != null) { logger.debug( "Found (and removed) session-attribute name=[{0}] value=[{1}] and cached bridgeRequestScope=[{2}]", bridgeRequestScopeKey, bridgeRequestScopeId, bridgeRequestScope); if (portletResponse instanceof StateAwareResponse) { logger.debug( "Setting former session-attribute as render parameter name=[{0}] value=[{1}]", bridgeRequestScopeKey, bridgeRequestScopeId); StateAwareResponse stateAwareResponse = (StateAwareResponse) portletResponse; stateAwareResponse.setRenderParameter(bridgeRequestScopeKey, bridgeRequestScopeId); } } else { logger.error( "Found session attribute name=[{0}] value=[{1}] but bridgeRequestScope is not in the cache", bridgeRequestScopeKey, bridgeRequestScopeId); } } } // Otherwise, return a new factory created instance. if (bridgeRequestScope == null) { bridgeRequestScope = BridgeRequestScopeFactory.getBridgeRequestScopeInstance( portletRequest, portletConfig, bridgeConfig); } } } protected void maintainBridgeRequestScope( PortletRequest portletRequest, PortletResponse portletResponse, BridgeRequestScope.Transport bridgeRequestScopeTransport) { String bridgeRequestScopeId = bridgeRequestScope.getId(); bridgeRequestScopeCache.put(bridgeRequestScopeId, bridgeRequestScope); String bridgeRequestScopeKey = portletName + PARAM_BRIDGE_REQUEST_SCOPE_ID; if (bridgeRequestScopeTransport == BridgeRequestScope.Transport.PORTLET_SESSION_ATTRIBUTE) { // TCK TestPage071: nonFacesResourceTest // TCK TestPage073: scopeAfterRedisplayResourcePPRTest PortletSession portletSession = portletRequest.getPortletSession(true); portletSession.setAttribute(bridgeRequestScopeKey, bridgeRequestScopeId); } else { if (portletResponse instanceof StateAwareResponse) { logger.debug( "Setting render parameter name=[{0}] value=[{1}]", bridgeRequestScopeKey, bridgeRequestScopeId); try { StateAwareResponse stateAwareResponse = (StateAwareResponse) portletResponse; stateAwareResponse.setRenderParameter(bridgeRequestScopeKey, bridgeRequestScopeId); } catch (IllegalStateException e) { // If a redirect occurred, then swallow/ignore the IllegalStateException if (bridgeRequestScope.isRedirectOccurred()) { // The Portlet API JavaDocs indicate that StateAwareResponse.setRenderParameter(String, // String) // must throw an IllegalStateException if ActionResponse.sendRedirect(String) was // previously // called. The JSR 329 TCK TestPage039 (requestNoScopeOnRedirectTest) and TestPage176 // (redirectActionTest) both perform pseudo-redirects (effectively treated like // navigation-rules // from one JSF viewId to another). Since the tests don't actually call // ActionResponse.sendRedirect(String), this condition is never reached by the TCK. // However, // this condition is a real-world use-case and so the IllegalStateException must be // swallowed/ignored here so that portlet lifecycle processing is able to continue. For // more // information, see: http://issues.liferay.com/browse/FACES-1367 } // Otherwise throw the IllegalStateException. else { throw e; } } } } } }
/** @author Neil Griffin */ public class ExternalContextImpl extends ExternalContextCompat_2_2_Impl { // Logger private static final Logger logger = LoggerFactory.getLogger(ExternalContextImpl.class); // Private Constants private static final boolean LIFERAY_PORTAL_DETECTED = ProductMap.getInstance().get(ProductConstants.LIFERAY_PORTAL).isDetected(); private static final boolean RICHFACES_DETECTED = ProductMap.getInstance().get(ProductConstants.RICHFACES).isDetected(); private static final String ORG_RICHFACES_EXTENSION = "org.richfaces.extension"; // Pre-initialized Data Members private ApplicationMap applicationMap; private BeanManager beanManager; private Map<String, Object> requestAttributeMap; private Iterator<Locale> requestLocales; private Map<String, Object> sessionMap; // Lazily-Initialized Data Members private String authType; private BridgeAfterViewContentRequest bridgeAfterViewContentRequest; private BridgeAfterViewContentResponse bridgeAfterViewContentResponse; private Map<String, String> initParameterMap; private String remoteUser; private Map<String, Object> requestCookieMap; private Locale requestLocale; private Principal userPrincipal; public ExternalContextImpl( PortletContext portletContext, PortletRequest portletRequest, PortletResponse portletResponse) { super(portletContext, portletRequest, portletResponse); BeanManagerFactory beanManagerFactory = (BeanManagerFactory) FactoryExtensionFinder.getFactory(BeanManagerFactory.class); this.beanManager = beanManagerFactory.getBeanManager(); try { boolean requestChanged = false; boolean responseChanged = false; preInitializeObjects(requestChanged, responseChanged); } catch (Exception e) { logger.error(e); } } @Override public void dispatch(String path) throws IOException { // Indicate that JSP AFTER_VIEW_CONTENT processing has been de-activated. This will make it // possible for the // Mojarra JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method to // successfully call // {@link ExternalContextImpl#setResponse(Object)} in order to undo the // ViewHandlerResponseWrapper and restore // the original PortletResponse. bridgeContext.setProcessingAfterViewContent(false); logger.debug("De-activated JSP AFTER_VIEW_CONTENT"); bridgeContext.dispatch(path); } /** @see ExternalContext#encodeNamespace(String) */ @Override public String encodeNamespace(String name) { if (name == null) { return bridgeContext.getResponseNamespace(); } else if (RICHFACES_DETECTED && (name.equals(ORG_RICHFACES_EXTENSION))) { // http://issues.liferay.com/browse/FACES-1416 return name; } else { return bridgeContext.getResponseNamespace() + name; } } /** @see ExternalContext#encodeResourceURL(String) */ @Override public String encodeResourceURL(String url) { return bridgeContext.encodeResourceURL(url).toString(); } @Override public void log(String message) { portletContext.log(message); } @Override public void log(String message, Throwable exception) { portletContext.log(message, exception); } @Override public void redirect(String url) throws IOException { bridgeContext.redirect(url); } /** * In order to increase runtime performance, this method caches values of objects that are * typically called more than once during the JSF lifecycle. Other values will be cached lazily, * or might not be cached since their getter methods may never get called. * * @param requestChanged Flag indicating that this method is being called because {@link * #setRequest(Object)} was called. * @param responseChanged Flag indicating that this method is being called because {@link * #setResponse(Object)} was called. */ protected void preInitializeObjects(boolean requestChanged, boolean responseChanged) { if (requestChanged) { bridgeContext.setPortletRequest(portletRequest); } if (responseChanged) { bridgeContext.setPortletResponse(portletResponse); } // Retrieve the portlet lifecycle phase. portletPhase = bridgeContext.getPortletRequestPhase(); // Determines whether or not methods annotated with the @PreDestroy annotation are // preferably invoked // over the @BridgePreDestroy annotation. String preferPreDestroyInitParam = getInitParameter(BridgeConfigConstants.PARAM_PREFER_PRE_DESTROY1); if (preferPreDestroyInitParam == null) { // Backward compatibility preferPreDestroyInitParam = getInitParameter(BridgeConfigConstants.PARAM_PREFER_PRE_DESTROY2); } boolean preferPreDestroy = BooleanHelper.toBoolean(preferPreDestroyInitParam, true); // Initialize the application map. applicationMap = new ApplicationMap(portletContext, beanManager, preferPreDestroy); // Determines whether or not JSF @ManagedBean classes annotated with @RequestScoped should be // distinct for // each portlet when running under Liferay Portal. boolean distinctRequestScopedManagedBeans = false; if (LIFERAY_PORTAL_DETECTED) { distinctRequestScopedManagedBeans = BooleanHelper.toBoolean( getInitParameter(BridgeConfigConstants.PARAM_DISTINCT_REQUEST_SCOPED_MANAGED_BEANS), false); } // Initialize the request attribute map. Set<String> removedAttributeNames = null; BridgeRequestScope bridgeRequestScope = bridgeContext.getBridgeRequestScope(); if (bridgeRequestScope != null) { removedAttributeNames = bridgeRequestScope.getRemovedAttributeNames(); } else { removedAttributeNames = new HashSet<String>(); } requestAttributeMap = new RequestAttributeMap( portletRequest, beanManager, bridgeContext.getPortletContainer().getResponseNamespace(), preferPreDestroy, distinctRequestScopedManagedBeans, removedAttributeNames); // Initialize the session map. sessionMap = new SessionMap( portletRequest.getPortletSession(), beanManager, PortletSession.PORTLET_SCOPE, preferPreDestroy); // Initialize the init parameter map. initParameterMap = Collections.unmodifiableMap(new InitParameterMap(portletContext)); // Initialize the request context path. requestContextPath = portletRequest.getContextPath(); // Initialize the request locales. requestLocales = new LocaleIterator(portletRequest.getLocales()); } @Override public Map<String, Object> getApplicationMap() { return applicationMap; } @Override public String getAuthType() { if (authType == null) { authType = portletRequest.getAuthType(); } return authType; } @Override public Object getContext() { return portletContext; } @Override public boolean isUserInRole(String role) { return portletRequest.isUserInRole(role); } @Override public String getInitParameter(String name) { return bridgeContext.getInitParameter(name); } @Override public Map<String, String> getInitParameterMap() { return initParameterMap; } @Override public String getRemoteUser() { if (remoteUser == null) { remoteUser = portletRequest.getRemoteUser(); } return remoteUser; } @Override public Object getRequest() { // If JSP AFTER_VIEW_CONTENT processing has been activated by the // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method, then return a // ServletRequest that // wraps/decorates the current PortletRequest. This is necessary because the MyFaces // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method has a Servlet API // dependency due to // explicit casts to HttpServletRequest. if (bridgeContext.isProcessingAfterViewContent()) { if ((bridgeAfterViewContentRequest == null) || (bridgeAfterViewContentRequest.getWrapped() != portletRequest)) { BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory = (BridgeWriteBehindSupportFactory) FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class); bridgeAfterViewContentRequest = bridgeWriteBehindSupportFactory.getBridgeAfterViewContentRequest(portletRequest); } return bridgeAfterViewContentRequest; } else { return portletRequest; } } @Override public void setRequest(Object request) { this.portletRequest = (PortletRequest) request; try { boolean requestChanged = true; boolean responseChanged = false; preInitializeObjects(requestChanged, responseChanged); } catch (Exception e) { logger.error(e); } } @Override public String getRequestCharacterEncoding() { if (portletRequest instanceof ClientDataRequest) { ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest; String requestCharacterEncoding = clientDataRequest.getCharacterEncoding(); if (manageIncongruities) { try { incongruityContext.setRequestCharacterEncoding(requestCharacterEncoding); } catch (Exception e) { logger.error(e); } } return requestCharacterEncoding; } else { if (manageIncongruities) { return incongruityContext.getRequestCharacterEncoding(); } else { // The Mojarra 2.x {@link MultiViewHandler#initView(FacesContext)} method expects a null // value to be // returned, so throwing an IllegalStateException is not an option. return null; } } } @Override public void setRequestCharacterEncoding(String encoding) throws UnsupportedEncodingException, IllegalStateException { // Although the JSF API's ViewHandler.initView(FacesContext) method will call this method during // the portlet // RENDER_PHASE, the RenderRequest does not implement the ClientDataRequest interface, which // means it does not // have a setCharacterEncoding(String) method, therefore this should only be done in the case of // a // ClientDataRequest. if (portletRequest instanceof ClientDataRequest) { ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest; try { clientDataRequest.setCharacterEncoding(encoding); } catch (IllegalStateException e) { // TestPage141: setRequestCharacterEncodingActionTest -- exception is to be ignored } } else { if (manageIncongruities) { incongruityContext.setRequestCharacterEncoding(encoding); } else { // TestPage140: setRequestCharacterEncodingRenderTest expects this to be a no-op so throwing // an // IllegalStateException is not an option. } } } @Override public String getRequestContentType() { if (portletRequest instanceof ClientDataRequest) { ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest; // If using ICEfaces 3.0.x/2.0.x then need to return the legacy value. // http://issues.liferay.com/browse/FACES-1228 String requestContentType = null; if (isICEfacesLegacyMode(clientDataRequest)) { requestContentType = clientDataRequest.getResponseContentType(); } else { requestContentType = clientDataRequest.getContentType(); } if (manageIncongruities) { incongruityContext.setRequestContentType(requestContentType); } return requestContentType; } else { if (manageIncongruities) { return incongruityContext.getRequestContentType(); } else { // TestPage166: getRequestContentTypeEventTest expects this condition to return null so // throwing an // IllegalStateException is not an option. return null; } } } @Override public String getRequestContextPath() { return requestContextPath; } @Override public Map<String, Object> getRequestCookieMap() { if (requestCookieMap == null) { requestCookieMap = new RequestCookieMap(portletRequest.getCookies()); } return requestCookieMap; } @Override public Map<String, String> getRequestHeaderMap() { return bridgeContext.getRequestHeaderMap(); } @Override public Map<String, String[]> getRequestHeaderValuesMap() { return bridgeContext.getRequestHeaderValuesMap(); } @Override public Locale getRequestLocale() { if (requestLocale == null) { requestLocale = portletRequest.getLocale(); } return requestLocale; } @Override public Iterator<Locale> getRequestLocales() { return requestLocales; } @Override public Map<String, Object> getRequestMap() { return requestAttributeMap; } @Override public Map<String, String> getRequestParameterMap() { return bridgeContext.getRequestParameterMap(); } @Override public Iterator<String> getRequestParameterNames() { return getRequestParameterMap().keySet().iterator(); } @Override public Map<String, String[]> getRequestParameterValuesMap() { return bridgeContext.getRequestParameterValuesMap(); } /** * This method returns the relative path to the viewId that is to be rendered. * * @see javax.faces.context.ExternalContext#getRequestPathInfo() */ @Override public String getRequestPathInfo() { return bridgeContext.getRequestPathInfo(); } /** Section 6.1.3.1 of the JSR 329 spec describes the logic for this method. */ @Override public String getRequestServletPath() { return bridgeContext.getRequestServletPath(); } @Override public URL getResource(String path) throws MalformedURLException { return portletContext.getResource(path); } @Override public InputStream getResourceAsStream(String path) { return portletContext.getResourceAsStream(path); } @Override public Set<String> getResourcePaths(String path) { return portletContext.getResourcePaths(path); } @Override public Object getResponse() { // If JSP AFTER_VIEW_CONTENT processing has been activated by the // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method, then return a // ServletResponse that is // able to handle the AFTER_VIEW_CONTENT feature. This is necessary because the Mojarra // JspViewHandlingStrategy#getWrapper(ExternalContext) method has a Servlet API dependency due // to explicit casts // to HttpServletResponse. Additionally, the MyFaces // JspViewDeclarationLanguage#buildView(FacesContext, // UIViewRoot) method has an explicit cast to HttpServletResponse. if (bridgeContext.isProcessingAfterViewContent()) { if (facesImplementationServletResponse == null) { if ((bridgeAfterViewContentResponse == null) || (bridgeAfterViewContentResponse.getWrapped() != portletResponse)) { BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory = (BridgeWriteBehindSupportFactory) FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class); bridgeAfterViewContentResponse = bridgeWriteBehindSupportFactory.getBridgeAfterViewContentResponse( portletResponse, getRequestLocale()); } return bridgeAfterViewContentResponse; } else { return facesImplementationServletResponse; } } else { if (isBridgeFlashServletResponseRequired()) { return createFlashHttpServletResponse(); } else { return portletResponse; } } } @Override public void setResponse(Object response) { // Assume that the JSP_AFTER_VIEW_CONTENT feature is deactivated. facesImplementationServletResponse = null; // If JSP AFTER_VIEW_CONTENT processing has been activated by the bridge's // ViewDeclarationLanguageJspImpl#buildView(FacesContext, UIViewRoot) method, then wrap the // specified response // object with a ServletResponse that is able to handle the AFTER_VIEW_CONTENT feature. This is // necessary // because the Mojarra JspViewHandlingStrategy#getWrapper(ExternalContext) method has a Servlet // API dependency // due to explicit casts to HttpServletResponse. if (bridgeContext.isProcessingAfterViewContent()) { // If the specified response is of type HttpServletResponseWrapper, then it is almost certain // that Mojarra's // JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method is // attempting to wrap the // bridge's response object (that it originally got by calling the // ExternalContext#getResponse() method) // with it's ViewHandlerResponseWrapper, which extends HttpServletResponseWrapper. if (response instanceof HttpServletResponseWrapper) { this.facesImplementationServletResponse = (ServletResponse) response; HttpServletResponseWrapper httpServletResponseWrapper = (HttpServletResponseWrapper) response; ServletResponse wrappedServletResponse = httpServletResponseWrapper.getResponse(); if (wrappedServletResponse instanceof BridgeAfterViewContentResponse) { BridgeAfterViewContentResponse bridgeAfterViewContentPreResponse = (BridgeAfterViewContentResponse) wrappedServletResponse; PortletResponse wrappedPortletResponse = bridgeAfterViewContentPreResponse.getWrapped(); BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory = (BridgeWriteBehindSupportFactory) FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class); BridgeWriteBehindResponse bridgeWriteBehindResponse = bridgeWriteBehindSupportFactory.getBridgeWriteBehindResponse( (MimeResponse) wrappedPortletResponse, facesImplementationServletResponse); // Note: See comments in BridgeContextImpl#dispatch(String) regarding Liferay's inability // to // accept a wrapped response. This is indeed supported in Pluto. this.portletResponse = (PortletResponse) bridgeWriteBehindResponse; } else { // Since we're unable to determine the wrapped PortletResponse, the following line will // throw an // intentional ClassCastException. Note that this case should never happen. this.portletResponse = (PortletResponse) response; } } // Otherwise, the specified response is of type BridgeAfterViewContentResponse, then Mojarra's // JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method is trying // to restore the // bridge's response object that it originally got from calling the // ExternalContext#getResponse() method // prior to wrapping with it's ViewHandlerResponseWrapper. else if (response instanceof BridgeAfterViewContentResponse) { BridgeAfterViewContentResponse bridgeAfterViewContentResponse = (BridgeAfterViewContentResponse) response; this.portletResponse = bridgeAfterViewContentResponse.getWrapped(); } // Otherwise, assume that the specified response is a PortletResponse. else { this.portletResponse = (PortletResponse) response; } } // Otherwise, since the JSF AFTER_VIEW_CONTENT feature is not activated, assume that the // specified response is // a PortletResponse. else { this.portletResponse = (PortletResponse) response; } try { boolean requestChanged = false; boolean responseChanged = true; preInitializeObjects(requestChanged, responseChanged); } catch (Exception e) { logger.error(e); } } @Override public String getResponseCharacterEncoding() { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; String characterEncoding = mimeResponse.getCharacterEncoding(); if (manageIncongruities) { incongruityContext.setResponseCharacterEncoding(characterEncoding); } return characterEncoding; } else { if (manageIncongruities) { return incongruityContext.getResponseCharacterEncoding(); } else { if (portletResponse instanceof StateAwareResponse) { String characterEncoding = (String) bridgeContext.getAttributes().get(ViewHandlerImpl.RESPONSE_CHARACTER_ENCODING); if (characterEncoding != null) { // Workaround for patch applied to Mojarra in JAVASERVERFACES-3023 return characterEncoding; } else { // TCK TestPage169: getResponseCharacterEncodingActionTest // TCK TestPage180: getResponseCharacterEncodingEventTest throw new IllegalStateException(); } } else { return null; } } } } /** @see ExternalContext#setResponseCharacterEncoding(String) */ @Override public void setResponseCharacterEncoding(String encoding) { if (encoding != null) { if (portletResponse instanceof ResourceResponse) { ResourceResponse resourceResponse = (ResourceResponse) portletResponse; resourceResponse.setCharacterEncoding(encoding); } else { if (manageIncongruities) { incongruityContext.setResponseCharacterEncoding(encoding); } else { // TestPage196: setResponseCharacterEncodingTest expects this to be a no-op so throwing // IllegalStateException is not an option. } } } } /** @see {@link ExternalContext#getResponseContentType()} */ @Override public String getResponseContentType() { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; String responseContentType = mimeResponse.getContentType(); if (responseContentType == null) { responseContentType = portletRequest.getResponseContentType(); } return responseContentType; } else { // TCK TestPage173: getResponseContentTypeActionTest // TCK TestPage174: getResponseContentTypeEventTest throw new IllegalStateException(); } } /** @see {@link ExternalContext#getSession(boolean)} */ @Override public Object getSession(boolean create) { return portletRequest.getPortletSession(create); } @Override public Map<String, Object> getSessionMap() { return sessionMap; } @Override public Principal getUserPrincipal() { if (userPrincipal == null) { userPrincipal = portletRequest.getUserPrincipal(); } return userPrincipal; } }
/** @author Neil Griffin */ @RequestScoped @ManagedBean public class HtmlInputFileBackingBean { // Logger private static final Logger logger = LoggerFactory.getLogger(HtmlInputFileBackingBean.class); // Injections @ManagedProperty(value = "#{htmlInputFileModelBean}") private HtmlInputFileModelBean htmlInputFileModelBean; // Private Data Members private Part uploadedPart; public void deleteUploadedFile(ActionEvent actionEvent) { UICommand uiCommand = (UICommand) actionEvent.getComponent(); String fileId = (String) uiCommand.getValue(); try { List<UploadedFile> uploadedFiles = htmlInputFileModelBean.getUploadedFiles(); UploadedFile uploadedFileToDelete = null; for (UploadedFile uploadedFile : uploadedFiles) { if (uploadedFile.getId().equals(fileId)) { uploadedFileToDelete = uploadedFile; break; } } if (uploadedFileToDelete != null) { uploadedFileToDelete.delete(); uploadedFiles.remove(uploadedFileToDelete); logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName()); } } catch (Exception e) { logger.error(e); } } public Part getUploadedPart() { return uploadedPart; } public void setHtmlInputFileModelBean(HtmlInputFileModelBean htmlInputFileModelBean) { // Injected via @ManagedProperty annotation this.htmlInputFileModelBean = htmlInputFileModelBean; } public void setUploadedPart(Part uploadedPart) { this.uploadedPart = uploadedPart; String id = Long.toString(((long) hashCode()) + System.currentTimeMillis()); UploadedFile uploadedFile = new UploadedFilePart(uploadedPart, id, UploadedFile.Status.FILE_SAVED); htmlInputFileModelBean.getUploadedFiles().add(uploadedFile); } }
/** * This class represents a simple "non-encoded" {@link BaseURL}, meaning an implementation that * simply wraps a String based URL without providing any encoding. The only methods that are meant * to be called is {@link BaseURLNonEncodedStringImpl#toString()} and {@link * BaseURLNonEncodedStringImpl#write(Writer, boolean)}. All other methods throw an {@link * UnsupportedOperationException}. * * @author Neil Griffin */ public class BaseURLNonEncodedStringImpl implements BaseURL { // Logger private static final Logger logger = LoggerFactory.getLogger(BaseURLNonEncodedStringImpl.class); // Private Data Members private String url; private Map<String, String[]> parameterMap; private String query; private String main; private String toStringValue; public BaseURLNonEncodedStringImpl(String urlWithParameters) { this.url = urlWithParameters; this.parameterMap = new HashMap<String, String[]>(); } public BaseURLNonEncodedStringImpl(String url, Map<String, String[]> parameterMap) { this.url = url; this.parameterMap = parameterMap; } public void addProperty(String key, String value) { throw new UnsupportedOperationException(); } @Override public String toString() { if (toStringValue == null) { StringBuilder buf = new StringBuilder(); buf.append(getMain()); String queryString = getQuery(); if (queryString.length() > 0) { buf.append(StringPool.QUESTION); buf.append(queryString); } toStringValue = buf.toString(); } return toStringValue; } public void write(Writer out) throws IOException { throw new UnsupportedOperationException(); } public void write(Writer out, boolean escapeXML) throws IOException { // Note: Ignore the escapeXML parameter because this class is simply supposed to return the // original URL string. out.write(url); } /** Returns the main part of the URL, which is everything up until the question mark. */ protected String getMain() { if (main == null) { int queryPos = url.indexOf(StringPool.QUESTION); if (queryPos >= 0) { main = url.substring(0, queryPos); } else { main = url; } } return main; } public void setParameter(String name, String value) { throw new UnsupportedOperationException(); } public void setParameter(String name, String[] values) { throw new UnsupportedOperationException(); } public Map<String, String[]> getParameterMap() { throw new UnsupportedOperationException(); } public void setParameters(Map<String, String[]> parameters) { throw new UnsupportedOperationException(); } public void setProperty(String key, String value) { throw new UnsupportedOperationException(); } /** Returns the query-string part of the URL (without a leading question mark). */ protected String getQuery() { if (query == null) { StringBuilder buf = new StringBuilder(); // Get the original query-string from the URL. String originalQuery = StringPool.BLANK; boolean firstParam = true; int queryPos = url.indexOf(StringPool.QUESTION); if (queryPos >= 0) { originalQuery = url.substring(queryPos + 1); } // Keep track of all the parameters that are appended to the return value. Set<String> processedParameterNames = new HashSet<String>(parameterMap.size()); // The TCK expects query parameters to appear in exactly the same order as they do in the // query-string of // the original URL. For this reason, need to iterate over the parameters found in the // original // query-string. String[] queryParameters = originalQuery.split(BridgeConstants.REGEX_AMPERSAND_DELIMITER); // For each parameter found in the original query-string: for (String queryParameter : queryParameters) { if ((queryParameter != null) && (queryParameter.length() > 0)) { // Parse the name and value from the name=value pair. String[] nameValueArray = queryParameter.split("[=]"); String name = null; String[] values = null; if (nameValueArray.length == 1) { name = nameValueArray[0]; values = new String[] {StringPool.BLANK}; } else if (nameValueArray.length == 2) { name = nameValueArray[0]; // If the parameter name is present in the parameter map, then that means it should be // appended // to the return value. Otherwise, it should not be appended, because absence from the // parameter // map means that it was deliberately removed. values = parameterMap.get(name); } if ((name != null) && (values != null) && (values.length > 0)) { if (firstParam) { firstParam = false; } else { buf.append(StringPool.AMPERSAND); } buf.append(name); buf.append(StringPool.EQUAL); buf.append(values[0]); processedParameterNames.add(name); } // Otherwise, log an error. else { // Note that "javax.portlet.faces.BackLink" is sometimes deliberately removed and // therefore is // not an error. if (!Bridge.BACK_LINK.equals(name)) { logger.error("Invalid name=value pair=[{0}] in URL=[{1}]", queryParameter, url); } } } } // Now iterate through the entire parameter map to see and append any additional parameters to // the return // value. Set<Entry<String, String[]>> mapEntries = parameterMap.entrySet(); for (Map.Entry<String, String[]> mapEntry : mapEntries) { String name = mapEntry.getKey(); if (!processedParameterNames.contains(name)) { String[] values = mapEntry.getValue(); if ((values != null) && (values.length > 0)) { if (firstParam) { firstParam = false; } else { buf.append(StringPool.AMPERSAND); } buf.append(name); buf.append(StringPool.EQUAL); buf.append(values[0]); } } } query = buf.toString(); } return query; } public void setSecure(boolean secure) throws PortletSecurityException { throw new UnsupportedOperationException(); } }
/** * This class is a runtime wrapper around the RichFaces FileUploadRenderer class that makes the * rich:fileUpload component compatible with a portlet environment. * * @author Neil Griffin */ public class FileUploadRendererRichFacesImpl extends RendererWrapper { // Logger private static final Logger logger = LoggerFactory.getLogger(FileUploadRendererRichFacesImpl.class); // Private Constants private static final String RICHFACES_UPLOADED_FILE_FQCN = "org.richfaces.model.UploadedFile"; private static final String RICHFACES_FILE_UPLOAD_EVENT_FQCN = "org.richfaces.event.FileUploadEvent"; // Private Data Members private Renderer wrappedRenderer; public FileUploadRendererRichFacesImpl(Renderer renderer) { this.wrappedRenderer = renderer; } /** * This method overrides the {@link #decode(FacesContext, UIComponent)} method so that it can * avoid a Servlet-API dependency in the RichFaces FileUploadRenderer. Note that rich:fileUpload * will do an Ajax postback and invoke the JSF lifecycle for each individual file. */ @Override public void decode(FacesContext facesContext, UIComponent uiComponent) { try { // Get the UploadedFile from the request attribute map. ContextMapFactory contextMapFactory = (ContextMapFactory) FactoryExtensionFinder.getFactory(ContextMapFactory.class); BridgeContext bridgeContext = BridgeContext.getCurrentInstance(); Map<String, Collection<UploadedFile>> uploadedFileMap = contextMapFactory.getUploadedFileMap(bridgeContext); if (uploadedFileMap != null) { // Use reflection to create a dynamic proxy class that implements the RichFaces UploadedFile // interface. Class<?> uploadedFileInterface = Class.forName(RICHFACES_UPLOADED_FILE_FQCN); Class<?> fileUploadEventClass = Class.forName(RICHFACES_FILE_UPLOAD_EVENT_FQCN); ClassLoader classLoader = uploadedFileInterface.getClassLoader(); String clientId = uiComponent.getClientId(facesContext); Collection<UploadedFile> uploadedFiles = uploadedFileMap.get(clientId); if (uploadedFiles != null) { for (UploadedFile uploadedFile : uploadedFiles) { RichFacesUploadedFileHandler richFacesUploadedFileHandler = new RichFacesUploadedFileHandler(uploadedFile); Object richFacesUploadedFile = Proxy.newProxyInstance( classLoader, new Class[] {uploadedFileInterface}, richFacesUploadedFileHandler); FacesEvent fileUploadEvent = (FacesEvent) fileUploadEventClass .getConstructor(UIComponent.class, uploadedFileInterface) .newInstance(uiComponent, richFacesUploadedFile); // Queue the RichFaces FileUploadEvent instance so that it can be handled with an // ActionListener. uiComponent.queueEvent(fileUploadEvent); } } } } catch (Exception e) { logger.error(e); } } @Override public Renderer getWrapped() { return wrappedRenderer; } public class RichFacesUploadedFileHandler implements InvocationHandler { // Private Constants private static final String METHOD_DELETE = "delete"; private static final String METHOD_GET_CONTENT_TYPE = "getContentType"; private static final String METHOD_GET_DATA = "getData"; private static final String METHOD_GET_INPUT_STREAM = "getInputStream"; private static final String METHOD_GET_NAME = "getName"; private static final String METHOD_GET_SIZE = "getSize"; private static final String METHOD_WRITE = "write"; // Private Data Members private UploadedFile uploadedFile; public RichFacesUploadedFileHandler(UploadedFile uploadedFile) { this.uploadedFile = uploadedFile; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (METHOD_DELETE.equals(methodName)) { File file = new File(uploadedFile.getAbsolutePath()); file.delete(); return null; } else if (METHOD_GET_CONTENT_TYPE.equals(methodName)) { return uploadedFile.getContentType(); } else if (METHOD_GET_DATA.equals(methodName)) { return getBytes(); } else if (METHOD_GET_INPUT_STREAM.equals(methodName)) { return new FileInputStream(uploadedFile.getAbsolutePath()); } else if (METHOD_GET_NAME.equals(methodName)) { return uploadedFile.getName(); } else if (METHOD_GET_SIZE.equals(methodName)) { return uploadedFile.getSize(); } else if (METHOD_WRITE.equals(methodName)) { String fileName = (String) args[0]; OutputStream outputStream = new FileOutputStream(fileName); outputStream.write(getBytes()); outputStream.close(); return null; } else { // Unsupported method. return null; } } protected byte[] getBytes() { byte[] bytes = null; try { File file = new File(uploadedFile.getAbsolutePath()); if (file.exists()) { RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); bytes = new byte[(int) randomAccessFile.length()]; randomAccessFile.readFully(bytes); randomAccessFile.close(); } } catch (Exception e) { logger.error(e); } return bytes; } } }
/** @author Neil Griffin */ public class BridgePhaseEventImpl extends BridgePhaseCompat_2_2_Impl { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgePhaseEventImpl.class); // Private Data Members private EventRequest eventRequest; private EventResponse eventResponse; public BridgePhaseEventImpl( EventRequest eventRequest, EventResponse eventResponse, PortletConfig portletConfig) { super(portletConfig); this.eventRequest = eventRequest; this.eventResponse = eventResponse; } public void execute() throws BridgeDefaultViewNotSpecifiedException, BridgeException { logger.debug(Logger.SEPARATOR); logger.debug("execute(EventRequest, EventResponse) portletName=[{0}]", portletName); try { // If there is a bridgeEventHandler registered in portlet.xml, then String bridgeEventHandlerAttributeName = Bridge.BRIDGE_PACKAGE_PREFIX + portletName + "." + Bridge.BRIDGE_EVENT_HANDLER; BridgeEventHandler bridgeEventHandler = (BridgeEventHandler) portletContext.getAttribute(bridgeEventHandlerAttributeName); init(eventRequest, eventResponse, Bridge.PortletPhase.EVENT_PHASE); if (bridgeEventHandler != null) { // Restore the BridgeRequestScope that may have started during the ACTION_PHASE. bridgeRequestScope.restoreState(facesContext); // PROPOSED-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-202 bridgeRequestScope.setPortletMode(eventRequest.getPortletMode()); // Execute the JSF lifecycle so that ONLY the RESTORE_VIEW phase executes (note that this // this is // accomplished by the IPCPhaseListener). facesLifecycle.execute(facesContext); // If there were any "handled" exceptions queued, then throw a BridgeException. Throwable handledException = getJSF2HandledException(facesContext); if (handledException != null) { throw new BridgeException(handledException); } // Otherwise, if there were any "unhandled" exceptions queued, then throw a BridgeException. Throwable unhandledException = getJSF2UnhandledException(facesContext); if (unhandledException != null) { throw new BridgeException(unhandledException); } // Set a flag on the bridge request scope indicating that the Faces Lifecycle has executed. bridgeRequestScope.setFacesLifecycleExecuted(true); // If there is a bridgeEventHandler registered in portlet.xml, then invoke the handler so // that it // can process the event payload. logger.debug( "Invoking {0} for class=[{1}]", bridgeEventHandlerAttributeName, bridgeEventHandler.getClass()); Event event = eventRequest.getEvent(); EventNavigationResult eventNavigationResult = bridgeEventHandler.handleEvent(facesContext, event); if (eventNavigationResult != null) { String oldViewId = facesContext.getViewRoot().getViewId(); String fromAction = eventNavigationResult.getFromAction(); String outcome = eventNavigationResult.getOutcome(); logger.debug( "Invoking navigationHandler fromAction=[{0}] outcome=[{1}]", fromAction, outcome); NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler(); navigationHandler.handleNavigation(facesContext, fromAction, outcome); String newViewId = facesContext.getViewRoot().getViewId(); bridgeRequestScope.setNavigationOccurred(!oldViewId.equals(newViewId)); } // Save the faces view root and any messages in the faces context so that they can be // restored during // the RENDER_PHASE of the portlet lifecycle. bridgeRequestScope.saveState(facesContext); // Assume that the bridge request scope should be maintained from the EVENT_PHASE into the // RENDER_PHASE by utilizing render parameters. BridgeRequestScope.Transport bridgeRequestScopeTransport = BridgeRequestScope.Transport.RENDER_PARAMETER; Serializable eventPayload = event.getValue(); // FACES-1465: If the portlet developer intentionally wrapped the event payload is with an // EventPayloadWrapper, then determine whether or not this is happening during a redirect. // If this is // the case, then the bridge request scope must be maintained from the EVENT_PHASE into the // RENDER_PHASE // by utilizing a portlet session attribute. This is because render parameters will not // survive a // redirect. if ((eventPayload != null) && (eventPayload instanceof EventPayloadWrapper)) { EventPayloadWrapper eventPayloadWrapper = (EventPayloadWrapper) eventPayload; if (eventPayloadWrapper.isRedirect()) { bridgeRequestScopeTransport = BridgeRequestScope.Transport.PORTLET_SESSION_ATTRIBUTE; } } maintainBridgeRequestScope(eventRequest, eventResponse, bridgeRequestScopeTransport); // Process the outgoing public render parameters. // TCK TestPage064: eventControllerTest processOutgoingPublicRenderParameters(facesLifecycle); } // Maintain the render parameters set in the ACTION_PHASE so that they carry over to the // RENDER_PHASE. bridgeContext.getPortletContainer().maintainRenderParameters(eventRequest, eventResponse); // Spec 6.6 (Namespacing) indicateNamespacingToConsumers(facesContext.getViewRoot(), eventResponse); } catch (Throwable t) { throw new BridgeException(t); } finally { cleanup(); } } protected void processOutgoingPublicRenderParameters(Lifecycle lifecycle) { PhaseListener[] phaseListeners = lifecycle.getPhaseListeners(); for (PhaseListener phaseListener : phaseListeners) { if (phaseListener instanceof IPCPhaseListener) { IPCPhaseListener ipcPhaseListener = (IPCPhaseListener) phaseListener; ipcPhaseListener.processOutgoingPublicRenderParameters(bridgeContext, facesContext); break; } } } }
/** * This class provides a compatibility layer that isolates differences between JSF1 and JSF2. * * @author Neil Griffin */ public abstract class ExternalContextCompatImpl extends ExternalContext { // Logger private static final Logger logger = LoggerFactory.getLogger(ExternalContextCompatImpl.class); // Private Constants private static final String COOKIE_PROPERTY_COMMENT = "comment"; private static final String COOKIE_PROPERTY_DOMAIN = "domain"; private static final String COOKIE_PROPERTY_MAX_AGE = "maxAge"; private static final String COOKIE_PROPERTY_PATH = "path"; private static final String COOKIE_PROPERTY_SECURE = "secure"; // Lazy-Initialized Data Members private BridgeFlash bridgeFlash; private Boolean iceFacesLegacyMode; private String portletContextName; // Private Data Members private BridgeConfig bridgeConfig; // Protected Data Members protected BridgeContext bridgeContext; protected ServletResponse facesImplementationServletResponse; protected IncongruityContext incongruityContext; protected boolean manageIncongruities; protected PortletContext portletContext; protected PortletRequest portletRequest; protected PortletResponse portletResponse; protected Bridge.PortletPhase portletPhase; protected String requestContextPath; public ExternalContextCompatImpl( PortletContext portletContext, PortletRequest portletRequest, PortletResponse portletResponse) { this.portletContext = portletContext; this.portletRequest = portletRequest; this.portletResponse = portletResponse; // Get the bridge configuration. BridgeConfigFactory bridgeConfigFactory = (BridgeConfigFactory) BridgeFactoryFinder.getFactory(BridgeConfigFactory.class); this.bridgeConfig = bridgeConfigFactory.getBridgeConfig(); // Get the BridgeContext. this.bridgeContext = BridgeContext.getCurrentInstance(); this.incongruityContext = bridgeContext.getIncongruityContext(); // Determine whether or not lifecycle incongruities should be managed. this.manageIncongruities = BooleanHelper.toBoolean( bridgeContext.getInitParameter(BridgeConfigConstants.PARAM_MANAGE_INCONGRUITIES), true); } /** * @see {@link ExternalContext#addResponseCookie(String, String, Map)} * @since JSF 2.0 */ @Override public void addResponseCookie(String name, String value, Map<String, Object> properties) { Cookie cookie = new Cookie(name, value); if ((properties != null) && !properties.isEmpty()) { try { String comment = (String) properties.get(COOKIE_PROPERTY_COMMENT); if (comment != null) { cookie.setComment(comment); } String domain = (String) properties.get(COOKIE_PROPERTY_DOMAIN); if (domain != null) { cookie.setDomain(domain); } Integer maxAge = (Integer) properties.get(COOKIE_PROPERTY_MAX_AGE); if (maxAge != null) { cookie.setMaxAge(maxAge); } String path = (String) properties.get(COOKIE_PROPERTY_PATH); if (path != null) { cookie.setPath(path); } Boolean secure = (Boolean) properties.get(COOKIE_PROPERTY_SECURE); if (secure != null) { cookie.setSecure(secure); } } catch (ClassCastException e) { logger.error(e.getMessage(), e); } } portletResponse.addProperty(cookie); } /** * @see {@link ExternalContext#addResponseHeader(String, String)} * @since JSF 2.0 */ @Override public void addResponseHeader(String name, String value) { if (portletResponse instanceof ResourceResponse) { ResourceResponse resourceResponse = (ResourceResponse) portletResponse; resourceResponse.addProperty(name, value); } else { logger.warn( "Unable to call {0} for portletResponse=[{1}] because it is not a ResourceResponse.", "portletResponse.addProperty(String, String)", portletResponse.getClass().getName()); } } /** * Note: The reason why this method appears here in {@link ExternalContextCompatImpl} is because * it needs to be overridden by {@link ExternalContextCompat_2_2_Impl} since it has special * requirements for JSF 2.2. * * @see {@link ExternalContext#encodeActionURL(String, Map)} * @since JSF 1.0 */ @Override public String encodeActionURL(String url) { if (isEncodingFormWithPrimeFacesAjaxFileUpload()) { return encodePartialActionURL(url); } else { return bridgeContext.encodeActionURL(url).toString(); } } /** * @see {@link ExternalContext#encodeBookmarkableURL(String, Map)} * @since JSF 2.0 */ @Override public String encodeBookmarkableURL(String baseUrl, Map<String, List<String>> parameters) { String renderURL = null; if (baseUrl != null) { String viewId = baseUrl; if (baseUrl.startsWith(requestContextPath)) { viewId = baseUrl.substring(requestContextPath.length()); } try { if ((portletPhase == Bridge.PortletPhase.RENDER_PHASE) || (portletPhase == Bridge.PortletPhase.RESOURCE_PHASE)) { PortletURL portletRenderURL = bridgeContext.getPortletContainer().createRenderURL(baseUrl); portletRenderURL.setParameter(bridgeConfig.getViewIdRenderParameterName(), viewId); if (parameters != null) { for (Map.Entry<String, List<String>> parameter : parameters.entrySet()) { String name = parameter.getKey(); if (name != null) { List<String> values = parameter.getValue(); if (values != null) { int size = values.size(); if (size > 0) { if (size == 1) { String value = values.get(0); if (value != null) { portletRenderURL.setParameter(name, value); } } else { logger.warn("Unable to append multiple values for parameter name=[{0]", name); } } } } } } renderURL = portletRenderURL.toString(); } else { logger.error( "Unable to encode bookmarkable URL during Bridge.PortletPhase.[{0}] -- you should call BridgeUtil.getPortletRequestPhase() and check for Bridge.PortletPhase.RENDER_PHASE or Bridge.PortletPhase.RESOURCE_PHASE before calling ExternalContext.encodeBookmarkableURL(...).", portletPhase); } } catch (Exception e) { logger.error(e.getMessage(), e); } } else { logger.warn("Unable to encode RenderURL for url=[null]"); } return renderURL; } /** * @see {@link ExternalContext#encodePartialActionURL(String)} * @since JSF 2.0 */ @Override public String encodePartialActionURL(String url) { return bridgeContext.encodePartialActionURL(url).toString(); } /** * @see {@link ExternalContext#encodeRedirectURL(String, Map)} * @since JSF 2.0 */ @Override public String encodeRedirectURL(String baseUrl, Map<String, List<String>> parameters) { return bridgeContext.encodeRedirectURL(baseUrl, parameters).toString(); } /** * @see {@link ExternalContext#invalidateSession()} * @since JSF 2.0 */ @Override public void invalidateSession() { portletRequest.getPortletSession().invalidate(); } /** * @see {@link ExternalContext#responseFlushBuffer()} * @since JSF 2.0 */ @Override public void responseFlushBuffer() throws IOException { if (portletResponse instanceof MimeResponse) { if (facesImplementationServletResponse != null) { // This happens when Mojarra's JspViewHandlingStrategy#buildView(FacesContext context, // UIViewRoot) // executes. facesImplementationServletResponse.flushBuffer(); } else { MimeResponse mimeResponse = (MimeResponse) portletResponse; mimeResponse.flushBuffer(); } } else { if (manageIncongruities) { incongruityContext.responseFlushBuffer(); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#responseReset()} * @since JSF 2.0 */ @Override public void responseReset() { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; mimeResponse.reset(); } else { if (manageIncongruities) { incongruityContext.responseReset(); } else { throw new IllegalStateException(); } } } /** * The Portlet API does not have an equivalent to {@link HttpServletResponse.sendError(int, * String)}. Since the Mojarra JSF implementation basically only calls this when a Facelet is not * found, better in a portlet environment to simply log an error and throw an IOException up the * call stack so that the portlet will give the portlet container a chance to render an error * message. * * @see {@link ExternalContext#responseSendError(int, String)} * @since JSF 2.0 */ @Override public void responseSendError(int statusCode, String message) throws IOException { String errorMessage = "Status code " + statusCode + ": " + message; logger.error(errorMessage); throw new IOException(errorMessage); } protected HttpServletResponse createFlashHttpServletResponse() { return new FlashHttpServletResponse(portletResponse, getRequestLocale()); } // NOTE: PROPOSED-FOR-JSR344-API // http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1070 // NOTE: PROPOSED-FOR-BRIDGE3-API (Called by BridgeRequestScope in order to restore the Flash // scope) // https://issues.apache.org/jira/browse/PORTLETBRIDGE-207 public void setBridgeFlash(BridgeFlash bridgeFlash) { this.bridgeFlash = bridgeFlash; } /** * @see {@link ExternalContext#getContextName()} * @since JSF 2.0 */ @Override public String getContextName() { if (portletContextName == null) { portletContextName = portletContext.getPortletContextName(); } return portletContextName; } /** * @see {@link ExternalContext#isResponseCommitted()} * @since JSF 2.0 */ @Override public boolean isResponseCommitted() { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; boolean responseCommitted = mimeResponse.isCommitted(); if (manageIncongruities) { incongruityContext.setResponseCommitted(responseCommitted); } return responseCommitted; } else { if (manageIncongruities) { return incongruityContext.isResponseCommitted(); } else { throw new IllegalStateException(); } } } protected boolean isBridgeFlashServletResponseRequired() { return ((bridgeFlash != null) && bridgeFlash.isServletResponseRequired()); } protected boolean isEncodingFormWithPrimeFacesAjaxFileUpload() { FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext.getAttributes().get(PrimeFacesFileUpload.AJAX_FILE_UPLOAD) != null) { return true; } else { return false; } } @Override public boolean isSecure() { return portletRequest.isSecure(); } protected boolean isICEfacesLegacyMode(ClientDataRequest clientDataRequest) { if (iceFacesLegacyMode == null) { iceFacesLegacyMode = Boolean.FALSE; String requestContentType = clientDataRequest.getContentType(); if ((requestContentType != null) && requestContentType .toLowerCase() .startsWith(BridgeConstants.MULTIPART_CONTENT_TYPE_PREFIX)) { Product iceFaces = ProductMap.getInstance().get(ProductConstants.ICEFACES); if (iceFaces.isDetected() && ((iceFaces.getMajorVersion() == 2) || ((iceFaces.getMajorVersion() == 3) && (iceFaces.getMinorVersion() == 0)))) { iceFacesLegacyMode = Boolean.TRUE; } } } return iceFacesLegacyMode; } @Override public Flash getFlash() { if (bridgeFlash == null) { BridgeFlashFactory bridgeFlashFactory = (BridgeFlashFactory) BridgeFactoryFinder.getFactory(BridgeFlashFactory.class); bridgeFlash = bridgeFlashFactory.getBridgeFlash(); } return bridgeFlash; } /** * @see {@link ExternalContext#getMimeType(String)} * @since JSF 2.0 */ @Override public String getMimeType(String fileName) { String mimeType = portletContext.getMimeType(fileName); if ((mimeType == null) || (mimeType.length() == 0)) { mimeType = FileNameUtil.getFileNameMimeType(fileName); } return mimeType; } /** * @see {@link ExternalContext#getRealPath(String)} * @since JSF 2.0 */ @Override public String getRealPath(String path) { return portletContext.getRealPath(path); } /** * @see {@link ExternalContext#getRequestContentLength()} * @since JSF 2.0 */ @Override public int getRequestContentLength() { int requestContentLength = -1; if (portletRequest instanceof ClientDataRequest) { ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest; requestContentLength = clientDataRequest.getContentLength(); if (manageIncongruities) { incongruityContext.setRequestContentLength(requestContentLength); } return requestContentLength; } else { if (manageIncongruities) { return incongruityContext.getRequestContentLength(); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#getRequestScheme()} * @since JSF 2.0 */ @Override public String getRequestScheme() { return portletRequest.getScheme(); } /** * @see {@link ExternalContext#getRequestServerName()} * @since JSF 2.0 */ @Override public String getRequestServerName() { return portletRequest.getServerName(); } /** * @see {@link ExternalContext#getRequestServerPort()} * @since JSF 2.0 */ @Override public int getRequestServerPort() { return portletRequest.getServerPort(); } /** * @see {@link ExternalContext#getResponseBufferSize()} * @since JSF 2.0 */ @Override public int getResponseBufferSize() { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; int responseBufferSize = mimeResponse.getBufferSize(); if (manageIncongruities) { incongruityContext.setResponseBufferSize(responseBufferSize); } return responseBufferSize; } else { if (manageIncongruities) { return incongruityContext.getResponseBufferSize(); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#setResponseBufferSize(int)} * @since JSF 2.0 */ @Override public void setResponseBufferSize(int size) { if (portletResponse instanceof ResourceResponse) { if (bridgeContext.getPortletContainer().isAbleToSetResourceResponseBufferSize()) { ResourceResponse resourceResponse = (ResourceResponse) portletResponse; resourceResponse.setBufferSize(size); } } else { if (manageIncongruities) { incongruityContext.setResponseBufferSize(size); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#setResponseContentLength(int)} * @since JSF 2.0 */ @Override public void setResponseContentLength(int length) { if (portletResponse instanceof ResourceResponse) { ResourceResponse resourceResponse = (ResourceResponse) portletResponse; resourceResponse.setContentLength(length); } else { if (manageIncongruities) { incongruityContext.setResponseContentLength(length); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#setResponseContentType(String)} * @since JSF 2.0 */ @Override public void setResponseContentType(String contentType) { if (portletResponse instanceof MimeResponse) { MimeResponse mimeResponse = (MimeResponse) portletResponse; bridgeContext.getPortletContainer().setMimeResponseContentType(mimeResponse, contentType); } else { if (manageIncongruities) { incongruityContext.setResponseContentType(contentType); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#setResponseHeader(String, String)} * @since JSF 2.0 */ @Override public void setResponseHeader(String name, String value) { addResponseHeader(name, value); } /** * @see {@link ExternalContext#getResponseOutputStream()} * @since JSF 2.0 */ @Override public OutputStream getResponseOutputStream() throws IOException { if (portletResponse instanceof MimeResponse) { if (facesImplementationServletResponse != null) { logger.debug( "Delegating to AFTER_VIEW_CONTENT servletResponse=[{0}]", facesImplementationServletResponse); return facesImplementationServletResponse.getOutputStream(); } else { MimeResponse mimeResponse = (MimeResponse) portletResponse; return mimeResponse.getPortletOutputStream(); } } else { if (manageIncongruities) { return incongruityContext.getResponseOutputStream(); } else { throw new IllegalStateException(); } } } /** * @see {@link ExternalContext#getResponseOutputWriter()} * @since JSF 2.0 */ @Override public Writer getResponseOutputWriter() throws IOException { if (portletResponse instanceof MimeResponse) { if (facesImplementationServletResponse != null) { logger.debug( "Delegating to AFTER_VIEW_CONTENT servletResponse=[{0}]", facesImplementationServletResponse); return facesImplementationServletResponse.getWriter(); } else { return bridgeContext.getResponseOutputWriter(); } } else { if (manageIncongruities) { return incongruityContext.getResponseOutputWriter(); } else { throw new IllegalStateException(); } } } /** * Sets the status of the portlet response to the specified status code. Note that this is only * possible for a portlet request of type PortletResponse because that is the only type of portlet * response that is delivered directly back to the client (without additional markup added by the * portlet container). * * @see {@link ExternalContext#setResponseStatus(int)} * @since JSF 2.0 */ @Override public void setResponseStatus(int statusCode) { if (portletResponse instanceof ResourceResponse) { ResourceResponse resourceResponse = (ResourceResponse) portletResponse; resourceResponse.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(statusCode)); } else { if (manageIncongruities) { incongruityContext.setResponseStatus(statusCode); } else { // Mojarra will call this method if a runtime exception occurs during execution of the JSF // lifecycle, so // must not throw an IllegalStateException. } } } @Override public int getSessionMaxInactiveInterval() { PortletSession portletSession = (PortletSession) getSession(true); return portletSession.getMaxInactiveInterval(); } @Override public void setSessionMaxInactiveInterval(int sessionMaxInactiveInterval) { PortletSession portletSession = (PortletSession) getSession(true); portletSession.setMaxInactiveInterval(sessionMaxInactiveInterval); } }
/** * This class is designed to support the {@link BridgeRequestScopeAttributeAdded} annotation. It has * to be specified as a listener in the WEB-INF/web.xml descriptor like this: <code> * <pre> * <listener> * <listener-class>com.liferay.faces.bridge.context.map.BridgeRequestAttributeListener</listener-class> * </listener> * </pre> * </code> * * @see http://issues.liferay.com/browse/FACES-146 * @author Neil Griffin */ public class BridgeRequestAttributeListener implements ServletRequestAttributeListener { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeRequestAttributeListener.class); /** * This method is called after an attribute is added to the ServletRequest. Note that this should * only get called for remote WSRP portlets. For more info, see: * http://issues.liferay.com/browse/FACES-146 */ public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) { // NOTE: We only care about phases prior to the RENDER_PHASE because we're concerned here about // managed beans // that get added to the request scope when the BridgeRequestScope begins. We're trying to // provide those managed // beans with an opportunity to prepare for an unexpected invocation of their methods annotated // with // @PreDestroy. ServletRequest servletRequest = servletRequestAttributeEvent.getServletRequest(); PortletPhase phase = (PortletPhase) servletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE); // If this is taking place within a PortletRequest handled by the bridge in any phase prior to // the // RENDER_PHASE, then if ((phase != null) && (phase != PortletPhase.RENDER_PHASE)) { // If the attribute being added is not excluded, then invoke all methods on the attribute // value (class // instance) that are annotated with the BridgeRequestScopeAttributeAdded annotation. String attributeName = servletRequestAttributeEvent.getName(); BridgeContext bridgeContext = BridgeContext.getCurrentInstance(); BridgeConfig bridgeConfig = bridgeContext.getBridgeConfig(); Set<String> excludedRequestScopeAttributes = bridgeConfig.getExcludedRequestAttributes(); if (!excludedRequestScopeAttributes.contains(attributeName)) { Object attributeValue = servletRequestAttributeEvent.getValue(); logger.trace("Attribute added name=[{0}] value=[{1}]", attributeName, attributeValue); if (attributeValue != null) { Method[] methods = attributeValue.getClass().getMethods(); if (methods != null) { for (Method method : methods) { if (method != null) { if (method.isAnnotationPresent(BridgeRequestScopeAttributeAdded.class)) { try { method.invoke(attributeValue, new Object[] {}); } catch (Exception e) { logger.error(e); } } } } } } } } } /** * This method is called after an attribute is removed from the ServletRequest. One might expect * that this is a good time to call any managed bean methods annotated with @BridgePreDestroy, but * that actually takes place in the Bridge's {@link RequestAttributeMap#remove(Object)} method. * Note that this should only get called for remote WSRP portlets. For more info, see: * http://issues.liferay.com/browse/FACES-146 */ public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) { String attributeName = servletRequestAttributeEvent.getName(); Object attributeValue = servletRequestAttributeEvent.getValue(); logger.trace("Attribute removed name=[{0}] value=[{1}]", attributeName, attributeValue); } /** * This method is called after an attribute is replaced in the ServletRequest. One might expect * that this is a good time to call any managed bean methods annotated with @BridgePreDestroy, but * that actually takes place in the Bridge's {@link RequestAttributeMap#remove(Object)} method. * Note that this should only get called for remote WSRP portlets. For more info, see: * http://issues.liferay.com/browse/FACES-146 */ public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) { String attributeName = servletRequestAttributeEvent.getName(); Object attributeValue = servletRequestAttributeEvent.getValue(); logger.trace("Attribute replaced name=[{0}] value=[{1}]", attributeName, attributeValue); } }
/** * This abstract class serves as a generic JSF {@link Renderer} that invokes the JSP tag lifecycle * of a Liferay Portal JSP tag and encodes the output. Unlike its parent {@link PortalTagRenderer}, * encoding of the JSP tag output is delayed so that child JSP tags have an opportunity to influence * rendering of their parent JSP tag. * * @author Juan Gonzalez */ public abstract class DelayedPortalTagRenderer<U extends UIComponent, T extends Tag> extends PortalTagRenderer<U, T> { // Logger private static final Logger logger = LoggerFactory.getLogger(DelayedPortalTagRenderer.class); @Override public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException { // Create an instance of the JSP tag that corresponds to the JSF component. T tag = newTag(); copyAttributes(facesContext, cast(uiComponent), tag); uiComponent.getAttributes().put(CORRESPONDING_JSP_TAG, tag); } @Override public void encodeChildren(FacesContext facesContext, UIComponent uiComponent) throws IOException { // Encode each of the children using a writer that can capture the child markup as a string. ResponseWriter originalResponseWriter = facesContext.getResponseWriter(); RenderKit renderKit = facesContext.getRenderKit(); StringWriter bufferedChildrenMarkupWriter = new StringWriter(); ResponseWriter stringResponseWriter = renderKit.createResponseWriter(bufferedChildrenMarkupWriter, null, StringPool.UTF8); facesContext.setResponseWriter(stringResponseWriter); List<UIComponent> children = uiComponent.getChildren(); for (UIComponent child : children) { child.encodeAll(facesContext); } facesContext.setResponseWriter(originalResponseWriter); // Get the output of the JSP tag (and all child JSP tags). Map<String, Object> componentAttributes = uiComponent.getAttributes(); Tag tag = (Tag) componentAttributes.get(CORRESPONDING_JSP_TAG); PortalTagOutput portalTagOutput; try { portalTagOutput = getPortalTagOutput(facesContext, uiComponent, tag); String preChildMarkup = portalTagOutput.getMarkup(); String postChildMarkup = null; // Determine the point at which children should be inserted into the markup. String childInsertionMarker = getChildInsertionMarker(); if (childInsertionMarker != null) { int pos = preChildMarkup.indexOf(childInsertionMarker); if (pos > 0) { postChildMarkup = preChildMarkup.substring(pos).trim(); preChildMarkup = preChildMarkup.substring(0, pos).trim(); } } // Encode the output of the JSP tag up until the point at which children should be inserted. StringBuilder markup = new StringBuilder(3); markup.append(preChildMarkup); // Ensure that scripts are rendered at the bottom of the page. String scripts = portalTagOutput.getScripts(); if (scripts != null) { RendererUtil.renderScript(scripts, null); } // Encode the children markup. String childrenMarkup = bufferedChildrenMarkupWriter.toString(); if (childrenMarkup != null) { markup.append(childrenMarkup); } // Encode the output of the JSP tag that is to appear after the children. if (postChildMarkup != null) { markup.append(postChildMarkup); } ResponseWriter responseWriter = facesContext.getResponseWriter(); logger.debug("Markup before transformation:{0}", markup); StringBuilder processedMarkup = getMarkup(uiComponent, markup); logger.debug("Markup after transformation:{0}", processedMarkup); responseWriter.write(processedMarkup.toString()); } catch (Exception e) { throw new IOException(e); } } @Override public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException { uiComponent.getAttributes().remove(CORRESPONDING_JSP_TAG); } @Override public boolean getRendersChildren() { return true; } protected StringBuilder getMarkup(UIComponent uiComponent, StringBuilder markup) throws Exception { return markup; } }
/** @author Neil Griffin */ public class BridgeRequestScopeLiferayImpl extends BridgeRequestScopeImpl { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeRequestScopeLiferayImpl.class); // serialVersionUID private static final long serialVersionUID = 1814762389345663517L; // Private Constants private static final String[] LIFERAY_ATTRIBUTE_NAMES; private static final String[] PORTLET_REQUEST_ATTRIBUTE_NAMES = new String[] { PortletRequest.CCPP_PROFILE, PortletRequest.LIFECYCLE_PHASE, PortletRequest.RENDER_HEADERS, PortletRequest.RENDER_MARKUP, PortletRequest.RENDER_PART, PortletRequest.USER_INFO }; static { // Set the value of the LIFERAY_ATTRIBUTE_NAMES constant. Need to use reflection in order to // determine all of // the public constants because different versions of the portal source have different sets of // constants. This // approach minimizes diffs in the different source branches for the bridge. List<String> fieldList = new ArrayList<String>(); Field[] fields = JavaConstants.class.getFields(); for (Field field : fields) { String fieldName = field.getName(); if ((fieldName != null) && fieldName.startsWith("JAVAX")) { try { Object value = field.get(null); if ((value != null) && (value instanceof String)) { fieldList.add((String) value); } } catch (Exception e) { logger.error(e); } } } LIFERAY_ATTRIBUTE_NAMES = fieldList.toArray(new String[fieldList.size()]); } public BridgeRequestScopeLiferayImpl( PortletRequest portletRequest, PortletConfig portletConfig, BridgeConfig bridgeConfig) { super(portletRequest, portletConfig, bridgeConfig); } /** * This is a method-override that provides specific behavior for Liferay Portal. Specifically, * since Liferay Portal does not implement the POST-REDIRECT-GET design pattern, not all instance * types listed in Section 5.1.2 of the Spec can be candidates for exclusion. */ @Override protected boolean isExcludedRequestAttributeByInstance( String attributeName, Object attributeValue) { boolean excluded = false; if (attributeValue != null) { if ((attributeValue instanceof ExternalContext) || (attributeValue instanceof FacesContext)) { // Always safe to exclude when running under Liferay Portal. excluded = true; } else if (attributeValue instanceof PortletConfig) { // Liferay Portal includes request attribute named "javax.portlet.config" that must not be // excluded. It // also includes an attribute named "javax.portlet.portlet" that is the current // GenericFacesPortlet // (which extends GenericPortlet). But since GenericPortlet implements the PortletConfig // interface, need // to prevent it from being excluded as well. if (!JavaConstants.JAVAX_PORTLET_CONFIG.equals(attributeName) && !JavaConstants.JAVAX_PORTLET_PORTLET.equals(attributeName)) { excluded = true; } } else if (attributeValue instanceof PortletRequest) { // Liferay Portal includes request attribute named "javax.portlet.request" that must not be // excluded. if (!JavaConstants.JAVAX_PORTLET_REQUEST.equals(attributeName)) { excluded = true; } } else if (attributeValue instanceof PortletResponse) { // Liferay Portal includes request attribute named "javax.portlet.response" that must not be // excluded. if (!JavaConstants.JAVAX_PORTLET_RESPONSE.equals(attributeName)) { excluded = true; } } else if ((attributeValue instanceof PortalContext) || (attributeValue instanceof PortletContext) || (attributeValue instanceof PortletPreferences) || (attributeValue instanceof PortletSession)) { excluded = true; } else if ((attributeValue instanceof HttpSession) || (attributeValue instanceof ServletConfig) || (attributeValue instanceof ServletContext) || (attributeValue instanceof ServletRequest) || (attributeValue instanceof ServletResponse)) { // Can only exclude attributes that are not Liferay objects. For example, Liferay Portal // includes // a request attribute named "com.liferay.portal.kernel.servlet.PortletServletRequest" that // must not be // excluded. if (!attributeValue.getClass().getName().startsWith("com.liferay")) { excluded = true; } } } return excluded; } /** * This is a method-override that provides specific behavior for Liferay Portal. Specifically, * since Liferay Portal does not implement the POST-REDIRECT-GET design pattern, not all instance * types listed in Section 5.1.2 of the Spec can be candidates for exclusion. */ @Override protected boolean isExcludedRequestAttributeByNamespace(String attributeName) { boolean excluded = false; if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_FACES) || isNamespaceMatch(attributeName, EXCLUCED_NAMESPACE_JAVAX_SERVLET) || isNamespaceMatch(attributeName, EXCLUCED_NAMESPACE_JAVAX_SERVLET_INCLUDE)) { // Always safe to exclude when running under Liferay Portal. excluded = true; } else if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_PORTLET_FACES)) { if (!Bridge.PORTLET_LIFECYCLE_PHASE.equals(attributeName)) { // The "javax.portlet.faces.phase" request attribute must never be excluded, as it is // required by {@link // BridgeUtil#getPortletRequestPhase()}. excluded = true; } } else if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_PORTLET)) { excluded = true; } if (excluded) { for (String liferayAttributeName : LIFERAY_ATTRIBUTE_NAMES) { if (liferayAttributeName.equals(attributeName)) { excluded = false; break; } } } if (excluded) { for (String portletRequestAttributeName : PORTLET_REQUEST_ATTRIBUTE_NAMES) { if (portletRequestAttributeName.equals(attributeName)) { excluded = false; break; } } } return excluded; } }
// J- @FacesRenderer( componentFamily = InputRichText.COMPONENT_FAMILY, rendererType = InputRichText.RENDERER_TYPE) // J+ public class InputRichTextRenderer extends PortalTagRenderer<InputRichText, InputEditorTag> implements SystemEventListener { // Logger private static final Logger logger = LoggerFactory.getLogger(InputRichTextRenderer.class); // Templates private static WYSIWYGTemplate wysiwygTemplate; @Override public InputRichText cast(UIComponent uiComponent) { return (InputRichText) uiComponent; } @Override public void copyFrameworkAttributes( FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) { inputEditorTag.setCssClass(inputRichText.getStyleClass()); // When ckeditor.jsp renders a hidden textarea, the name is rendered as the id and name // attributes of the // textarea element. Since this renderer creates its own textarea, it is necessary to set a name // that will // not interfere when decoding. String editorType = getEditorType(inputRichText); String escapedEditorName = inputRichText.getClientId(); char separatorChar = UINamingContainer.getSeparatorChar(facesContext); escapedEditorName = escapedEditorName.replace(separatorChar, '_').concat("_jsptag"); if ("bbcode".equals(editorType)) { inputEditorTag.setName(escapedEditorName + "_bbcodeInput"); } else { inputEditorTag.setName(escapedEditorName + "_nonInput"); } } @Override public void copyNonFrameworkAttributes( FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) { inputEditorTag.setConfigParams(inputRichText.getConfigParams()); inputEditorTag.setContentsLanguageId(inputRichText.getContentsLanguageId()); inputEditorTag.setEditorImpl(inputRichText.getEditorKey()); inputEditorTag.setFileBrowserParams(inputRichText.getFileBrowserParams()); char separatorChar = UINamingContainer.getSeparatorChar(facesContext); String clientId = inputRichText.getClientId(); String functionNamespace = clientId.replace(separatorChar, '_'); inputEditorTag.setInitMethod(functionNamespace + "init"); inputEditorTag.setOnBlurMethod(functionNamespace + "blur"); inputEditorTag.setOnChangeMethod(functionNamespace + "change"); inputEditorTag.setOnFocusMethod(functionNamespace + "focus"); inputEditorTag.setResizable(inputRichText.isResizable()); inputEditorTag.setSkipEditorLoading(inputRichText.isSkipEditorLoading()); inputEditorTag.setToolbarSet(inputRichText.getToolbarSet()); } @Override public void decode(FacesContext facesContext, UIComponent uiComponent) { ExternalContext externalContext = facesContext.getExternalContext(); Map<String, String> requestParameterMap = externalContext.getRequestParameterMap(); String clientId = uiComponent.getClientId(); char separatorChar = UINamingContainer.getSeparatorChar(facesContext); String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag"); String submittedValue = requestParameterMap.get(escapedEditorName + "_bbcodeInput"); if (submittedValue == null) { submittedValue = requestParameterMap.get(escapedEditorName); } InputRichText inputRichText = (InputRichText) uiComponent; inputRichText.setSubmittedValue(submittedValue); } @Override public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException { // Encode the starting <div> element that represents the rich text editor. ResponseWriter responseWriter = facesContext.getResponseWriter(); responseWriter.startElement(StringPool.DIV, uiComponent); String clientId = uiComponent.getClientId(); char separatorChar = UINamingContainer.getSeparatorChar(facesContext); String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag"); responseWriter.writeAttribute(StringPool.ID, clientId, null); RendererUtil.encodeStyleable(responseWriter, (Styleable) uiComponent); // Encode the starting <textarea> element. InputRichText inputRichText = (InputRichText) uiComponent; responseWriter.startElement("textarea", uiComponent); responseWriter.writeAttribute(StringPool.ID, clientId + "_input", null); responseWriter.writeAttribute(StringPool.NAME, escapedEditorName, null); responseWriter.writeAttribute(Styleable.STYLE, "display:none;", null); // Encode the onblur/onchange/onfocus attributes and any associated client behavior scripts. String onblur = inputRichText.getOnblur(); String onchange = inputRichText.getOnchange(); String onfocus = inputRichText.getOnfocus(); Map<String, List<ClientBehavior>> clientBehaviorMap = inputRichText.getClientBehaviors(); for (String eventName : inputRichText.getEventNames()) { List<ClientBehavior> clientBehaviorsForEvent = clientBehaviorMap.get(eventName); if (clientBehaviorsForEvent != null) { for (ClientBehavior clientBehavior : clientBehaviorsForEvent) { ClientBehaviorContext clientBehaviorContext = ClientBehaviorContext.createClientBehaviorContext( facesContext, inputRichText, eventName, clientId, null); String clientBehaviorScript = clientBehavior.getScript(clientBehaviorContext); if (clientBehaviorScript != null) { if ("valueChange".equals(eventName) || "change".equals(eventName)) { if (onchange != null) { clientBehaviorScript = onchange.concat(";").concat(clientBehaviorScript); onchange = null; } responseWriter.writeAttribute("onchange", clientBehaviorScript, null); } else if ("blur".equals(eventName)) { if (onblur != null) { clientBehaviorScript = onblur.concat(";").concat(clientBehaviorScript); onblur = null; } responseWriter.writeAttribute("onblur", clientBehaviorScript, null); } else if ("focus".equals(eventName)) { if (onfocus != null) { clientBehaviorScript = onfocus.concat(";").concat(clientBehaviorScript); onfocus = null; } responseWriter.writeAttribute("onfocus", clientBehaviorScript, null); } } } } } if (onblur != null) { responseWriter.writeAttribute("onblur", onblur, null); } if (onchange != null) { responseWriter.writeAttribute("onchange", onchange, null); } if (onfocus != null) { responseWriter.writeAttribute("onfocus", onfocus, null); } // Encode the value of the component as a child of the textarea element. Object value = inputRichText.getValue(); if (value != null) { responseWriter.writeText(value, null); } // Encode the closing </textarea> element. responseWriter.endElement("textarea"); // Encode the script that contains functions with names specific to this component, so that they // can be // invoked directly by the JavaScript generated by the JSP tag. String formattedTemplate = wysiwygTemplate.format(facesContext, inputRichText); responseWriter.startElement(StringPool.SCRIPT, uiComponent); responseWriter.writeAttribute(StringPool.TYPE, ContentTypes.TEXT_JAVASCRIPT, null); responseWriter.write(formattedTemplate); responseWriter.endElement(StringPool.SCRIPT); // Begin the JSP tag lifecycle and write the output to the response. super.encodeBegin(facesContext, uiComponent); } @Override public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException { // End writing the output of the JSP tag lifecycle. super.encodeEnd(facesContext, uiComponent); // Encode the ending <div> element that represents the rich text editor. ResponseWriter responseWriter = facesContext.getResponseWriter(); responseWriter.endElement(StringPool.DIV); } @Override public InputEditorTag newTag() { return new InputEditorTag(); } @Override public void processEvent(SystemEvent postConstructApplicationEvent) throws AbortProcessingException { // Due to ClassLoader problems during static initialization, it is necessary to delay creation // of singleton // instances of template classes until the PostConstructApplicationEvent is sent. try { FacesContext startupFacesContext = FacesContext.getCurrentInstance(); boolean minified = startupFacesContext.isProjectStage(ProjectStage.Production); wysiwygTemplate = new WYSIWYGTemplate(minified); } catch (Exception e) { logger.error(e); } } @Override public boolean isListenerForSource(Object source) { return ((source != null) && (source instanceof Application)); } protected String getEditorType(InputRichText inputRichText) { String editorType = PropsUtil.get(PropsKeys.EDITOR_WYSIWYG_DEFAULT); String editorKey = inputRichText.getEditorKey(); if (editorKey != null) { editorType = PropsUtil.get(editorKey); } return editorType; } }
/** * Mojarra has a vendor-specific Service Provider Interface (SPI) for dependency injection called * the InjectionProvider. This class provides the ability to leverage the InjectionProvider instance * for invoking methods annotated with {@link javax.annotation.PreDestroy}. * * @author Neil Griffin */ public class PreDestroyInvokerMojarraImpl extends PreDestroyInvokerImpl { // Logger private static final Logger logger = LoggerFactory.getLogger(PreDestroyInvokerMojarraImpl.class); // Private Constants private static final String INVOKE_PRE_DESTROY = "invokePreDestroy"; // Private Data Members private Method invokePreDestroyMethod; private Object mojarraInjectionProvider; public PreDestroyInvokerMojarraImpl(Map<String, Object> applicationMap) { this.mojarraInjectionProvider = getInjectionProvider(applicationMap); try { this.invokePreDestroyMethod = mojarraInjectionProvider .getClass() .getMethod(INVOKE_PRE_DESTROY, new Class[] {Object.class}); } catch (Exception e) { logger.error(e); } } @Override public void invokeAnnotatedMethods(Object managedBean, boolean preferPreDestroy) { if (preferPreDestroy) { if (invokePreDestroyMethod != null) { try { logger.debug( "Invoking methods annotated with @PreDestroy: mojarraInjectionProvider=[{0}] managedBean=[{1}]", mojarraInjectionProvider, managedBean); invokePreDestroyMethod.invoke(mojarraInjectionProvider, managedBean); } catch (Exception e) { logger.error(e); } } else { super.invokeAnnotatedMethods(managedBean, preferPreDestroy); } } else { super.invokeAnnotatedMethods(managedBean, preferPreDestroy); } } @Override public String toString() { return mojarraInjectionProvider.toString(); } protected Object getInjectionProvider(Map<String, Object> applicationMap) { try { Object applicationAssociate = applicationMap.get("com.sun.faces.ApplicationAssociate"); // If the ApplicationAssociate instance is available, then return the InjectionProvider that // it knows about. if (applicationAssociate != null) { // Note that the ApplicationAssociate instance will be available during startup if the // Mojarra // ConfigureListener executes prior to the BridgeSessionListener. It will also be available // during // execution of the JSF lifecycle. Method getInjectionProviderMethod = applicationAssociate.getClass().getMethod("getInjectionProvider", new Class[] {}); Object mojarraInjectionProvider = getInjectionProviderMethod.invoke(applicationAssociate, new Object[] {}); logger.debug("mojarraInjectionProvider=[{0}]", mojarraInjectionProvider); return mojarraInjectionProvider; } // Otherwise, return null. else { // Note that the ApplicationAssociate instance will be null if this method is called during // startup and // the BridgeSessionListener executes prior to the Mojarra ConfigureListener. This can be // remedied by // explicitly specifying com.sun.faces.config.ConfigureListener as a listener in the // WEB-INF/web.xml // descriptor. return null; } } catch (Exception e) { logger.error(e); return null; } } }
/** @author Neil Griffin */ public class BridgeRequestScopeManagerImpl implements BridgeRequestScopeManager { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeRequestScopeManagerImpl.class); public void removeBridgeRequestScopesByPortlet(PortletConfig portletConfig) { String portletNameToRemove = portletConfig.getPortletName(); PortletContext portletContext = portletConfig.getPortletContext(); BridgeRequestScopeCache bridgeRequestScopeCache = BridgeRequestScopeCacheFactory.getBridgeRequestScopeCacheInstance(portletContext); Set<Map.Entry<String, BridgeRequestScope>> mapEntries = bridgeRequestScopeCache.entrySet(); if (mapEntries != null) { List<String> keysToRemove = new ArrayList<String>(); for (Map.Entry<String, BridgeRequestScope> mapEntry : mapEntries) { BridgeRequestScope bridgeRequestScope = mapEntry.getValue(); String bridgeRequestScopeId = bridgeRequestScope.getId(); String portletName = bridgeRequestScopeId.split("[:][:][:]")[0]; if (portletNameToRemove.equals(portletName)) { keysToRemove.add(mapEntry.getKey()); } } for (String key : keysToRemove) { bridgeRequestScopeCache.remove(key); } } } /** * This method is designed to be invoked from a {@link javax.servlet.http.HttpSessionListener} * like {@link BridgeSessionListener} when a session timeout/expiration occurs. The logic in this * method is a little awkward because we have to try and remove BridgeRequestScope instances from * {@link Map} instances in the {@link ServletContext} rather than the {@link PortletContext} * because we only have access to the Servlet-API when sessions expire. */ public void removeBridgeRequestScopesBySession(HttpSession httpSession) { // For each ServletContext attribute name: String httpSessionId = httpSession.getId(); ServletContext servletContext = httpSession.getServletContext(); Enumeration<String> attributeNames = servletContext.getAttributeNames(); if (attributeNames != null) { while (attributeNames.hasMoreElements()) { String attributeName = attributeNames.nextElement(); // Get the value associated with the current attribute name. Object attributeValue = servletContext.getAttribute(attributeName); // If the value is a type of java.util.Map then it is possible that it contains // BridgeRequestScope // instances. if ((attributeValue != null) && (attributeValue instanceof Map)) { // Prepare to iterate over the map entries. Map<?, ?> map = (Map<?, ?>) attributeValue; Set<?> entrySet = null; try { entrySet = map.entrySet(); } catch (Exception e) { // ignore -- some maps like Mojarra's Flash scope will throw a NullPointerException } if (entrySet != null) { // Iterate over the map entries, and build up a list of BridgeRequestScope keys that are // to be // removed. Doing it this way prevents ConcurrentModificationExceptions from being // thrown. List<Object> keysToRemove = new ArrayList<Object>(); for (Object mapEntryAsObject : entrySet) { Map.Entry<?, ?> mapEntry = (Map.Entry<?, ?>) mapEntryAsObject; Object key = mapEntry.getKey(); Object value = mapEntry.getValue(); if ((value != null) && (value instanceof BridgeRequestScope)) { BridgeRequestScope bridgeRequestScope = (BridgeRequestScope) value; String bridgeRequestScopeSessionId = bridgeRequestScope.getId().split("[:][:][:]")[1]; if (httpSessionId.equals(bridgeRequestScopeSessionId)) { keysToRemove.add(key); } } } // For each BridgeRequestScope key that is to be removed: for (Object bridgeRequestScopeId : keysToRemove) { // Remove it from the map. Object bridgeRequestScope = map.remove(bridgeRequestScopeId); logger.debug( "Removed bridgeRequestScopeId=[{0}] bridgeRequestScope=[{1}] from cache due to session timeout", bridgeRequestScopeId, bridgeRequestScope); } } } } } } }
/** @author Neil Griffin */ public class ExtELResolver extends ELResolverBase { public static final String VAR_NAME_I18N = "i18n"; private static final Logger logger = LoggerFactory.getLogger(ExtELResolver.class); static { // Initialize the list of static feature descriptors. addFeatureDescriptor(VAR_NAME_I18N, String.class); } private I18N i18n; @Override protected Object resolveProperty(ELContext elContext, Object base, String property) { return null; } @Override protected Object resolveVariable(ELContext elContext, String varName) { Object value = null; try { if (varName.equals(VAR_NAME_I18N)) { if (i18n == null) { i18n = new I18N(); } value = i18n; } } catch (Exception e) { throw new ELException("Failed to resolve variable [" + varName + "]", e); } if (value == null) { if (logger.isDebugEnabled()) { logger.debug("Unable to resolve variable [" + varName + "] value=" + value); } } else { if (logger.isDebugEnabled()) { logger.debug("Resolved variable [" + varName + "] value=" + value); } } return value; } @Override public Class<?> getCommonPropertyType(ELContext elContext, Object base) { Class<?> commonPropertyType = null; return commonPropertyType; } @Override public void setValue(ELContext elContext, Object base, Object property, Object value) { if (elContext == null) { // Throw an exception as directed by the JavaDoc for ELContext. throw new NullPointerException("elContext may not be null"); } if ((property != null) && (property instanceof String)) { String propertyAsString = (String) property; if (propertyAsString.equals(VAR_NAME_I18N)) { throw new PropertyNotWritableException(propertyAsString); } } } @Override public boolean isReadOnly(ELContext elContext, Object base, Object property) { return true; } }
/** @author Neil Griffin */ @RequestScoped @ManagedBean public class BridgeInputFileBackingBean { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeInputFileBackingBean.class); @ManagedProperty(value = "#{bridgeInputFileModelBean}") private BridgeInputFileModelBean bridgeInputFileModelBean; public void deleteUploadedFile(ActionEvent actionEvent) { UICommand uiCommand = (UICommand) actionEvent.getComponent(); String fileId = (String) uiCommand.getValue(); try { List<UploadedFile> uploadedFiles = bridgeInputFileModelBean.getUploadedFiles(); UploadedFile uploadedFileToDelete = null; for (UploadedFile uploadedFile : uploadedFiles) { if (uploadedFile.getId().equals(fileId)) { uploadedFileToDelete = uploadedFile; break; } } if (uploadedFileToDelete != null) { uploadedFileToDelete.delete(); uploadedFiles.remove(uploadedFileToDelete); logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName()); } } catch (Exception e) { logger.error(e); } } public void handleFileUpload(FileUploadEvent fileUploadEvent) { List<UploadedFile> uploadedFiles = bridgeInputFileModelBean.getUploadedFiles(); UploadedFile uploadedFile = fileUploadEvent.getUploadedFile(); if (uploadedFile.getStatus() == UploadedFile.Status.FILE_SAVED) { FacesContext facesContext = FacesContext.getCurrentInstance(); FacesMessage facesMessage = new FacesMessage( "Received fileUploadEvent for file named '" + uploadedFile.getName() + "' in the " + fileUploadEvent.getPhaseId().toString() + " phase."); facesContext.addMessage(null, facesMessage); uploadedFiles.add(uploadedFile); logger.debug( "Received fileName=[{0}] absolutePath=[{1}]", uploadedFile.getName(), uploadedFile.getAbsolutePath()); } else { logger.error( "Failed to receive uploaded file due to error status=[{0}] message=[{1}]", uploadedFile.getStatus(), uploadedFile.getMessage()); } } public void setBridgeInputFileModelBean(BridgeInputFileModelBean bridgeInputFileModelBean) { // Injected via @ManagedProperty annotation this.bridgeInputFileModelBean = bridgeInputFileModelBean; } }
/** * This class is a portlet-specific implementation of the Faces Application. Its purpose is to * override the {@link createComponent(String)} and {@link getResourceHandler()} methods so that * additional portlet-specific instances can be introduced into the Faces lifecycle. Note that * instances of this class are generated by the custom {@link ApplicationFactoryImpl}. * * @author Neil Griffin */ public class ApplicationImpl extends ApplicationWrapper { // Logger private static final Logger logger = LoggerFactory.getLogger(ApplicationImpl.class); // Private Data Members private Application wrappedApplication; private boolean wrapHandlerAtRuntime = true; public ApplicationImpl(Application application) { this.wrappedApplication = application; } /** * This method provides the ability to supply an instance of the bridge API's {@link * PortletNamingContainerUIViewRoot} class which properly handles namespacing of "id" attributes * for portlets. * * @see Application#createComponent(String) */ @Override public UIComponent createComponent(String componentType) throws FacesException { if (componentType.equals(UIViewRoot.COMPONENT_TYPE) && BridgeUtil.isPortletRequest()) { return new UIViewRootBridgeImpl(); } else { return wrappedApplication.createComponent(componentType); } } @Override public UIComponent createComponent( FacesContext facesContext, String componentType, String rendererType) { UIComponent wrappedUIComponent = wrappedApplication.createComponent(facesContext, componentType, rendererType); if (componentType.equals(DataPaginator.COMPONENT_TYPE)) { // Workaround for: http://jira.icesoft.org/browse/ICE-6398 DataPaginator dataPaginator = new DataPaginatorBridgeImpl(wrappedUIComponent); try { dataPaginator.setUIData(dataPaginator.findUIData(facesContext)); wrappedUIComponent = dataPaginator; } catch (Exception e) { logger.error(e); } } return wrappedUIComponent; } /** * The normal way of adding a {@link NavigationHandler} to a JSF application is to have a * navigation-handler element in the faces-config.xml descriptor. Unfortunately the bridge can't * use this mechanism, because it must ensure that the {@link BridgeNavigationHandler} is the * outermost instance in the chain-of-responsibility. While this could be done with * <ordering><after><others/></after></others> in the bridge's * META-INF/faces-config.xml file, the bridge must use * <ordering><before><others/></before></others> in order to * maintain compatibility with ICEfaces and other component libraries. So because of this, it is * necessary to provide this override of the {@link #getNavigationHandler()} method in order to * ensure that the {@link BridgeNavigationHandler} is the outermost instance. */ @Override public NavigationHandler getNavigationHandler() { // NOTE: Mojarra uses a servlet context listener to pre-load all the faces-config.xml files in // the classpath. // During this initialization, it will call this method override for whatever reason. But we // can't ask the // BridgeFactoryFinder to find the BridgeNavigationHandler factory at that time because it // relies on the // PortletContext object which can only be retrieved at runtime. So for this reason, we have to // delay the // wrapping the Faces default NavigationHandler until a PortletRequest happens at runtime. if (wrapHandlerAtRuntime) { FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext != null) { try { PortletRequest portletRequest = (PortletRequest) facesContext.getExternalContext().getRequest(); if (portletRequest != null) { BridgeNavigationHandler bridgeNavigationHandler = new BridgeNavigationHandlerImpl(super.getNavigationHandler()); super.setNavigationHandler(bridgeNavigationHandler); wrapHandlerAtRuntime = false; } } catch (UnsupportedOperationException e) { // ignore -- MyFaces does not permit calling getRequest() during startup. } } } return super.getNavigationHandler(); } @Override public ResourceHandler getResourceHandler() { ResourceHandler resourceHandler = super.getResourceHandler(); if (resourceHandler != null) { resourceHandler = new ResourceHandlerOuterImpl(resourceHandler); } return resourceHandler; } /** @see ApplicationWrapper#getWrapped() */ @Override public Application getWrapped() { return wrappedApplication; } }
/** @author Neil Griffin */ public class BridgePhaseRenderImpl extends BridgePhaseCompat_2_2_Impl { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgePhaseRenderImpl.class); // Private Data Members private RenderRequest renderRequest; private RenderResponse renderResponse; public BridgePhaseRenderImpl( RenderRequest renderRequest, RenderResponse renderResponse, PortletConfig portletConfig, BridgeConfig bridgeConfig) { super(portletConfig, bridgeConfig); this.renderRequest = BridgePortletRequestFactory.getRenderRequestInstance( renderRequest, renderResponse, portletConfig, bridgeConfig); this.renderResponse = BridgePortletResponseFactory.getRenderResponseInstance( renderRequest, renderResponse, portletConfig, bridgeConfig); } @Override public void execute() throws BridgeException { logger.debug(Logger.SEPARATOR); logger.debug( "execute(RenderRequest, RenderResponse) portletName=[{0}] portletMode=[{1}]", portletName, renderRequest.getPortletMode()); Object renderPartAttribute = renderRequest.getAttribute(RenderRequest.RENDER_PART); if ((renderPartAttribute != null) && renderPartAttribute.equals(RenderRequest.RENDER_HEADERS)) { doFacesHeaders(renderRequest, renderResponse); } else { try { execute(null); } catch (BridgeException e) { throw e; } catch (Throwable t) { throw new BridgeException(t); } finally { cleanup(renderRequest); } logger.debug(Logger.SEPARATOR); } } @Override protected void cleanup(PortletRequest portletRequest) { // If required, cause the BridgeRequestScope to go out-of-scope. if (!bridgeRequestScopePreserved) { bridgeRequestScopeCache.remove(bridgeRequestScope.getId()); } super.cleanup(portletRequest); } protected void doFacesHeaders(RenderRequest renderRequest, RenderResponse renderResponse) { logger.trace( "doFacesHeaders(RenderRequest, RenderResponse) this=[{0}], renderRequest=[{1}], renderResponse=[{2}]", this, renderRequest, renderResponse); } protected void execute(String renderRedirectViewId) throws BridgeException, IOException { init(renderRequest, renderResponse, Bridge.PortletPhase.RENDER_PHASE); // If the portlet mode has not changed, then restore the faces view root and messages that would // have been saved during the ACTION_PHASE of the portlet lifecycle. Section 5.4.1 requires that // the // BridgeRequestScope must not be restored if there is a change in portlet modes detected. boolean facesLifecycleExecuted = bridgeRequestScope.isFacesLifecycleExecuted(); bridgeRequestScope.restoreState(facesContext); if (bridgeRequestScope.isPortletModeChanged()) { bridgeRequestScopeCache.remove(bridgeRequestScope.getId()); } // If a render-redirect URL was specified, then it is necessary to create a new view from the // URL and place it // in the FacesContext. if (renderRedirectViewId != null) { renderRequest.setAttribute(BridgeExt.RENDER_REDIRECT_AFTER_DISPATCH, Boolean.TRUE); ViewHandler viewHandler = facesContext.getApplication().getViewHandler(); UIViewRoot uiViewRoot = viewHandler.createView(facesContext, renderRedirectViewId); facesContext.setViewRoot(uiViewRoot); logger.debug("Performed render-redirect to viewId=[{0}]", renderRedirectViewId); } // NOTE: PROPOSE-FOR-BRIDGE3-API Actually, the proposal would be to REMOVE // Bridge.IS_POSTBACK_ATTRIBUTE from the Bridge API, because JSF 2.0 introduced the // FacesContext#isPostBack() method. // http://javaserverfaces.java.net/nonav/docs/2.0/javadocs/javax/faces/context/FacesContext.html#isPostback() if (bridgeRequestScope.getBeganInPhase() == Bridge.PortletPhase.ACTION_PHASE) { ExternalContext externalContext = facesContext.getExternalContext(); externalContext.getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE); } logger.debug( "portletName=[{0}] facesLifecycleExecuted=[{1}]", portletName, facesLifecycleExecuted); // If the JSF lifecycle executed back in the ACTION_PHASE of the portlet lifecycle, then if (facesLifecycleExecuted) { // TCK TestPage054: prpUpdatedFromActionTest PhaseEvent restoreViewPhaseEvent = new PhaseEvent(facesContext, PhaseId.RESTORE_VIEW, facesLifecycle); PhaseListener[] phaseListeners = facesLifecycle.getPhaseListeners(); for (PhaseListener phaseListener : phaseListeners) { if (phaseListener instanceof IPCPhaseListener) { phaseListener.afterPhase(restoreViewPhaseEvent); break; } } } // Otherwise, in accordance with Section 5.2.6 of the Spec, execute the JSF lifecycle so that // ONLY the // RESTORE_VIEW phase executes. Note that this is accomplished by the // RenderRequestPhaseListener. else { try { ExternalContext externalContext = facesContext.getExternalContext(); String viewId = getFacesViewId(externalContext); logger.debug("Executing Faces lifecycle for viewId=[{0}]", viewId); } catch (BridgeException e) { logger.error("Unable to get viewId due to {0}", e.getClass().getSimpleName()); throw e; } // Attach the JSF 2.2 client window to the JSF lifecycle so that Faces Flows can be utilized. attachClientWindowToLifecycle(facesContext, facesLifecycle); // Execute the JSF lifecycle. facesLifecycle.execute(facesContext); } // If there were any "handled" exceptions queued, then throw a BridgeException. Throwable handledException = getJSF2HandledException(facesContext); if (handledException != null) { throw new BridgeException(handledException); } // Otherwise, if there were any "unhandled" exceptions queued, then throw a BridgeException. Throwable unhandledException = getJSF2UnhandledException(facesContext); if (unhandledException != null) { throw new BridgeException(unhandledException); } // Otherwise, if the PortletMode has changed, and a navigation-rule hasn't yet fired (which // could have happened // in the EVENT_PHASE), then switch to the appropriate PortletMode and navigate to the current // viewId in the // UIViewRoot. if (bridgeRequestScope.isPortletModeChanged() && !bridgeRequestScope.isNavigationOccurred()) { BridgeNavigationHandler bridgeNavigationHandler = getBridgeNavigationHandler(facesContext); PortletMode fromPortletMode = bridgeRequestScope.getPortletMode(); PortletMode toPortletMode = renderRequest.getPortletMode(); bridgeNavigationHandler.handleNavigation(facesContext, fromPortletMode, toPortletMode); } // Determines whether or not lifecycle incongruities should be managed. boolean manageIncongruities = PortletConfigParam.ManageIncongruities.getBooleanValue(portletConfig); // Now that we're executing the RENDER_PHASE of the Portlet lifecycle, before the JSF // RENDER_RESPONSE phase is executed, we have to fix some incongruities between the Portlet // lifecycle and the JSF lifecycle that may have occurred during the ACTION_PHASE of the Portlet // lifecycle. if (manageIncongruities) { incongruityContext.makeCongruous(facesContext); } // Execute the RENDER_RESPONSE phase of the faces lifecycle. logger.debug("Executing Faces render"); facesLifecycle.render(facesContext); // Set the view history according to Section 5.4.3 of the Bridge Spec. setViewHistory(facesContext.getViewRoot().getViewId()); // Spec 6.6 (Namespacing) indicateNamespacingToConsumers(facesContext.getViewRoot(), renderResponse); // If a render-redirect occurred, then ExternalContext externalContext = facesContext.getExternalContext(); Writer writer = getResponseOutputWriter(externalContext); Map<String, Object> requestMap = externalContext.getRequestMap(); Boolean renderRedirect = (Boolean) requestMap.remove(BridgeExt.RENDER_REDIRECT); if ((renderRedirect != null) && renderRedirect) { // Cleanup the old FacesContext since a new one will be created in the recursive method call // below. facesContext.responseComplete(); facesContext.release(); // If the render-redirect standard feature is enabled in web.xml or portlet.xml, then the // ResponseOutputWriter has buffered up markup that must be discarded. This is because we // don't want the // markup from the original Faces view to be included with the markup of Faces view found in // the // redirect URL. if (writer instanceof RenderRedirectWriter) { RenderRedirectWriter responseOutputWriter = (RenderRedirectWriter) writer; responseOutputWriter.discard(); } // Recursively call this method with the render-redirect URL so that the RENDER_RESPONSE phase // of the // JSF lifecycle will be re-executed according to the new Faces viewId found in the redirect // URL. renderRedirectViewId = (String) requestMap.remove(BridgeExt.RENDER_REDIRECT_VIEW_ID); execute(renderRedirectViewId); } // Otherwise, else { // In the case that a render-redirect took place, need to render the buffered markup to the // response. if (writer instanceof RenderRedirectWriter) { RenderRedirectWriter responseOutputWriter = (RenderRedirectWriter) writer; responseOutputWriter.render(); } } } protected BridgeNavigationHandler getBridgeNavigationHandler(FacesContext facesContext) { BridgeNavigationHandler bridgeNavigationHandler; NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler(); if (navigationHandler instanceof BridgeNavigationHandler) { bridgeNavigationHandler = (BridgeNavigationHandler) navigationHandler; } else { bridgeNavigationHandler = new BridgeNavigationHandlerImpl(navigationHandler); } return bridgeNavigationHandler; } @Override protected void initBridgeRequestScope( PortletRequest portletRequest, PortletResponse portletResponse, PortletPhase portletPhase) { super.initBridgeRequestScope(portletRequest, portletResponse, portletPhase); // If the portlet container does not support the POST-REDIRECT-GET design pattern, then the // ACTION_PHASE and // RENDER_PHASE are both part of a single HTTP POST request. In such cases, the excluded request // attributes must // be pro-actively removed here in the RENDER_PHASE (providing that the bridge request scope was // created in the // ACTION_PHASE). Note that this must take place prior to the FacesContext getting constructed. // This is because // the FacesContextFactory delegation chain might consult a request attribute that is supposed // to be excluded. // This is indeed the case with Apache Trinidad {@link // org.apache.myfaces.trinidadinternal.context.FacesContextFactoryImpl.CacheRenderKit} // constructor, which // consults a request attribute named "org.apache.myfaces.trinidad.util.RequestStateMap" that // must first be // excluded. PortalContext portalContext = portletRequest.getPortalContext(); String postRedirectGetSupport = portalContext.getProperty(BridgePortalContext.POST_REDIRECT_GET_SUPPORT); if ((postRedirectGetSupport == null) && (bridgeRequestScope.getBeganInPhase() == Bridge.PortletPhase.ACTION_PHASE)) { bridgeRequestScope.removeExcludedAttributes(renderRequest); } } /** * Sets the "javax.portlet.faces.viewIdHistory.<code>portletMode</code>" session attribute * according to the requirements in Section 5.4.3 of the Bridge Spec. There is no corresponding * getter method, because the value is meant to be retrieved by developers via an EL expression. * * @param viewId The current Faces viewId. */ protected void setViewHistory(String viewId) { String attributeName = Bridge.VIEWID_HISTORY.concat(".").concat(renderRequest.getPortletMode().toString()); PortletSession portletSession = renderRequest.getPortletSession(); portletSession.setAttribute(attributeName, viewId); } }
// J- @FacesRenderer( componentFamily = OutputTooltip.COMPONENT_FAMILY, rendererType = OutputTooltip.RENDERER_TYPE) @ResourceDependencies({ @ResourceDependency( library = "liferay-faces-alloy", name = "build/aui-css/css/bootstrap.min.css"), @ResourceDependency(library = "liferay-faces-alloy", name = "build/aui/aui-min.js"), @ResourceDependency(library = "liferay-faces-alloy", name = "liferay.js") }) // J+ public class OutputTooltipRenderer extends OutputTooltipRendererBase { // Logger private static final Logger logger = LoggerFactory.getLogger(OutputTooltipRenderer.class); @Override public void encodeChildren(FacesContext facesContext, UIComponent uiComponent) throws IOException { List<UIComponent> children = uiComponent.getChildren(); if (children != null) { for (UIComponent child : children) { child.encodeAll(facesContext); } } } @Override public void encodeJavaScriptCustom(FacesContext facesContext, UIComponent uiComponent) throws IOException { ResponseWriter responseWriter = facesContext.getResponseWriter(); OutputTooltip tooltip = (OutputTooltip) uiComponent; // alloy's divs should be in place and hidden by now. // so we need to unhide the div we have hidden until now. // any chance for blinking should be over by now. responseWriter.write( "A.one('" + StringPool.POUND + ComponentUtil.escapeClientId(tooltip.getClientId(facesContext)) + "')._node['style'].display = 'block';"); } @Override public void encodeMarkupBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException { ResponseWriter responseWriter = facesContext.getResponseWriter(); OutputTooltipResponseWriter outputTooltipResponseWriter = new OutputTooltipResponseWriter(responseWriter, uiComponent); OutputTooltip outputTooltip = (OutputTooltip) uiComponent; if (outputTooltip.getFor() == null) { if (facesContext.isProjectStage(ProjectStage.Development)) { logger.error( "The outputTooltip needs to point to something. Try using its 'for' attribute to point to an 'id' in the component tree."); } } // Mojarra's HTML Basic calls encodeEnd for fun super.encodeMarkupEnd(facesContext, uiComponent, outputTooltipResponseWriter); } @Override public void encodeMarkupEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException { ResponseWriter responseWriter = facesContext.getResponseWriter(); responseWriter.endElement(StringPool.DIV); } @Override protected void encodeCssClass( ResponseWriter responseWriter, OutputTooltip outputTooltip, String styleClass, boolean first) throws IOException { encodeNonEscapedString(responseWriter, CSS_CLASS, styleClass, first); } @Override protected void encodeHiddenAttributes( ResponseWriter responseWriter, OutputTooltip tooltip, boolean first) throws IOException { FacesContext facesContext = FacesContext.getCurrentInstance(); // contentBox String clientId = tooltip.getClientId(facesContext); String contentBox = StringPool.POUND + ComponentUtil.escapeClientId(clientId); encodeNonEscapedString(responseWriter, AlloyRendererUtil.CONTENT_BOX, contentBox, first); first = false; // render : true encodeWidgetRender(responseWriter, first); } @Override protected void encodeTrigger( ResponseWriter responseWriter, OutputTooltip outputTooltip, String for_, boolean first) throws IOException { UIComponent uiComponent = outputTooltip.findComponent(for_); if (uiComponent != null) { String forClientId = uiComponent.getClientId(); for_ = StringPool.POUND + ComponentUtil.escapeClientId(forClientId); } encodeNonEscapedString(responseWriter, TRIGGER, for_, first); } @Override protected void encodeZIndex( ResponseWriter responseWriter, OutputTooltip outputTooltip, Integer zIndex, boolean first) throws IOException { if (zIndex == Integer.MIN_VALUE) { encodeNonEscapedObject( responseWriter, Z_INDEX, AlloyRendererUtil.LIFERAY_Z_INDEX_TOOLTIP, first); } else { super.encodeZIndex(responseWriter, outputTooltip, zIndex, first); } } @Override public String getDelegateComponentFamily() { return OutputTooltip.DELEGATE_COMPONENT_FAMILY; } @Override public String getDelegateRendererType() { return OutputTooltip.DELEGATE_RENDERER_TYPE; } }
/** * This is a JSF backing managed-bean for the applicant.xhtml composition. * * @author "Neil Griffin" */ @ManagedBean(name = "applicantBackingBean") @RequestScoped public class ApplicantBackingBean implements Serializable { // serialVersionUID private static final long serialVersionUID = 2947548873495692163L; // Logger private static final Logger logger = LoggerFactory.getLogger(ApplicantBackingBean.class); // Injections @ManagedProperty(value = "#{applicantModelBean}") private transient ApplicantModelBean applicantModelBean; @ManagedProperty(value = "#{applicantViewBean}") private transient ApplicantViewBean applicantViewBean; @ManagedProperty(value = "#{listModelBean}") private transient ListModelBean listModelBean; public void deleteUploadedFile(ActionEvent actionEvent) { try { List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles(); String uploadedFileId = applicantViewBean.getUploadedFileId(); UploadedFile uploadedFileToDelete = null; for (UploadedFile uploadedFile : uploadedFiles) { if (uploadedFile.getId().equals(uploadedFileId)) { uploadedFileToDelete = uploadedFile; break; } } if (uploadedFileToDelete != null) { uploadedFileToDelete.delete(); uploadedFiles.remove(uploadedFileToDelete); logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName()); } } catch (Exception e) { logger.error(e); } } public void handleFileUpload(FileUploadEvent event) { List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles(); ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); PortletSession portletSession = (PortletSession) externalContext.getSession(false); String uniqueFolderName = portletSession.getId(); org.primefaces.model.UploadedFile uploadedFile = event.getFile(); UploadedFileWrapper uploadedFileWrapper = new UploadedFileWrapper(uploadedFile, UploadedFile.Status.FILE_SAVED, uniqueFolderName); uploadedFiles.add(uploadedFileWrapper); logger.debug( "Received fileName=[{0}] absolutePath=[{1}]", uploadedFileWrapper.getName(), uploadedFileWrapper.getAbsolutePath()); } public void postalCodeListener(ValueChangeEvent valueChangeEvent) { try { String newPostalCode = (String) valueChangeEvent.getNewValue(); City city = listModelBean.getCityByPostalCode(newPostalCode); if (city != null) { applicantModelBean.setAutoFillCity(city.getCityName()); applicantModelBean.setAutoFillProvinceId(city.getProvinceId()); } } catch (Exception e) { logger.error(e.getMessage(), e); FacesMessageUtil.addGlobalUnexpectedErrorMessage(FacesContext.getCurrentInstance()); } } public String submit() { if (logger.isDebugEnabled()) { logger.debug("firstName=" + applicantModelBean.getFirstName()); logger.debug("lastName=" + applicantModelBean.getLastName()); logger.debug("emailAddress=" + applicantModelBean.getEmailAddress()); logger.debug("phoneNumber=" + applicantModelBean.getPhoneNumber()); logger.debug("dateOfBirth=" + applicantModelBean.getDateOfBirth()); logger.debug("city=" + applicantModelBean.getCity()); logger.debug("provinceId=" + applicantModelBean.getProvinceId()); logger.debug("postalCode=" + applicantModelBean.getPostalCode()); logger.debug("comments=" + applicantModelBean.getComments()); List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles(); for (UploadedFile uploadedFile : uploadedFiles) { logger.debug("uploadedFile=[{0}]", uploadedFile.getName()); } } // Delete the uploaded files. try { List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles(); for (UploadedFile uploadedFile : uploadedFiles) { uploadedFile.delete(); logger.debug("Deleted file=[{0}]", uploadedFile.getName()); } // Store the applicant's first name in JSF 2 Flash Scope so that it can be picked up // for use inside of confirmation.xhtml FacesContext facesContext = FacesContext.getCurrentInstance(); facesContext .getExternalContext() .getFlash() .put("firstName", applicantModelBean.getFirstName()); applicantModelBean.clearProperties(); return "success"; } catch (Exception e) { logger.error(e.getMessage(), e); FacesMessageUtil.addGlobalUnexpectedErrorMessage(FacesContext.getCurrentInstance()); return "failure"; } } public void setApplicantModelBean(ApplicantModelBean applicantModelBean) { // Injected via @ManagedProperty annotation this.applicantModelBean = applicantModelBean; } public void setApplicantViewBean(ApplicantViewBean applicantViewBean) { // Injected via @ManagedProperty annotation this.applicantViewBean = applicantViewBean; } public void setListModelBean(ListModelBean listModelBean) { // Injected via @ManagedProperty annotation this.listModelBean = listModelBean; } }
/** * This is a renderer for the liferay-ui-internal:input-editor component. * * @author Neil Griffin */ public class InputEditorInternalRenderer extends Renderer implements CleanupRenderer { // Logger private static final Logger logger = LoggerFactory.getLogger(InputEditorInternalRenderer.class); // Private Constants private static final String EDITOR_NAME_TOKEN = "%EDITOR_NAME%"; private static final String ONBLUR_JS; private static final String ONBLUR_METHOD_NAME_TOKEN = "%ONBLUR_METHOD_NAME%"; private static final String COMMENT_CDATA_CLOSE = "// " + StringPool.CDATA_CLOSE; private static final String CKEDITOR = "ckeditor"; static { StringBuilder onBlurJS = new StringBuilder(); onBlurJS.append("(function() {"); onBlurJS.append("var ckEditor = CKEDITOR.instances['"); onBlurJS.append(EDITOR_NAME_TOKEN); onBlurJS.append("'];"); onBlurJS.append("ckEditor.on('blur',"); onBlurJS.append("function () {"); onBlurJS.append(ONBLUR_METHOD_NAME_TOKEN); onBlurJS.append("();"); onBlurJS.append("});"); onBlurJS.append("})();"); ONBLUR_JS = onBlurJS.toString(); } @Override public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException { super.encodeBegin(facesContext, uiComponent); InputEditorInternal inputEditorInternal = (InputEditorInternal) uiComponent; ResponseWriter responseWriter = facesContext.getResponseWriter(); ExternalContext externalContext = facesContext.getExternalContext(); PortletRequest portletRequest = (PortletRequest) externalContext.getRequest(); PortletResponse portletResponse = (PortletResponse) externalContext.getResponse(); HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(portletRequest); httpServletRequest = new NonNamespacedHttpServletRequest(httpServletRequest); HttpServletResponse httpServletResponse = PortalUtil.getHttpServletResponse(portletResponse); PortletRequest liferayPortletRequest = getLiferayPortletRequest(portletRequest); boolean resourcePhase = (liferayPortletRequest instanceof ResourceRequest); Map<String, Object> attributes = inputEditorInternal.getAttributes(); String onBlurMethod = (String) attributes.get("onBlurMethod"); String editorImpl = (String) attributes.get("editorImpl"); if (editorImpl == null) { editorImpl = CKEDITOR; } // Build up a URL that can be used to invoke the liferay-ui:input-editor JSP tag. String url = "/resources/liferay-ui/jsp/input-editor.jsp"; StringBuilder queryString = new StringBuilder(); queryString.append(StringPool.QUESTION); queryString.append("editorImpl"); queryString.append(StringPool.EQUAL); queryString.append(editorImpl); queryString.append(StringPool.AMPERSAND); queryString.append("height"); queryString.append(StringPool.EQUAL); queryString.append(attributes.get("height")); queryString.append(StringPool.AMPERSAND); queryString.append("initMethod"); queryString.append(StringPool.EQUAL); queryString.append(attributes.get("initMethod")); queryString.append(StringPool.AMPERSAND); queryString.append("name"); queryString.append(StringPool.EQUAL); String editorName = (String) attributes.get("name"); queryString.append(editorName); queryString.append(StringPool.AMPERSAND); queryString.append("onChangeMethod"); queryString.append(StringPool.EQUAL); queryString.append(attributes.get("onChangeMethod")); queryString.append(StringPool.AMPERSAND); queryString.append("skipEditorLoading"); queryString.append(StringPool.EQUAL); if (resourcePhase) { // FACES-1439: Ensure that the <script src=".../ckeditor.js" /> element is not included in the // response by // specifying skipEditorLoading="true" during Ajax requests. queryString.append(Boolean.TRUE.toString()); } else { queryString.append(Boolean.FALSE.toString()); } queryString.append(StringPool.AMPERSAND); queryString.append("toolbarSet"); queryString.append(StringPool.EQUAL); queryString.append(attributes.get("toolbarSet")); queryString.append(StringPool.AMPERSAND); queryString.append("width"); queryString.append(StringPool.EQUAL); queryString.append(attributes.get("width")); url = url + queryString.toString(); // Invoke the tag and capture it's output in a String, rather than having the output go directly // to the // response. RequestDispatcher requestDispatcher = httpServletRequest.getRequestDispatcher(url); JspIncludeResponse jspIncludeResponse = new JspIncludeResponse(httpServletResponse); try { requestDispatcher.include(httpServletRequest, jspIncludeResponse); } catch (ServletException e) { logger.error(e.getMessage()); throw new IOException(e.getMessage()); } String bufferedResponse = jspIncludeResponse.getBufferedResponse(); if (bufferedResponse != null) { // Note: Trim the buffered response since there is typically over 100 newlines at the // beginning. bufferedResponse = bufferedResponse.trim(); // If rendering an instance of the CKEditor, then String editorType = EditorUtil.getEditorValue(httpServletRequest, editorImpl); if (editorType.indexOf(CKEDITOR) >= 0) { String namespace = portletResponse.getNamespace(); // FACES-1441: The liferay-ui:input-editor JSP tag (and associated ckeditor.jsp file) do not // provide a // way to hook-in to the "onblur" callback feature of the CKEditor. In order to overcome // this // limitation, it is necessary to append a <script>...</script> to the response that // provides this // ability. String onBlurScript = getOnBlurScript(editorName, onBlurMethod, namespace); // If running within an Ajax request, include the "onblur" callback script must be included // directly // to the response. if (resourcePhase) { StringBuilder scriptMarkup = new StringBuilder(); scriptMarkup.append(StringPool.LESS_THAN); scriptMarkup.append(StringPool.SCRIPT); scriptMarkup.append(StringPool.GREATER_THAN); scriptMarkup.append(StringPool.CDATA_OPEN); scriptMarkup.append(onBlurScript); scriptMarkup.append(COMMENT_CDATA_CLOSE); scriptMarkup.append(StringPool.LESS_THAN); scriptMarkup.append(StringPool.FORWARD_SLASH); scriptMarkup.append(StringPool.SCRIPT); scriptMarkup.append(StringPool.GREATER_THAN); bufferedResponse = bufferedResponse.concat(scriptMarkup.toString()); } // Otherwise, append the script to the "LIFERAY_SHARED_AUI_SCRIPT_DATA" request attribute, // which will // cause the script to be rendered at the bottom of the portal page. else { ScriptData scriptData = (ScriptData) externalContext.getRequestMap().get(WebKeys.AUI_SCRIPT_DATA); scriptData.append(getPortletId(portletRequest), onBlurScript, null); } // FACES-1439: If the component was rendered on the page on the previous JSF lifecycle, then // prevent it // from being re-initialized by removing all <script>...</script> elements. boolean scriptsRemoved = false; String clientId = inputEditorInternal.getClientId(); if (resourcePhase && inputEditorInternal.isPreviouslyRendered()) { logger.debug("Preventing re-initialization of CKEditor for clientId=[{0}]", clientId); ParsedResponse parsedResponse = new ParsedResponse(bufferedResponse); bufferedResponse = parsedResponse.getNonScripts(); scriptsRemoved = true; } // FACES-1422: Move the scripts to the <eval>...</eval> section of the partial-response so // that they // will execute properly. This has the added benefit of preempt a DOM-diff with ICEfaces. if (resourcePhase && !scriptsRemoved) { logger.debug( "Moving CKEditor scripts to <eval>...</eval> section of the partial-response for clientId=[{0}]", clientId); ParsedResponse parsedResponse = new ParsedResponse(bufferedResponse); bufferedResponse = parsedResponse.getNonScripts(); String scripts = parsedResponse.getScripts(); LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance(); liferayFacesContext.getJavaScriptMap().put(clientId, scripts); logger.trace(scripts); } } // Write the captured output from the JSP tag to the Faces responseWriter. logger.trace(bufferedResponse); responseWriter.write(bufferedResponse); } } public void encodeCleanup(FacesContext facesContext, UIComponent uiComponent) throws IOException { PortletResponse portletResponse = (PortletResponse) facesContext.getExternalContext().getResponse(); String namespace = portletResponse.getNamespace(); String editorName = uiComponent.getParent().getParent().getClientId(); StringBuilder scriptBuilder = new StringBuilder(); // Build up a JavaScript fragment that will cleanup the DOM. scriptBuilder.append("var oldEditor = CKEDITOR.instances['"); scriptBuilder.append(namespace); scriptBuilder.append(editorName); scriptBuilder.append("']; if (oldEditor) {"); scriptBuilder.append("oldEditor.destroy(true);"); scriptBuilder.append("delete window['"); scriptBuilder.append(namespace); scriptBuilder.append(editorName); scriptBuilder.append("'];"); scriptBuilder.append("}"); String script = scriptBuilder.toString(); LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance(); liferayFacesContext.getJavaScriptMap().put(editorName, script); logger.trace(script); } protected PortletRequest getLiferayPortletRequest(PortletRequest portletRequest) { PortletRequest liferayPortletRequest = portletRequest; if (liferayPortletRequest instanceof PortletRequestWrapper) { PortletRequestWrapper portletRequestWrapper = (PortletRequestWrapper) portletRequest; liferayPortletRequest = getLiferayPortletRequest(portletRequestWrapper.getRequest()); } return liferayPortletRequest; } protected String getOnBlurScript(String editorName, String onBlurMethod, String namespace) { String onBlurScript = ONBLUR_JS; // Replace %EDITOR_NAME% token with specified editor name. int editorNameTokenPos = onBlurScript.indexOf(EDITOR_NAME_TOKEN); if (editorNameTokenPos > 0) { onBlurScript = onBlurScript.substring(0, editorNameTokenPos) + namespace + editorName + onBlurScript.substring(editorNameTokenPos + EDITOR_NAME_TOKEN.length()); } // Replace %ONBLUR_METHOD_NAME% token with specified onblur method name. int onBlurTokenPos = onBlurScript.indexOf(ONBLUR_METHOD_NAME_TOKEN); if (onBlurTokenPos > 0) { onBlurScript = onBlurScript.substring(0, onBlurTokenPos) + namespace + onBlurMethod + onBlurScript.substring(onBlurTokenPos + ONBLUR_METHOD_NAME_TOKEN.length()); } return onBlurScript; } protected String getPortletId(PortletRequest portletRequest) { String portletId = StringPool.BLANK; Portlet portlet = (Portlet) portletRequest.getAttribute(WebKeys.RENDER_PORTLET); if (portlet != null) { portletId = portlet.getPortletId(); } return portletId; } protected class ParsedResponse { private String scripts; private String nonScripts; public ParsedResponse(String response) { StringBuilder scriptBuilder = new StringBuilder(); String beginScriptToken = StringPool.LESS_THAN + StringPool.SCRIPT; String endScriptToken = StringPool.FORWARD_SLASH + StringPool.SCRIPT + StringPool.GREATER_THAN; int endElementLength = endScriptToken.length(); boolean done1 = false; while (!done1) { int beginPos = response.indexOf(beginScriptToken); int endPos = response.indexOf(endScriptToken, beginPos); if ((beginPos >= 0) && (endPos > beginPos)) { String script = response.substring(beginPos, endPos + endElementLength); boolean done2 = false; while (!done2) { int cdataOpenPos = script.indexOf(StringPool.CDATA_OPEN); if (cdataOpenPos > 0) { script = script.substring(cdataOpenPos + StringPool.CDATA_OPEN.length()); int cdataClosePos = script.indexOf(COMMENT_CDATA_CLOSE); if (cdataClosePos > 0) { script = script.substring(0, cdataClosePos); } } else { done2 = true; } } scriptBuilder.append(script); response = response.substring(0, beginPos) + response.substring(endPos + endElementLength); } else { done1 = true; } } this.scripts = scriptBuilder.toString().trim(); this.nonScripts = response.trim(); } public String getNonScripts() { return nonScripts; } public String getScripts() { return scripts; } } }
/** @author Neil Griffin */ public class PDFUtil { private static final Logger logger = LoggerFactory.getLogger(PDFUtil.class); public static byte[] TXT2PDF( String htmlFragment, String headMarkup, String pdfTitle, String description, String author) throws IOException { byte[] pdf = null; if (htmlFragment != null) { StringBuilder xhtml = new StringBuilder(); xhtml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); xhtml.append( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); xhtml.append("<html>"); if ((pdfTitle != null) || (description != null) || (author != null)) { xhtml.append("<head>"); } if (description != null) { xhtml.append("<meta name=\"description\" content=\""); xhtml.append(description); xhtml.append("\" />"); } if (description != null) { xhtml.append("<meta name=\"author\" content=\""); xhtml.append(author); xhtml.append("\" />"); } if (pdfTitle != null) { xhtml.append("<title>"); xhtml.append(pdfTitle); xhtml.append("</title>"); } if (headMarkup != null) { xhtml.append(headMarkup); } if ((pdfTitle != null) || (description != null)) { xhtml.append("</head>"); } xhtml.append("<body>"); if (htmlFragment != null) { htmlFragment = htmlFragment.replace("\n", "<br />"); } xhtml.append(htmlFragment); xhtml.append("</body>"); xhtml.append("</html>"); pdf = XHTML2PDF(xhtml.toString()); } return pdf; } public static byte[] XHTML2PDF(String xhtml) throws IOException { byte[] pdf = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { ITextRenderer itextRenderer = new ITextRenderer(); itextRenderer.setDocumentFromString(xhtml); itextRenderer.layout(); itextRenderer.createPDF(byteArrayOutputStream); pdf = byteArrayOutputStream.toByteArray(); } catch (Exception e) { logger.error(e.getMessage(), e); logger.error("vvv--- Offending XHTML ---vvv"); logger.error(xhtml); throw new IOException(e.getMessage()); } return pdf; } }
/** @author Neil Griffin */ public class BridgeResourceURLImpl extends BridgeResourceURLCompatImpl { // Logger private static final Logger logger = LoggerFactory.getLogger(BridgeResourceURLImpl.class); // Private Pseudo-Constants private static Set<String> EXCLUDED_PARAMETER_NAMES = new HashSet<String>(); static { EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_MODE_PARAMETER); EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_SECURE_PARAMETER); EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_WINDOWSTATE_PARAMETER); } // Private Data Members private boolean inProtocol; private PortletContainer portletContainer; private boolean viewLink; public BridgeResourceURLImpl(String url, String currentFacesViewId, BridgeContext bridgeContext) { super(url, currentFacesViewId, bridgeContext); this.portletContainer = bridgeContext.getPortletContainer(); } public void replaceBackLinkParameter(FacesContext facesContext) { String backLinkViewId = facesContext.getViewRoot().getViewId(); String backLinkURL = facesContext.getApplication().getViewHandler().getActionURL(facesContext, backLinkViewId); String backLinkEncodedActionURL = StringPool.BLANK; try { backLinkEncodedActionURL = URLEncoder.encode( facesContext.getExternalContext().encodeActionURL(backLinkURL), StringPool.UTF8); } catch (UnsupportedEncodingException e) { logger.error(e.getMessage()); } String newParamName = removeParameter(Bridge.BACK_LINK); setParameter(newParamName, backLinkEncodedActionURL); } @Override protected BaseURL toBaseURL() throws MalformedURLException { BaseURL baseURL = null; // If the URL is opaque, meaning it starts with something like "portlet:" or "mailto:" and // doesn't have the double-forward-slash like "http://" does, then if (isOpaque()) { // If the specified URL starts with "portlet:", then return a BaseURL that contains the // modified // parameters. This will be a URL that represents navigation to a different viewId. if (isPortletScheme()) { // TCK TestPage005: modeViewIDTest // TCK TestPage042: requestRenderIgnoresScopeViaCreateViewTest // TCK TestPage043: requestRenderRedisplayTest // TCK TestPage044: requestRedisplayOutOfScopeTest // TCK TestPage049: renderRedirectTest // TCK TestPage050: ignoreCurrentViewIdModeChangeTest // TCK TestPage051: exceptionThrownWhenNoDefaultViewIdTest String portletMode = getParameter(Bridge.PORTLET_MODE_PARAMETER); boolean modeChanged = ((portletMode != null) && (portletMode.length() > 0)); String security = getParameter(Bridge.PORTLET_SECURE_PARAMETER); String windowState = getParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER); String urlWithModifiedParameters = _toString(modeChanged); Bridge.PortletPhase urlPortletPhase = getPortletPhase(); if (urlPortletPhase == Bridge.PortletPhase.ACTION_PHASE) { baseURL = portletContainer.createActionURL(urlWithModifiedParameters); } else if (urlPortletPhase == Bridge.PortletPhase.RENDER_PHASE) { baseURL = portletContainer.createRenderURL(urlWithModifiedParameters); } else { baseURL = portletContainer.createResourceURL(urlWithModifiedParameters); } // If the URL string is self-referencing, meaning, it targets the current Faces view, then // copy the // render parameters from the current PortletRequest to the BaseURL. NOTE: This has the // added benefit of // copying the bridgeRequestScopeId render parameter, which will preserve the // BridgeRequestScope if the // user clicks on the link (invokes the BaseURL). if (isSelfReferencing()) { setRenderParameters(baseURL); } // If the portlet container created a PortletURL, then apply the PortletMode and WindowState // to the // PortletURL. if (baseURL instanceof PortletURL) { PortletURL portletURL = (PortletURL) baseURL; setPortletModeParameter(portletMode, portletURL); setWindowStateParameter(windowState, portletURL); } // Apply the security. setSecureParameter(security, baseURL); } // Otherwise, return the a BaseURL string representation (unmodified value) as required by the // Bridge Spec. else { // TCK TestPage128: encodeResourceURLOpaqueTest baseURL = new BaseURLNonEncodedStringImpl(url, getParameterMap()); } } // Otherwise, if the URL is external, then return an encoded BaseURL string representation of // the URL. else if (isExternal()) { // TCK TestPage130: encodeResourceURLForeignExternalURLBackLinkTest baseURL = new BaseURLEncodedExternalStringImpl(url, getParameterMap(), bridgeContext); } // Otherwise, if the URL is identified by the ResourceHandler as a JSF2 resource URL, then else if (isFaces2ResourceURL()) { // If the URL has already been encoded, then return the URL string unmodified. if (isEncodedFaces2ResourceURL()) { // FACES-63: Prevent double-encoding of resource URLs baseURL = new BaseURLNonEncodedStringImpl(url, getParameterMap()); } // Otherwise, return a ResourceURL that can retrieve the JSF2 resource. else { baseURL = portletContainer.createResourceURL(url); } } // Otherwise, if the URL is relative, in that it starts with "../", then return a BaseURL string // representation // of the URL that contains the context-path. else if (isPathRelative()) { // TCK TestPage131: encodeResourceURLRelativeURLTest // TCK TestPage132: encodeResourceURLRelativeURLBackLinkTest baseURL = new BaseURLRelativeStringImpl(url, getParameterMap(), bridgeContext); } // Otherwise, if the URL originally contained the "javax.portlet.faces.ViewLink" which // represents navigation // to a different Faces view, then else if (viewLink) { String urlWithModifiedParameters = _toString(false, EXCLUDED_PARAMETER_NAMES); String portletMode = getParameter(Bridge.PORTLET_MODE_PARAMETER); String windowState = getParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER); boolean secure = BooleanHelper.toBoolean(getParameter(Bridge.PORTLET_SECURE_PARAMETER)); // If the URL targets a Faces viewId, then return a PortletURL (Action URL) that targets the // view with the // appropriate PortletMode, WindowState, and Security settings built into the URL. For more // info, see // JavaDoc comments for {@link Bridge#VIEW_LINK}. if (isFacesViewTarget()) { // TCK TestPage135: encodeResourceURLViewLinkTest // TCK TestPage136: encodeResourceURLViewLinkWithBackLinkTest baseURL = new PortletURLFacesTargetActionImpl( bridgeContext, urlWithModifiedParameters, portletMode, windowState, secure); } // Otherwise, return a PortletURL (Render URL) that contains the "_jsfBridgeNonFacesView" // render parameter, // which is a signal to the GenericFacesPortlet to dispatch to this non-Faces target when the // URL is // requested. Note that this seems to be a use-case that is contradictory with the JavaDoc for // Brige#VIEW_LINK which claims navigation to a different view. But there are a number of // tests in the TCK // that utilize this (see below). else { // TCK TestPage097: encodeActionURLNonJSFViewRenderTest // TCK TestPage098: encodeActionURLNonJSFViewWithParamRenderTest // TCK TestPage099: encodeActionURLNonJSFViewWithModeRenderTest // TCK TestPage100: encodeActionURLNonJSFViewWithInvalidModeRenderTest // TCK TestPage101: encodeActionURLNonJSFViewWithWindowStateRenderTest // TCK TestPage102: encodeActionURLNonJSFViewWithInvalidWindowStateRenderTest // TCK TestPage103: encodeActionURLNonJSFViewResourceTest // TCK TestPage104: encodeActionURLNonJSFViewWithParamResourceTest // TCK TestPage105: encodeActionURLNonJSFViewWithModeResourceTest // TCK TestPage106: encodeActionURLNonJSFViewWithInvalidModeResourceTest // TCK TestPage107: encodeActionURLNonJSFViewWithWindowStateResourceTest // TCK TestPage108: encodeActionURLNonJSFViewWithInvalidWindowStateResourceTest baseURL = new PortletURLNonFacesTargetRenderImpl( bridgeContext, urlWithModifiedParameters, portletMode, windowState, secure, getURI().getPath()); } } // Otherwise, if the URL targets a Faces viewId, then return a ResourceURL that targets the // view. else if (isFacesViewTarget()) { // TCK TestPage073: scopeAfterRedisplayResourcePPRTest // TCK TestPage121: encodeActionURLJSFViewResourceTest // TCK TestPage122: encodeActionURLWithParamResourceTest // TCK TestPage123: encodeActionURLWithModeResourceTest // TCK TestPage124: encodeActionURLWithInvalidModeResourceTest // TCK TestPage125: encodeActionURLWithWindowStateResourceTest // TCK TestPage126: encodeActionURLWithInvalidWindowStateResourceTest // TCK TestPage127: encodeURLEscapingTest // TCK TestPage137: encodeResourceURLWithModeTest String urlWithModifiedParameters = _toString(false, EXCLUDED_PARAMETER_NAMES); baseURL = portletContainer.createResourceURL(urlWithModifiedParameters); } // Otherwise, if the bridge must encode the URL to satisfy "in-protocol" resource serving, then // return a // an appropriate ResourceURL. else if (inProtocol) { // TCK TestPage071: nonFacesResourceTest String urlWithModifiedParameters = _toString(false); ResourceURL resourceURL = portletContainer.createResourceURL(urlWithModifiedParameters); resourceURL.setResourceID(getContextRelativePath()); baseURL = resourceURL; } // Otherwise, assume that the URL is for an resource external to the portlet context like // "/portalcontext/resources/foo.png" and return a BaseURL string representation of it. else { // TCK TestPage133: encodeResourceURLTest baseURL = new BaseURLEncodedExternalStringImpl(url, getParameterMap(), bridgeContext); } return baseURL; } public void setInProtocol(boolean inProtocol) { this.inProtocol = inProtocol; } public void setViewLink(boolean viewLink) { this.viewLink = viewLink; } }