2013-10-08 3 views
0

У меня проблема с моим проектом для исследований. У меня простой проект с одним сервлетом, и мне нужно иметь некоторые CDI-компоненты с различными областями. Эта часть была действительно простой, но я должен быть в состоянии ввести HttpSession в каждую из моих CDI beans. Чтобы решить эту проблему, я заставил ServletRequestListener получить объект HttpServletRequest, я храню этот объект в объектно-ориентированном компоненте в объекте ThreadLocal и в этом компоненте у меня есть метод производителя для объекта HttpSession из сохраненного HttpServletRequest. После этого я могу вводить HttpSession в любой CDI-компонент, кроме компонентов сеанса. Сессия правильно вводится этому компоненту после инициализации сеанса, но для второго запроса в том же сеансе у меня есть исключение нулевого указателя, потому что сеансовый компонент создается (или десериализован) перед методом RequestInitialized, а мой производитель возвращает значение null, что является незаконным accoprding to stacktrace ,HttpSession CDI-инъекция в проекте сервлета

Вот StackTrace из второго запроса в одном сеансе:

org.jboss.weld.exceptions.IllegalProductException: WELD-000052 Cannot return null from a non-dependent producer method: [method] @Produces @RequestScoped public pl.lab2.cdi.producers.SessionObjectsProducer.getSession() 
    org.jboss.weld.bean.AbstractProducerBean.checkReturnValue(AbstractProducerBean.java:217) 
    org.jboss.weld.bean.AbstractProducerBean.create(AbstractProducerBean.java:300) 
    org.jboss.weld.context.AbstractContext.get(AbstractContext.java:107) 
    org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:90) 
    org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:104) 
    org.jboss.weld.proxies.HttpSession$776413422$Proxy$_$$_WeldClientProxy.getId(HttpSession$776413422$Proxy$_$$_WeldClientProxy.java) 
    pl.lab2.bean.SessionBean.toString(SessionBean.java:31) 
    java.lang.String.valueOf(String.java:2854) 
    java.lang.StringBuilder.append(StringBuilder.java:128) 
    org.jboss.weld.context.SerializableContextualInstanceImpl.toString(SerializableContextualInstanceImpl.java:60) 
    java.lang.String.valueOf(String.java:2854) 
    java.lang.StringBuilder.append(StringBuilder.java:128) 
    org.jboss.weld.context.beanstore.AttributeBeanStore.attach(AttributeBeanStore.java:109) 
    org.jboss.weld.context.AbstractBoundContext.activate(AbstractBoundContext.java:66) 
    org.jboss.weld.servlet.WeldListener.requestInitialized(WeldListener.java:141) 
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) 
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) 
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) 
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) 
    java.lang.Thread.run(Thread.java:724) 

И источники:

Слушатель

package pl.lab2.servlet; 

import org.apache.log4j.Logger; 
import pl.lab2.cdi.BeanManagerHelper; 
import pl.lab2.servlet.events.literal.*; 

import javax.servlet.*; 
import javax.servlet.http.HttpServletRequest; 

public class ServletListener implements ServletRequestListener { 
    private static final Logger log = Logger.getLogger(ServletListener.class); 

    @Override 
    public void requestDestroyed(ServletRequestEvent sre) { 
     log.info("request destroyed event"); 
     BeanManagerHelper.getBeanManagerByJNDI().fireEvent((HttpServletRequest) sre.getServletRequest(), DestroyedLiteral.INSTANCE); 
    } 

    @Override 
    public void requestInitialized(ServletRequestEvent sre) { 
     log.info("request initialized event"); 
     BeanManagerHelper.getBeanManagerByJNDI().fireEvent((HttpServletRequest) sre.getServletRequest(), InitializedLiteral.INSTANCE); 
    } 
} 

Держатель

package pl.lab2.servlet; 

import org.apache.log4j.Logger; 
import pl.lab2.servlet.events.Destroyed; 
import pl.lab2.servlet.events.Initialized; 

import javax.enterprise.context.ApplicationScoped; 
import javax.enterprise.event.Observes; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 

@ApplicationScoped 
public class ServletObjectHolder { 
    private static final Logger log = Logger.getLogger(ServletObjectHolder.class); 
    private final ThreadLocal<HttpServletRequest> threadRequest = new ThreadLocal<HttpServletRequest>(); 

