[jboss-cvs] jboss-seam/src/main/org/jboss/seam/core ...

Gavin King gavin.king at jboss.com
Wed May 30 20:55:40 EDT 2007


  User: gavin   
  Date: 07/05/30 20:55:40

  Modified:    src/main/org/jboss/seam/core        Dispatcher.java
                        Events.java
  Added:       src/main/org/jboss/seam/core        AbstractDispatcher.java
                        ThreadPoolDispatcher.java
                        TimerServiceDispatcher.java
                        TimerServiceSchedule.java
  Removed:     src/main/org/jboss/seam/core        LocalDispatcher.java
  Log:
  JBSEAM-395
  
  Revision  Changes    Path
  1.19      +43 -397   jboss-seam/src/main/org/jboss/seam/core/Dispatcher.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Dispatcher.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/core/Dispatcher.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -b -r1.18 -r1.19
  --- Dispatcher.java	30 May 2007 23:23:45 -0000	1.18
  +++ Dispatcher.java	31 May 2007 00:55:40 -0000	1.19
  @@ -1,397 +1,43 @@
   package org.jboss.seam.core;
   
  -import static org.jboss.seam.annotations.Install.BUILT_IN;
  -
  -import java.io.Serializable;
  -import java.lang.annotation.Annotation;
  -import java.lang.reflect.Method;
  -import java.util.Date;
   import java.util.concurrent.Callable;
   
  -import javax.annotation.PostConstruct;
  -import javax.annotation.Resource;
  -import javax.ejb.EJBException;
  -import javax.ejb.NoSuchObjectLocalException;
  -import javax.ejb.Stateless;
  -import javax.ejb.Timeout;
  -import javax.ejb.Timer;
  -import javax.ejb.TimerHandle;
  -import javax.ejb.TimerService;
  -import javax.interceptor.Interceptors;
  +import javax.ejb.Local;
   
   import org.jboss.seam.Component;
  -import org.jboss.seam.annotations.Install;
  -import org.jboss.seam.annotations.Name;
  -import org.jboss.seam.annotations.timer.Duration;
  -import org.jboss.seam.annotations.timer.Expiration;
  -import org.jboss.seam.annotations.timer.IntervalDuration;
  -import org.jboss.seam.contexts.Contexts;
  -import org.jboss.seam.contexts.Lifecycle;
  -import org.jboss.seam.ejb.SeamInterceptor;
   import org.jboss.seam.intercept.InvocationContext;
  -import org.jboss.seam.util.Reflections;
   
   /**
  - * Dispatcher for asynchronous methods.
  + * Interface to be implemented by any strategy for dispatching
  + * asynchronous method calls and asynchronous events.
    * 
    * @author Gavin King
    *
  + * @param <T> the type of the timer object
    */
  - at Stateless
  - at Name("org.jboss.seam.core.dispatcher")
  - at Interceptors(SeamInterceptor.class)
  - at Install(value=false, precedence=BUILT_IN)
  -public class Dispatcher implements LocalDispatcher<Timer>
  + at Local
  +public interface Dispatcher<T, S>
   {
  +   /**
  +    * Schedule an asynchronous method call
  +    * 
  +    * @return some kind of timer object, or null
  +    */
  +   public T scheduleInvocation(InvocationContext invocation, Component component);
  +   /**
  +    * Schedule a timed event
  +    * 
  +    * @return some kind of timer object, or null
  +    */
  +   public T scheduleTimedEvent(String type, S schedule, Object... parameters);
      
  -   public static final String EXECUTING_ASYNCHRONOUS_CALL = "org.jboss.seam.core.executingAsynchronousCall";
  -   
  -   @Resource TimerService timerService;
  -   
  -   public static abstract class Asynchronous implements Serializable
  -   {
  -      static final long serialVersionUID = -551286304424595765L;
  -      
  -      private Long processId;
  -      private Long taskId;
  -      
  -      protected Asynchronous()
  -      {
  -         if ( Init.instance().isJbpmInstalled() )
  -         {
  -            BusinessProcess businessProcess = BusinessProcess.instance();
  -            processId = businessProcess.getProcessId();
  -            taskId = BusinessProcess.instance().getTaskId();
  -         }        
  -      }
  -      
  -      public void execute(Timer timer)
  -      {
  -         
  -         //TODO: shouldn't this take place in a Seam context anyway??!? (bug in EJB3?)
  -         
  -         Lifecycle.beginCall();
  -         Contexts.getEventContext().set(EXECUTING_ASYNCHRONOUS_CALL, true);
  -         try
  -         {
  -            if (taskId!=null)
  -            {
  -               BusinessProcess.instance().resumeTask(taskId);
  -            }
  -            else if (processId!=null)
  -            {
  -               BusinessProcess.instance().resumeProcess(processId);
  -            }
  -            
  -            Contexts.getEventContext().set("timer", timer);
  -         
  -            call();
  -            
  -         }
  -         finally
  -         {
  -            Contexts.getEventContext().remove(EXECUTING_ASYNCHRONOUS_CALL);
  -            Lifecycle.endCall();
  -         }
  -         
  -      }
  -      
  -      protected abstract void call();
  -   }
  -   
  -   static class AsynchronousInvocation extends Asynchronous
  -   {
  -      static final long serialVersionUID = 7426196491669891310L;
  -      
  -      private String methodName;
  -      private Class[] argTypes;
  -      private Object[] args;
  -      private String componentName;
  -      
  -      public AsynchronousInvocation(Method method, String componentName, Object[] args)
  -      {
  -         this.methodName = method.getName();
  -         this.argTypes = method.getParameterTypes();
  -         this.args = args==null ? new Object[0] : args;
  -         this.componentName = componentName;
  -      }
  -      
  -      @Override
  -      protected void call()
  -      {
  -         Object target = Component.getInstance(componentName);
  -         
  -         Method method;
  -         try
  -         {
  -            method = target.getClass().getMethod(methodName, argTypes);
  -         }
  -         catch (NoSuchMethodException nsme)
  -         {
  -            throw new IllegalStateException(nsme);
  -         }
  -         
  -         Reflections.invokeAndWrap(method, target, args);
  -      }
  -   }
  -   
  -   static class AsynchronousEvent extends Asynchronous
  -   {
  -      static final long serialVersionUID = 2074586442931427819L;
  -      
  -      private String type;
  -      private Object[] parameters;
  -
  -      public AsynchronousEvent(String type, Object[] parameters)
  -      {
  -         this.type = type;
  -         this.parameters = parameters;
  -      }
  -
  -      @Override
  -      public void call()
  -      {
  -         Events.instance().raiseEvent(type, parameters);
  -      }
  -      
  -   }
  -   
  -   @PostConstruct 
  -   public void postConstruct() {} //workaround for a bug in EJB3
  -   
  -   @Timeout
  -   public void dispatch(Timer timer)
  -   {
  -      ( (Asynchronous) timer.getInfo() ).execute(timer);
  -   }
  -   
  -   public Timer scheduleEvent(String type, Long duration, Date expiration, Long intervalDuration, Object... parameters)
  -   {
  -      return schedule( duration, expiration, intervalDuration, new AsynchronousEvent(type, parameters) );
  -   }
  -   
  -   public Timer scheduleInvocation(InvocationContext invocation, Component component)
  -   {
  -      Long duration = 0l;
  -      Date expiration = null;
  -      Long intervalDuration = null;
  -      Annotation[][] parameterAnnotations = invocation.getMethod().getParameterAnnotations();
  -      for ( int i=0; i<parameterAnnotations.length; i++ )
  -      {
  -         Annotation[] annotations = parameterAnnotations[i];
  -         for (Annotation annotation: annotations)
  -         {
  -            if ( annotation.annotationType().equals(Duration.class) )
  -            {
  -               duration = (Long) invocation.getParameters()[i];
  -            }
  -            else if ( annotation.annotationType().equals(IntervalDuration.class) )
  -            {
  -               intervalDuration = (Long) invocation.getParameters()[i];
  -            }
  -            else if ( annotation.annotationType().equals(Expiration.class) )
  -            {
  -               expiration = (Date) invocation.getParameters()[i];
  -            }
  -         }
  -      }
  -
  -      AsynchronousInvocation asynchronousInvocation = new AsynchronousInvocation(
  -            invocation.getMethod(), 
  -            component.getName(), 
  -            invocation.getParameters()
  -         );
  -      
  -       return schedule(duration, expiration, intervalDuration, asynchronousInvocation);
  -      
  -   }
  -
  -   private Timer schedule(Long duration, Date expiration, Long intervalDuration, Asynchronous asynchronous)
  -   {
  -      if (intervalDuration!=null)
  -      {
  -         if (expiration!=null)
  -         {
  -             return new TimerProxy(timerService.createTimer(expiration, intervalDuration, asynchronous));
  -         }
  -         else
  -         {
  -             return new TimerProxy(timerService.createTimer(duration, intervalDuration, asynchronous));
  -         }            
  -      }
  -      else if (expiration!=null)
  -      {
  -          return new TimerProxy(timerService.createTimer(expiration, asynchronous));
  -      }
  -      else
  -      {
  -          return new TimerProxy(timerService.createTimer(duration, asynchronous));
  -      }
  -   }
  -
  -   public static LocalDispatcher instance()
  -   {
  -      if ( !Contexts.isApplicationContextActive() )
  -      {
  -         throw new IllegalStateException("no application context active");
  -      }
  -      return (LocalDispatcher) Component.getInstance(Dispatcher.class);         
  -   }
  -   
  -    public Object call(Callable task) 
  -    {
  -        try 
  -        {
  -            return task.call();
  -        } 
  -        catch (RuntimeException e) 
  -        {
  -            // just pass along runtime exceptions
  -            throw e;
  -        } 
  -        catch (Exception e) 
  -        {
  -            throw new RuntimeException(e);
  -        }
  -    }
  -
  -    static class TimerProxy 
  -        implements Timer
  -    {
  -        Timer timer;
  -
  -        public TimerProxy(Timer timer)    
  -            throws  IllegalStateException,
  -                    NoSuchObjectLocalException,
  -                    EJBException
  -        {
  -            this.timer = timer;
  -        }
  -        
  -        private Object callInContext(Callable callable) 
  -        {
  -            return Dispatcher.instance().call(callable);
  -        }
  -
  -        public void cancel() 
  -            throws
  -                IllegalStateException,
  -                NoSuchObjectLocalException,
  -                EJBException
  -        {
  -            callInContext(new Callable() {
  -                    public Object call() 
  -                    {
  -                        timer.cancel();
  -                        return null;
  -                    }
  -                });
  -        }
  -
  -        public TimerHandle getHandle()
  -            throws
  -                IllegalStateException,
  -                NoSuchObjectLocalException,
  -                EJBException
  -        {
  -            TimerHandle handle = (TimerHandle) 
  -                callInContext(new Callable() {
  -                        public Object call() 
  -                        {
  -                            return timer.getHandle();
  -                        }
  -                    });
  -            return new TimerHandleProxy(handle);
  -        }
  -
  -        public Serializable getInfo() 
  -            throws
  -                IllegalStateException,
  -                NoSuchObjectLocalException,
  -                EJBException
  -        {
  -            return (Serializable) 
  -                callInContext(new Callable() {
  -                        public Object call() 
  -                        {
  -                            return timer.getInfo();
  -                        }
  -                    });            
  -        }
  -        public Date getNextTimeout() 
  -            throws
  -                IllegalStateException,
  -                NoSuchObjectLocalException,
  -                EJBException
  -        {
  -            return (Date) 
  -                callInContext(new Callable() {
  -                        public Object call() 
  -                        {
  -                            return timer.getNextTimeout();
  -                        }
  -                    });            
  -        }
  -        
  -        public long getTimeRemaining()    
  -            throws IllegalStateException,
  -                   NoSuchObjectLocalException,
  -                   EJBException
  -        {
  -            return (Long) 
  -                callInContext(new Callable() {
  -                        public Object call() 
  -                        {
  -                            return timer.getTimeRemaining();
  -                        }
  -                    });  
  -        }
  -    }
  -
  -    static class TimerHandleProxy
  -        implements TimerHandle, 
  -                   Serializable
  -    {
  -        private static final long serialVersionUID = 6913362944260154627L;
  -      
  -        TimerHandle handle;
  -
  -        public TimerHandleProxy(TimerHandle handle) 
  -        {
  -            this.handle = handle;
  -        }
  -        
  -        private Object callInContext(Callable callable) 
  -        {
  -            return Dispatcher.instance().call(callable);
  -        }
  +   /**
  +    * Schedule an asynchronous event
  +    * 
  +    * @return some kind of timer object, or null
  +    */
  +   public T scheduleAsynchronousEvent(String type, Object... parameters);
   
  -        public Timer getTimer() 
  -            throws IllegalStateException,
  -                   NoSuchObjectLocalException,
  -                   EJBException 
  -        {
  -            Timer timer = (Timer) callInContext( new Callable() {
  -                public Object call() 
  -                {
  -                    try
  -                    {
  -                        return handle.getTimer();
  -                    }
  -                    catch (NoSuchObjectLocalException nsoe)
  -                    {
  -                        return null;
  -                    }           
  -                }
  -            } );
  -            if (timer==null)
  -            {
  -               throw new NoSuchObjectLocalException();
  -            }
  -            else
  -            {
  -               return new TimerProxy(timer);
  -            }
  -        }
  -    }
  +   //TODO: move somewhere else!
  +   public Object call(Callable task);
   }
  
  
  
  1.26      +59 -29    jboss-seam/src/main/org/jboss/seam/core/Events.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Events.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/core/Events.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -b -r1.25 -r1.26
  --- Events.java	30 May 2007 20:27:06 -0000	1.25
  +++ Events.java	31 May 2007 00:55:40 -0000	1.26
  @@ -3,7 +3,6 @@
   import static org.jboss.seam.InterceptionType.NEVER;
   import static org.jboss.seam.annotations.Install.BUILT_IN;
   
  -import java.util.Date;
   import java.util.List;
   
   import org.jboss.seam.Component;
  @@ -19,6 +18,12 @@
   import org.jboss.seam.log.LogProvider;
   import org.jboss.seam.log.Logging;
   
  +/**
  + * Support for Seam component-driven events
  + * 
  + * @author Gavin King
  + *
  + */
   @Scope(ScopeType.STATELESS)
   @Intercept(NEVER)
   @Name("org.jboss.seam.core.events")
  @@ -28,12 +33,25 @@
      
      private static final LogProvider log = Logging.getLogProvider(Events.class);
      
  +   /**
  +    * Add a new listener for a given event type
  +    * 
  +    * @param type the event type
  +    * @param methodBindingExpression a method binding, expressed in EL
  +    * @param argTypes the argument types of the method binding
  +    */
      public void addListener(String type, String methodBindingExpression, Class... argTypes)
      {
         MethodExpression methodBinding = Expressions.instance().createMethodExpression(methodBindingExpression, Object.class, argTypes);
         Init.instance().addObserverMethodExpression(type, methodBinding);
      }
      
  +   /**
  +    * Raise an event that is to be processed synchronously
  +    * 
  +    * @param type the event type
  +    * @param parameters parameters to be passes to the listener method
  +    */
      public void raiseEvent(String type, Object... parameters)
      {
         //TODO: find a way to map event parameters to params in an EL-defined listener
  @@ -66,49 +84,61 @@
         }
      }
      
  +   /**
  +    * Raise an event that is to be processed asynchronously
  +    * 
  +    * @param type the event type
  +    * @param parameters parameters to be passes to the listener method
  +    */
      public void raiseAsynchronousEvent(String type, Object... parameters)
      {
  -      getDispatcher().scheduleEvent(type, 0l, null, null, parameters);
  +      getDispatcher().scheduleAsynchronousEvent(type, parameters);
      }
   
  -   protected LocalDispatcher getDispatcher()
  -   {
  -      LocalDispatcher dispatcher = Dispatcher.instance();
  -      if (dispatcher==null)
  +   /**
  +    * Raise an event that is to be processed according to a "schedule"
  +    * 
  +    * @see TimerServiceSchedule for use of the EJB timer service
  +    * 
  +    * @param type the event type
  +    * @param schedule the schedule object, specific to the dispatcher strategy
  +    * @param parameters parameters to be passes to the listener method
  +    */
  +   public void raiseTimedEvent(String type, Object schedule, Object... parameters)
  +   {
  +      getDispatcher().scheduleTimedEvent(type, schedule, parameters);
  +   }
  +   
  +   /**
  +    * Raise an event that is to be processed after successful completion of 
  +    * the current transaction
  +    * 
  +    * @param type the event type
  +    * @param parameters parameters to be passes to the listener method
  +    */
  +   public void raiseTransactionSuccessEvent(String type, Object... parameters)
         {
  -         throw new IllegalStateException("org.jboss.seam.core.dispatcher is not installed");
  -      }
  -      return dispatcher;
  +      getTransactionListener().scheduleEvent(type, parameters);
      }
      
  -   public void raiseTransactionSuccessEvent(String type, Object... parameters)
  +   private LocalTransactionListener getTransactionListener()
      {
         LocalTransactionListener transactionListener = TransactionListener.instance();
         if (transactionListener==null)
         {
            throw new IllegalStateException("org.jboss.seam.core.transactionListener is not installed");
         }
  -      transactionListener.scheduleEvent(type, parameters);
  +      return transactionListener;
      }
      
  -   public void raiseTimedEvent(String type, long duration, Object... parameters)
  +   protected Dispatcher getDispatcher()
      {
  -      getDispatcher().scheduleEvent(type, duration, null, null, parameters);
  -   }
  -   
  -   public void raiseTimedEvent(String type, Date expiration, Object... parameters)
  -   {
  -      getDispatcher().scheduleEvent(type, null, expiration, null, parameters);
  -   }
  -   
  -   public void raiseTimedEvent(String type, Date expiration, long intervalDuration, Object... parameters)
  +      Dispatcher dispatcher = AbstractDispatcher.instance();
  +      if (dispatcher==null)
      {
  -      getDispatcher().scheduleEvent(type, null, expiration, intervalDuration, parameters);
  +         throw new IllegalStateException("org.jboss.seam.core.dispatcher is not installed");
      }
  -   
  -   public void raiseTimedEvent(String type, long duration, long intervalDuration)
  -   {
  -      getDispatcher().scheduleEvent(type, duration, null, intervalDuration);
  +      return dispatcher;
      }
      
      public static boolean exists()
  
  
  
  1.1      date: 2007/05/31 00:55:40;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/AbstractDispatcher.java
  
  Index: AbstractDispatcher.java
  ===================================================================
  package org.jboss.seam.core;
  
  import java.io.Serializable;
  import java.lang.reflect.Method;
  import java.util.concurrent.Callable;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.util.Reflections;
  
  /**
   * Abstract Dispatcher implementation
   * 
   * @author Gavin King
   *
   */
  public abstract class AbstractDispatcher<T, S> implements Dispatcher<T, S>
  {
     
     public static final String EXECUTING_ASYNCHRONOUS_CALL = "org.jboss.seam.core.executingAsynchronousCall";
        
     public static Dispatcher instance()
     {
        if ( !Contexts.isApplicationContextActive() )
        {
           throw new IllegalStateException("no application context active");
        }
        return (Dispatcher) Component.getInstance("org.jboss.seam.core.dispatcher");         
     }
  
     public static abstract class Asynchronous implements Serializable
     {
        static final long serialVersionUID = -551286304424595765L;
        
        private Long processId;
        private Long taskId;
        
        protected Asynchronous()
        {
           if ( Init.instance().isJbpmInstalled() )
           {
              BusinessProcess businessProcess = BusinessProcess.instance();
              processId = businessProcess.getProcessId();
              taskId = BusinessProcess.instance().getTaskId();
           }        
        }
        
        public void execute(Object timer)
        {
           
           //TODO: shouldn't this take place in a Seam context anyway??!? (bug in EJB3?)
           
           Lifecycle.beginCall();
           Contexts.getEventContext().set(EXECUTING_ASYNCHRONOUS_CALL, true);
           try
           {
              if (taskId!=null)
              {
                 BusinessProcess.instance().resumeTask(taskId);
              }
              else if (processId!=null)
              {
                 BusinessProcess.instance().resumeProcess(processId);
              }
              
              Contexts.getEventContext().set("timer", timer);
           
              call();
              
           }
           finally
           {
              Contexts.getEventContext().remove(EXECUTING_ASYNCHRONOUS_CALL);
              Lifecycle.endCall();
           }
           
        }
        
        protected abstract void call();
     }
     
     static class AsynchronousInvocation extends Asynchronous
     {
        static final long serialVersionUID = 7426196491669891310L;
        
        private String methodName;
        private Class[] argTypes;
        private Object[] args;
        private String componentName;
        
        public AsynchronousInvocation(Method method, String componentName, Object[] args)
        {
           this.methodName = method.getName();
           this.argTypes = method.getParameterTypes();
           this.args = args==null ? new Object[0] : args;
           this.componentName = componentName;
        }
        
        @Override
        protected void call()
        {
           Object target = Component.getInstance(componentName);
           
           Method method;
           try
           {
              method = target.getClass().getMethod(methodName, argTypes);
           }
           catch (NoSuchMethodException nsme)
           {
              throw new IllegalStateException(nsme);
           }
           
           Reflections.invokeAndWrap(method, target, args);
        }
     }
     
     static class AsynchronousEvent extends Asynchronous
     {
        static final long serialVersionUID = 2074586442931427819L;
        
        private String type;
        private Object[] parameters;
  
        public AsynchronousEvent(String type, Object[] parameters)
        {
           this.type = type;
           this.parameters = parameters;
        }
  
        @Override
        public void call()
        {
           Events.instance().raiseEvent(type, parameters);
        }
        
     }
     
      //TODO: move down to TimerServiceDispatcher!
      public Object call(Callable task) 
      {
          try 
          {
              return task.call();
          } 
          catch (RuntimeException e) 
          {
              // just pass along runtime exceptions
              throw e;
          } 
          catch (Exception e) 
          {
              throw new RuntimeException(e);
          }
      }
  }
  
  
  
  1.1      date: 2007/05/31 00:55:40;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/ThreadPoolDispatcher.java
  
  Index: ThreadPoolDispatcher.java
  ===================================================================
  package org.jboss.seam.core;
  
  import static org.jboss.seam.annotations.Install.BUILT_IN;
  
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  
  import javax.ejb.Timer;
  import javax.interceptor.Interceptors;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.annotations.Install;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.annotations.Scope;
  import org.jboss.seam.ejb.SeamInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * Dispatcher implementation that uses a java.util.concurrent
   * ThreadPoolExecutor.
   * 
   * @author Gavin King
   *
   */
  @Scope(ScopeType.APPLICATION)
  @Name("org.jboss.seam.core.dispatcher")
  @Interceptors(SeamInterceptor.class)
  @Install(value=false, precedence=BUILT_IN)
  public class ThreadPoolDispatcher extends AbstractDispatcher
  {
     private ExecutorService executor = Executors.newCachedThreadPool();
      
     public Object scheduleTimedEvent(String type, Object schedule, Object... parameters)
     {
        throw new UnsupportedOperationException();
     }
     
     public Object scheduleAsynchronousEvent(String type, Object... parameters)
     {  
        final Asynchronous event = new AsynchronousEvent(type, parameters);
        executor.execute( new Runnable() {
           public void run()
           {
              event.execute(null);
           }
        } );
        return null;
     }
      
     public Timer scheduleInvocation(InvocationContext invocation, Component component)
     {
        final Asynchronous call = new AsynchronousInvocation( 
                 invocation.getMethod(),
                 component.getName(),
                 invocation.getParameters() 
              );
        executor.execute( new Runnable() {
           public void run()
           {
              call.execute(null);
           }
        } );
        return null;
     }
     
  }
  
  
  
  1.1      date: 2007/05/31 00:55:40;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/TimerServiceDispatcher.java
  
  Index: TimerServiceDispatcher.java
  ===================================================================
  package org.jboss.seam.core;
  
  import static org.jboss.seam.annotations.Install.BUILT_IN;
  
  import java.io.Serializable;
  import java.lang.annotation.Annotation;
  import java.util.Date;
  import java.util.concurrent.Callable;
  
  import javax.annotation.PostConstruct;
  import javax.annotation.Resource;
  import javax.ejb.EJBException;
  import javax.ejb.NoSuchObjectLocalException;
  import javax.ejb.Stateless;
  import javax.ejb.Timeout;
  import javax.ejb.Timer;
  import javax.ejb.TimerHandle;
  import javax.ejb.TimerService;
  import javax.interceptor.Interceptors;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.annotations.Install;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.annotations.timer.Duration;
  import org.jboss.seam.annotations.timer.Expiration;
  import org.jboss.seam.annotations.timer.IntervalDuration;
  import org.jboss.seam.ejb.SeamInterceptor;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * Dispatcher implementation that uses the EJB
   * TimerService.
   * 
   * @author Gavin King
   *
   */
  @Stateless
  @Name("org.jboss.seam.core.dispatcher")
  @Interceptors(SeamInterceptor.class)
  @Install(value=false, precedence=BUILT_IN)
  public class TimerServiceDispatcher 
     extends AbstractDispatcher<Timer, TimerServiceSchedule>
     implements Dispatcher<Timer, TimerServiceSchedule> //workaround a bug in JBoss EJB3
  {
     
     @Resource TimerService timerService;
  
     @PostConstruct 
     public void postConstruct() {} //workaround for a bug in EJB3
     
     @Timeout
     public void dispatch(Timer timer)
     {
        ( (Asynchronous) timer.getInfo() ).execute(timer);
     }
     
     public Timer scheduleTimedEvent(String type, TimerServiceSchedule timerServiceSchedule, Object... parameters)
     {
        return schedule( 
                 timerServiceSchedule.getDuration(), 
                 timerServiceSchedule.getExpiration(), 
                 timerServiceSchedule.getIntervalDuration(), 
                 new AsynchronousEvent(type, parameters) 
              );
     }
     
     public Timer scheduleAsynchronousEvent(String type, Object... parameters)
     {
        return schedule( 0l, null, null, new AsynchronousEvent(type, parameters) );
     }
     
     public Timer scheduleInvocation(InvocationContext invocation, Component component)
     {
        Long duration = 0l;
        Date expiration = null;
        Long intervalDuration = null;
        Annotation[][] parameterAnnotations = invocation.getMethod().getParameterAnnotations();
        for ( int i=0; i<parameterAnnotations.length; i++ )
        {
           Annotation[] annotations = parameterAnnotations[i];
           for (Annotation annotation: annotations)
           {
              if ( annotation.annotationType().equals(Duration.class) )
              {
                 duration = (Long) invocation.getParameters()[i];
              }
              else if ( annotation.annotationType().equals(IntervalDuration.class) )
              {
                 intervalDuration = (Long) invocation.getParameters()[i];
              }
              else if ( annotation.annotationType().equals(Expiration.class) )
              {
                 expiration = (Date) invocation.getParameters()[i];
              }
           }
        }
  
        AsynchronousInvocation asynchronousInvocation = new AsynchronousInvocation(
              invocation.getMethod(), 
              component.getName(), 
              invocation.getParameters()
           );
        
        return schedule(duration, expiration, intervalDuration, asynchronousInvocation);
        
     }
     
     private Timer schedule(Long duration, Date expiration, Long intervalDuration, Asynchronous asynchronous)
     {
        return new TimerProxy( scheduleWithTimerService(duration, expiration, intervalDuration, asynchronous) );
     }
  
     private Timer scheduleWithTimerService(Long duration, Date expiration, Long intervalDuration, Asynchronous asynchronous)
     {
        if (intervalDuration!=null)
        {
           if (expiration!=null)
           {
               return timerService.createTimer(expiration, intervalDuration, asynchronous);
           }
           else
           {
               return timerService.createTimer(duration, intervalDuration, asynchronous);
           }            
        }
        else if (expiration!=null)
        {
            return timerService.createTimer(expiration, asynchronous);
        }
        else if (duration!=null)
        {
            return timerService.createTimer(duration, asynchronous);
        }
        else
        {
           throw new IllegalArgumentException("TimerServiceSchedule is empty");
        }
     }
     
      static class TimerProxy 
          implements Timer
      {
          Timer timer;
  
          public TimerProxy(Timer timer)    
              throws  IllegalStateException,
                      NoSuchObjectLocalException,
                      EJBException
          {
              this.timer = timer;
          }
          
          private Object callInContext(Callable callable) 
          {
              return TimerServiceDispatcher.instance().call(callable);
          }
  
          public void cancel() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              callInContext(new Callable() {
                      public Object call() 
                      {
                          timer.cancel();
                          return null;
                      }
                  });
          }
  
          public TimerHandle getHandle()
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              TimerHandle handle = (TimerHandle) 
                  callInContext(new Callable() {
                          public Object call() 
                          {
                              return timer.getHandle();
                          }
                      });
              return new TimerHandleProxy(handle);
          }
  
          public Serializable getInfo() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              return (Serializable) 
                  callInContext(new Callable() {
                          public Object call() 
                          {
                              return timer.getInfo();
                          }
                      });            
          }
          public Date getNextTimeout() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              return (Date) 
                  callInContext(new Callable() {
                          public Object call() 
                          {
                              return timer.getNextTimeout();
                          }
                      });            
          }
          
          public long getTimeRemaining()    
              throws IllegalStateException,
                     NoSuchObjectLocalException,
                     EJBException
          {
              return (Long) 
                  callInContext(new Callable() {
                          public Object call() 
                          {
                              return timer.getTimeRemaining();
                          }
                      });  
          }
      }
  
      static class TimerHandleProxy
          implements TimerHandle, 
                     Serializable
      {
          private static final long serialVersionUID = 6913362944260154627L;
        
          TimerHandle handle;
  
          public TimerHandleProxy(TimerHandle handle) 
          {
              this.handle = handle;
          }
          
          private Object callInContext(Callable callable) 
          {
              return TimerServiceDispatcher.instance().call(callable);
          }
  
          public Timer getTimer() 
              throws IllegalStateException,
                     NoSuchObjectLocalException,
                     EJBException 
          {
              Timer timer = (Timer) callInContext( new Callable() {
                  public Object call() 
                  {
                      try
                      {
                          return handle.getTimer();
                      }
                      catch (NoSuchObjectLocalException nsoe)
                      {
                          return null;
                      }           
                  }
              } );
              if (timer==null)
              {
                 throw new NoSuchObjectLocalException();
              }
              else
              {
                 return new TimerProxy(timer);
              }
          }
      }
  }
  
  
  
  1.1      date: 2007/05/31 00:55:40;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/core/TimerServiceSchedule.java
  
  Index: TimerServiceSchedule.java
  ===================================================================
  /**
   * 
   */
  package org.jboss.seam.core;
  
  import java.io.Serializable;
  import java.util.Date;
  
  /**
   * A "schedule" for a timed event executed by
   * the EJB timer service.
   * 
   * @author Gavin King
   *
   */
  public class TimerServiceSchedule implements Serializable
  {
     private Long duration;
     private Date expiration;
     private Long intervalDuration;
     
     public Long getDuration()
     {
        return duration;
     }
     
     public Date getExpiration()
     {
        return expiration;
     }
     
     public Long getIntervalDuration()
     {
        return intervalDuration;
     }
     
     public TimerServiceSchedule(Long duration, Date expiration, Long intervalDuration)
     {
        this.duration = duration;
        this.expiration = expiration;
        this.intervalDuration = intervalDuration;
     }
     
  }
  
  



More information about the jboss-cvs-commits mailing list