13 Replies Latest reply on Jan 25, 2013 2:56 PM by fernando.rubbo

    Need to replace LoggingInterceptor

    fernando.rubbo

      Hi,

       

       

      I have some monitoring requirements in our app in which it is necessary to replace the jboss interceptor org.jboss.as.ejb3.component.interceptors.LoggingInterceptor with our own implementation. The question is: how can we do this?

       

       

      For example:

      1) one requirement is that we have a time threshold for services execution. So that, whenever a service took more than this threshold an alert is sent to the monitoring team.

      2) We must know which user is calling the service. Nowadays developer don't care about this because our interceptor handle this.

      3) Another requirement is a better service logging support  We must have more service information before and after the call. For example: service name, parameters, time, returning, etc

      4) It is important to say that we can not use EJB interceptor because we must run this interceptor before as possible in the stack. At least, we MUST run this interceptor before the transaction interceptor. The reason is once CMTTxInterceptor commits the transaction an error at commit time may happen. In this case our interceptor MUST detect it and handle it. Using EJB interceptor it seems to be impossible once the commit happens after it has finished.

       

       

      The point is: in older versions of jboss it was a simple task to perform using jboss-aop.

       

       

      Solutions we have discussed up until now:

      1) replace org.jboss.as.ejb3.component.interceptors.LoggingInterceptor with our implementation (seem to be the best one)

      2) refactor the hole app to use UserTransactions (complex, time consuming, error prone and sucks)

      3) flush() at the end of all method services. (ugly, hack and sucks)

      4) use an third part aop implementation

       

       

      Thanks in advance,

      Fernando Rubbo

        • 1. Re: Need to replace LoggingInterceptor
          nickarls

          If you use ejb-jar.xml to bind an interceptor to all ejbs, where in the interceptor stack does it end up?

          • 2. Re: Need to replace LoggingInterceptor
            fernando.rubbo

            Hi Nicklas,

             

            As far as I know, any EJB interceptor (specified in ejb-jar.xml or using @Interceptor) has the same lifecicle that the EJB it is intercepting has. So, it lives along together with the EJB. In my understanding, the stack would be something like this:

             

            1. ...
            2. LoggingInterceptor
            3. ...
            4. SecurityInterceptor
            5. ...
            6. CMTTxInterceptor
            7. ...
            8. <MyInterceptor>
            9. <MyEJB>

             

            What I would like is

             

            1. ...
            2. <MyInterceptor>
            3. LoggingInterceptor
            4. ...
            5. SecurityInterceptor
            6. ...
            7. CMTTxInterceptor
            8. ...
            9. <MyEJB>

             

            OR

             

            1. ...
            2. <MyInterceptor> replacing LoggingInterceptor
            3. ...
            4. SecurityInterceptor
            5. ...
            6. CMTTxInterceptor
            7. ...
            8. <MyEJB>

             

             

            Please, let me know if my understanding is incorrect.

            Thanks in advance

            • 3. Re: Need to replace LoggingInterceptor
              nickarls

              Hmm. Looking at the stacktrace should reveal what interceptors an exception passed along. I haven't looked at the code that sets up the interceptor stack (SessionBeanComponentDescription?) so I don't know what the chances are of sneaking in a custom interceptor in the right place there. And even if it would be possible it sounds a bit brutal.

               

              Having a CDI bean with a decorator wrapping the EJB sounds a bit intrusive, too. And not even sure that would work...

              • 4. Re: Need to replace LoggingInterceptor
                fernando.rubbo

                I understand your point when you say "it sounds a bit brutal", but I think jboss (or, maybe, JavaEE spec) should provide a way to customize such interceptor stack. Without this, we have no alternative (as far as I know) without hacking out the code whenever we face such a common requirement.

                 

                It is important to say that it was a pretty ease task in older versions of jboss. Once the SLSB interceptor stack were implemented using jboss-aop. I haven't looked into the code yet, but I it does seem to be hardcoded into some jboss code. Do you have any idea were they define the interceptor chain. So we could download the source code and take a look on it?

                • 5. Re: Need to replace LoggingInterceptor
                  nickarls

                  Not the first or the last chain in the link but the https://github.com/jbossas/jboss-as/blob/master/ee/src/main/java/org/jboss/as/ee/component/ComponentConfiguration.java looks to be involved (perhaps https://github.com/jbossas/jboss-as/blob/master/ejb3/src/main/java/org/jboss/as/ejb3/component/session/SessionBeanComponentDescription.java is used for building the stack at some point). It might be possible to extend the AS at some point (deployment processor?) to add an interceptor with an appropriate priority. 


                  I just glanced at the code so I might be off on the wrong track, perhaps some dev might shed some light. It's only source code so if you don't care how much stabbing of the code you do, I'm sure it's doable ;-)

                   

                  The sources can be pull from github.

                  • 6. Re: Need to replace LoggingInterceptor
                    fernando.rubbo

                    I think I found it in class EJBComponentDescription and it is hardcoded. :-(

                     

                    [code]

                        protected void setupViewInterceptors(final EJBViewDescription view) {

                            // add a logging interceptor (to take care of EJB3 spec, section 14.3 logging requirements)

                            view.getConfigurators().add(new ViewConfigurator() {

                                @Override

                                public void configure(DeploymentPhaseContext context, ComponentConfiguration componentConfiguration, ViewDescription description, ViewConfiguration viewConfiguration) throws DeploymentUnitProcessingException {

                                    viewConfiguration.addViewInterceptor(LoggingInterceptor.FACTORY, InterceptorOrder.View.EJB_EXCEPTION_LOGGING_INTERCEPTOR);

                                    viewConfiguration.addViewInterceptor(new ImmediateInterceptorFactory(new TCCLInterceptor(componentConfiguration.getModuleClassLoader())), InterceptorOrder.View.TCCL_INTERCEPTOR);

                     

                     

                                    //If this is the EJB 2.x local or home view add the exception transformer interceptor

                                    if (view.getMethodIntf() == MethodIntf.LOCAL && EJBLocalObject.class.isAssignableFrom(viewConfiguration.getViewClass())) {

                                        viewConfiguration.addViewInterceptor(EjbExceptionTransformingInterceptorFactories.LOCAL_INSTANCE, InterceptorOrder.View.REMOTE_EXCEPTION_TRANSFORMER);

                                    } else if (view.getMethodIntf() == MethodIntf.LOCAL_HOME) {

                                        viewConfiguration.addViewInterceptor(EjbExceptionTransformingInterceptorFactories.LOCAL_INSTANCE, InterceptorOrder.View.REMOTE_EXCEPTION_TRANSFORMER);

                                    }

                     

                     

                                    final List<SetupAction> ejbSetupActions = context.getDeploymentUnit().getAttachmentList(Attachments.OTHER_EE_SETUP_ACTIONS);

                                    if (!ejbSetupActions.isEmpty()) {

                                        viewConfiguration.addViewInterceptor(AdditionalSetupInterceptor.factory(ejbSetupActions), InterceptorOrder.View.EE_SETUP);

                                    }

                     

                     

                                    viewConfiguration.addViewInterceptor(shutDownInterceptorFactory, InterceptorOrder.View.SHUTDOWN_INTERCEPTOR);

                                }

                            });

                            this.addCurrentInvocationContextFactory(view);

                            this.setupSecurityInterceptors(view);

                            this.setupRemoteViewInterceptors(view);

                            view.getConfigurators().addFirst(new NamespaceViewConfigurator());

                         }

                    [/code]

                     

                    It looks simple to implement my own interceptor and rebuild the as code. However, I think this strategy is to much intrusive and every update/migration will be a pain in the ass (we have had to many issues like this  in the past). Do you think it is possible to jboss team to make a dynamic configuration for that? or through a subsystem or through a system property (for example: -Dejb3.LoggingInterceptorFactoryClass=com.xxx.MyLoggingInterceptorFactory). I've already opened an issue https://issues.jboss.org/browse/AS7-6022 for that.

                     

                    Please, let me know your thoughts

                     

                    Thanks,

                    Fernando Rubbo

                    • 7. Re: Need to replace LoggingInterceptor
                      fernando.rubbo

                      Anyone from Jboss developers have any idea if this kind of change request could be implemented into jboss?

                      I'm asking this because we need to know how should we proceed. Or we wait for an inproved interceptor stack configuration or we go for a "hacking alternative". Particularly I dislike the second option.

                      • 8. Re: Need to replace LoggingInterceptor
                        jaikiran

                        Isn't this what you are looking for https://issues.jboss.org/browse/AS7-5897

                        • 9. Re: Need to replace LoggingInterceptor
                          fernando.rubbo

                          Yes.. that is it.. \o/

                           

                          I've just marked issue AS7-6022 as duplicate of AS7-5897

                           

                          We will be thankfull if you could prioritize this issue.

                           

                          Thanks for you help

                          • 10. Re: Need to replace LoggingInterceptor
                            jaikiran

                            Fernando, the current AS7 upstream nightly build now has this feature implemented. Would you want to test it against your application and let us know how it goes. Here's an example of how to configure the container-interceptors https://github.com/jbossas/jboss-as/tree/master/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/ejb/container/interceptor (take a look at that testcase and the jboss-ejb3.xml included there).

                            • 11. Re: Need to replace LoggingInterceptor
                              jaikiran
                              • 12. Re: Need to replace LoggingInterceptor
                                fernando.rubbo

                                Hi Jaikiran,

                                 

                                First of all, thanks for your implementation.

                                 

                                Second, sorry by the delay. We are very busy here.

                                 

                                Third..

                                I haven't downloaded the nightly build yet, but I would like to ask you a question about compatibility. Thake the following code as an example (please, read the comments):

                                 

                                <code>

                                public class ContainerInterceptor

                                {

                                 

                                    @AroundInvoke

                                    public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {

                                 

                                        /*

                                        In older version of jboss we were used to use org.jboss.aop.joinpoint.MethodInvocation class. For example:

                                 

                                            public Object invoke(Invocation invocation) throws Throwable

                                            {

                                                final MethodInvocation mi = (MethodInvocation) invocation;

                                 

                                        So, I can see the following correspondence in the new container interceptor strategy.

                                        */

                                 

                                        // to get the arguments

                                        Object[] parameters = invocationContext.getParameters(); // ~ mi.getArguments()

                                 

                                 

                                        // to know which method has been called

                                        Method method = invocationContext.getMethod(); // ~ mi.getMethod();

                                 

                                        // to know which class has been called

                                        Object target = invocationContext.getTarget(); // ~ mi.getTargetObject();

                                        /*

                                         However, according to documentation (https://docs.jboss.org/author/display/AS72/Container+interceptors) this

                                         "method is illegal for container interceptors since these interceptors are invoked way before the EJB components

                                         are setup or instantiated".

                                 

                                          SO, THE QUESTION IS: how do I get the target class? Note, I'm not interested in the target object, but in the class. Is it possible to get using method.getDeclaringClass()??? 

                                         */

                                 

                                        // to go on

                                        return invocationContext.proceed(); // ~ mi.invokeNext()

                                    }

                                </code>

                                 

                                Thanks again

                                • 13. Re: Need to replace LoggingInterceptor
                                  fernando.rubbo

                                  Hi Jaikiran

                                   

                                  I've some time today for testing it in with the nightly build and it seems to work as expected

                                   

                                  interceptor stack

                                   


                                  TCCLInterceptor

                                  AditionalSetupInterceptor

                                  NamespaceContextInterceptor

                                  *LoggingInteceptor

                                  ShutdownInterceptor



                                  <MY CONTAINER INTERCEPTOR>



                                  *SecurityContextInterceptor

                                  CuncurrentInvocationInterceptor

                                  *CMTTxInterceptor

                                  PooledInstanceInterceptor

                                  ComponentDispatcherInterceptor

                                  SBInvocationInterceptor

                                  *ExecutionTimeInterceptor

                                  UserInterceptorFactory

                                  ManagedReferneceMethodInterceptor



                                  <MY EJB Interceptor>

                                  <MY EJB>

                                   

                                   

                                  Thanks,

                                  Fernando Rubbo