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            LOG.debug("Scheduled Event notification received. Performing action: {} on route: {}", action, route.getId());
042    
043            ServiceStatus routeStatus = route.getRouteContext().getCamelContext().getRouteStatus(route.getId());
044            if (action == Action.START) {
045                if (routeStatus == ServiceStatus.Stopped) {
046                    startRoute(route);
047                } else if (routeStatus == ServiceStatus.Suspended) {
048                    startConsumer(route.getConsumer());
049                }
050            } else if (action == Action.STOP) {
051                if ((routeStatus == ServiceStatus.Started) || (routeStatus == ServiceStatus.Suspended)) {
052                    stopRoute(route, getRouteStopGracePeriod(), getTimeUnit());
053                }
054            } else if (action == Action.SUSPEND) {
055                if (routeStatus == ServiceStatus.Started) {
056                    stopConsumer(route.getConsumer());
057                } else {
058                    LOG.warn("Route is not in a started state and cannot be suspended. The current route state is {}", routeStatus);
059                }
060            } else if (action == Action.RESUME) {
061                if (routeStatus == ServiceStatus.Started) {
062                    startConsumer(route.getConsumer());
063                } else {
064                    LOG.warn("Route is not in a started state and cannot be resumed. The current route state is {}", routeStatus);
065                }
066            }       
067        }
068    
069        public void scheduleRoute(Action action) throws Exception {
070            Route route = scheduledRouteDetails.getRoute();
071            
072            JobDetail jobDetail = createJobDetail(action, route);
073            Trigger trigger = createTrigger(action, route);
074            updateScheduledRouteDetails(action, jobDetail, trigger);
075            
076            loadCallbackDataIntoSchedulerContext(jobDetail, action, route);
077            getScheduler().scheduleJob(jobDetail, trigger);
078    
079            if (LOG.isInfoEnabled()) {
080                LOG.info("Scheduled trigger: {} for action: {} on route: ", new Object[]{trigger.getFullName(), action, route.getId()});
081            }
082        }
083    
084        public void pauseRouteTrigger(Action action) throws SchedulerException {
085            String triggerName = retrieveTriggerName(action);
086            String triggerGroup = retrieveTriggerGroup(action);
087            
088            getScheduler().pauseTrigger(triggerName, triggerGroup);
089    
090            LOG.debug("Scheduled trigger: {}.{} is paused", triggerGroup, triggerName);
091        }
092        
093        public void resumeRouteTrigger(Action action) throws SchedulerException {
094            String triggerName = retrieveTriggerName(action);
095            String triggerGroup = retrieveTriggerGroup(action);
096            
097            getScheduler().resumeTrigger(triggerName, triggerGroup);
098    
099            LOG.debug("Scheduled trigger: {}.{} is resumed", triggerGroup, triggerName);
100        }
101    
102        public void deleteRouteJob(Action action) throws SchedulerException {
103            String jobDetailName = retrieveJobDetailName(action);
104            String jobDetailGroup = retrieveJobDetailGroup(action);
105            
106            if (!getScheduler().isShutdown()) {
107                getScheduler().deleteJob(jobDetailName, jobDetailGroup);
108            }
109    
110            LOG.debug("Scheduled Job: {}.{} is deleted", jobDetailGroup, jobDetailName);
111        }
112        
113        protected JobDetail createJobDetail(Action action, Route route) throws Exception {
114            JobDetail jobDetail = null;
115            
116            if (action == Action.START) {
117                jobDetail = new JobDetail(JOB_START + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
118            } else if (action == Action.STOP) {
119                jobDetail = new JobDetail(JOB_STOP + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
120            } else if (action == Action.SUSPEND) {
121                jobDetail = new JobDetail(JOB_SUSPEND + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
122            } else if (action == Action.RESUME) {
123                jobDetail = new JobDetail(JOB_RESUME + route.getId(), JOB_GROUP + route.getId(), ScheduledJob.class);
124            }
125            
126            return jobDetail;
127        }
128            
129        protected void updateScheduledRouteDetails(Action action, JobDetail jobDetail, Trigger trigger) throws Exception {
130            if (action == Action.START) {
131                scheduledRouteDetails.setStartJobDetail(jobDetail);
132                scheduledRouteDetails.setStartTrigger(trigger);
133            } else if (action == Action.STOP) {
134                scheduledRouteDetails.setStopJobDetail(jobDetail);
135                scheduledRouteDetails.setStopTrigger(trigger);
136            } else if (action == Action.SUSPEND) {
137                scheduledRouteDetails.setSuspendJobDetail(jobDetail);
138                scheduledRouteDetails.setSuspendTrigger(trigger);
139            } else if (action == Action.RESUME) {
140                scheduledRouteDetails.setResumeJobDetail(jobDetail);
141                scheduledRouteDetails.setResumeTrigger(trigger);
142            }
143        }
144        
145        protected void loadCallbackDataIntoSchedulerContext(JobDetail jobDetail, Action action, Route route) throws SchedulerException {
146            getScheduler().getContext().put(jobDetail.getName(), new ScheduledJobState(action, route));
147        }    
148            
149        public String retrieveTriggerName(Action action) {
150            String triggerName = null;
151    
152            if (action == Action.START) {
153                triggerName = scheduledRouteDetails.getStartTrigger().getName();
154            } else if (action == Action.STOP) {
155                triggerName = scheduledRouteDetails.getStopTrigger().getName();
156            } else if (action == Action.SUSPEND) {
157                triggerName = scheduledRouteDetails.getSuspendTrigger().getName();
158            } else if (action == Action.RESUME) {
159                triggerName = scheduledRouteDetails.getResumeTrigger().getName();
160            }
161            
162            return triggerName;
163        }
164    
165        public String retrieveTriggerGroup(Action action) {
166            String triggerGroup = null;
167    
168            if (action == Action.START) {
169                triggerGroup = scheduledRouteDetails.getStartTrigger().getGroup();
170            } else if (action == Action.STOP) {
171                triggerGroup = scheduledRouteDetails.getStopTrigger().getGroup();
172            } else if (action == Action.SUSPEND) {
173                triggerGroup = scheduledRouteDetails.getSuspendTrigger().getGroup();
174            } else if (action == Action.RESUME) {
175                triggerGroup = scheduledRouteDetails.getResumeTrigger().getGroup();
176            }
177            
178            return triggerGroup;
179        }
180        
181        public String retrieveJobDetailName(Action action) {
182            String jobDetailName = null;
183    
184            if (action == Action.START) {
185                jobDetailName = scheduledRouteDetails.getStartJobDetail().getName();
186            } else if (action == Action.STOP) {
187                jobDetailName = scheduledRouteDetails.getStopJobDetail().getName();
188            } else if (action == Action.SUSPEND) {
189                jobDetailName = scheduledRouteDetails.getSuspendJobDetail().getName();
190            } else if (action == Action.RESUME) {
191                jobDetailName = scheduledRouteDetails.getResumeJobDetail().getName();
192            }
193            
194            return jobDetailName;
195        }
196    
197        public String retrieveJobDetailGroup(Action action) {
198            String jobDetailGroup = null;
199    
200            if (action == Action.START) {
201                jobDetailGroup = scheduledRouteDetails.getStartJobDetail().getGroup();
202            } else if (action == Action.STOP) {
203                jobDetailGroup = scheduledRouteDetails.getStopJobDetail().getGroup();
204            } else if (action == Action.SUSPEND) {
205                jobDetailGroup = scheduledRouteDetails.getSuspendJobDetail().getGroup();
206            } else if (action == Action.RESUME) {
207                jobDetailGroup = scheduledRouteDetails.getResumeJobDetail().getGroup();
208            }
209            
210            return jobDetailGroup;
211        } 
212        
213        public ScheduledRouteDetails getScheduledRouteDetails() {
214            return scheduledRouteDetails;
215        }
216    
217        public void setScheduledRouteDetails(ScheduledRouteDetails scheduledRouteDetails) {
218            this.scheduledRouteDetails = scheduledRouteDetails;
219        }
220    
221        public void setScheduler(Scheduler scheduler) {
222            this.scheduler = scheduler;
223        }
224    
225        public Scheduler getScheduler() {
226            return scheduler;
227        }
228    
229        public void setRouteStopGracePeriod(int routeStopGracePeriod) {
230            this.routeStopGracePeriod = routeStopGracePeriod;
231        }
232    
233        public int getRouteStopGracePeriod() {
234            return routeStopGracePeriod;
235        }
236    
237        public void setTimeUnit(TimeUnit timeUnit) {
238            this.timeUnit = timeUnit;
239        }
240    
241        public TimeUnit getTimeUnit() {
242            return timeUnit;
243        }      
244    
245    }