简体   繁体   中英

Wildfly 8 SEAM2 redirect - javax.faces.context.PartialViewContextFactory

I'm migrating an application running on legacy AS (with plenty of legacy stuff inside). The starting state was Java 1.7, JBoss 5.1GA, Hibernate 3, SEAM 2.2.2, jBPM 3.9 and some legacy richfaces.

I managed to deploy it on Java 1.8, Wildfly 8.2 with Hibernate 4.3.7, SEAM 2.3.1 and RichFaces 4.5.6. Since SEAM 2.3 is capable of JSF2 I also upgraded JSF to 2.2 (Mojarra 2.2.8 implementation which is shipped wich Wildfly). Because of using SEAM I had to drop CDI (WELD) from the application server (commented WELD out in the standalone-full.xml). Also did a rewrite on jBPM to make it work with new Hibernate.

The app seems to be deploying correctly, everything catches up fine (no errors). When I access the web interface, the login page loads just fine. I enter my login info and then - after successful login - there comes a redirect which is called from the depths of the app through a facade like this:

import org.jboss.seam.faces.Redirect;
class C {
    public static void showPage(String page) {
        Redirect redirect = Redirect.instance();
        redirect.setViewId(page);       
        redirect.execute();
    }
}

Called this way, the exception is thrown and webpage processing stops. The exception:

SEVERE [javax.faces] (default task-8) Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?
SEVERE [javax.faces] (default task-8) Application was not properly initialized at startup, could not find Factory: javax.faces.context.PartialViewContextFactory. Attempting to find backup.
...
Caused by: org.jboss.seam.faces.RedirectException: Could not find backup for factory javax.faces.context.PartialViewContextFactory. 
    at org.jboss.seam.faces.FacesManager.redirect(FacesManager.java:237) [jboss-seam.jar:2.3.1.Final]
    at org.jboss.seam.faces.FacesManager.redirect(FacesManager.java:190) [jboss-seam.jar:2.3.1.Final]
    at org.jboss.seam.faces.Redirect.execute(Redirect.java:154) [jboss-seam.jar:2.3.1.Final]

However there are other redirects - all specified explicitly in pages.xml - which are working fine.

There are not any conflicting libraries (like widespread MyFaces vs. Mojarra problem), there is only Mojarra. Also ruled out those bugs:

https://issues.jboss.org/browse/WFLY-2594

https://java.net/jira/browse/JAVASERVERFACES-3189

Does anyone know how to solve this? Please note that throwing out SEAM is unfortunately not an option here.

I will post more details (configuration, more info, ...) on request.

UPDATE: I debugged a bit more - adding some logging directly into SEAM's FacesManager. The logging looks like this:

private void redirect(String viewId, FacesContext context, String url)
   {
      url = Pages.instance().encodeScheme(viewId, context, url);
      if ( log.isDebugEnabled() )
      {
         log.debug("redirecting to: " + url);
      }
      ExternalContext externalContext = context.getExternalContext();
      controllingRedirect = true;
      try
      {  
         log.debug("Trying to get context...");
         log.debug("Contexts.getEventContext(): "+Contexts.getEventContext());
         Contexts.getEventContext().set(REDIRECT_FROM_MANAGER, "");
         log.debug("REDIRECT_FROM_MANAGER set");
         log.debug("externalContext: "+externalContext);
         externalContext.redirect( externalContext.encodeActionURL(url) );
      }
      catch (IOException ioe)
      {
         throw new RedirectException(ioe);
      }
      catch (IllegalStateException ise)
      {
          log.debug("Caught illegal state exception.");
         throw new RedirectException(ise.getMessage());
      }
      finally
      {
         Contexts.getEventContext().remove(REDIRECT_FROM_MANAGER);
         controllingRedirect = false;
      }
      context.responseComplete();
   }

Logging output just before the exception occurs:

DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) redirecting to: /idm/user/personal/personal.seam?cid=2
DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) Trying to get context...
DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) Contexts.getEventContext(): BasicContext(EVENT)
DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) REDIRECT_FROM_MANAGER set
DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) externalContext: org.richfaces.context.SkinningExternalContextFactory$ExternalContextWrapperImpl@1dcafb6
DEBUG [org.jboss.seam.faces.FacesManager] (default task-5) Caught illegal state exception.

UPDATE 2:

So, I was fiddling with debug messages in SEAM and (so far) discovered this:

DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) viewId: /adminOrUser/home.xhtml
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) parameters: {}
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) includeConversationId: true
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) includePageParams: true
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) FacesContext.getCurrentInstance: com.sun.faces.context.FacesContextImpl@67667a
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) context.getApplication: com.sun.faces.application.ApplicationImpl@134d311
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) context.getApplication.getViewHandler: org.jboss.as.jsf.injection.weld.WildFlyConversationAwareViewHandler@151c033
DEBUG [org.jboss.seam.faces.FacesManager] (default task-14) context.getApplication.getViewHandler.getRedirectURL: /idm/adminOrUser/home.seam

