2011-01-21 14 views
7

¿Hay alguna manera de recuperar una sesión de un POJO? O, en última instancia, para recuperar un frijol de un POJO.Recuperando el contexto, la sesión y la solicitud del servlet en un POJO fuera del contenedor

Para aclarar:

Básicamente estoy creando un grano desde un servlet y necesito acceder a las propiedades de ese frijol desde fuera del contenedor web (de un POJO). No puedo pasar la solicitud al pojo; y la solicitud es necesaria para recuperar la sesión.

Más específicamente tengo una aplicación web que utiliza el marco Cactus para ejecutar pruebas JUnit desde una interfaz web. Sin embargo, el servlet que invoca el corredor de prueba JUnit se compila en un jar; Agregué menús desplegables adicionales para cambiar la configuración desde la cual se leerá la prueba JUnit para cambiar entre diferentes entornos (clústeres WLI), por lo que dado que el servlet de corredor ya está compilado, no puedo modificarlo para manejar los parámetros adicionales de los múltiples entornos. He intentado el enfoque de persistencia de escribir en un archivo .dat para el cual la prueba JUnit se leerá a través de una clase Reader; También he probado el enfoque de bean que finalmente no era accesible desde la prueba JUnit.

+0

¿Puede por favor explicar un poco sobre su problema? – Sid

+0

Describe mejor tu problema. Claramente tienes una aplicación web que está manipulando datos. Parece que necesita almacenarlo y luego hacer referencia externa a la aplicación web. – DwB

+0

Bien, vea las ediciones anteriores, gracias. – TheWolf

Respuesta

11

Sólo y sólo si su POJO se está ejecutando en el mismo hilo como el HttpServletRequest está corriendo, entonces usted será capaz de lograr esto con ayuda de ThreadLocal<T>.

Crear la clase siguiente:

public final class YourContext implements AutoCloseable { 

    private static ThreadLocal<YourContext> instance = new ThreadLocal<>(); 

    private HttpServletRequest request; 
    private HttpServletResponse response; 

    private YourContext(HttpServletRequest request, HttpServletResponse response) { 
     this.request = request; 
     this.response = response; 
    } 

    public static YourContext create(HttpServletRequest request, HttpServletResponse response) { 
     YourContext context = new YourContext(request, response); 
     instance.set(context); 
     return context; 
    } 

    public static YourContext getCurrentInstance() { 
     return instance.get(); 
    } 

    @Override  
    public void close() { 
     instance.remove(); 
    } 

    public HttpServletRequest getRequest() { 
     return request; 
    } 

    public HttpSession getSession() { 
     return request.getSession(); 
    } 

    public ServletContext getServletContext() { 
     return request.getServletContext(); 
    } 

    // ... (add if necessary more methods here which return/delegate the request/response).  
} 

