12 Replies Latest reply on May 16, 2013 8:33 AM by xiang yingbing

    JBoss 7: How to inject some meta data into EJBContext on EJB client side? How to controll concurrent access?

    xiang yingbing Master

      Dear all,

       

       

       

      In JBoss 5,

       

      (a) we can inject some meta data on client side:

       

      import java.io.Serializable;

       

      import org.jboss.aop.advice.Interceptor;

      import org.jboss.aop.joinpoint.Invocation;

      import org.slf4j.Logger;

      import org.slf4j.LoggerFactory;

       

       

      /**

      * It will be downloaded from server to client, so must implement Serializable.

      * @author yxiang

      *

      */

      public class SessionTokenInjectInterceptor implements Interceptor, Serializable{

          private static final long serialVersionUID = 1L;

       

          public final static Logger logger = LoggerFactory.getLogger(SessionTokenInjectInterceptor.class);

       

          public String getName() {

              return SessionTokenInjectInterceptor.class.getSimpleName();

          }

       

          public Object invoke(Invocation invocation) throws Throwable {

              String sessionId = "ybxiang."+String.valueOf(System.currentTimeMillis());

              logger.info("=========SessionTokenInjectInterceptor set metadata[GroupName_Session/KEY_SESSION_ID]:"+sessionId);

             invocation.getMetaData().addMetaData("GroupName_Session","KEY_SESSION_ID",sessionId);

              //

              return invocation.invokeNext();

          }

      }

       

       

      (b) we can retrieve the meta data on server side:

       

      import org.jboss.aop.advice.Interceptor;

      import org.jboss.aop.joinpoint.Invocation;

      import org.slf4j.Logger;

      import org.slf4j.LoggerFactory;

       

      public class SessionTokenRetriveInterceptor implements Interceptor{

          public final static Logger logger = LoggerFactory.getLogger(SessionTokenRetriveInterceptor.class);

       

          public String getName() {

              return SessionTokenRetriveInterceptor.class.getSimpleName();

          }

       

          public Object invoke(Invocation invocation) throws Throwable {

              try{

                  Object metaData = invocation.getMetaData().getMetaData("GroupName_Session","KEY_SESSION_ID");

                  logger.warn("======SessionTokenRetriveInterceptor,metaData="+metaData);

       

                  System.out.println(Thread.currentThread().getStackTrace());

       

                  return invocation.invokeNext();

              }finally{

              }

          }

      }

       

      (c)  ejb3-interceptors-aop.xml

       

      <?xml version="1.0" encoding="UTF-8"?>

       

      <aop xmlns="urn:jboss:aop-beans:1.0">

         ...  

         <!-- added by ybxiang -->

         <interceptor class="com.ybxiang.jbossaop.ejb3metadata.common.SessionTokenInjectInterceptor" scope="PER_VM"/>

         <interceptor class="com.ybxiang.jbossaop.ejb3metadata.server.SessionTokenRetriveInterceptor" scope="PER_VM"/>

         ...

         <stack name="StatelessSessionClientInterceptors">

            <interceptor-ref name="com.ybxiang.jbossaop.ejb3metadata.common.SessionTokenInjectInterceptor"/>

            ...

         </stack>

       

         ...

       

         <stack name="ClusteredStatelessSessionClientInterceptors">

            <interceptor-ref name="com.ybxiang.jbossaop.ejb3metadata.common.SessionTokenInjectInterceptor"/>

            <interceptor-ref name="org.jboss.ejb3.remoting.ClusteredIsLocalInterceptor"/>

            <interceptor-ref name="org.jboss.ejb3.security.client.SecurityClientInterceptor"/>

            <interceptor-ref name="org.jboss.aspects.tx.ClientTxPropagationInterceptor"/>

            <interceptor-ref name="org.jboss.aspects.remoting.ClusterChooserInterceptor"/>

            <interceptor-ref name="org.jboss.aspects.remoting.InvokeRemoteInterceptor"/>

         </stack>   

          ...

         <domain name="Stateless Bean" extends="Intercepted Bean" inheritBindings="true">

            <!-- added by ybxiang -->

            <bind pointcut="execution(public * @javax.ejb.Remote->*(..)) AND execution(public * $instanceof{com.ybxiang.jbossaop.ejb3metadata.server.EJB3Hello}->*(..))">

               <interceptor-ref name="com.ybxiang.jbossaop.ejb3metadata.server.SessionTokenRetriveInterceptor"/>

            </bind>

       

            ...

         </domain>

         ...

      </aop>

              ( It is really complicated in JBoss 5! )

       

       

      But those jboss-sepecified annotations(org.jboss.aop.advice.*)  are NOT available in jboss 7.

       

      How to implement the same function in jboss 7?

       

       

       

       

       

      My case introduction:

       

      1. Each EJB client must call LoginInEjb.login(String username, String password) method to get the session token(a long string). In this method, we will generate one session token and save it into DB.

      2.One username has at most 5 different session tokens.

          If the 6th EJB client tries to call LoginInEjb.login(String username, String password) with same username, exception will be thrown.

       

      3. Business logic bean is SecuredRemoteSession.java.

      4. SessionTokenInterceptor.java is an interceptor. It is used to retrieve the session token like above SecuredRemoteSession.getNameFree() does.

            If the session token does NOT exist in DB, one secure exception is thrown.

       

      5. If one evil ejb client has connected to the jboss server, we can delete the session token to force it log out.

       

      Now, my questioin:

      During calling ISecuredRemoteSession's method in my EJB client, how to access to save session token into the EJB Context?

        • 1. Re: How to inject some data into EJBContext on EJB client side.
          xiang yingbing Master

          Any tip is appreciated.

          Thanks!!!

           

          Please help me.

           

          • 2. Re: How to inject some data into EJBContext on EJB client side.
            xiang yingbing Master

            I read the whole book "Enterprise.JavaBeans.3.1_6th.Edition.pdf".

            But there is nothing usefull except interceptor.

            There is NO same case in this book.

             

            Don't you need such function? (I think It is a common requirement!)

            How do you implement such funtion?

            • 3. Re: How to inject some data into EJBContext on EJB client side.
              xiang yingbing Master

              I read ejb client source code(jboss-ejb-client-1.0.11.Final-sources.jar and jboss-remoting-3.2.8.GA-sources.jar) whole night, only found one usefull info:

              EJBClientContext.getCurrent().putAttachment(..., ...);
              

               

               

              There is no examples from google. JBoss 7 is realy complicated to me!

               

              Can I implement above function through Attachment?

              Should I read JAAS related sourcecode on the server side?

               

               

              If this framework does NOT satisfiy me, I have to add some dirty code into my session bean.

              • 5. Re: How to inject some data into EJBContext on EJB client side.
                xiang yingbing Master

                I think I have found the solution:

                https://community.jboss.org/message/747498?tstart=0

                 

                 

                 

                 

                 

                 

                WARNING:

                just as https://community.jboss.org/message/747498?tstart=0 said, there is a bug in jboss ejb client jar in jboss 7.1.1 Final, so please upgrade it to jboss-ejb-client-1.0.11.Final.jar.

                Or you can use JBoss 7.2.0 alpha1.

                 

                 

                 

                 

                 

                Now I post my solution here for those who are intrested in it

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

                1. server side interceptor

                 

                import java.util.Date;
                
                import javax.annotation.Resource;
                import javax.ejb.EJBContext;
                import javax.interceptor.AroundInvoke;
                import javax.interceptor.InvocationContext;
                import javax.persistence.EntityManager;
                import javax.persistence.PersistenceContext;
                
                import org.jboss.logging.Logger;
                
                import com.ybxiang.nms.common.exception.NotExistingSessionTokenException;
                import com.ybxiang.nms.common.exception.NullSessionTokenException;
                import com.ybxiang.nms.common.util.ServerClientSharedConstants;
                import com.ybxiang.nms.ejb.entity.Session;
                
                /**
                 * Tasks in this interceptor:
                 * (a) check if session token exist
                 * (b) update last update date
                 */
                public class SessionTokenInterceptor {
                    Logger log = Logger.getLogger(SessionTokenInterceptor.class);
                
                    @PersistenceContext
                    protected EntityManager em;
                
                    @Resource
                    private EJBContext ejbContext;
                
                    @AroundInvoke
                    public Object processSessionToken(final InvocationContext invocationContext) throws Exception{
                        //1. session token
                        //log.info("retrieve SESSION TOKEN from invocation context instead of ejbContext");
                        String sessionToken = (String)invocationContext.getContextData().get(ServerClientSharedConstants.SESSION_TOKEN_KEY);
                        //log.debug("SESSION_TOKEN:"+sessionToken);//good!
                
                        //2. JAAS username
                        //log.info("retrieve JAAS username");
                        String username = ejbContext.getCallerPrincipal().getName();//JAAS username
                
                        //3. check
                        if(sessionToken==null){
                            log.error("User["+username+"] has no SESSION TOKEN, so is NOT allowed to do more in this system.");
                            throw NullSessionTokenException.INSTANCE;
                        }
                        if(! isSessionTokenExisting(sessionToken)){
                            log.error("User["+username+"] is using invalid SESSION TOKEN, so is NOT allowed to do more in this system.");
                            throw NotExistingSessionTokenException.INSTANCE;
                        }
                
                        //4. call original method and return its result so that other interceptor can continue
                        try{
                             return invocationContext.proceed();
                        }finally{
                        }
                    }
                
                
                    private boolean isSessionTokenExisting(String sessionToken){
                        //1.find it from DB.
                        Session session = (Session)em.createNamedQuery(Session.NamedQuery_name_FindByToken)
                        .setParameter(Session.NamedQuery_param_FindByToken_token, sessionToken)
                        .getSingleResult();
                
                        //2. check
                        if(session==null){
                            return false;
                        }
                
                        //3. update last access date. 
                        session.setLastUpdated(new Date());
                        em.merge(session);
                        //
                        return true;
                    }
                }
                

                 

                 

                 

                2. apply it on session bean

                 

                @Remote(ISecuredRemoteSession.class)
                @Stateless
                @DeclareRoles("admin")
                @Interceptors({SessionTokenInterceptor.class, AuditInterceptor.class})
                public class SecuredRemoteSession implements ISecuredRemoteSession{
                    @PersistenceContext
                    protected EntityManager em;
                
                    @Resource
                    private EJBContext ejbContext;    
                
                    //return SESSION TOKEN
                    public String shakeHands() throws Exception{
                
                    }
                
                    //...
                }
                

                 

                 

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

                 

                3. client side interceptor

                 

                import org.jboss.ejb.client.EJBClientInterceptor;
                import org.jboss.ejb.client.EJBClientInvocationContext;
                
                import com.ybxiang.nms.common.util.ServerClientSharedConstants;
                
                public class SessionTokenInterceptor implements EJBClientInterceptor{
                    @Override
                    public void handleInvocation(EJBClientInvocationContext context)throws Exception {
                        if(ClientCache.getInstance().getSessionToken()!=null){
                            context.getContextData().put(ServerClientSharedConstants.SESSION_TOKEN_KEY, ClientCache.getInstance().getSessionToken());
                        }
                
                        //2. This line must be executed! If NOT, the calling will be blocked!
                        context.sendRequest();
                    }
                
                    @Override
                    public Object handleInvocationResult(EJBClientInvocationContext context)
                            throws Exception {
                
                        //This line must be executed! If NOT, the calling will be blocked!
                        return context.getResult();
                    }
                
                }
                

                 

                 

                4. apply it on EJBClientContext

                public class ClientManager{
                    //...
                    private void initSecuredRemoteSession(String serverIP, String username, String password) throws Exception{
                        String jndiName = "ejb:nms-server-ear/nms-server-ejb//SecuredRemoteSession!" + ISecuredRemoteSession.class.getName();//ear:good
                
                        Properties p = new Properties();
                        {
                            p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true");
                            p.put("remote.connections", "default");
                            p.put("remote.connection.default.host", serverIP);
                            p.put("remote.connection.default.port", "4447");
                            p.put("remote.connection.default.username", username);
                            p.put("remote.connection.default.password", password);
                            ...
                        }        
                
                        EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
                        ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
                        EJBClientContext.setSelector(selector);
                
                        EJBClientContext.getCurrent().registerInterceptor(0,new SessionTokenInterceptor());        
                
                        Properties props = new Properties();
                        props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                        context = new InitialContext(props);        
                        securedRemoteSessionProxy = (ISecuredRemoteSession)context.lookup(jndiName);     
                        if(securedRemoteSessionProxy==null){
                            log.error("securedRemoteSessionProxy should NOT be null.");
                        }
                    }
                    //...
                }
                

                 

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

                • 6. Re: How to inject some data into EJBContext on EJB client side.
                  jaikiran pai Master

                  Sorry about the late reply but yes you found the right solution. If you are still running into issues related to this, feel free to post it here.

                  1 of 1 people found this helpful
                  • 7. Re: How to inject some data into EJBContext on EJB client side.
                    xiang yingbing Master

                    Thank you sir!

                     

                    After having used jboss7 about 2 month, I love it so much because it is so wonderful and jboss guys are so warm-hearted to me!

                     

                    Now, those most critical issues in my system are fixed, codes are getting cleaner and clearer.

                    I am happy!

                     

                    • 8. Re: JBoss 7: How to inject some meta data into EJBContext on EJB client side? How to controll concurrent access?
                      Julien Boz Newbie

                      Hello,

                       

                      I try do do same but I don't know how to enable my EJBClientInterceptor implementation.

                      My EJB is inject (by @Inject) in my JSF controller (@Named).

                      I've try to register my EJBClientInterceptor implementation like other @Interceptor in my JSF web based application but it doesn't work.

                       

                      Thanks.

                      • 9. Re: JBoss 7: How to inject some meta data into EJBContext on EJB client side? How to controll concurrent access?
                        xiang yingbing Master

                        Why NOT post your codes here?

                        I can NOT answer you because your description is too simple.

                        • 10. Re: JBoss 7: How to inject some meta data into EJBContext on EJB client side? How to controll concurrent access?
                          jaikiran pai Master

                          Julien, please create a separate thread to discuss your question. Please include all relevant details in that new thread.

                          • 11. Re: JBoss 7: How to inject some meta data into EJBContext on EJB client side? How to controll concurrent access?
                            james viet Newbie

                            Hi Xiang,

                             

                            I'm going to work on EJB Interceptor. Could you plz shared your source code for reference?