001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.routepolicy.quartz;
018    
019    import java.util.concurrent.TimeUnit;
020    
021    import org.apache.camel.Route;
022    import org.apache.camel.ServiceStatus;
023    import org.apache.camel.impl.RoutePolicySupport;
024    import org.quartz.JobDetail;
025    import org.quartz.Scheduler;
026    import org.quartz.SchedulerException;
027    import org.quartz.Trigger;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    public abstract class ScheduledRoutePolicy extends RoutePolicySupport implements ScheduledRoutePolicyConstants {
032        private static final transient Logger LOG = LoggerFactory.getLogger(ScheduledRoutePolicy.class);
033        protected ScheduledRouteDetails scheduledRouteDetails;
034        private Scheduler scheduler;
035        private int routeStopGracePeriod;
036        private TimeUnit timeUnit; 
037    
038        protected abstract Trigger createTrigger(Action action, Route route) throws Exception;
039    
040        protected void onJobExecute(Action action, Route route) throws Exception {
041            if (LOG.isDebugEnabled()) {
042                LOG.debug("Scheduled Event notification received. Performing requested operation " + action + " for route " + route.getId());
043            }
044            ServiceStatus routeStatus = route.getRouteContext().getCamelContext().getRouteStatus(route.getId());
045            if (action == Action.START) {
046                if (routeStatus == ServiceStatus.Stopped) {
047                    startRoute(route);
048                } else if (routeStatus == ServiceStatus.Suspended) {
049                    startConsumer(route.getConsumer());
050                }
051            } else if (action == Action.STOP) {
052                if ((routeStatus == ServiceStatus.Started) || (routeStatus == ServiceStatus.Suspended)) {
053                    stopRoute(route, getRouteStopGracePeriod(), getTimeUnit());
054                }
055            } else if (action == Action.SUSPEND) {
056                if (routeStatus == ServiceStatus.Started) {
057                    stopConsumer(route.getConsumer());
058                } else {
059                    if (LOG.isWarnEnabled()) {
060                        LOG.warn("Route is not in a started state and cannot be suspended. The current route state is " + routeStatus);
061                    }
062                }
063            } else if (action == Action.RESUME) {
064                if (routeStatus == ServiceStatus.Started) {
065                    startConsumer(route.getConsumer());
066                } else {
067                    if (LOG.isWarnEnabled()) {
068                        LOG.warn("Route is not in a started state and cannot be resumed. The current route state is " + routeStatus);
069                    }
070                }
071            }       
072        }
073    
074        public void scheduleRoute(Action action) throws Exception {
075            Route route = scheduledRouteDetails.getRoute();
076            
077            JobDetail jobDetail = createJobDetail(action, route);
078            Trigger trigger = createTrigger(action, route);
079            updateScheduledRouteDetails(action, jobDetail, trigger);
080            
081            loadCallbackDataIntoSchedulerContext(jobDetail, action, route);
082            getScheduler().scheduleJob(jobDetail, trigger);
083            
084            if (LOG.isDebugEnabled()) {
085                LOG.debug("Scheduled Trigger: " + trigger.getFullName()  + " is operational");
086            }
087        }    
088    
089        public void pauseRouteTrigger(Action action) throws SchedulerException {
090            String triggerName = retrieveTriggerName(action);
091            String triggerGroup = retrieveTriggerGroup(action);
092            
093            getScheduler().pauseTrigger(triggerName, triggerGroup);
094    
095            if (LOG.isDebugEnabled()) {
096                LOG.debug("Scheduled Trigger: " + triggerGroup + "." + triggerName + " is paused");
097            }
098        }
099        
100        public void resumeRouteTrigger(Action action) throws SchedulerException {
101            String triggerName = retrieveTriggerName(action);
102            String triggerGroup = retrieveTriggerGroup(action);
103            
104            getScheduler().resumeTrigger(triggerName, triggerGroup);
105    
106            if (LOG.isDebugEnabled()) {
107                LOG.debug("Scheduled Trigger: " + triggerGroup + "." + triggerName + " has been resumed");
108            }
109        }
110    
111        public void deleteRouteJob(Action action) throws SchedulerException {
112            String jobDetailName = retrieveJobDetailName(action);
113            String jobDetailGroup = retrieveJobDetailGroup(action);
114            
115            if (!getScheduler().isShutdown()) {
116                getScheduler().deleteJob(jobDetailName, jobDetailGroup);
117            }
118    
119            if (LOG.isDebugEnabled()) {
120                LOG.debug("Scheduled Job: " + jobDetailGroup + "." + jobDetailName + " has been deleted");
121            }
122        }
123        
124        protected JobDetail createJobDetail(Action action, Route route) throws Exception {
125            JobDetail jobDetail = null;
126            
127            if (action == Action.START) {
128                jobDetail = new JobDetail(JOB_START + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
129            } else if (action == Action.STOP) {
130                jobDetail = new JobDetail(JOB_STOP + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
131            } else if (action == Action.SUSPEND) {
132                jobDetail = new JobDetail(JOB_SUSPEND + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
133            } else if (action == Action.RESUME) {
134                jobDetail = new JobDetail(JOB_RESUME + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
135            }
136            
137            return jobDetail;
138        }
139            
140        protected void updateScheduledRouteDetails(Action action, JobDetail jobDetail, Trigger trigger) throws Exception {
141            if (action == Action.START) {
142                scheduledRouteDetails.setStartJobDetail(jobDetail);
143                scheduledRouteDetails.setStartTrigger(trigger);
144            } else if (action == Action.STOP) {
145                scheduledRouteDetails.setStopJobDetail(jobDetail);
146                scheduledRouteDetails.setStopTrigger(trigger);
147            } else if (action == Action.SUSPEND) {
148                scheduledRouteDetails.setSuspendJobDetail(jobDetail);
149                scheduledRouteDetails.setSuspendTrigger(trigger);
150            } else if (action == Action.RESUME) {
151                scheduledRouteDetails.setResumeJobDetail(jobDetail);
152                scheduledRouteDetails.setResumeTrigger(trigger);
153            }
154        }
155        
156        protected void loadCallbackDataIntoSchedulerContext(JobDetail jobDetail, Action action, Route route) throws SchedulerException {
157            getScheduler().getContext().put(jobDetail.getName(), new ScheduledJobState(action, route));
158        }    
159            
160        public String retrieveTriggerName(Action action) {
161            String triggerName = null;
162    
163            if (action == Action.START) {
164                triggerName = scheduledRouteDetails.getStartTrigger().getName();
165            } else if (action == Action.STOP) {
166                triggerName = scheduledRouteDetails.getStopTrigger().getName();
167            } else if (action == Action.SUSPEND) {
168                triggerName = scheduledRouteDetails.getSuspendTrigger().getName();
169            } else if (action == Action.RESUME) {
170                triggerName = scheduledRouteDetails.getResumeTrigger().getName();
171            }
172            
173            return triggerName;
174        }
175    
176        public String retrieveTriggerGroup(Action action) {
177            String triggerGroup = null;
178    
179            if (action == Action.START) {
180                triggerGroup = scheduledRouteDetails.getStartTrigger().getGroup();
181            } else if (action == Action.STOP) {
182                triggerGroup = scheduledRouteDetails.getStopTrigger().getGroup();
183            } else if (action == Action.SUSPEND) {
184                triggerGroup = scheduledRouteDetails.getSuspendTrigger().getGroup();
185            } else if (action == Action.RESUME) {
186                triggerGroup = scheduledRouteDetails.getResumeTrigger().getGroup();
187            }
188            
189            return triggerGroup;
190        }
191        
192        public String retrieveJobDetailName(Action action) {
193            String jobDetailName = null;
194    
195            if (action == Action.START) {
196                jobDetailName = scheduledRouteDetails.getStartJobDetail().getName();
197            } else if (action == Action.STOP) {
198                jobDetailName = scheduledRouteDetails.getStopJobDetail().getName();
199            } else if (action == Action.SUSPEND) {
200                jobDetailName = scheduledRouteDetails.getSuspendJobDetail().getName();
201            } else if (action == Action.RESUME) {
202                jobDetailName = scheduledRouteDetails.getResumeJobDetail().getName();
203            }
204            
205            return jobDetailName;
206        }
207    
208        public String retrieveJobDetailGroup(Action action) {
209            String jobDetailGroup = null;
210    
211            if (action == Action.START) {
212                jobDetailGroup = scheduledRouteDetails.getStartJobDetail().getGroup();
213            } else if (action == Action.STOP) {
214                jobDetailGroup = scheduledRouteDetails.getStopJobDetail().getGroup();
215            } else if (action == Action.SUSPEND) {
216                jobDetailGroup = scheduledRouteDetails.getSuspendJobDetail().getGroup();
217            } else if (action == Action.RESUME) {
218                jobDetailGroup = scheduledRouteDetails.getResumeJobDetail().getGroup();
219            }
220            
221            return jobDetailGroup;
222        } 
223        
224        public ScheduledRouteDetails getScheduledRouteDetails() {
225            return scheduledRouteDetails;
226        }
227    
228        public void setScheduledRouteDetails(ScheduledRouteDetails scheduledRouteDetails) {
229            this.scheduledRouteDetails = scheduledRouteDetails;
230        }
231    
232        public void setScheduler(Scheduler scheduler) {
233            this.scheduler = scheduler;
234        }
235    
236        public Scheduler getScheduler() {
237            return scheduler;
238        }
239    
240        public void setRouteStopGracePeriod(int routeStopGracePeriod) {
241            this.routeStopGracePeriod = routeStopGracePeriod;
242        }
243    
244        public int getRouteStopGracePeriod() {
245            return routeStopGracePeriod;
246        }
247    
248        public void setTimeUnit(TimeUnit timeUnit) {
249            this.timeUnit = timeUnit;
250        }
251    
252        public TimeUnit getTimeUnit() {
253            return timeUnit;
254        }      
255    
256    }