6 Replies Latest reply on Dec 14, 2009 9:41 PM by markwigmans

    How to change Synchronized.DEFAULT_TIMEOUT without recompilation

      I think the subject says it all:


      How to change Synchronized.DEFAULT_TIMEOUT without recompilation?


      Someone decided that 1 second was good enought as the default value for Synchronized.DEFAULT_TIMEOUT
      and hardcoded that in to Seam.


      The needs of my application disagree, for my application X is better, the value of X is not relevant, what is relevant is that I want to play with this value globally, and I have more than 500 components in my system and I do not want to have to modify open each and everyone of this files and modify it to be able to find the best value for X.


      Any suggestions on what should can I do? (Please do not suggest to open and modify each and every .java file in my project)


      Help!!!

        • 1. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation

          Seems like the only way to do it would be to replace org.jboss.seam.core.SynchronizationInterceptor with my own custom implementation that reads the value from components.xml.


          But since SynchronizationInterceptor is a core part of Seam I do not feel comfortable doing this...

          • 2. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation
            kragoth

            You could try reflectively setting the value of Component.timeout at startup time or creation of a component. So intercept the creation of a component and reflectively set it's timeout value.


            Don't have time to investigate if this will be enough to get you going, but it might be.


            Based on the line in the SynchronizationInterceptor


            if ( lock.tryLock( getComponent().getTimeout(), TimeUnit.MILLISECONDS ) )
            



            All you need to do is make sure the call to getComponent.getTimeout() returns your X value.



            Anyways, just an idea.


            • 3. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation

              Finally found the place where the default interceptors are defined org.jboss.seam.core.Init:


              public static List<String> DEFAULT_INTERCEPTORS = new ArrayList<String>(Arrays.asList(
                       SynchronizationInterceptor.class.getName(),
                       AsynchronousInterceptor.class.getName(),
                       RemoveInterceptor.class.getName(),
                       HibernateSessionProxyInterceptor.class.getName(),
                       EntityManagerProxyInterceptor.class.getName(),
                       MethodContextInterceptor.class.getName(),
                       EventInterceptor.class.getName(),
                       ConversationalInterceptor.class.getName(),
                       BusinessProcessInterceptor.class.getName(),
                       ConversationInterceptor.class.getName(),
                       BijectionInterceptor.class.getName(),
                       RollbackInterceptor.class.getName(),
                       TransactionInterceptor.class.getName(),
                       WSSecurityInterceptor.class.getName(),
                       SecurityInterceptor.class.getName()
                       )); 
              



              This list (and the reasons for this particular order) should be part of Seam documentation but I could not find it.


              So now I am going to use:


              <core:init debug="true">
                <core:interceptors>
                 ...
                </core:interceptors>
               </core:init>
              



              To replace SynchronizationInterceptor with my own more flexible ConfigurableSynchronizationInterceptor class...


              Hope it works...

              • 4. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation

                Here is how, first, adjust your list of interceptors in components.xml (remove SynchronizationInterceptor, add your custom ConfigurableSynchronizationInterceptor):


                <core:init debug="true">
                  <core:interceptors>
                   <!-- <value>org.jboss.seam.core.SynchronizationInterceptor</value>-->
                   <value>my.company.ConfigurableSynchronizationInterceptor</value>
                   <value>org.jboss.seam.async.AsynchronousInterceptor</value>
                   <value>org.jboss.seam.ejb.RemoveInterceptor</value>
                   <value>org.jboss.seam.persistence.HibernateSessionProxyInterceptor</value>
                   <value>org.jboss.seam.persistence.EntityManagerProxyInterceptor</value>
                   <value>org.jboss.seam.core.MethodContextInterceptor</value>
                   <value>org.jboss.seam.core.EventInterceptor</value>
                   <value>org.jboss.seam.core.ConversationalInterceptor</value>
                   <value>org.jboss.seam.bpm.BusinessProcessInterceptor</value>
                   <value>org.jboss.seam.core.ConversationInterceptor</value>
                   <value>org.jboss.seam.core.BijectionInterceptor</value>
                   <value>org.jboss.seam.transaction.RollbackInterceptor</value>
                   <value>org.jboss.seam.transaction.TransactionInterceptor</value>
                   <value>org.jboss.seam.webservice.WSSecurityInterceptor</value>
                   <value>org.jboss.seam.security.SecurityInterceptor</value>
                  </core:interceptors>
                 </core:init>
                



                Write your own interceptor with configurable timeout:


                @Interceptor(type=InterceptorType.CLIENT)
                public class ConfigurableSynchronizationInterceptor extends AbstractInterceptor
                {   
                   
                   private ReentrantLock lock = new ReentrantLock(true);
                   
                   @AroundInvoke
                   public Object aroundInvoke(InvocationContext invocation) throws Exception
                   {      
                        SynchronizationConfiguration cfg=(SynchronizationConfiguration) Component.getInstance("synchronizationConfiguration");
                        if ( lock.tryLock( cfg.getSynchronizationTimeOut(), TimeUnit.MILLISECONDS ) )
                      {
                         try
                         {
                            return invocation.proceed();
                         }
                         finally
                         {
                            lock.unlock();
                         }
                      }
                      else
                      {
                         throw new LockTimeoutException("could not acquire lock on @Synchronized component: " + 
                               getComponent().getName());
                      }
                   }
                   
                   public boolean isInterceptorEnabled()
                   {
                      return getComponent().isSynchronize();
                   }
                
                }
                



                Create a class that you will use to set and store the configurable timeout value:


                public class SynchronizationConfiguration {
                
                     private long synchronizationTimeOut;
                
                     public long getSynchronizationTimeOut() {
                          return synchronizationTimeOut;
                     }
                
                     public void setSynchronizationTimeOut(long synchronizationTimeOut) {
                          this.synchronizationTimeOut = synchronizationTimeOut;
                     }
                     
                     
                }
                



                Configure the timeout value in components.xml:


                 <component
                  class="my.company.SynchronizationConfiguration"
                  name="synchronizationConfiguration" scope="application">
                  <property name="synchronizationTimeOut">60000</property>
                  </component>
                



                And that is it, now you can change the synchronizationTimeOut for ALL the components in your application in a single place, without any recompilation.


                IMO this should be part of Seam core... why it was not implemented like this since the beginning?...

                • 5. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation

                  And so a new JIRA issue is created: JBSEAM-4459

                  • 6. Re: How to change Synchronized.DEFAULT_TIMEOUT without recompilation
                    markwigmans
                    Greate code, just what I needed. I think that if explicit a timeout is given, you can this that as well:

                    ..
                    final Method method = invocation.getMethod();
                    final Synchronized annotation = method.getDeclaringClass().getAnnotation(Synchronized.class);
                    long timeout = annotation != null ? annotation.timeout() : cfg.getSynchronizationTimeOut();
                           
                    if (lock.tryLock(timeout, TimeUnit.MILLISECONDS)) {
                    ..