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

Gavin King gavin.king at jboss.com
Tue Jun 19 15:08:46 EDT 2007


  User: gavin   
  Date: 07/06/19 15:08:46

  Added:       src/main/org/jboss/seam/async           
                        AbstractDispatcher.java CronSchedule.java
                        Dispatcher.java LocalTimerServiceDispatcher.java
                        LocalTransactionListener.java QuartzDispatcher.java
                        Schedule.java ThreadPoolDispatcher.java
                        TimerSchedule.java TimerServiceDispatcher.java
                        package-info.java
  Log:
  repackaged built-in components
  sorry for breakage, but it had to happen eventually :-(
  
  Revision  Changes    Path
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/AbstractDispatcher.java
  
  Index: AbstractDispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import java.io.Serializable;
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Method;
  import java.util.Date;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.annotations.timer.IntervalCron;
  import org.jboss.seam.annotations.timer.Duration;
  import org.jboss.seam.annotations.timer.Expiration;
  import org.jboss.seam.annotations.timer.FinalExpiration;
  import org.jboss.seam.annotations.timer.IntervalDuration;
  import org.jboss.seam.bpm.BusinessProcess;
  import org.jboss.seam.contexts.Contexts;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.core.Events;
  import org.jboss.seam.core.Init;
  import org.jboss.seam.intercept.InvocationContext;
  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();
     }
     
     protected 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;
        }
        
        public AsynchronousInvocation(InvocationContext invocation, Component component)
        {
           this( invocation.getMethod(), component.getName(), invocation.getParameters() );
        }
        
        @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);
        }
     }
     
     protected 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: Throw exception when there are multiple interval params
     //       Make use of finalExpiration
     //       Make use of NthBusinessDay
     protected Schedule createSchedule(InvocationContext invocation)
     {
        Long duration = null;
        Date expiration = null;
        Date finalExpiration = null;
  
        Long intervalDuration = null;
        String cron = null;
        // NthBusinessDay intervalBusinessDay = 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];
              }
              else if ( annotation.annotationType().equals(FinalExpiration.class) )
              {
                 finalExpiration = (Date) invocation.getParameters()[i];
              }
              else if ( annotation.annotationType().equals(IntervalCron.class) )
              {
                 cron = (String) invocation.getParameters()[i];
              }
           }
        }
        
        if ( cron!=null ) 
        {
          return new CronSchedule(duration, expiration, cron, finalExpiration);
        } 
        else 
        {
          return new TimerSchedule(duration, expiration, intervalDuration, finalExpiration);
        }
     }
     
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/CronSchedule.java
  
  Index: CronSchedule.java
  ===================================================================
  package org.jboss.seam.async;
  
  import java.util.Date;
  
  /**
   * A "cron schedule" for a timed event executed by
   * the Quartz CronTrigger.
   * 
   * @author Michael Yuan
   *
   */
  public class CronSchedule extends Schedule
  {
     private String cron;
     
     String getCron()
     {
        return cron;
     }
     
     /**
      * @param duration the delay before the first event occurs
      * @param cron the unix cron string to control how the events are repeated
      */
     public CronSchedule(Long duration, String cron)
     {
        super(duration);
        this.cron = cron;
     }
  
     /**
      * @param expiration the datetime at which the first event occurs
      * @param cron the unix cron string to control how the events are repeated
      */
     public CronSchedule(Date expiration, String cron)
     {
        super(expiration);
        this.cron = cron;
     }
  
     CronSchedule(Long duration, Date expiration, String cron, Date finalExpiration)
     {
        super(duration, expiration, finalExpiration);
        this.cron = cron;
     }
  
     CronSchedule() {}
     
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/Dispatcher.java
  
  Index: Dispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * 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
   */
  public interface Dispatcher<T, S>
  {
     /**
      * Schedule an asynchronous method call, examining annotations
      * upon the method to determine the schedule
      * 
      * @return some kind of timer object, or null
      */
     public T scheduleInvocation(InvocationContext invocation, Component component);
     /**
      * Schedule a timed (delayed and/or periodic) event
      * 
      * @return some kind of timer object, or null
      */
     public T scheduleTimedEvent(String type, S schedule, Object... parameters);
     
     /**
      * Schedule an immediate asynchronous event
      * 
      * @return some kind of timer object, or null
      */
     public T scheduleAsynchronousEvent(String type, Object... parameters);
     
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/LocalTimerServiceDispatcher.java
  
  Index: LocalTimerServiceDispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import java.util.concurrent.Callable;
  
  import javax.ejb.Local;
  import javax.ejb.Timer;
  
  
  /**
   * Local interface for TimerServiceDispatcher.
   * 
   * @author Gavin King
   *
   */
  @Local
  public interface LocalTimerServiceDispatcher extends Dispatcher<Timer, TimerSchedule>
  {   
     public Object call(Callable task);
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/LocalTransactionListener.java
  
  Index: LocalTransactionListener.java
  ===================================================================
  package org.jboss.seam.async;
  
  import javax.ejb.Local;
  import javax.transaction.Synchronization;
  
  @Local
  public interface LocalTransactionListener
  {
     public void scheduleEvent(String type, Object... parameters);
     public void registerSynchronization(Synchronization sync);
     public void destroy();
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/QuartzDispatcher.java
  
  Index: QuartzDispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import static org.jboss.seam.annotations.Install.BUILT_IN;
  
  import java.io.Serializable;
  import java.rmi.server.UID;
  import java.util.Date;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.annotations.Create;
  import org.jboss.seam.annotations.Destroy;
  import org.jboss.seam.annotations.Install;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.annotations.Scope;
  import org.jboss.seam.intercept.InvocationContext;
  import org.jboss.seam.log.LogProvider;
  import org.jboss.seam.log.Logging;
  import org.quartz.CronTrigger;
  import org.quartz.Job;
  import org.quartz.JobDataMap;
  import org.quartz.JobDetail;
  import org.quartz.JobExecutionContext;
  import org.quartz.JobExecutionException;
  import org.quartz.Scheduler;
  import org.quartz.SchedulerException;
  import org.quartz.SchedulerFactory;
  import org.quartz.SimpleTrigger;
  
  /**
   * Dispatcher implementation that uses the Quartz library.
   * 
   * @author Michael Yuan
   *
   */
  @Scope(ScopeType.APPLICATION)
  @Name("org.jboss.seam.core.dispatcher")
  @Install(value=false, precedence=BUILT_IN)
  public class QuartzDispatcher extends AbstractDispatcher<QuartzDispatcher.QuartzTriggerHandle, Schedule>
  {
     
     private static final LogProvider log = Logging.getLogProvider(QuartzDispatcher.class);
     private static Scheduler scheduler;
  
     @Create
     public void initScheduler() 
     {
       SchedulerFactory schedulerFactory = new org.quartz.impl.StdSchedulerFactory();
       try 
       {
         scheduler = schedulerFactory.getScheduler();
         scheduler.start();
         log.info("The QuartzDispatcher has started");
       } 
       catch (SchedulerException se) {
         log.error("Cannot get or start a Quartz Scheduler");
         se.printStackTrace ();
       }
     }
  
     public QuartzTriggerHandle scheduleAsynchronousEvent(String type, Object... parameters)
     {  
        String jobName = nextUniqueName();
        String triggerName = nextUniqueName();
        
        JobDetail jobDetail = new JobDetail(jobName, null, QuartzJob.class);
        jobDetail.getJobDataMap().put("async", new AsynchronousEvent(type, parameters));
         
        SimpleTrigger trigger = new SimpleTrigger(triggerName, null);
        
        log.info("In the scheduleAsynchronousEvent()");
  
        try 
        {
          scheduler.scheduleJob(jobDetail, trigger);
          return new QuartzTriggerHandle(triggerName);
        } 
        catch (SchedulerException se) 
        {
          log.error("Cannot Schedule a Quartz Job");
          se.printStackTrace ();
          return null;
        }
     }
      
     public QuartzTriggerHandle scheduleTimedEvent(String type, Schedule schedule, Object... parameters)
     {
        log.info("In the scheduleTimedEvent()");
        try 
        {
          return scheduleWithQuartzService( schedule, new AsynchronousEvent(type, parameters) );
        } 
        catch (SchedulerException se) 
        {
          log.error("Cannot Schedule a Quartz Job");
          se.printStackTrace ();
          return null;
        }
     }
     
     public QuartzTriggerHandle scheduleInvocation(InvocationContext invocation, Component component)
     {
        log.info("In the scheduleInvocation()");
        try 
        {
          return scheduleWithQuartzService( 
                 createSchedule(invocation), 
                 new AsynchronousInvocation(invocation, component)
              );
        } 
        catch (SchedulerException se) {
          log.error("Cannot Schedule a Quartz Job");
          se.printStackTrace ();
          return null;
        }
     }
        
     private static Date calculateDelayedDate (long delay)
     {
       Date now = new Date ();
       now.setTime(now.getTime() + delay);
       return now;
     }
  
     private QuartzTriggerHandle scheduleWithQuartzService(Schedule schedule, Asynchronous async) throws SchedulerException
     {
        log.info("In the scheduleWithQuartzService()");
        
        String jobName = nextUniqueName();
        String triggerName = nextUniqueName();
        
        JobDetail jobDetail = new JobDetail(jobName, null, QuartzJob.class);
        jobDetail.getJobDataMap().put("async", async);
  
        if (schedule instanceof CronSchedule) 
        {
          CronSchedule cronSchedule = (CronSchedule) schedule; 
          try 
          {
            CronTrigger trigger = new CronTrigger (triggerName, null);
            trigger.setCronExpression(cronSchedule.getCron());
            trigger.setEndTime(cronSchedule.getFinalExpiration());
  
            if ( cronSchedule.getExpiration()!=null )
            {
              trigger.setStartTime (cronSchedule.getExpiration());
            }
            else if ( cronSchedule.getDuration()!=null )
            {
              trigger.setStartTime (calculateDelayedDate(cronSchedule.getDuration()));
            }
  
            scheduler.scheduleJob( jobDetail, trigger );
  
          } 
          catch (Exception e) 
          {
            log.error ("Cannot submit cron job");
            e.printStackTrace ();
            return null;
          }
        } 
        else if (schedule instanceof TimerSchedule && ((TimerSchedule) schedule).getIntervalDuration() != null) 
        {
           TimerSchedule timerSchedule = (TimerSchedule) schedule;
           if ( timerSchedule.getExpiration()!=null )
           {
              SimpleTrigger trigger = new SimpleTrigger(triggerName, null, timerSchedule.getExpiration(), timerSchedule.getFinalExpiration(), SimpleTrigger.REPEAT_INDEFINITELY, timerSchedule.getIntervalDuration());
              scheduler.scheduleJob( jobDetail, trigger );
  
           }
           else if ( timerSchedule.getDuration()!=null )
           {
               SimpleTrigger trigger = new SimpleTrigger(triggerName, null, calculateDelayedDate(timerSchedule.getDuration()), timerSchedule.getFinalExpiration(), SimpleTrigger.REPEAT_INDEFINITELY, timerSchedule.getIntervalDuration());
               scheduler.scheduleJob( jobDetail, trigger );
  
           }
           else
           {
              SimpleTrigger trigger = new SimpleTrigger(triggerName, null, null, timerSchedule.getFinalExpiration(), SimpleTrigger.REPEAT_INDEFINITELY, timerSchedule.getIntervalDuration());
              scheduler.scheduleJob( jobDetail, trigger );
  
           }
        } 
        else 
        {
          if ( schedule.getExpiration()!=null )
          {
              SimpleTrigger trigger = new SimpleTrigger (triggerName, null, schedule.getExpiration());
              scheduler.scheduleJob(jobDetail, trigger);
  
          }
          else if ( schedule.getDuration()!=null )
          {
              SimpleTrigger trigger = new SimpleTrigger (triggerName, null, calculateDelayedDate(schedule.getDuration()));
              scheduler.scheduleJob(jobDetail, trigger);
  
          }
          else
          {
             SimpleTrigger trigger = new SimpleTrigger(triggerName, null);
             scheduler.scheduleJob(jobDetail, trigger);
  
          }
        }
  
        return new QuartzTriggerHandle (triggerName);
     }
     
     private String nextUniqueName ()
     {
        return (new UID()).toString();
     }
     
     @Destroy
     public void destroy()
     {
        log.info("The QuartzDispatcher is shut down");
        try {
          scheduler.shutdown();
        } catch (SchedulerException se) {
          log.error("Cannot shutdown the Quartz Scheduler");
          se.printStackTrace ();
        }
        
     }
     
     public static class QuartzJob implements Job
     {
        private AbstractDispatcher.Asynchronous async;
        
        public QuartzJob() { }
  
        public void execute(JobExecutionContext context)
            throws JobExecutionException
        {
           log.info("Start executing Quartz job");
           JobDataMap dataMap = context.getJobDetail().getJobDataMap();
           async = (AbstractDispatcher.Asynchronous)dataMap.get("async");
           async.execute(null);
           log.info("End executing Quartz job");
        }
     }
     
     public static class QuartzTriggerHandle implements Serializable
     {
        private String triggerName;
          
        public QuartzTriggerHandle(String triggerName) 
        {
           this.triggerName = triggerName; 
        }
  
        public void cancel() throws SchedulerException
        {
           log.info("Cancel executing Quartz job");
           scheduler.unscheduleJob(triggerName, null);
        }
        
        public void pause() throws SchedulerException
        {
           log.info("Pause executing Quartz job");
           scheduler.pauseTrigger(triggerName, null);
           
        }
        
        public void resume() throws SchedulerException
        {
           log.info("Resume executing Quartz job");
           scheduler.resumeTrigger(triggerName, null);
        }
     }
  
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/Schedule.java
  
  Index: Schedule.java
  ===================================================================
  package org.jboss.seam.async;
  
  import java.io.Serializable;
  import java.util.Date;
  
  /**
   * A "schedule" for a timed event executed by
   * a timer service which supports delayed
   * timed events. It is the base class for the more
   * useful TimerSchedule and CronSchedule classes.
   * 
   * @author Michael Yuan
   *
   */
  public class Schedule implements Serializable
  {
     private Long duration;
     private Date expiration;
     private Date finalExpiration;
     
     Long getDuration()
     {
        return duration;
     }
     
     Date getExpiration()
     {
        return expiration;
     }
     
     Date getFinalExpiration()
     {
        return finalExpiration;
     }
  
     /**
      * @param duration the delay before the event occurs
      * @param expiration the datetime at which the event occurs
      */
     Schedule(Long duration, Date expiration)
     {
        this.duration = duration;
        this.expiration = expiration;
     }
  
     /**
      * @param duration the delay before the event occurs
      * @param expiration the datetime at which the event occurs
      * @param finalExpiration the datetime at which the event ends
      */
     Schedule(Long duration, Date expiration, Date finalExpiration)
     {
        this.duration = duration;
        this.expiration = expiration;
        this.finalExpiration = finalExpiration;
     }
  
     /**
      * @param duration the delay before the event occurs
      */
     public Schedule(Long duration)
     {
        this.duration = duration;
     }
  
     /**
      * @param expiration the datetime at which the event occurs
      */
     public Schedule(Date expiration)
     {
        this.expiration = expiration;
     }
  
     public Schedule () { }
  
     @Override
     public int hashCode()
     {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((duration == null) ? 0 : duration.hashCode());
        result = prime * result + ((expiration == null) ? 0 : expiration.hashCode());
        return result;
     }
  
     @Override
     public boolean equals(Object obj)
     {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final Schedule other = (Schedule) obj;
        if (duration == null)
        {
           if (other.duration != null) return false;
        }
        else if (!duration.equals(other.duration)) return false;
        if (expiration == null)
        {
           if (other.expiration != null) return false;
        }
        else if (!expiration.equals(other.expiration)) return false;
        return true;
     }
     
     
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/ThreadPoolDispatcher.java
  
  Index: ThreadPoolDispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import static org.jboss.seam.annotations.Install.BUILT_IN;
  
  import java.util.Date;
  import java.util.concurrent.Executors;
  import java.util.concurrent.Future;
  import java.util.concurrent.ScheduledExecutorService;
  import java.util.concurrent.TimeUnit;
  
  import org.jboss.seam.Component;
  import org.jboss.seam.ScopeType;
  import org.jboss.seam.annotations.Destroy;
  import org.jboss.seam.annotations.Install;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.annotations.Scope;
  import org.jboss.seam.intercept.InvocationContext;
  
  /**
   * Dispatcher implementation that uses a java.util.concurrent
   * ScheduledThreadPoolExecutor.
   * 
   * @author Gavin King
   *
   */
  @Scope(ScopeType.APPLICATION)
  @Name("org.jboss.seam.core.dispatcher")
  @Install(precedence=BUILT_IN)
  public class ThreadPoolDispatcher extends AbstractDispatcher<Future, TimerSchedule>
  {
     private int threadPoolSize = 10; 
     
     private ScheduledExecutorService executor = Executors.newScheduledThreadPool(threadPoolSize);
      
     public Future scheduleAsynchronousEvent(String type, Object... parameters)
     {  
        return executor.submit( new RunnableAsynchronous( new AsynchronousEvent(type, parameters) ) );
     }
      
     public Future scheduleTimedEvent(String type, TimerSchedule schedule, Object... parameters)
     {
        return scheduleWithExecutorService( schedule, new RunnableAsynchronous( new AsynchronousEvent(type, parameters) ) );
     }
     
     public Future scheduleInvocation(InvocationContext invocation, Component component)
     {
        return scheduleWithExecutorService( 
                 (TimerSchedule) createSchedule(invocation), 
                 new RunnableAsynchronous( new AsynchronousInvocation(invocation, component) ) 
              );
     }
     
     private static long toDuration(Date expiration)
     {
        return expiration.getTime() - new Date().getTime();
     }
     
     private Future scheduleWithExecutorService(TimerSchedule schedule, Runnable runnable)
     {
        if ( schedule.getIntervalDuration()!=null )
        {
           if ( schedule.getExpiration()!=null )
           {
              return executor.scheduleAtFixedRate( runnable, toDuration( schedule.getExpiration() ), schedule.getIntervalDuration(), TimeUnit.MILLISECONDS );
           }
           else if ( schedule.getDuration()!=null )
           {
               return executor.scheduleAtFixedRate( runnable, schedule.getDuration(), schedule.getIntervalDuration(), TimeUnit.MILLISECONDS );
           }
           else
           {
              return executor.scheduleAtFixedRate( runnable, 0l, schedule.getIntervalDuration(), TimeUnit.MILLISECONDS );
           }
        }
        else if ( schedule.getExpiration()!=null )
        {
            return executor.schedule( runnable, toDuration( schedule.getExpiration() ), TimeUnit.MILLISECONDS );
        }
        else if ( schedule.getDuration()!=null )
        {
            return executor.schedule( runnable, schedule.getDuration(), TimeUnit.MILLISECONDS );
        }
        else
        {
           return executor.schedule(runnable, 0l, TimeUnit.MILLISECONDS);
        }
     }
     
     @Destroy
     public void destroy()
     {
        executor.shutdown();
        try
        {
           executor.awaitTermination(5, TimeUnit.SECONDS);
        }
        catch (InterruptedException ie)
        {
           
        }
     }
     
     static class RunnableAsynchronous implements Runnable
     {
        private AbstractDispatcher.Asynchronous async;
        
        RunnableAsynchronous(Asynchronous async)
        {
           this.async = async;
        }
        
        public void run()
        {
           async.execute(null);
        }
     }
  
     public int getThreadPoolSize()
     {
        return threadPoolSize;
     }
  
     public void setThreadPoolSize(int threadPoolSize)
     {
        this.threadPoolSize = threadPoolSize;
     }
     
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/TimerSchedule.java
  
  Index: TimerSchedule.java
  ===================================================================
  package org.jboss.seam.async;
  
  import java.util.Date;
  
  /**
   * A "schedule" for a timed event executed by
   * the EJB timer service or some other timer
   * service which supports delayed and/or periodic
   * timed events.
   * 
   * @author Gavin King
   *
   */
  public class TimerSchedule extends Schedule
  {
     private Long intervalDuration;
     
     Long getIntervalDuration()
     {
        return intervalDuration;
     }
     
     /**
      * @param duration the delay before the event occurs
      */
     public TimerSchedule(Long duration)
     {
        super(duration);
     }
  
     /**
      * @param expiration the datetime at which the event occurs
      */
     public TimerSchedule(Date expiration)
     {
        super(expiration);
     }
  
     /**
      * @param duration the delay before the first event occurs
      * @param intervalDuration the period between the events
      */
     public TimerSchedule(Long duration, Long intervalDuration)
     {
        super(duration);
        this.intervalDuration = intervalDuration;
     }
  
     /**
      * @param expiration the datetime at which the first event occurs
      * @param intervalDuration the period between the events
      */
     public TimerSchedule(Date expiration, Long intervalDuration)
     {
        super(expiration);
        this.intervalDuration = intervalDuration;
     }
  
     TimerSchedule(Long duration, Date expiration, Long intervalDuration)
     {
        super(duration, expiration);
        this.intervalDuration = intervalDuration;
     }
  
     TimerSchedule(Long duration, Date expiration, Long intervalDuration, Date finalExpiration)
     {
        super(duration, expiration, finalExpiration);
        this.intervalDuration = intervalDuration;
     }
  
     TimerSchedule() {}
     
     
     
     public static final TimerSchedule ONCE_IMMEDIATELY = new TimerSchedule();
  
     @Override
     public int hashCode()
     {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((intervalDuration == null) ? 0 : intervalDuration.hashCode());
        return result;
     }
  
     @Override
     public boolean equals(Object obj)
     {
        if (!super.equals(obj)) return false;
        final TimerSchedule other = (TimerSchedule) obj;
        if (intervalDuration == null)
        {
           if (other.intervalDuration != null) return false;
        }
        else if (!intervalDuration.equals(other.intervalDuration)) return false;
        return true;
     }
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/TimerServiceDispatcher.java
  
  Index: TimerServiceDispatcher.java
  ===================================================================
  package org.jboss.seam.async;
  
  import static org.jboss.seam.annotations.Install.BUILT_IN;
  
  import java.io.Serializable;
  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.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, TimerSchedule>
     implements LocalTimerServiceDispatcher
  {
     
     @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, TimerSchedule schedule, Object... parameters)
     {
        return new TimerProxy( scheduleWithTimerService( schedule, new AsynchronousEvent(type, parameters) ) );
     }
     
     public Timer scheduleAsynchronousEvent(String type, Object... parameters)
     {
        return new TimerProxy( timerService.createTimer( 0l, new AsynchronousEvent(type, parameters) ) );
     }
     
     public Timer scheduleInvocation(InvocationContext invocation, Component component)
     {
        return new TimerProxy( scheduleWithTimerService( (TimerSchedule) createSchedule(invocation), new AsynchronousInvocation(invocation, component) ) );
        
     }
  
     private Timer scheduleWithTimerService(TimerSchedule schedule, Asynchronous asynchronous)
     {
        if ( schedule.getIntervalDuration()!=null )
        {
           if ( schedule.getExpiration()!=null )
           {
               return timerService.createTimer( schedule.getExpiration(), schedule.getIntervalDuration(), asynchronous );
           }
           else if ( schedule.getDuration()!=null )
           {
               return timerService.createTimer( schedule.getDuration(), schedule.getIntervalDuration(), asynchronous );
           }
           else
           {
              return timerService.createTimer( 0l, schedule.getIntervalDuration(), asynchronous );
           }
        }
        else if ( schedule.getExpiration()!=null )
        {
            return timerService.createTimer( schedule.getExpiration(), asynchronous );
        }
        else if ( schedule.getDuration()!=null )
        {
            return timerService.createTimer( schedule.getDuration(), asynchronous );
        }
        else
        {
           return timerService.createTimer(0l, asynchronous);
        }
     }
     
      static class TimerProxy 
          implements Timer
      {
          Timer timer;
  
          public TimerProxy(Timer timer)    
              throws  IllegalStateException,
                      NoSuchObjectLocalException,
                      EJBException
          {
              this.timer = timer;
          }
          
          public void cancel() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              instance().call(new Callable() {
                   public Object call() 
                   {
                       timer.cancel();
                       return null;
                   }
               });
          }
  
          public TimerHandle getHandle()
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              TimerHandle handle = (TimerHandle) 
                  instance().call(new Callable() {
                       public Object call() 
                       {
                           return timer.getHandle();
                       }
                   });
              return new TimerHandleProxy(handle);
          }
  
          public Serializable getInfo() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              return (Serializable) 
                  instance().call(new Callable() {
                       public Object call() 
                       {
                           return timer.getInfo();
                       }
                   });            
          }
          public Date getNextTimeout() 
              throws
                  IllegalStateException,
                  NoSuchObjectLocalException,
                  EJBException
          {
              return (Date) 
                  instance().call(new Callable() {
                       public Object call() 
                       {
                           return timer.getNextTimeout();
                       }
                   });            
          }
          
          public long getTimeRemaining()    
              throws IllegalStateException,
                     NoSuchObjectLocalException,
                     EJBException
          {
              return (Long) 
                  instance().call(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;
          }
          
          public Timer getTimer() 
              throws IllegalStateException,
                     NoSuchObjectLocalException,
                     EJBException 
          {
              Timer timer = (Timer) instance().call(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);
              }
          }
      }
  
      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);
          }
      }
      public static LocalTimerServiceDispatcher instance()
      {
         return ( (LocalTimerServiceDispatcher) AbstractDispatcher.instance() );
      }
  
  }
  
  
  
  1.1      date: 2007/06/19 19:08:46;  author: gavin;  state: Exp;jboss-seam/src/main/org/jboss/seam/async/package-info.java
  
  Index: package-info.java
  ===================================================================
  @Namespace(value="http://jboss.com/products/seam/async", prefix="org.jboss.seam.async")
  package org.jboss.seam.async;
  
  import org.jboss.seam.annotations.Namespace;
  
  
  



More information about the jboss-cvs-commits mailing list