    public HttpSession getSession() { 
     log.info("get session"); 
     if (threadRequest.get() != null) { 
      return threadRequest.get().getSession(); 
     } 
     return null; 
    } 

    public void servletRequestInitialized(@Observes @Initialized final HttpServletRequest request) { 
     log.info("receive request initialization"); 
     threadRequest.set(request); 
    } 

    public void servletRequestDestroyed(@Observes @Destroyed final HttpServletRequest request) { 
     log.info("receive request destroyed"); 
     threadRequest.set(null); 
    } 
} 

Производитель

package pl.lab2.cdi.producers; 

import org.apache.log4j.Logger; 
import pl.lab2.servlet.ServletObjectHolder; 

import javax.enterprise.context.RequestScoped; 
import javax.enterprise.inject.Produces; 
import javax.inject.Inject; 
import javax.servlet.http.HttpSession; 
import java.io.Serializable; 

public class SessionObjectsProducer implements Serializable { 
    private static final Logger log = Logger.getLogger(SessionObjectsProducer.class); 

    @Inject 
    private ServletObjectHolder servletObjectHolder; 

    @Produces 
    @RequestScoped 
    public HttpSession getSession() { 
     log.info("get session"); 
     return servletObjectHolder.getSession(); 
    } 
} 

Session Bean

package pl.lab2.bean; 

import javax.enterprise.context.SessionScoped; 
import javax.inject.Inject; 
import javax.inject.Named; 
import javax.servlet.http.HttpSession; 
import java.io.Serializable; 

@SessionScoped 
@Named 
public class SessionBean implements Serializable { 
    private String name; 
    @Inject 
    private HttpSession session; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @Override 
    public String toString() { 
     return "SessionBean{" + 
       "name='" + name + "', " + 
       "sessionId='" + session.getId() + "'" + 
       '}'; 
    } 
} 

И сервлет:

package pl.lab2.servlet; 

import org.apache.log4j.Logger; 
import org.jboss.weld.context.ConversationContext; 
import org.jboss.weld.context.http.Http; 
import pl.lab2.bean.ApplicationBean; 
import pl.lab2.bean.ConversationBean; 
import pl.lab2.bean.RequestBean; 
import pl.lab2.bean.SessionBean; 
import pl.lab2.cdi.producers.SessionObjectsProducer; 

import javax.enterprise.context.Conversation; 
import javax.inject.Inject; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import java.io.IOException; 
import java.io.PrintWriter; 

public class ServletDispatcher extends HttpServlet { 
    private static final Logger log = Logger.getLogger(ServletDispatcher.class); 
    @Inject 
    private ApplicationBean applicationBean; 
    @Inject 
    private SessionBean sessionBean; 
    @Inject 
    private ConversationBean conversationBean; 
    @Inject 
    private RequestBean requestBean; 
    @Inject 
    private Conversation conversation; 
    @Inject 
    @Http 
    private ConversationContext conversationContext; 
    @Inject 
    private SessionObjectsProducer sessionObjectsProducer; 

    @Override 
    public void init() throws ServletException { 
     super.init(); 
     conversationContext.setParameterName("cId"); 
    } 

    @Override 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, 
      IOException { 
     this.request(request, response); 
    } 

    @Override 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, 
      IOException { 
     this.request(request, response); 
    } 

    private void request(HttpServletRequest request, HttpServletResponse response) throws IOException { 
     log.info("request started in session " + request.getSession().getId()); 
     String cid = request.getParameter(conversationContext.getParameterName()); 
     if (cid != null) { 
      conversationContext.activate(cid); 
     } else { 
      conversationContext.activate(); 
     } 

     takeActions(request); 
     updateData(request); 
     printState(response.getWriter(), request); 
    } 

    private void printState(PrintWriter writer, HttpServletRequest request) { 
     writer.print("<div>"); 
     writer.print("<div>Beans:</div>"); 
     writer.print(applicationBean.toString() + "<br />"); 
     writer.print(sessionBean.toString() + "<br />"); 
     writer.print(conversationBean.toString() + "<br />"); 
     writer.print(requestBean.toString() + "<br />"); 
     writer.print("</div>"); 
     writer.print("<div>"); 
     writer.print("<div>Data:</div>"); 
     writer.print("session id: " + request.getSession().getId() + "<br />"); 
     writer.print("conversation id: " + conversation.getId() + "<br />"); 
     writer.print("</div>"); 
    } 

