3

I am trying to port a Tomcat app to JettyRunner 9.2 I want to move my app to Heroku, so I need to start it with either an embedded server, or JettyRunner. I thought JettyRunner would be easiest, as I could keep a WAR format, and make it easy to port away if necessary.

Any help would be much appreciated. If I can't get it to work soon, I may try embedded Tomcat, or look at hosting which doesn't require me to change my container.

If a different method of using Jetty - maybe embedded Jetty would be easier, please let me know and point me to some details.

So, to the app behaviour. The app seems to be ported fine and starts ok, but I'm getting an error on login. Here is the exception

2014-12-26 05:18:21.189:WARN:oejs.session:org.eclipse.jetty.server.session.HashSessionManager@69f63d95Timer: Problem scavenging sessions
java.lang.NullPointerException
    at com.sun.faces.application.view.ViewScopeContextManager.destroyBeans(Unknown Source)
    at com.sun.faces.application.view.ViewScopeContextManager.sessionDestroyed(Unknown Source)
    at com.sun.faces.application.view.ViewScopeManager.sessionDestroyed(Unknown Source)
    at com.sun.faces.application.WebappLifecycleListener.sessionDestroyed(Unknown Source)
    at com.sun.faces.config.ConfigureListener.sessionDestroyed(Unknown Source)
    at org.eclipse.jetty.server.session.AbstractSessionManager.removeSession(AbstractSessionManager.java:772)
    at org.eclipse.jetty.server.session.AbstractSession.timeout(AbstractSession.java:302)
    at org.eclipse.jetty.server.session.HashSessionManager.scavenge(HashSessionManager.java:358)
    at org.eclipse.jetty.server.session.HashSessionManager$Scavenger.run(HashSessionManager.java:84)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Here are my jetty and jsf dependencies:

    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.2.6.v20141205</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.2.6.v20141205</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.faces</artifactId>
        <version>2.2.9</version>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>

Here is my maven jetty plugin section of my pom:

        <plugin>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>${org.eclipse.jetty.version}</version>
            <configuration>
                <webApp>
                    <overrideDescriptor>src/main/webapp/WEB-INF/jetty-web-override.xml</overrideDescriptor>
                </webApp>
                <contextXml>src/main/webapp/WEB-INF/jetty-context.xml</contextXml>
            </configuration>
        </plugin>

Listeners in my web.xml

<listener>
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
<listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

jetty-web-override.xml

<web-app version="3.0" 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_3_0.xsd">

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

<resource-env-ref>
    <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>

jetty-env.xml

    <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
    <New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>
        <Ref id="webAppCtx"/>
    </Arg>
    <Arg>BeanManager</Arg>
    <Arg>
        <New class="javax.naming.Reference">
            <Arg>javax.enterprise.inject.spi.BeanManager</Arg>
            <Arg>org.jboss.weld.resources.ManagerObjectFactory</Arg>
            <Arg/>
        </New>
    </Arg>
</New>
</Configure>

and finally, jetty.context:

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" 

"http://www.eclipse.org/jetty/configure.dtd">

<Configure class="org.eclipse.jetty.webapp.WebAppContext">

<Set name="serverClasses">
    <Array type="java.lang.String">
        <Item>-org.eclipse.jetty.servlet.ServletContextHandler.Decorator</Item>
    </Array>
</Set>
</Configure>
Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136
Ramesh
  • 613
  • 1
  • 10
  • 28

3 Answers3

3

This issue is caused by a bug in the JSF implementation to do with ViewScoped beans, which is described here The described bug is in JSF 2.29 and 2.28. The fix is in 2.30, which is not yet released.

I tried going back versions in the 2.2 heirarchy. 2.27 and before this bug disappeared, but other bugs occur in ViewScoped beans.

It looks like View Scoped beans are basically broken in jsf 2.2 (as far as I looked), so as a temporary measure, I have changed all my View Scoped beans to Request Scoped. This avoids the error.

Ramesh
  • 613
  • 1
  • 10
  • 28
2

I just made the following workaround. I'm using Jetty 9.2, CDI 1.2 (Weld) and Mojarra 2.28.

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.spi.CDI;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.ExternalContextFactory;
import javax.faces.context.ExternalContextWrapper;

import com.sun.faces.util.Util;

public class CDIViewScopeFixExternalContextFactory extends ExternalContextFactory{

private final ExternalContextFactory wrapped;

public CDIViewScopeFixExternalContextFactory(ExternalContextFactory wrapped){
    this.wrapped = wrapped;
}

@Override
public ExternalContext getExternalContext(Object context, Object request,
        Object response) throws FacesException {
    ExternalContext externalContext = getWrapped().getExternalContext(context, request, response);
    CDIViewScopeWorkaround wrapper = new CDIViewScopeWorkaround(externalContext);
    return wrapper;
}


@Override
public ExternalContextFactory getWrapped() {
    return this.wrapped;
}

private static class CDIViewScopeWorkaround extends ExternalContextWrapper{

    private static String CDI_KEY;
    static {
        try {
            Field f = Util.class.getDeclaredField("CDI_AVAILABLE_PER_APP_KEY");
            f.setAccessible(true);
            CDI_KEY  = (String) f.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private final ExternalContext wrapped;

    public CDIViewScopeWorkaround(ExternalContext wrapped){
        this.wrapped = wrapped;
    }


    @Override
    public ExternalContext getWrapped() {
        return wrapped;
    }

    @Override
    public Map<String, Object> getApplicationMap() {
        MapFix mapFix = new MapFix(super.getApplicationMap());
        return mapFix;
    }
}

private static class MapFix extends MapWrapper<String,Object>{

    public MapFix(Map<String, Object> delegate) {
        super(delegate);
    }

    @Override
    public Object get(Object key) {
        if(CDIViewScopeWorkaround.CDI_KEY.equals(key)){
            return CDI.current().getBeanManager();
        }
        return super.get(key);
    }
}


private static class MapWrapper<K,V> implements Map<K,V>{

    private Map<K,V> delegate;

    public int size() {
        return delegate.size();
    }

    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    public boolean containsKey(Object key) {
        return delegate.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return delegate.containsValue(value);
    }

    public V get(Object key) {
        return delegate.get(key);
    }

    public V put(K key, V value) {
        return delegate.put(key, value);
    }

    public V remove(Object key) {
        return delegate.remove(key);
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        delegate.putAll(m);
    }

    public void clear() {
        delegate.clear();
    }

    public Set<K> keySet() {
        return delegate.keySet();
    }

    public Collection<V> values() {
        return delegate.values();
    }

    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return delegate.entrySet();
    }

    public boolean equals(Object o) {
        return delegate.equals(o);
    }

    public int hashCode() {
        return delegate.hashCode();
    }

    public MapWrapper(Map<K,V> delegate){
        this.delegate = delegate;
    }
}
}

faces-config.xml

    <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.ord/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <application>
       …
    </application>

     <factory>
        <external-context-factory>your.package.CDIViewScopeFixExternalContextFactory</external-context-factory>
    </factory>
</faces-config>
Marco Bettiol
  • 531
  • 3
  • 12
0

I have the same issue with a 7.0.55 tomcat on a linux system. For me, JAVASERVERFACES-3450 is not the problem, because this ticket refers to null instances of view scoped beans which are already destroyed.

Our exception in ViewScopeContextManager.destroyBeans(Unknown Source) occurs because of a null instance of beanManager.

With a Tomcat 7.0.55 on a windows system, everything works... :(

Ginkgochris
  • 455
  • 4
  • 25