12 Replies Latest reply on Jun 16, 2016 11:02 AM by jimmy.pannier

    remote ejb with context data.

    jimmy.pannier

      Hi,

      I need to create ejb client to remote an ejb but with data in context.

       

      So i have a method to construct a ejb client.

       

      /**

        * Get service needed authentication

        *

        * @param userContext

        * @return

        */

        public T getService(final String fullUserId, final String applicationName) {

          try {

            final Properties ejbClientContextProps = new Properties();

            ejbClientContextProps.put("org.jboss.ejb.client.scoped.context", "true");

            final Context initialContext = new InitialContext(ejbClientContextProps);

            // find the EJB client context which is scoped to this JNDI context

            final EJBClientContext scopedEJBClientContext = (EJBClientContext) initialContext.lookup("ejb:/EJBClientContext");

            // register the interceptor against the scoped EJB client context

            scopedEJBClientContext.registerInterceptor(0x99999, new ProxyInterceptor(fullUserId, applicationName));

            return (T) initialContext.lookup(jndiName);

          }

          catch (NamingException e) {

            LOGGER.warn("Service non disponible : " + jndiName + ", " + e);

          }

       

          return null;

       

        }

       

      The interceptor fills data in context

       

      public class ProxyInterceptor implements EJBClientInterceptor {

       

        public static final String FULL_USER_ID     = "fullUserId";

        public static final String APPLICATION_NAME = "applicationName";

        private final String       fullUserId;

        private final String       applicationName;

       

        /**

         *

         */

        public ProxyInterceptor(final String fullUserId, final String applicationName) {

          this.fullUserId = fullUserId;

          this.applicationName = applicationName;

        }

       

        /*

         * (non-Javadoc)

         * @see org.jboss.ejb.client.EJBClientInterceptor#handleInvocation(org.jboss.ejb.client.EJBClientInvocationContext)

         */

        @Override

        public void handleInvocation(final EJBClientInvocationContext ctx) throws Exception {

          ctx.getContextData().put(FULL_USER_ID, fullUserId);

          ctx.getContextData().put(APPLICATION_NAME, applicationName);

          ctx.sendRequest();

        }

       

        /*

         * (non-Javadoc)

         * @see org.jboss.ejb.client.EJBClientInterceptor#handleInvocationResult(org.jboss.ejb.client.EJBClientInvocationContext)

         */

        @Override

        public Object handleInvocationResult(EJBClientInvocationContext ctx) throws Exception {

          return ctx.getResult();

        }

       

      }

       

      And in the implementation of the ejb, i try to get data via an annotation

       

      @Resource

        private EJBContext                    context;

       

      /*

        * (non-Javadoc)

        * @see com.inovelan.cloud.user.api.server.service.IUserEjbService#getUserContext()

        */

        @Override

        public String getUserContext() {

      return (String) context.getContextData().get(ProxyInterceptor.FULL_USER_ID);

        }

       

      The problem is that the method getUserContext() returns null.

      1) why does it returns null  ?

      2) Is there another way to pass data than using the property org.jboss.ejb.client.scoped.context ? (because context must always manually closed by the developper --> Scoped EJB client contexts - WildFly 9 - Project Documentation Editor)

        • 1. Re: remote ejb with context data.
          jaikiran

          Is the scoped EJB client context being created just to add this client interceptor? Or is there another reason for creating a scoped EJB client context?

          • 2. Re: remote ejb with context data.
            jimmy.pannier

            - the scoped client context is only used to fill the context with datas ( put by the interceptor )  and reuse them in the implementation. ( i don't register any other interceptor).

            - i use scoped client context because i don't have found another way to do that

            • 3. Re: remote ejb with context data.
              jaikiran

              Can you show us how/where the getService method gets used/called from in your application? Also the relevant snippets which show the lookup and invocation on that looked up EJB on the client side. If possible attach this client side of application.

              • 4. Re: remote ejb with context data.
                jimmy.pannier

                OK.

                We have a multi project architecture. Here is simplified presentation

                 

                - There is a ear, that contains ejb implementation ( logic method implementation, database access, ... )

                - There is a war (web project client) that remote ejbs located in the ear.

                 

                ****************

                WAR PROJECT

                ****************

                In the war project, there are some proxy classes ( our convention for naming the classes that remote the ejbs in the ear).

                for example, here is a class that exposes a webservice and/or service errai

                 

                @Service

                @Interceptors({ExceptionInterceptor.class})

                @Stateless

                @Local(IDirectoryWebService.class)

                @WebService(name = "directory")

                @SOAPBinding(style = SOAPBinding.Style.RPC)

                public class ProxyDirectoryWebService implements IDirectoryWebService{

                 

                    public String someMethodOfWs(){

                          getService().someMethodOfEjbInEar();

                 

                    }

                 

                  private IDirectoryEjbService getService() {

                    return new ServiceProxy<IDirectoryEjbService>(IDirectoryEjbService.JNDI_NAME).getSecuredService();

                  }

                 

                 

                }

                 

                **************************

                ServiceProxy class UTIL

                ****************************

                Each method in webservice entrypoint of the WAR call this class which has job to create the remote ejb client with data.

                 

                 

                public class ServiceProxy<T> extends ProxyCloudUtils<T> {

                 

                  private static final Logger LOGGER = Logger.getLogger(ServiceProxy.class.getSimpleName());

                 

                  /**

                  * @param jndiName

                  */

                  public ServiceProxy(String jndiName) {

                    super(jndiName);

                  }

                 

                  /**

                  * Retourne le service en mode connecté

                  *

                  * @return

                  */

                  public T getSecuredService() {

                    T service = null;

                    try {

                      service = getService(AuthenticationServerUtils.getUserContext(false).getFullUserId(), AuthenticationServerUtils.getApplicationName());

                    }

                    catch (final AuthenticationException e) {

                      LOGGER.error(e);

                    }

                    if (service == null) {

                      throw new ServiceUnavailableException();

                    }

                    return service;

                  }

                 

                  /**

                  * Retourne le service en mode deconnecté

                  *

                  * @return

                  */

                  public T getUnsecuredService() {

                    final T service = getService();

                    if (service == null) {

                      throw new ServiceUnavailableException();

                    }

                    return service;

                 

                  }

                }

                 

                The method AuthenticationServerUtils.getUserContext(false).getFullUserId()  is a method that return user data in HttpSession, errai session....

                 

                ********************

                EAR Project

                ********************

                @javax.ejb.Stateless

                @Remote(IDirectoryEjbService.class)

                @Local(DirectoryServiceImpl.class)

                public class DirectoryServiceImpl implements IDirectoryEjbService {

                 

                  @Resource

                  private EJBContext                     context;

                 

                 

                     @Override

                     public void someMethodOfEjbInEar(){

                     String   userId = context.getContextData().get(ProxyInterceptor.FULL_USER_ID);

                     }

                }

                • 5. Re: remote ejb with context data.
                  jimmy.pannier

                  Note that i'm using the namespace java global for lookup :

                  java:global/cloud-ear/cloud-core-impl/DirectoryServiceImpl!com.inovelan.cloud.api.directory.service.IDirectoryEjbService

                  • 6. Re: remote ejb with context data.
                    jaikiran

                    I haven't looked at that code, you posted, completely yet (will do later today) but you will have to use ejb: in your lookups for this to work.

                    • 7. Re: remote ejb with context data.
                      jimmy.pannier

                      Yes i've added the comment after read your article.

                      EJB invocations from a remote client using JNDI - JBoss AS 7.1 - Project Documentation Editor

                      Thanks again. i'll test.

                      • 8. Re: remote ejb with context data.
                        jimmy.pannier

                        When using naming "ejb:" i get an

                        11:50:38,511 ERROR [stderr] (default task-24) java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:cloud-ear, moduleName:cloud-core-impl, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@17c5b882

                         

                             final Properties ejbClientContextProps = new Properties();

                             ejbClientContextProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

                             ejbClientContextProps.put("org.jboss.ejb.client.scoped.context", "true"); ---> if i remove this line, ejb proxy work (no exception above) but context data always null.

                              LOGGER.info("lookup for ejb  : " + jndiName);

                              InitialContext context = new InitialContext(ejbClientContextProps);

                              service = (T) context.lookup(jndiName);

                        • 9. Re: remote ejb with context data.
                          jaikiran

                          I plan to try this out against one of the WildFly testcases and see why this isn't working as expected. I'll update this thread when I've something to report.

                          • 10. Re: remote ejb with context data.
                            jimmy.pannier

                            Ok, i'm waiting for your report.

                            For the moment i'll change my implementation. in my war i will instantiate a static initialcontext (so i don't have to close it each time) with a unique proxyinterceptor (which calls another class to get data and fill them in context in handleInvocation method).

                            • 11. Re: remote ejb with context data.
                              jaikiran


                              I see what's going on (after testing it out myself locally), but before suggesting a solution, can you explain a bit more about this code:

                              AuthenticationServerUtils.getUserContext(false).getFullUserId()

                              Can you show us what the code inside that looks like? Does it rely on ThreadLocals and such or how does it get hold of the HTTP session from which to get the full user id?

                              • 12. Re: remote ejb with context data.
                                jimmy.pannier

                                package com.inovelan.cloud.api.user;

                                 

                                 

                                import com.inovelan.cloud.api.user.model.AbstractBaseContext;

                                import com.inovelan.cloud.api.user.model.RequestContext;

                                import com.inovelan.cloud.api.user.service.IUserEjbService;

                                import com.inovelan.cloud.api.user.shared.model.UserContext;

                                import com.inovelan.cloud.api.user.shared.util.AuthenticationException;

                                import com.inovelan.cloud.common.proxy.ProxyCloudUtils;

                                 

                                 

                                import org.apache.commons.lang3.StringUtils;

                                import org.apache.log4j.Logger;

                                import org.jboss.errai.bus.server.api.RpcContext;

                                 

                                 

                                import javax.servlet.http.Cookie;

                                import javax.servlet.http.HttpServletRequest;

                                import javax.ws.rs.ServiceUnavailableException;

                                 

                                 

                                public class AuthenticationServerUtils {

                                 

                                 

                                  private static final Logger                                LOGGER                = Logger.getLogger(AuthenticationServerUtils.class);

                                  private static ProxyCloudUtils<IUserEjbService>            PROXY_USER            = new ProxyCloudUtils<IUserEjbService>(IUserEjbService.JNDI_NAME);

                                 

                                  private static InheritableThreadLocal<AbstractBaseContext> tlAbstractBaseContext = new InheritableThreadLocal<>();

                                  private static InheritableThreadLocal<RequestContext>      tlRequestContext      = new InheritableThreadLocal<>();

                                 

                                  public final static AbstractBaseContext getAbstractBaseContext() {

                                    LOGGER.debug("getAbstractBaseContext() - tlAbstractBaseContext = " + tlAbstractBaseContext);

                                    AbstractBaseContext abstractBaseContext = tlAbstractBaseContext.get();

                                    LOGGER.debug("getAbstractBaseContext() - return = " + abstractBaseContext);

                                    return abstractBaseContext;

                                  }

                                 

                                 

                                  public final static String getApplicationName() {

                                    String applicationName = null;

                                   

                                    RequestContext requestContext = getRequestContext();

                                    if (requestContext != null) {

                                      // Http

                                      applicationName = requestContext.getApplicationName();

                                      LOGGER.debug("getApplicationName() - Http - applicationName : " + applicationName);

                                    }

                                    else {

                                      // Websocket, rpccontext.gethttpsession if part of Errai Framework

                                      try {

                                        applicationName = (String) RpcContext.getHttpSession().getAttribute(EHttpSessionAttribute.ApplicationName.getAttributeAsString());

                                        LOGGER.debug("getApplicationName() - Websocket - applicationName : " + applicationName);

                                      }

                                      catch (Exception e) {

                                      }

                                    }

                                    return applicationName;

                                  }

                                 

                                  public final static String getAuthCookie(HttpServletRequest httpServletRequest) {

                                    LOGGER.debug("getAuthCookie(" + httpServletRequest + ")");

                                   

                                    if (httpServletRequest.getCookies() != null) {

                                      for (Cookie cookie : httpServletRequest.getCookies()) {

                                        // LOGGER.debug("getAuthCookie(...) - cookie.getName() : '" + cookie.getName() + "' = '" + cookie.getValue() + "'");

                                        if (cookie.getName().equals(EAuthenticationMode.getAuthenticationMode().getCookieName())) {

                                          return cookie.getValue();

                                        }

                                      }

                                    }

                                    return null;

                                  }

                                 

                                 

                                  public final static String getFullUserId() throws AuthenticationException {

                                    String fullUserId = null;

                                   

                                    AbstractBaseContext abstractBaseContext = getAbstractBaseContext();

                                    if (abstractBaseContext != null) {

                                      // Http

                                      fullUserId = abstractBaseContext.getFullUserId();

                                      LOGGER.debug("getFullUserId() - Http - fullUserId : " + fullUserId);

                                    }

                                    else {

                                      // Websocket

                                      try {

                                        fullUserId = (String) RpcContext.getHttpSession().getAttribute(EHttpSessionAttribute.FullUserId.getAttributeAsString());

                                        LOGGER.debug("getFullUserId() - Websocket - fullUserId : " + fullUserId);

                                      }

                                      catch (Exception e) {

                                      }

                                    }

                                   

                                    if (StringUtils.isNotBlank(fullUserId)) {

                                      return fullUserId;

                                    }

                                    throw new AuthenticationException("Unavailable user context");

                                  }

                                 

                                  public final static RequestContext getRequestContext() {

                                    LOGGER.debug("getRequestContext() - tlRequestContext = " + tlRequestContext);

                                    RequestContext requestContext = tlRequestContext.get();

                                    LOGGER.debug("getRequestContext() - return = " + requestContext);

                                    return requestContext;

                                  }

                                 

                                 

                                  public final static UserContext getUserContext(boolean forceNew) throws AuthenticationException {

                                    return getUserService().getUserContext(getFullUserId(), forceNew);

                                  }

                                 

                                  public final static void setAbstractBaseContext(AbstractBaseContext abstractBaseContext) {

                                    LOGGER.debug("setAbstractBaseContext(" + abstractBaseContext + ")");

                                    tlAbstractBaseContext.set(abstractBaseContext);

                                  }

                                 

                                  public final static void setRequestContext(RequestContext requestContext) {

                                    LOGGER.debug("setRequestContext(" + requestContext + ")");

                                    tlRequestContext.set(requestContext);

                                  }

                                 

                                  protected static IUserEjbService getUserService() {

                                    IUserEjbService service = PROXY_USER.getAnonymousService();

                                    if (service == null) {

                                      throw new ServiceUnavailableException();

                                    }

                                    return service;

                                  }

                                }