    private void takeActions(HttpServletRequest request) { 
     if ("begin".equals(request.getParameter("conversationState"))) conversation.begin(); 
     else if ("end".equals(request.getParameter("conversationState"))) conversation.end(); 
    } 

    private void updateData(HttpServletRequest request) { 
     if (request.getParameter("application") != null) { 
      applicationBean.setName(request.getParameter("application")); 
     } 
     if (request.getParameter("session") != null) { 
      sessionBean.setName(request.getParameter("session")); 
     } 
     if (request.getParameter("conversation") != null) { 
      conversationBean.setName(request.getParameter("conversation")); 
     } 
     if (request.getParameter("request") != null) { 
      requestBean.setName(request.getParameter("request")); 
     } 
    } 
} 

Чтобы сделать это я использую шов/источники сервлетные образуют GitHub как пример.

Я загрузил свои текущие коды на dropbox, просто создайте, разверните на JBoss как 7.1.1.Final, перейдите на localhost: 8080/lab2, дважды нажмите F5, и вы увидите проблему.

+0

У серпа сервака были некоторые проблемы. Вы просмотрели модуль сервлета в [Apache DeltaSpike] (https://github.com/apache/deltaspike/tree/master/deltaspike/modules/servlet)? – LightGuard

+0

Спасибо за ответ :) Я не нашел его раньше, но вижу несколько различий, и ни одна из них не работает :( Я пробовал раньше, чтобы получить httpServletRequest из фильтра, без эффекта Когда я пытаюсь сделать свой держатель статический класс ther не отличается от , когда я устанавливаю HttpSession как SessionScoped У меня есть такое исключение: rg.jboss.weld.exceptions.IllegalProductException: WELD-000053 Производители не могут объявить пассивирующую область и возвращать несериализуемый класс: [method] @ Производит @ SessionScoped public pl.lab2.cdi.producers.SessionObjectsProducer.getSession() – gandalfml

+0

Хм, может быть что-то в банке сервлетов сварки, потому что это не полностью интегрированный CDI. – LightGuard

ответ

1

Что-то, как просто следующий будет делать то, что вы хотите, и работать как шарм:

import javax.enterprise.context.RequestScoped; 
import javax.enterprise.inject.Produces; 
import javax.servlet.ServletRequestEvent; 
import javax.servlet.ServletRequestListener; 
import javax.servlet.annotation.WebListener; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 

// NOTE: this produces a request scoped session object because that's what the OP seems to want 
@WebListener 
public class SessionProducer implements ServletRequestListener { 

    private static ThreadLocal<HttpSession> SESSIONS = new ThreadLocal<>(); 

    @Override 
    public void requestDestroyed(ServletRequestEvent sre) { 
     SESSIONS.remove(); 
    } 

    @Override 
    public void requestInitialized(ServletRequestEvent sre) { 
     SESSIONS.set(HttpServletRequest.class.cast(sre.getServletRequest()).getSession()); 
    } 

    @Produces @RequestScoped 
    protected HttpSession getSession() { 
     return SESSIONS.get(); 
    } 

} 

Наслаждайтесь!

+0

К сожалению, это не сработает. Я добавляю регистратор, чтобы узнать порядок вызовов методов в вашем классе. Для получения первого запроса (инициализация из HTTPSession) заказ был: SessionProducer.requestInitialized SessionProducer.getSession SessionProducer.requestDestroyed И это было хорошо, но для второго запроса первый метод, называемый был SessionProducer.getSession, и это было до SessionProducer.requestInitialized и из-за этого getSession возвращает null и jboss дает мне исключение WELD-000052 Не удается вернуть значение null из метода независящего производителя. – gandalfml

+0

@gandalfml Он работает на GlassFish 3. Какую версию JBoss вы используете, может быть, я могу воспроизвести ее. – rdcrng

+0

Я развертываю JBoss как 7.1.1.Final – gandalfml

1

Я выяснил, что проблема была в моем методе toString в сеансе. В этом методе я попытался получить идентификатор сеанса, но по каким-то причинам (например, по протоколированию) cdi вызывает метод toString перед инициализацией запроса. Когда я удалял доступ к объекту сеанса из метода toString, все работает нормально.

0

Использование JSF, на самом деле вы будете иметь доступ до вашей HttpSession с FacesContext ...

у нас не все конфигурации и здесь я не вижу Цель этой конфигурации не один использовать сервлет как это и вас может перейти к сеансу http через параметр запроса, а не с инъекцией ...

Смежные вопросы