package fi.jab.jsf; import java.io.IOException; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; import javax.faces.application.ViewHandler; import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.portlet.PortletException; import javax.portlet.PortletSecurityException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.UnavailableException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.myfaces.config.FacesConfigurator; import org.apache.myfaces.context.ReleaseableExternalContext; import org.apache.myfaces.context.portlet.PortletExternalContextImpl; import org.apache.myfaces.context.servlet.ServletFacesContextImpl; import org.apache.myfaces.shared_impl.util.ClassUtils; import org.apache.myfaces.shared_impl.util.StateUtils; import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory; import org.apache.myfaces.shared_impl.util.serial.SerialFactory; import org.apache.myfaces.shared_impl.webapp.webxml.WebXml; import fi.jab.jsf.myfaces.WebXmlParser; /** * java.lang.IllegalStateException: Can not call encodeNamespace() during a portlet ActionRequest * http://issues.apache.org/jira/browse/MYFACES-1359?page=all * * http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/MyFacesGenericPortlet.java?revision=417505&view=markup * * @author jarkko * */ public class MyFacesGenericPortlet extends org.apache.myfaces.portlet.MyFacesGenericPortlet { private static final Log log = LogFactory .getLog(MyFacesGenericPortlet.class); @Override protected void nonFacesRequest(RenderRequest request, RenderResponse response) throws PortletException { super.nonFacesRequest(request, response); } @Override public void render(RenderRequest request, RenderResponse response) throws PortletException, PortletSecurityException, IOException { super.render(request, response); } @Override protected void doDispatch(RenderRequest request, RenderResponse response) throws PortletException, PortletSecurityException, IOException { super.doDispatch(request, response); } @Override protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { super.doView(request, response); } @Override protected void nonFacesRequest(RenderRequest request, RenderResponse response, String view) throws PortletException { if (log.isTraceEnabled()) { log.trace("Non-faces request: contextPath = " + request.getContextPath()); } setContentType(request, response); // do this in case nonFacesRequest is called by a subclass ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder .getFactory(FactoryFinder.APPLICATION_FACTORY); Application application = appFactory.getApplication(); ViewHandler viewHandler = application.getViewHandler(); FacesContext facesContext = facesContext(request, response); UIViewRoot viewRoot = viewHandler.createView(facesContext, view); viewRoot.setViewId(view); facesContext.setViewRoot(viewRoot); long start = 0; if (log.isTraceEnabled()) { start = System.currentTimeMillis(); log.trace("Nonfaces request: Rendering " + view); } lifecycle.render(facesContext); if (log.isTraceEnabled()) { long end = System.currentTimeMillis(); log.trace("Nonfaces request: Rendering " + view + " finished. Took " + (end - start) + " ms."); } } @Override // http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/MyFacesGenericPortlet.java?revision=417505&view=markup protected void facesRender(RenderRequest request, RenderResponse response) throws PortletException, IOException { if (log.isTraceEnabled()) log.trace("called facesRender"); setContentType(request, response); String viewId = request.getParameter(VIEW_ID); long start = 0; if (log.isTraceEnabled()) { start = System.currentTimeMillis(); log.trace("Faces rendering " + viewId); } if ((viewId == null) || sessionTimedOut(request)) { if (log.isTraceEnabled()) { log .trace("Faces rendering: viewId not found or session timed out, calling nonFacesRequest for " + viewId); } setPortletRequestFlag(request); nonFacesRequest(request, response); return; } setPortletRequestFlag(request); try { ServletFacesContextImpl facesContext = (ServletFacesContextImpl) request .getPortletSession().getAttribute(CURRENT_FACES_CONTEXT); // depending on the Portal implementation, facesContext could be // null after a redeploy if (facesContext == null) { if (log.isTraceEnabled()) { log .trace("Faces rendering: no facesContext found, calling nonFacesRequest for " + viewId); } setPortletRequestFlag(request); nonFacesRequest(request, response); return; } // TODO: not sure if this can happen. Also double check this against // spec section 2.1.3 if (facesContext.getResponseComplete()) { if (log.isTraceEnabled()) { log .trace("Faces render: Response already completed for view " + viewId); } return; } ReleaseableExternalContext ctx = makeExternalContext(request, response); facesContext.setExternalContext(ctx); lifecycle.render(facesContext); } catch (Throwable e) { handleExceptionFromLifecycle(e); } finally { if (log.isTraceEnabled()) { long end = System.currentTimeMillis(); log.trace("Faces rendering finished " + viewId + " took " + (end - start) + " ms."); } } } @Override public void init() throws PortletException, UnavailableException { super.init(); } @Override protected void initMyFaces() { try { Boolean b = (Boolean) portletContext.getAttribute(FACES_INIT_DONE); if (b == null || b.booleanValue() == false) { if (log.isTraceEnabled()) { log.trace("Initializing MyFaces"); } // Load the configuration ExternalContext externalContext = new PortletExternalContextImpl( portletContext, null, null); // And configure everything new FacesConfigurator(externalContext).configure(); // parse web.xml - not sure if this is needed for portlet // WebXml.init(externalContext); init(externalContext); // What is this supposed to do?? // if (portletContext.getInitParameter(StateUtils.INIT_SECRET) != null) { // // Yes, but how? // // StateUtils.initSecret( externalContext ); // } handleSerialFactory(externalContext); portletContext.setAttribute(FACES_INIT_DONE, Boolean.TRUE); } else { // FIXME do we want to show this? if (log.isDebugEnabled()) { log.debug("MyFaces already initialized"); } } } catch (Exception ex) { log.error("Error initializing MyFacesGenericPortlet", ex); } if (log.isInfoEnabled()) { log.info("Portlet " + getPortletName() + " initialized"); } } /******************************************************************************************************************* * should be called when initialising Servlet * * @param context */ public static void init(ExternalContext context) { WebXmlParser parser = new WebXmlParser(context); WebXml webXml = parser.parse(); context.getApplicationMap().put(WebXml.class.getName(), webXml); } public void handleSerialFactory(ExternalContext externalContext) { String serialProvider = externalContext .getInitParameter(StateUtils.SERIAL_FACTORY); SerialFactory serialFactory = null; if (serialProvider == null) { serialFactory = new DefaultSerialFactory(); } else { try { if (log.isTraceEnabled()) { log.debug("Using serialprovider " + serialProvider); } serialFactory = (SerialFactory) ClassUtils .newInstance(serialProvider); } catch (ClassCastException e) { log.error("Make sure '" + serialProvider + "' implements the correct interface", e); } catch (Exception e) { log.error(e); } finally { if (serialFactory == null) { serialFactory = new DefaultSerialFactory(); log.error("Using default serialization provider " + serialFactory); } } } if (log.isTraceEnabled()) { log.trace("Serialization provider : " + serialFactory.getClass()); } getPortletContext().setAttribute("org.apache.myfaces.SERIAL_FACTORY", serialFactory); externalContext.getApplicationMap().put(StateUtils.SERIAL_FACTORY, serialFactory); } }