5 Replies Latest reply on Dec 10, 2015 7:43 AM by marcial.atienzar

    Access to @RequestScoped from EJB

    marcial.atienzar

      Hello,

       

      We're using wildfly 9.0.2.Final

       

      I've a frest service like this:

      @Stateless
      @Path(PlaniOperations.WS_PLANILLA_ANUAL)
      @Produces(MediaType.TEXT_HTML)
      @DeclareRoles({Permisos.ROL_PUBLICO})
      @RolesAllowed(value = {Permisos.ROL_PUBLICO})
      @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
      public class PlanillaAnualWS {
          @GET
          @Produces(MediaType.APPLICATION_JSON)
          @Path(PlaniOperations.OP_SHOW_RESUMEN_BUTTON)
          public Boolean showResumenButton() {
              return bean.showResumenButton();
          }
      }
      

       

      And tthis ContainerRequestFilter:

      @Provider
      public class KyrianSessionFilter implements ContainerRequestFilter {
      
      
      
          @Inject
          private KyrianRequestContext requestCtx;
      
      
          @Override
          public void filter(ContainerRequestContext requestContext) throws IOException {
           
          KyrianUser usrSession = (KyrianUser) servletRequest.getSession().
                      getAttribute(CommonConstant.INSTANCE_SESSION_OPERTION_HEADER);
      
              if (log.isInfoEnabled()) {
                  log.info("ID DE SESION {} / {}", instanceSessionId, servletRequest.getRequestURI());
              }
      
              if (usrSession != null) {
                  // Añadimos a la request la información del Perfil asociado al instanceSessionId
                  requestCtx.setUsrSession(usrSession);
                  requestCtx.setInstanceId(instanceSessionId);
              }
      
      
          }
      
      }}
      

       

      This filter, takes the KyrianUser from HttpSession, and put it on KyrianRequestContext. I need this, to access user information on EJB.

       

      And finally, on EJB I've this code:

      @Stateless
      @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
      @DeclareRoles({Permisos.ROL_PUBLICO})
      @RolesAllowed(value = {Permisos.ROL_PUBLICO})
      public class PlanillaAnualBean {
      
      
          @Inject
          private KyrianRequestContext session;
      
          @EJB
          private PlaniBean beanPlani;
      
          /**
           * Se muestra el botón de resumen si el usuario emulado tiene colaboradores
           *
           * @return
           */
          public Boolean showResumenButton() {
              return beanPlani.hasColaboradores(session.getPerfilActual().getLogin());
          }
      }
      

       

      This code works well on 90% of times, sometimes I've a NPE that can't reproduce it on session.getPerfilActual().getLogin().

       

      I'm doing something wrong, or is it a better approach to do it?

        • 1. Re: Access to @RequestScoped from EJB
          tremes

          Hi,

          This seems to me a bit incomplete or I don't fully understand.  So KyrianRequestContext is @RequestScoped bean right? Can you please post this class content? How do you inject PlanillaAnualBean into PlanillaAnualWS? And what is exactly null? session.getPerfilActual() ?

          • 2. Re: Access to @RequestScoped from EJB
            marcial.atienzar

            Sorry, I've forgotten to put this class:

            @RequestScoped
            @Named("KyrianRequestContext")
            public class KyrianRequestContext implements Serializable {
            
                private static final long serialVersionUID = 780067625302064206L;
                public static final String DEFAULT_INSTANCE = "DEFAULT_INSTANCE";
            
                @Inject
                private Logger log;
            
                private KyrianUser usrSession;
                private SesionUsuario currentUser;
            
            
                public void setCurrentUser(SesionUsuario currentUser) {
                    this.currentUser = currentUser;
                }
            
                public SesionUsuario getValue() {
                    return currentUser;
                }
            
                public List<PerfilUsuario> getPerfiles() {
                    return usrSession.getPerfiles();
                }
            
                public String getLogin() {
                    return usrSession.getPrincipal().getLogin();
                }
            
                public String getLoginLdap() {
                    return usrSession.getPrincipal().getLoginAD();
                }
            
                public PerfilUsuario getPerfilPrincipal() {
                    return currentUser.getPerfilPrincipal();
                }
            
                public PerfilUsuario getPerfilActual() {
                    if(currentUser != null) {
                        return currentUser.getPerfilActual();
                    }
            
                    return null;
                }
            
                public PerfilUsuario getPerfilEmulado() {
                    if (log.isInfoEnabled() && currentUser.getPerfilEmulado() != null) {
                        log.info("Get perfil emulado {}", currentUser.getPerfilEmulado().getLogin());
                    }
                    return currentUser.getPerfilEmulado();
                }
            
                public boolean isAvailable() {
                    return currentUser != null;
                }
            
                @PreDestroy
                private void onDestroy() {
                    if (log.isInfoEnabled()) {
                        if (currentUser != null && currentUser.getPerfilActual() != null) {
                            log.info("DESTROY DEL BEAN DE REQUEST DEL USUARIO / PERFIL {} / {} Con hash {}",
                                    currentUser.getPerfilActual().getLogin(),
                                    currentUser.getPerfilActual().getPerfil(),
                                    this.hashCode());
                        }
                    }
                }
            
                @PostConstruct
                private void postConstruct() {
                    if (log.isInfoEnabled()) {
                        log.info("CONSTRUCT DEL BEAN DE REQUEST DEL USUARIO {}",this.hashCode());
                    }
                }
            
            
                public KyrianUser getUsrSession() {
                    return usrSession;
                }
            
                public void setUsrSession(KyrianUser usrSession) {
                    this.usrSession = usrSession;
                }
            
                /**
                 * @param idInstancia
                 */
                public void setInstanceId(String idInstancia) {
                    setCurrentUser(getSesionUsuario(idInstancia));
                }
            
                /**
                 * @param instanceId
                 * @return
                 */
                public SesionUsuario getSesionUsuario(String instanceId) {
            
                    if(instanceId == null || instanceId.isEmpty()){
                        log.warn("Nos está llegando un ID de instancia vacía");
                        instanceId = DEFAULT_INSTANCE;
                    }
            
                    if (log.isInfoEnabled()) {
                        log.info("Obteniendo objeto SesionUsuario para la instancia {} con hash {}", instanceId,this.hashCode());
                    }
            
                    SesionUsuario sesionUsuario;
            
                    if (usrSession.getSessions().containsKey(instanceId)) {
                        log.info("Tenemos el id de la instancia almacenado");
                        sesionUsuario = usrSession.getSessions().get(instanceId);
                    } else {
                        log.info("Procedemos a crear la nueva instancia de sesión del usuario");
                        sesionUsuario = new SesionUsuario();
                        sesionUsuario.setPerfilPrincipal(usrSession.getMiPerfilPrincipal());
                        usrSession.getSessions().put(instanceId, sesionUsuario);
                    }
            
            
                    return sesionUsuario;
                }
            }
            

             

            I think, that NPE occurs on session.getPerfilActual(), this returns null, and then causes NPE.

             

            I Inject the bean with this on PlanillaAnualWS:

            
            
            
            
            @EJB
            
            
            
            private PlanillaAnualBean bean;
            
            
            
            

             

            Sorry and lot of thanks.

            • 3. Re: Access to @RequestScoped from EJB
              tremes

              If session.getPerfilActual() is null then will be likely currentUser null in your KyrianRequestContext. I can't see any call to setInstanceId (where do you also set your currentUser). KyrianSessionFilter is still incomplete I guess. What is servletRequest? Where does instanceSessionId come from? Anyway I guess you have some request where there is no user/user session available...but that's just my guess. 

              • 4. Re: Access to @RequestScoped from EJB
                marcial.atienzar

                This is the full impl of KyrianSessionFilter:

                @Provider
                public class KyrianSessionFilter implements ContainerRequestFilter {
                
                    @Inject
                    private Logger log;
                
                    @Context
                    protected Providers workers;
                
                    @Context
                    private HttpServletRequest servletRequest;
                
                    @Inject
                    private KyrianRequestContext requestCtx;
                
                    @Override
                    public void filter(ContainerRequestContext requestContext) throws IOException {
                
                        log.info("ENTRAMOS FILTRO DE TRACER POR REQUEST");
                
                        String instanceSessionId;
                
                        MediaType mediaType = requestContext.getMediaType();
                        if (mediaType != null
                                && MediaType.MULTIPART_FORM_DATA_TYPE.getType().equals(mediaType.getType())
                                && MediaType.MULTIPART_FORM_DATA_TYPE.getSubtype().equals(mediaType.getSubtype())) {
                
                            //Guardamos el entityStream en un OutputStream auxiliar para poder accederlo varias veces
                            ByteArrayOutputStream auxOutputStream = new ByteArrayOutputStream();
                            IOUtils.copy(requestContext.getEntityStream(), auxOutputStream);
                
                            requestContext.getEntityStream().close();
                
                            MultipartFormDataInputImpl input = new MultipartFormDataInputImpl(mediaType, workers);
                            input.parse(new ByteArrayInputStream(auxOutputStream.toByteArray()));
                
                            instanceSessionId = KyrianSessionFilter.getMultipartBodyParameter(input,
                                    CommonConstant.INSTANCE_SESSION_OPERTION_HEADER);
                
                            //Reponemos el stream inicial en la request para que la petición continue correctamente
                            requestContext.setEntityStream(new ByteArrayInputStream(auxOutputStream.toByteArray()));
                            auxOutputStream.close();
                
                        } else {
                            instanceSessionId = requestContext.getHeaderString(CommonConstant.INSTANCE_SESSION_OPERTION_HEADER);
                        }
                
                        // Si no nos llega instancia, le damos el valor por defecto
                        if (instanceSessionId == null || instanceSessionId.isEmpty()) {
                            log.warn("Nos está llegando un ID de instancia vacía para {}", servletRequest.getRequestURI());
                            instanceSessionId = KyrianRequestContext.DEFAULT_INSTANCE;
                        }
                
                
                        KyrianUser usrSession = (KyrianUser) servletRequest.getSession().
                                getAttribute(CommonConstant.INSTANCE_SESSION_OPERTION_HEADER);
                
                        if (log.isInfoEnabled()) {
                            log.info("ID DE SESION {} / {}", instanceSessionId, servletRequest.getRequestURI());
                        }
                
                        if (usrSession != null) {
                            // Añadimos a la request la información del Perfil asociado al instanceSessionId
                            requestCtx.setUsrSession(usrSession);
                            requestCtx.setInstanceId(instanceSessionId);
                        }
                
                
                    }
                
                    /**
                     * @param input
                     * @param paramId
                     * @return
                     */
                    private static String getMultipartBodyParameter(MultipartFormDataInputImpl input, String paramId) {
                        Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
                        if (formDataMap != null) {
                            List<InputPart> header = formDataMap.get(paramId);
                            if (header != null && header.size() > 0) {
                                try {
                                    return header.get(0).getBodyAsString();
                                } catch (IOException e) {
                                    return null;
                                }
                            }
                        }
                
                        return null;
                    }
                }
                

                 

                 

                InstanceId come from web browser. The user can open 2 o more tabs, and every tab have its instance_id (we ha've the same session on all tabs, but in TAB1 user has emulate enterprise 1 (it's a instance_id) and in TAB2 user has emulate enterprise 2 (it's another instance id).

                 

                I don't know If I can't use this aproach of RequestContext merging REST with EJB, because EJB has a different scope from REST services.

                • 5. Re: Access to @RequestScoped from EJB
                  marcial.atienzar

                  I think what should occur may be produced as wildfly manages sessions with SSO enabled, and in some cases, it destroy the session and then create a new one, losing KyrianUser information