Implementar javax.servlet.Filter que hace lo siguiente en doFilter() método y se asigna en una url-pattern de interés, por ejemplo /* o en el servlet-name de su servlet del controlador frontal.

@Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException { 
    HttpServletRequest request = (HttpServletRequest) req; 
    HttpServletResponse response = (HttpServletResponse) res; 

    try (YourContext context = YourContext.create(request, response)) { 
     chain.doFilter(request, response); 
    } 
} 

Tenga en cuenta la importancia de la declaración try-with-resources. Garantiza que se llamará al YourContext#close() después de que el filtro haya hecho su trabajo y se borrará el recurso ThreadLocal. De lo contrario, el hilo aún lo incluirá cuando se lo recicle para otra solicitud HTTP.

Y así es como se podría utilizar en el POJO:

YourContext context = YourContext.getCurrentInstance(); 
HttpSession session = context.getSession(); 

Todo esto es básicamente también cómo los objetos de Context el marco media MVC obras, como JSF de FacesContext y el de Wicket.

Dicho eso, ¿has mirado CDI? Tal vez es más fácil hacer que los artefactos sean administrados por CDI para que pueda simplemente @Inject uno en el otro.

+0

Gracias, esto suena genial. ¿A qué paquete pertenece ThreadLocal con plantilla? El ThreadLocal nativo de JDK no acepta plantillas. – TheWolf

+0

Ok, lo encontré en JDK 6, estoy usando WLI 8 por lo que estoy limitado a JDK 1.4, ¿funcionará bien el objeto sin plantilla? – TheWolf

+1

El enlace 'ThreadLocal ' en mi respuesta apunta a 'java.lang.ThreadLocal' javadoc. No estoy seguro de lo que quiere decir con "plantillas", pero si realmente se está refiriendo al parámetro de tipo genérico '' (y tomando en cuenta su uso constante del término "POJO" pasado de moda), sospecho que no está 't en Java 1.5 todavía. En ese caso, simplemente omita '' en el ejemplo del código y aplique conversiones '(Contexto)' donde corresponda. Como indica el javadoc, el 'ThreadLocal' está disponible desde 1.2. – BalusC

2

A Pojo es un objeto antiguo de Java simple. POJOS no tiene nada que ver con las sesiones.

La sesión https está disponible en el objeto de solicitud.

Salida esto específicamente la interfaz HttpServletRequest

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/index.html

, y el método getSession().

Para la parte 'bean' de su pregunta. Un bean es una clase Java que cumple con 3 estándares.

  1. Sin arg constructor
  2. setters y getters para acceder a los campos privados
  3. Implementa serializable.

Un POJO es un frijol si sigue esas convenciones.

+0

Me refiero a recuperar una sesión web generada a partir de una sesión web (es decir, a partir de algún tipo de solicitud) desde un POJO fuera del contenedor web. (La sesión no viene del POJO, por supuesto). – TheWolf

+0

@Vapen 'a POJO fuera del contenedor web' de ninguna manera, necesita persistir los datos en algún lugar o de cualquier forma que necesite transferir datos –

+0

He intentado el enfoque de persistencia escribiendo los parámetros en un archivo .dat y encontré un archivo condición de carrera a las solicitudes concurrentes que acceden al archivo .dat. – TheWolf

2

Suponiendo que usted se refiere a la programación de servlets ....

No hay manera directa para llegar de un POJO a la sesión. Necesita obtener la sesión del objeto HttpServletRequest.

Hay 2 soluciones populares que he visto para hacer frente a esto.

La primera opción es crear un objeto de contexto de algún tipo que contenga la sesión. Este contexto luego se transfiere a la capa de su negocio para que sus POJO puedan obtener esta información si la necesitan.

La segunda opción es aprovechar el almacenamiento de ThreadLocal. A menudo, la sesión se coloca en el almacenamiento de ThreadLocal mediante un filtro o un interceptor. Entonces, cualquier objeto en su sistema puede recuperarlo del hilo. Este patrón aparece en muchos frameworks web como Spring y Struts.

+0

Necesito que el objeto de contexto sea con estado y mantenga su estado durante toda la vida de la sesión y también ser mutable, ¿es esto posible? – TheWolf

+0

Las soluciones que ofrecí solo tendrían acceso durante la vigencia de la solicitud. Sería posible atrapar una sesión y almacenar una referencia fuera del ciclo de vida de solicitud estándar, pero realmente no lo recomendaría. En ese punto, usted se compromete con la forma en que su contenedor de servlets maneja las sesiones. No realmente donde quieres estar. ¿Podría posiblemente reformular su pregunta para mostrar lo que quiere hacer en un nivel superior? Quizás obtener una referencia a una sesión no sea la mejor solución. – rfeak

+0

Gracias, Recientemente edité mi pregunta, ¿pueden verificar las nuevas ediciones? Puedo explicar los requisitos si es necesario :) – TheWolf

2

Sí, la hay.

Si está utilizando un marco web, por ejemplo Wicket, a menudo hay una forma de obtener la HttpSession actual. A partir de ahí, puede obtener Spring ApplicationContext y, si lo tiene, puede obtener Spring Beans. Esto funciona en cualquier ubicación, ya que estamos utilizando solo métodos de utilidad estáticos.

código Ejemplo:

import org.apache.wicket.protocol.http.WebApplication; 
import org.springframework.web.context.support.WebApplicationContextUtils; 
import org.springframework.web.context.WebApplicationContext; 

ServletContext sc = WebApplication.getServletContext(); 
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(sc); 

Object bean = wac.getBean("myBeanId"); 

Nota sin embargo que el filtro de la primavera y el filtro Wicket debe estar en su lugar y manejar la petición actual, de lo contrario los métodos de utilidad no funcionarán.

Si no quiso decir Spring Beans, entonces tendría que almacenarlos en la sesión HTTP usted mismo. Si no tiene un marco web, es posible que desee hacer lo que rfeak sugiere e implementar su propio ThreadLocal.

+0

"Object bean = wac.getBean (" myBeanId ");" cedería el bean de la sesión actual dado que tiene alcance de sesión? – TheWolf

+0

No, no es un bean de sesión, sino un Spring Bean del contexto de la aplicación. – mhaller

+0

-1 para inyectar Spring en la solución, aún es posible crear software sin ella. –

Cuestiones relacionadas