Jetty清理会话错误与视图范围的bean

时间:2014-12-26 10:21:22

标签: maven jsf heroku jetty cdi

我正在尝试将Tomcat应用程序移植到JettyRunner 9.2我想将我的应用程序移动到Heroku,所以我需要使用嵌入式服务器或JettyRunner启动它。我认为JettyRunner最简单,因为我可以保留WAR格式,并且如果需要的话可以轻松移开。

非常感谢任何帮助。如果我不能尽快让它工作,我可能会尝试嵌入Tomcat,或者查看不需要我更换容器的托管。

如果使用Jetty的其他方法 - 也许嵌入式Jetty会更容易,请告诉我并告诉我一些细节。

所以,对应用程序的行为。该应用程序似乎移植良好并开始正常,但我在登录时收到错误。这是例外

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)

这是我的jetty和jsf依赖项:

    <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>

这是我的pom的maven jetty插件部分:

        <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>

我的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>

码头的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>

码头-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>

最后,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>

3 个答案:

答案 0 :(得分:3)

此问题是由JSF实现中与ViewScoped bean相关的错误引起的,其中描述了here所描述的错误在JSF 2.29和2.28中。该修复程序在2.30,尚未发布。

我试过回溯2.2版本中的版本。 2.27在此错误消失之前,ViewScoped bean中会出现其他错误。

看起来View Scoped bean基本上在jsf 2.2中被破坏(据我所知),所以作为临时措施,我已将所有View Scoped bean更改为Request Scoped。这可以避免错误。

答案 1 :(得分:2)

我刚刚做了以下解决方法。 我正在使用Jetty 9.2,CDI 1.2(Weld)和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>

答案 2 :(得分:0)

我对linux系统上的7.0.55 tomcat也有同样的问题。 对我来说,JAVASERVERFACES-3450不是问题,因为这个票证引用了已被销毁的视图范围bean的空实例。

我们在ViewScopeContextManager.destroyBeans(未知来源)中发生异常是因为 beanManager 的空实例。

在Windows系统上使用Tomcat 7.0.55,一切正常...... :(