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.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.quartz.JobDetail;
027    import org.quartz.Scheduler;
028    import org.quartz.SchedulerException;
029    import org.quartz.Trigger;
030    
031    public abstract class ScheduledRoutePolicy extends RoutePolicySupport implements ScheduledRoutePolicyConstants {
032        private static final transient Log LOG = LogFactory.getLog(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(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(Action action, Route route) throws SchedulerException {
157            getScheduler().getContext().put(SCHEDULED_ACTION, action);
158            getScheduler().getContext().put(SCHEDULED_ROUTE, route);
159        }    
160            
161        public String retrieveTriggerName(Action action) {
162            String triggerName = null;
163    
164            if (action == Action.START) {
165                triggerName = scheduledRouteDetails.getStartTrigger().getName();
166            } else if (action == Action.STOP) {
167                triggerName = scheduledRouteDetails.getStopTrigger().getName();
168            } else if (action == Action.SUSPEND) {
169                triggerName = scheduledRouteDetails.getSuspendTrigger().getName();
170            } else if (action == Action.RESUME) {
171                triggerName = scheduledRouteDetails.getResumeTrigger().getName();
172            }
173            
174            return triggerName;
175        }
176    
177        public String retrieveTriggerGroup(Action action) {
178            String triggerGroup = null;
179    
180            if (action == Action.START) {
181                triggerGroup = scheduledRouteDetails.getStartTrigger().getGroup();
182            } else if (action == Action.STOP) {
183                triggerGroup = scheduledRouteDetails.getStopTrigger().getGroup();
184            } else if (action == Action.SUSPEND) {
185                triggerGroup = scheduledRouteDetails.getSuspendTrigger().getGroup();
186            } else if (action == Action.RESUME) {
187                triggerGroup = scheduledRouteDetails.getResumeTrigger().getGroup();
188            }
189            
190            return triggerGroup;
191        }
192        
193        public String retrieveJobDetailName(Action action) {
194            String jobDetailName = null;
195    
196            if (action == Action.START) {
197                jobDetailName = scheduledRouteDetails.getStartJobDetail().getName();
198            } else if (action == Action.STOP) {
199                jobDetailName = scheduledRouteDetails.getStopJobDetail().getName();
200            } else if (action == Action.SUSPEND) {
201                jobDetailName = scheduledRouteDetails.getSuspendJobDetail().getName();
202            } else if (action == Action.RESUME) {
203                jobDetailName = scheduledRouteDetails.getResumeJobDetail().getName();
204            }
205            
206            return jobDetailName;
207        }
208    
209        public String retrieveJobDetailGroup(Action action) {
210            String jobDetailGroup = null;
211    
212            if (action == Action.START) {
213                jobDetailGroup = scheduledRouteDetails.getStartJobDetail().getGroup();
214            } else if (action == Action.STOP) {
215                jobDetailGroup = scheduledRouteDetails.getStopJobDetail().getGroup();
216            } else if (action == Action.SUSPEND) {
217                jobDetailGroup = scheduledRouteDetails.getSuspendJobDetail().getGroup();
218            } else if (action == Action.RESUME) {
219                jobDetailGroup = scheduledRouteDetails.getResumeJobDetail().getGroup();
220            }
221            
222            return jobDetailGroup;
223        } 
224        
225        public ScheduledRouteDetails getScheduledRouteDetails() {
226            return scheduledRouteDetails;
227        }
228    
229        public void setScheduledRouteDetails(ScheduledRouteDetails scheduledRouteDetails) {
230            this.scheduledRouteDetails = scheduledRouteDetails;
231        }
232    
233        public void setScheduler(Scheduler scheduler) {
234            this.scheduler = scheduler;
235        }
236    
237        public Scheduler getScheduler() {
238            return scheduler;
239        }
240    
241        public void setRouteStopGracePeriod(int routeStopGracePeriod) {
242            this.routeStopGracePeriod = routeStopGracePeriod;
243        }
244    
245        public int getRouteStopGracePeriod() {
246            return routeStopGracePeriod;
247        }
248    
249        public void setTimeUnit(TimeUnit timeUnit) {
250            this.timeUnit = timeUnit;
251        }
252    
253        public TimeUnit getTimeUnit() {
254            return timeUnit;
255        }      
256    
257    }