View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.fulcrum.quartz.impl;
21  
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Properties;
26  import java.util.Set;
27  
28  import org.apache.avalon.framework.activity.Disposable;
29  import org.apache.avalon.framework.activity.Initializable;
30  import org.apache.avalon.framework.activity.Startable;
31  import org.apache.avalon.framework.configuration.Configurable;
32  import org.apache.avalon.framework.configuration.Configuration;
33  import org.apache.avalon.framework.configuration.ConfigurationException;
34  import org.apache.avalon.framework.logger.AbstractLogEnabled;
35  import org.apache.avalon.framework.logger.LogEnabled;
36  import org.apache.avalon.framework.parameters.Parameters;
37  import org.apache.avalon.framework.service.ServiceException;
38  import org.apache.avalon.framework.service.ServiceManager;
39  import org.apache.avalon.framework.service.Serviceable;
40  import org.apache.avalon.framework.thread.ThreadSafe;
41  import org.apache.fulcrum.quartz.QuartzScheduler;
42  import org.quartz.Job;
43  import org.quartz.JobDetail;
44  import org.quartz.JobExecutionContext;
45  import org.quartz.JobExecutionException;
46  import org.quartz.JobKey;
47  import org.quartz.JobListener;
48  import org.quartz.Scheduler;
49  import org.quartz.SchedulerException;
50  import org.quartz.Trigger;
51  import org.quartz.impl.StdSchedulerFactory;
52  import org.quartz.impl.matchers.GroupMatcher;
53  
54  /**
55   * Avalon service  wrapping the QuartzScheduler.
56   */
57  public class QuartzSchedulerImpl
58          extends AbstractLogEnabled
59          implements QuartzScheduler, Configurable, Serviceable, Disposable, Initializable, ThreadSafe, JobListener, Startable
60  {
61      /**
62       * the Avalon service serviceManager
63       */
64      private ServiceManager serviceManager;
65  
66      /**
67       * the Quartz scheduler instance
68       */
69      private Scheduler scheduler;
70  
71      /**
72       * the quartz property file
73       */
74      private String quartzPropertyFile;
75  
76      /**
77       * the quartz properties loaded from the XML configuration
78       */
79      private Properties quartzProperties;
80  
81      // === Avalon Lifecycle =================================================
82  
83      /**
84       * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
85       */
86      public void configure(Configuration conf) throws ConfigurationException
87      {
88          Configuration quartzConf = conf.getChild("configuration", true);
89  
90          if(quartzConf.getChild("properties", false) != null)
91          {
92              this.quartzProperties = Parameters.toProperties(Parameters.fromConfiguration(quartzConf.getChild("properties")));
93          }
94          else if(quartzConf.getChild("quartzPropertyFile", false) != null)
95          {
96              this.quartzPropertyFile = quartzConf.getChild("quartzPropertyFile").getValue();
97          }
98      }
99  
100     /**
101      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
102      */
103     public void service(ServiceManager manager) throws ServiceException
104     {
105         this.serviceManager = manager;
106     }
107 
108     /**
109      * @see org.apache.avalon.framework.activity.Initializable#initialize()
110      */
111     public void initialize() throws Exception
112     {
113         // instantiating a specific scheduler from a property file or properties
114         StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
115         if(this.quartzProperties != null)
116         {
117             getLogger().info("Pulling quartz configuration from the container XML configuration");
118             schedulerFactory.initialize(this.quartzProperties);
119         }
120         else if(this.quartzPropertyFile != null)
121         {
122             getLogger().info("Pulling quartz configuration from the following property file : " + this.quartzPropertyFile);
123             schedulerFactory.initialize(this.quartzPropertyFile);
124         }
125         else
126         {
127             getLogger().info("Using Quartz default configuration since no user-supplied configuration was found");
128             schedulerFactory.initialize();
129         }
130 
131         this.scheduler = schedulerFactory.getScheduler();
132 
133         // add this service instance as JobListener to allow basic monitoring
134         getScheduler().getListenerManager().addJobListener(this, new ArrayList());
135     }
136 
137     public void start() throws Exception
138     {
139         getScheduler().start();
140 
141         if(getLogger().isInfoEnabled())
142         {
143             logSchedulerConfiguration();
144         }
145 
146     }
147 
148     public void stop() throws Exception
149     {
150         getScheduler().standby();
151     }
152 
153     /**
154      * @see org.apache.avalon.framework.activity.Disposable#dispose()
155      */
156     public void dispose()
157     {
158         try
159         {
160             // shutdown() does not return until executing Jobs complete execution
161             this.scheduler.shutdown(true);
162         }
163         catch (SchedulerException e)
164         {
165             this.getLogger().warn("Problem shutting down quartz scheduler ", e);
166         }
167 
168         this.scheduler = null;
169         this.serviceManager = null;
170     }
171 
172     // === Service Interface Implementation =================================
173 
174     /**
175      * @see org.apache.fulcrum.quartz.QuartzScheduler#getScheduler()
176      */
177     public Scheduler getScheduler()
178     {
179         return scheduler;
180     }
181 
182     /**
183      * Calls getName() on jobListener
184      *
185      * @see org.quartz.JobListener#getName()
186      */
187     public String getName()
188     {
189         return getClass().getName();
190     }
191 
192     /**
193      * Hook to support jobs implementing Avalon interface such as
194      * LogEnabled and Serviceable.
195      *
196      * @see org.quartz.JobListener#jobToBeExecuted(org.quartz.JobExecutionContext)
197      */
198     public void jobToBeExecuted(JobExecutionContext context)
199     {
200         Job job = context.getJobInstance();
201 
202         // inject a logger instance
203         if(job instanceof LogEnabled)
204         {
205             ((LogEnabled) job).enableLogging(getLogger());
206         }
207 
208         // inject a ServiceManager instance
209         if (job instanceof Serviceable)
210         {
211             try
212             {
213                 ((Serviceable) job).service(serviceManager);
214             }
215             catch (ServiceException e)
216             {
217                 getLogger().error("Error servicing Job[" + job + "]", e);
218             }
219         }
220     }
221 
222     /**
223      * @see org.quartz.JobListener#jobWasExecuted(org.quartz.JobExecutionContext, org.quartz.JobExecutionException)
224      */
225     public void jobWasExecuted(JobExecutionContext context, JobExecutionException ex)
226     {
227         if (ex != null)
228         {
229             String msg = "Executing the job '" + context.getJobDetail().getKey() + "' failed";
230             getLogger().error(msg, ex.getCause());
231         }
232         else
233         {
234             if (getLogger().isDebugEnabled())
235             {
236                 getLogger().debug("Executing the job '" + context.getJobDetail().getKey() + "' took " + context.getJobRunTime() + " ms");
237             }
238         }
239     }
240 
241     /**
242      * @see org.quartz.JobListener#jobExecutionVetoed(org.quartz.JobExecutionContext)
243      */
244     public void jobExecutionVetoed(JobExecutionContext context)
245     {
246         // nothing to do
247     }
248 
249     // === Service Implementation ===========================================
250 
251     private void logSchedulerConfiguration() throws SchedulerException
252     {
253         List jobGroups = getScheduler().getJobGroupNames();
254         for (Iterator i = jobGroups.iterator(); i.hasNext();)
255         {
256             String jobGroup = (String)i.next();
257             Set jobsInGroup = getScheduler().getJobKeys(GroupMatcher.groupEquals(jobGroup));
258             getLogger().info("Job Group: " + jobGroup + " contains the following number of jobs : " + jobsInGroup.size());
259             for (Iterator j = jobsInGroup.iterator(); j.hasNext();)
260             {
261                 StringBuffer buffer = new StringBuffer();
262                 JobKey jobKey = (JobKey)j.next();
263                 JobDetail jobDetail = getScheduler().getJobDetail(jobKey);
264                 List jobTriggers = getScheduler().getTriggersOfJob(jobKey);
265                 buffer.append(jobDetail.getKey());
266                 buffer.append(" => ");
267                 if(jobTriggers != null && !jobTriggers.isEmpty())
268                 {
269                     Trigger jt = (Trigger)jobTriggers.get(0);
270                     buffer.append(jt.getKey());
271                     buffer.append(" (");
272                     buffer.append(jt.getNextFireTime());
273                     buffer.append(")");
274                 }
275                 else
276                 {
277                     buffer.append("no trigger defined");
278                 }
279 
280                 getLogger().info(buffer.toString());
281             }
282         }
283     }
284 }