View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.quartz;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.MuleException;
11  import org.mule.api.config.MuleProperties;
12  import org.mule.api.lifecycle.InitialisationException;
13  import org.mule.api.transport.ConnectorException;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.transport.AbstractConnector;
16  
17  import java.util.HashMap;
18  import java.util.Map;
19  import java.util.Properties;
20  
21  import org.quartz.Scheduler;
22  import org.quartz.SchedulerFactory;
23  import org.quartz.impl.StdSchedulerFactory;
24  
25  /**
26   * Creates a connection to a Quartz scheduler. This allows events to be scheduled at
27   * specific times, with repeated occurrences.
28   */
29  public class QuartzConnector extends AbstractConnector
30  {
31      public static final String QUARTZ = "quartz";
32  
33      public static final String PROPERTY_CRON_EXPRESSION = "cronExpression";
34      public static final String PROPERTY_REPEAT_INTERVAL = "repeatInterval";
35      public static final String PROPERTY_REPEAT_COUNT = "repeatCount";
36      public static final String PROPERTY_START_DELAY = "startDelay";
37      public static final String PROPERTY_PAYLOAD = "payload";
38  
39      public static final String PROPERTY_JOB_CONFIG = "jobConfig";
40      public static final String PROPERTY_JOB_DATA = "jobData";
41  
42      public static final String PROPERTY_JOB_REF = "jobRef";
43      public static final String PROPERTY_JOB_OBJECT = "jobObject";
44  
45      public static final String DEFAULT_GROUP_NAME = "mule";
46      public static final String QUARTZ_INSTANCE_NAME_PROPERTY = "org.quartz.scheduler.instanceName";
47  
48      private static final Object instanceNamesLock = new Object();
49      private static final Map<String, QuartzConnector> instanceNames = new HashMap<String, QuartzConnector>();
50  
51      /**
52       * Properties to be used for creating the scheduler.  If no properties are given, the
53       * scheduler will be created by <code>StdSchedulerFactory.getDefaultScheduler()</code>
54       */
55      private Properties factoryProperties = null;
56  
57      /**
58       * The scheduler instance.  This can be configured by the user and injected as a bean
59       * or if not, it will be created by Mule upon initialization.
60       */
61      private Scheduler quartzScheduler = null;
62  
63      public QuartzConnector(MuleContext context)
64      {
65          super(context);
66      }
67      
68      @Override
69      protected void doInitialise() throws InitialisationException
70      {
71          if (factoryProperties == null)
72          {
73              factoryProperties = new Properties();
74          }
75  
76          //Set the thread count, we can't seem to plug in our work manager unfortunately
77          factoryProperties.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
78          factoryProperties.setProperty("org.quartz.threadPool.threadCount", String.valueOf(getReceiverThreadingProfile().getMaxThreadsActive()));
79          String instanceName = factoryProperties.getProperty(QUARTZ_INSTANCE_NAME_PROPERTY);
80          if (instanceName == null)
81          {
82              factoryProperties.setProperty(QUARTZ_INSTANCE_NAME_PROPERTY, "scheduler-" + muleContext.getConfiguration().getId());
83          }
84          else
85          {
86              ensureUniqueInstanceNameBetweenMuleApps(instanceName);
87          }
88  
89          try
90          {
91              if (quartzScheduler == null)
92              {
93                  SchedulerFactory factory = new StdSchedulerFactory(factoryProperties);
94                  quartzScheduler = factory.getScheduler();
95              }
96              quartzScheduler.getContext().put(MuleProperties.MULE_CONTEXT_PROPERTY, muleContext);            
97          
98          }
99          catch (Exception e)
100         {
101             throw new InitialisationException(CoreMessages.initialisationFailure("Quartz connector"), e, this);
102         }
103     }
104 
105     @Override
106     protected void doDispose()
107     {
108         try
109         {
110             if (quartzScheduler != null)
111             {
112                 quartzScheduler.shutdown();
113             }
114         }
115         catch (Exception e)
116         {
117             logger.warn(CoreMessages.failedToStop("Quartz provider"), e);
118         }
119 
120         String instanceName = factoryProperties.getProperty(QUARTZ_INSTANCE_NAME_PROPERTY);
121         if (instanceName != null)
122         {
123             removeUpInstanceName(instanceName);
124         }
125     }
126 
127     private void ensureUniqueInstanceNameBetweenMuleApps(String instanceName) throws InitialisationException
128     {
129         synchronized (instanceNamesLock)
130         {
131             if (instanceNames.keySet().contains(instanceName))
132             {
133                 throw new InitialisationException(CoreMessages.initialisationFailure(String.format("Value '%s' of quartz connector property '%s' cannot be reused in different applications", instanceName, QUARTZ_INSTANCE_NAME_PROPERTY)), this);
134             }
135 
136             if (logger.isDebugEnabled())
137             {
138                 logger.debug("Adding quartz instance name: " + instanceName);
139             }
140 
141             instanceNames.put(instanceName, this);
142         }
143     }
144 
145     private void removeUpInstanceName(String instanceName)
146     {
147         if (logger.isDebugEnabled())
148         {
149             logger.debug("Removing quartz instance name: " + instanceName);
150         }
151 
152         synchronized (instanceNamesLock)
153         {
154             if (instanceNames.get(instanceName) == this)
155             {
156                 instanceNames.remove(instanceName);
157             }
158         }
159     }
160 
161     @Override
162     protected void doConnect() throws Exception
163     {
164         // template method
165     }
166 
167     @Override
168     protected void doDisconnect() throws Exception
169     {
170         // template method
171     }
172 
173     @Override
174     protected void doStart() throws MuleException
175     {
176         try
177         {
178             quartzScheduler.start();
179         }
180         catch (Exception e)
181         {
182             throw new ConnectorException(CoreMessages.failedToStart("Quartz provider"), this, e);
183         }
184     }
185 
186     @Override
187     protected void doStop() throws MuleException
188     {
189         try
190         {
191             if (quartzScheduler != null)
192             {
193                 quartzScheduler.standby();
194             }
195         }
196         catch (Exception e)
197         {
198             throw new ConnectorException(CoreMessages.failedToStop("Quartz provider"), this, e);
199         }
200     }
201 
202     public String getProtocol()
203     {
204         return QUARTZ;
205     }
206 
207     public Scheduler getQuartzScheduler()
208     {
209         return quartzScheduler;
210     }
211 
212     public void setQuartzScheduler(Scheduler scheduler)
213     {
214         this.quartzScheduler = scheduler;
215     }
216 
217     public Properties getFactoryProperties()
218     {
219         return factoryProperties;
220     }
221 
222     public void setFactoryProperties(Properties factoryProperties)
223     {
224         this.factoryProperties = factoryProperties;
225     }
226 }