The interesting part is org.jboss.as.jsf.injection.weld.WildFlyConversationAwareViewHandler which somehow bugs me. Why is there a class which could belong to WELD even when I disabled it? I didn't have a chance to investigate further but my theory is that I somehow got WELD into the deployment indirectly and weld thing then cause problems (conflicts?) because app should rely on SEAM.

UPDATE 3:

The notion of WELD-related issue is probably correct. As JSF implementation Wildfly uses Mojarra(2.2.8) integrated into the AS as jsf-impl-2.2.8-jbossorg-1.jar . Looking into the modules/system/layers/base/com/sun/jsf-impl/main/module.xml in the AS there are WELD dependencies:

<dependencies>
    ...
    <module name="org.jboss.weld.core"/>
    <module name="org.jboss.weld.spi"/>
</dependencies>

So either WELD still gets into the deployment as the dependency or the JSF implementation depends on something which is currently turned off.

When I turn the weld on I get following error:

ERROR [org.jboss.seam.exception.Exceptions] (default task-4) handled and logged exception: org.jboss.weld.context.NonexistentConversationException: WELD-000321: No conversation found to restore for id 2
    at org.jboss.weld.context.AbstractConversationContext.initialize(AbstractConversationContext.java:260) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
    at org.jboss.weld.context.http.LazyHttpConversationContextImpl.initialize(LazyHttpConversationContextImpl.java:68) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
    at org.jboss.weld.context.http.LazyHttpConversationContextImpl.checkContextInitialized(LazyHttpConversationContextImpl.java:96) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
    at org.jboss.weld.context.AbstractConversationContext.getCurrentConversation(AbstractConversationContext.java:460) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
    at org.jboss.weld.jsf.ConversationAwareViewHandler.getActionURL(ConversationAwareViewHandler.java:111) [weld-core-jsf-2.2.6.Final.jar:2014-10-03 10:05]
    at javax.faces.application.ViewHandlerWrapper.getActionURL(ViewHandlerWrapper.java:189) [jboss-jsf-api_2.2_spec-2.2.8.jar:2.2.8]
    at com.sun.faces.application.view.MultiViewHandler.getRedirectURL(MultiViewHandler.java:468) [jsf-impl-2.2.8-jbossorg-1.jar:]
    at javax.faces.application.ViewHandlerWrapper.getRedirectURL(ViewHandlerWrapper.java:250) [jboss-jsf-api_2.2_spec-2.2.8.jar:2.2.8]
    at org.jboss.seam.jsf.SeamViewHandler.getRedirectURL(SeamViewHandler.java:133) [jboss-seam.jar:2.3.1.Final]
    at javax.faces.application.ViewHandlerWrapper.getRedirectURL(ViewHandlerWrapper.java:250) [jboss-jsf-api_2.2_spec-2.2.8.jar:2.2.8]
    at javax.faces.application.ViewHandlerWrapper.getRedirectURL(ViewHandlerWrapper.java:250) [jboss-jsf-api_2.2_spec-2.2.8.jar:2.2.8]
    at org.jboss.weld.jsf.ConversationAwareViewHandler.getRedirectURL(ConversationAwareViewHandler.java:142) [weld-core-jsf-2.2.6.Final.jar:2014-10-03 10:05]
    at javax.faces.application.ViewHandlerWrapper.getRedirectURL(ViewHandlerWrapper.java:250) [jboss-jsf-api_2.2_spec-2.2.8.jar:2.2.8]
    at org.jboss.seam.faces.FacesManager.redirect(FacesManager.java:182) [jboss-seam.jar:2.3.1.Final]

Which means the conversation with id=2 is not found in WELD-managed context. This is no wonder because cid is generated by SEAM and WELD does not know about it at all.

There is a short doc about making JSF work with WELD: http://docs.jboss.org/weld/reference/latest/en-US/html/ri-spi.html#_jsf

Second possibility is to leave WELD turned off and change the JSF implementation so the jsf-impl-2.2.8-jbossorg-1.jar will not be used: https://developer.jboss.org/wiki/StepsToAddAnyNewJSFImplementationOrVersionToWildFly (Update: this does not seem to be working.)

Also interesting/related reading to the topic can be found here: JSF 1.2 on Wildfly 8 Final - weld-core-jsf is still referencing JSF 2.2 API

@jarda_mlejnek found out what was going on. The problem was in the jBPM framework.

Thing is, all the factories (ContextFactory, ApplicationFactory, PartialViewContextFactory, ...) were correctly initialized during application deploy - and were in place even when we were moving around in the GUI. Problem occured when we accessed webpage which started new jBPM process (some parts of the GUI are written that way, especially multi-step forms).

For locating factories, Mojarra uses FactoryFinder class which tracks current factories by searching a hashmap with a classloader as a key. When jBPM process started, it changed the classloader Faces have been seeing to its own (org.jbpm.instantiation.ProcessClassLoader), which, in turn, reinitialized Mojarra - and for this classloader no factories were created. From the Mojarra point of view, all factories were gone. It is possible this is some weird case of JAVASERVERFACES-3189 but, since our scenario is something highly nonstandard, we didn't report this behavior.

We solved this by patching Mojarra the way that re-registration of factories fired from jBPM does nothing and application works with factories that were created during deploy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM