View Javadoc

1   /*
2    * $Id: AbstractPollingMessageReceiver.java 10961 2008-02-22 19:01:02Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport;
12  
13  import org.mule.api.MuleException;
14  import org.mule.api.endpoint.InboundEndpoint;
15  import org.mule.api.lifecycle.CreateException;
16  import org.mule.api.service.Service;
17  import org.mule.api.transport.Connector;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.util.ObjectUtils;
20  
21  import java.util.Iterator;
22  import java.util.LinkedList;
23  import java.util.List;
24  
25  import edu.emory.mathcs.backport.java.util.concurrent.Future;
26  import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
27  import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService;
28  import edu.emory.mathcs.backport.java.util.concurrent.ScheduledFuture;
29  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
30  
31  /**
32   * <code>AbstractPollingMessageReceiver</code> implements a base class for polling
33   * message receivers. The receiver provides a {@link #poll()} method that implementations
34   * must implement to execute their custom code. Note that the receiver will not poll if
35   * the associated connector is not started.
36   */
37  public abstract class AbstractPollingMessageReceiver extends AbstractMessageReceiver
38  {
39      public static final long DEFAULT_POLL_FREQUENCY = 1000;
40      public static final TimeUnit DEFAULT_POLL_TIMEUNIT = TimeUnit.MILLISECONDS;
41  
42      public static final long DEFAULT_STARTUP_DELAY = 1000;
43  
44      private long frequency = DEFAULT_POLL_FREQUENCY;
45      private TimeUnit timeUnit = DEFAULT_POLL_TIMEUNIT;
46  
47      // @GuardedBy(itself)
48      protected final List schedules = new LinkedList();
49  
50      public AbstractPollingMessageReceiver(Connector connector,
51                                            Service service,
52                                            final InboundEndpoint endpoint) throws CreateException
53      {
54          super(connector, service, endpoint);
55      }
56  
57      protected void doStart() throws MuleException
58      {
59          try
60          {
61              this.schedule();
62          }
63          catch (Exception ex)
64          {
65              this.stop();
66              throw new CreateException(CoreMessages.failedToScheduleWork(), ex, this);
67          }
68      }
69  
70      protected void doStop() throws MuleException
71      {
72          this.unschedule();
73      }
74  
75      /**
76       * This method registers this receiver for periodic polling ticks with the connectors
77       * scheduler. Subclasses can override this in case they want to handle their polling
78       * differently.
79       * 
80       * @throws RejectedExecutionException
81       * @throws NullPointerException
82       * @throws IllegalArgumentException
83       * @see {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
84       */
85      protected void schedule()
86          throws RejectedExecutionException, NullPointerException, IllegalArgumentException
87      {
88          synchronized (schedules)
89          {
90              // we use scheduleWithFixedDelay to prevent queue-up of tasks when
91              // polling takes longer than the specified frequency, e.g. when the
92              // polled database or network is slow or returns large amounts of
93              // data.
94              ScheduledFuture schedule = connector.getScheduler().scheduleWithFixedDelay(
95                  new PollingReceiverWorkerSchedule(this.createWork()), DEFAULT_STARTUP_DELAY,
96                  this.getFrequency(), this.getTimeUnit());
97              schedules.add(schedule);
98  
99              if (logger.isDebugEnabled())
100             {
101                 logger.debug(ObjectUtils.identityToShortString(this) + " scheduled "
102                              + ObjectUtils.identityToShortString(schedule) + " with " + frequency
103                              + " " + getTimeUnit() + " polling frequency");
104             }
105         }
106     }
107 
108     /**
109      * This method cancels the schedules which were created in {@link #schedule()}.
110      * 
111      * @see {@link Future#cancel(boolean)}
112      */
113     protected void unschedule()
114     {
115         synchronized (schedules)
116         {
117             // cancel our schedules gently: do not interrupt when polling is in progress
118             for (Iterator i = schedules.iterator(); i.hasNext();)
119             {
120                 ScheduledFuture schedule = (ScheduledFuture)i.next();
121                 schedule.cancel(false);
122                 i.remove();
123 
124                 if (logger.isDebugEnabled())
125                 {
126                     logger.debug(ObjectUtils.identityToShortString(this) + " cancelled polling schedule: "
127                                  + ObjectUtils.identityToShortString(schedule));
128                 }
129             }
130         }
131     }
132 
133     protected PollingReceiverWorker createWork()
134     {
135         return new PollingReceiverWorker(this);
136     }
137 
138     public long getFrequency()
139     {
140         return frequency;
141     }
142 
143     // TODO a nifty thing would be on-the-fly adjustment (via JMX?) of the
144     // polling frequency by rescheduling without explicit stop()
145     public void setFrequency(long value)
146     {
147         if (value <= 0)
148         {
149             frequency = DEFAULT_POLL_FREQUENCY;
150         }
151         else
152         {
153             frequency = value;
154         }
155     }
156 
157     public TimeUnit getTimeUnit()
158     {
159         return timeUnit;
160     }
161 
162     public void setTimeUnit(TimeUnit timeUnit)
163     {
164         this.timeUnit = timeUnit;
165     }
166 
167     public abstract void poll() throws Exception;
168 
169 }