10 Replies Latest reply on May 9, 2012 4:09 PM by ngriffin7a

    Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge

    turner2448

      Hi

       

      I've seen various discussions around the above combination of technologies, but none with any definitive resolution.

       

      I have a JSF 2 portlet built using the portletfaces.org bridge (with icefaces) - the default Liferay 6 portlet framework from Liferay's plugins-sdk.

       

      The JSF portlet uses CDI for managed beans. I noticed the entry below that supposedly allowed Weld to operate in a portlet 2 environment by providing a cross context filter:

       

      https://github.com/weld/core/pull/140

       

      The problem is that I cannot get this to work, I get the error message java.lang.illegalstateexception: Not in a Servlet environment.

       

      I wondered if you experts would know whether Weld (running natively within a EE server such as JBOSS AS7 or in Tomcat 6\7 using the weld-servlet.jar) should operate in a portlet 2 environment with this patch applied?

       

      Cheers

       

      Tony

        • 1. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
          mstruk

          "Not in a Servlet environment" sounds like an old - pre-JBoss-AS7 version of Weld (1.1.2.AS7).

           

          The problem with that one was that it presupposed that facesContext.getExternalContext().getContext() would always return an instance of ServletContext which may not be the case when you use a portlet bridge (see WELD-150).

           

          The above patch doesn't work with WELD-1.0.1.SP3 for example.

          • 2. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
            turner2448

            Hi Marko

             

            This is using the latest Weld build, 1.1.6 final which has the cross context filter in the weld-servlet jar.

             

            It seems like you're saying that it should work in a portlet environment with the cross context filter included. Do you know if people are using it successfully?

             

            Cheers

             

            Tony

            • 3. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
              mstruk

              Can you post a full stacktrace, so we can see where the "Not in a Servlet environment" message originates?

               

              The patch only works as long as there are not some other issues present - like in your case - expectations about environment.

               

              Stack trace will make it clear where the issue originates, and if it's Weld issue or something else.

              • 4. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                turner2448

                Hi Marko

                 

                Here's the exception thrown by Tomcat 7.

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                12:45:51,144 ERROR [render_portlet_jsp:154] java.lang.IllegalStateException: Not in a servlet environment!
                at org.jboss.weld.environment.servlet.jsf.WeldApplication.beanManager(WeldApplication.java:103)
                at org.jboss.weld.environment.servlet.jsf.WeldApplication.init(WeldApplication.java:77)
                at org.jboss.weld.environment.servlet.jsf.WeldApplication.delegate(WeldApplication.java:85)
                at org.jboss.weld.environment.servlet.jsf.ForwardingApplication.getViewHandler(ForwardingApplication.java:277)
                at com.sun.faces.context.FacesContextImpl.isPostback(FacesContextImpl.java:210)
                at org.portletfaces.bridge.BridgeImpl.doFacesRequest(BridgeImpl.java:360)
                at org.portletfaces.bridge.GenericFacesPortlet.doView(GenericFacesPortlet.java:181)
                at javax.portlet.GenericPortlet.doDispatch(GenericPortlet.java:328)
                at javax.portlet.GenericPortlet.render(GenericPortlet.java:233)
                at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:100)
                at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:64)
                at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:93)
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
                at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:72)
                at org.jboss.weld.servlet.WeldCrossContextFilter.doFilter(WeldCrossContextFilter.java:62)
                at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
                at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
                at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:70)

                 

                web.xml is here (I've tried changing the servlet container from version 2.5 to version 3.0 but to no affect):

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                <?

                 

                xml version="1.0"

                ?>

                 

                <

                 

                web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

                >

                 

                <context-param

                >

                 

                <param-name>com.sun.faces.expressionFactory</param-name

                >

                 

                <param-value>org.jboss.el.ExpressionFactoryImpl</param-value

                >

                 

                </context-param

                >

                 

                <context-param

                >

                 

                <param-name>org.icefaces.uniqueResourceURLs</param-name

                >

                 

                <param-value>false</param-value

                >

                 

                </context-param

                >

                 

                <context-param

                >

                 

                <param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name

                >

                 

                <param-value>true</param-value

                >

                 

                </context-param

                >

                 

                <listener

                >

                 

                <listener-class>com.sun.faces.config.ConfigureListener</listener-class>

                 

                </listener>

                 

                <listener>

                 

                <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>

                 

                </listener

                >

                 

                <servlet

                >

                 

                <servlet-name>Faces Servlet</servlet-name

                >

                 

                <servlet-class>javax.faces.webapp.FacesServlet</servlet-class

                >

                 

                <load-on-startup>1</load-on-startup

                >

                 

                </servlet

                >

                 

                <servlet

                >

                 

                <servlet-name>ICEfaces Compatibility Resource Servlet</servlet-name

                >

                 

                <servlet-class>com.icesoft.faces.webapp.CompatResourceServlet</servlet-class

                >

                 

                <load-on-startup>1</load-on-startup

                >

                 

                </servlet

                >

                 

                <servlet-mapping

                >

                 

                <servlet-name>Faces Servlet</servlet-name

                >

                 

                <url-pattern>/icefaces/*</url-pattern

                >

                 

                </servlet-mapping

                >

                 

                <servlet-mapping

                >

                 

                <servlet-name>ICEfaces Compatibility Resource Servlet</servlet-name

                >

                 

                <url-pattern>/xmlhttp/*</url-pattern

                >

                 

                </servlet-mapping

                >

                 

                 

                 

                <filter

                >

                 

                <filter-name>WeldCrossContextFilter</filter-name

                >

                 

                <filter-class>org.jboss.weld.servlet.WeldCrossContextFilter</filter-class

                >

                 

                </filter

                >

                 

                 

                <filter-mapping

                >

                 

                <filter-name>WeldCrossContextFilter</filter-name

                >

                 

                <url-pattern>/*</url-pattern

                >

                 

                <dispatcher>INCLUDE</dispatcher

                >

                 

                <dispatcher>FORWARD</dispatcher

                >

                 

                <dispatcher>ERROR</dispatcher

                >

                 

                </filter-mapping

                >

                 

                <resource-env-ref

                >

                 

                <description>Object factory for the CDI Bean Manager</description

                >

                 

                <resource-env-ref-name>BeanManager</resource-env-ref-name

                >

                 

                <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type

                >

                </

                 

                resource-env-ref>

                 

                </

                 

                web-app

                >

                 

                Cheers

                 

                Tony

                • 5. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                  mstruk

                  This looks like a Weld issue indeed.

                   

                  Can you try build Weld from sources:

                   

                  git clone https://github.com/weld/core.git weld-core

                  cd weld-core

                   

                  (you can use master or checkout tag 1.1.6.Final if you want)

                   

                  Edit the following file: environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/jsf/WeldApplication.java

                   

                  Overwrite beanManager() method with the following implementation:

                   

                      private BeanManager beanManager() {

                          FacesContext facesContext;

                          if (beanManager == null && (facesContext = FacesContext.getCurrentInstance()) != null) {

                              ServletContext ctx = null;

                              Object obj = facesContext.getExternalContext().getContext();

                              if (!(obj instanceof ServletContext)) {

                                  Class clazz = obj.getClass();

                                  try {

                                      Method m = clazz.getMethod("getServletContext");

                                      ctx = (ServletContext) m.invoke(obj);

                                  } catch (Exception e) {

                                     throw new IllegalStateException("Not in a servlet environment!");

                                  }

                              }

                              ctx = (ServletContext) obj;

                              if (ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME) == null) {

                                  return null;

                              }

                              this.beanManager = (BeanManager) ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME);

                          }

                   

                   

                          return beanManager;

                      }

                   

                   

                  Build Weld:

                   

                  mvn clean install -DskipTests

                   

                  And try with this version (you should use environments/servlet/core/target/weld-servlet-core-*.jar).

                  • 6. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                    turner2448

                    Hi Marko

                     

                    I've built the jar file (weld-servlet-core-1.2.0-SNAPSHOT) as per your instructions and have deployed this to the lib directory of the portlet.

                     

                    The portlet doesn't deploy to the portal because it is mssing org.jboss.weld.servlet.api.helpers.ForwardingServletListener. This class is in the original weld-servlet.jar that I have now replaced with the rebuilt JAR.

                     

                    I'm assuming that you meant to replace one for the other (otherwise we would get classloading problems when loading the modified WeldApplication class).

                     

                    It just seems that the original jar file contains many more classes than the new jar, i.e. the new jar is a subset of the old one.

                     

                    Cheers

                     

                    Tony

                    • 7. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                      mstruk

                      Then try to patch 1.1.6.Final version since this is the one you use, so you won't have jar content mismatches.

                      • 8. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                        turner2448

                        Hi Marko

                         

                        Thanks for your help with this.

                         

                        I've patched the jar and deployed as suggested. Looking at the code I don't think that casting a portletcontext to a servletcontext will work within a portlet environment. Aside from the fact that you get a class cast exception, even if it were successful you would likely run into all sorts of problems later on.

                         

                        The Weld package would need to be portlet aware throughout in order for this to be a viable solution I guess.

                         

                        I'll post back if anything comes up.

                         

                        Cheers

                         

                        Tony

                        • 9. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                          mstruk

                          JSF API is loose at the point of external contexts precisely in order to allow different environments.

                          Method facesContext.getExternalContext().getContext() really returns a java.lang.Object type. And it can be anything.

                           

                          I guess that for all the different portlet bridges this should return a javax.portlet.PortletContext on which Weld can then call getAttribute() which should be delegated to the underlying ServletContext.

                           

                          The way it's written did work for me a while back with portletfaces bridge and Liferay 6, so I suppose it would work for you as well. I'm primarily interested if this is the only issue with Weld or is there more once you get beyond this one.

                           

                          A more proper way would then be something like:

                           

                              private BeanManager beanManager() {

                                  FacesContext facesContext;

                                  if (beanManager == null && (facesContext = FacesContext.getCurrentInstance()) != null) {

                                      Object obj = facesContext.getExternalContext().getContext();

                           

                                      if (obj instanceof ServletContext) {

                                          ServletContext ctx = (ServletContext) obj;

                                          if (ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME) == null) {

                                              return null;

                                          }

                                          this.beanManager = (BeanManager) ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME);

                                      } else if (obj instanceof javax.portlet.PortletContext) {

                                          javax.portlet.PortletContext ctx = (javax.portlet.PortletContext) obj;

                           

                                          if (ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME) == null) {

                                              return null;

                                          }

                                          this.beanManager = (BeanManager) ctx.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME);

                                      } else {

                                             throw new IllegalStateException("Not in a servlet or portlet environment!");

                                      }

                                  }

                           

                                  return beanManager;

                              }

                           

                           

                          I didn't test this, but it might work.

                           

                          Please, give it a try and report back the outcome.

                          • 10. Re: Weld\CDI, JSF 2, Liferay 6 portlet using portletfaces bridge
                            ngriffin7a

                            Latest results of my testing of Weld 1.1.7 with Liferay Portal can be found here:

                            http://issues.liferay.com/browse/FACES-1211