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.servicemix.quartz;
018    
019    import java.util.ArrayList;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    
024    import javax.jbi.management.DeploymentException;
025    import javax.jbi.messaging.ExchangeStatus;
026    import javax.jbi.messaging.InOnly;
027    import javax.jbi.messaging.MessageExchange;
028    import javax.jbi.messaging.MessagingException;
029    import javax.jbi.messaging.NormalizedMessage;
030    
031    import org.apache.servicemix.common.EndpointSupport;
032    import org.apache.servicemix.common.endpoints.ConsumerEndpoint;
033    import org.apache.servicemix.quartz.support.DefaultQuartzMarshaler;
034    import org.apache.servicemix.quartz.support.JobDetailBean;
035    import org.apache.servicemix.quartz.support.QuartzMarshaler;
036    import org.apache.servicemix.quartz.support.ServiceMixJob;
037    import org.quartz.Calendar;
038    import org.quartz.JobDetail;
039    import org.quartz.JobExecutionContext;
040    import org.quartz.JobExecutionException;
041    import org.quartz.ObjectAlreadyExistsException;
042    import org.quartz.Scheduler;
043    import org.quartz.Trigger;
044    import org.springframework.scheduling.quartz.JobDetailAwareTrigger;
045    
046    /**
047     * @org.apache.xbean.XBean element="endpoint"
048     */
049    public class QuartzEndpoint extends ConsumerEndpoint {
050    
051        private Trigger trigger;
052        private List<Trigger> triggers;
053        private Map<String, Calendar> calendars;
054        private JobDetail jobDetail;
055        private QuartzMarshaler marshaler = new DefaultQuartzMarshaler();
056        
057        /**
058         * @return the triggers
059         */
060        public List<Trigger> getTriggers() {
061            return triggers;
062        }
063    
064        /**
065         * @param triggers the triggers to set
066         */
067        public void setTriggers(List<Trigger> triggers) {
068            this.triggers = triggers;
069        }
070    
071        /**
072         * @return the trigger
073         */
074        public Trigger getTrigger() {
075            return trigger;
076        }
077    
078        /**
079         * @param trigger the trigger to set
080         */
081        public void setTrigger(Trigger trigger) {
082            this.trigger = trigger;
083        }
084    
085        /**
086         * @return the calendar
087         */
088        public Map<String, Calendar> getCalendars() {
089            return calendars;
090        }
091    
092        /**
093         * @param calendar the calendar to set
094         */
095        public void setCalendars(Map<String, Calendar> calendars) {
096            this.calendars = calendars;
097        }
098    
099        /**
100         * @return the job
101         */
102        public JobDetail getJobDetail() {
103            return jobDetail;
104        }
105    
106        /**
107         * @param job the job to set
108         */
109        public void setJobDetail(JobDetail job) {
110            this.jobDetail = job;
111        }
112    
113        public QuartzMarshaler getMarshaler() {
114            return marshaler;
115        }
116    
117        public void setMarshaler(QuartzMarshaler marshaler) {
118            this.marshaler = marshaler;
119        }
120        
121        @Override
122        public String getLocationURI() {
123            return null;
124        }
125    
126        public void process(MessageExchange exchange) throws Exception {
127            if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
128                throw new IllegalStateException("Unexpected ACTIVE exchange: " + exchange);
129            }
130        }
131    
132        public void onJobExecute(JobExecutionContext context) throws JobExecutionException {
133            if (logger.isDebugEnabled()) {
134                logger.debug("Firing Quartz Job with context: " + context);
135            }
136            try {
137                InOnly exchange = getExchangeFactory().createInOnlyExchange();
138                NormalizedMessage message = exchange.createMessage();
139                getMarshaler().populateNormalizedMessage(message, context);
140                exchange.setInMessage(message);
141                configureExchangeTarget(exchange);
142                send(exchange);
143            } catch (MessagingException e) {
144                throw new JobExecutionException(e);
145            }
146        }
147        
148        public void validate() throws DeploymentException {
149            super.validate();
150            if (trigger instanceof JobDetailAwareTrigger) {
151                if (jobDetail != null) {
152                    throw new DeploymentException("jobDetail can not be set on endpoint and trigger at the same time");
153                }
154                jobDetail = ((JobDetailAwareTrigger) trigger).getJobDetail();
155            }
156            if (jobDetail == null) {
157                JobDetailBean j = new JobDetailBean();
158                j.setName(EndpointSupport.getKey(this));
159                jobDetail = j;
160            }
161            if (triggers == null) {
162                triggers = new ArrayList<Trigger>();
163            }
164            if (trigger != null && triggers != null && triggers.size() > 0) {
165                throw new DeploymentException("trigger and triggers can not be set at the same time");
166            }
167            if (trigger != null) {
168                triggers.add(trigger);
169            }
170            if (calendars == null) {
171                calendars = new HashMap<String, Calendar>();
172            }
173            for (Trigger t : triggers) {
174                if (t.getCalendarName() != null && calendars.get(t.getCalendarName()) == null) {
175                    throw new DeploymentException("Trigger references an unknown calendar " + t.getCalendarName());
176                }
177                t.setJobName(jobDetail.getName());
178                t.setJobGroup(jobDetail.getGroup());
179            }
180        }
181        
182        public void start() throws Exception {
183            QuartzComponent component = (QuartzComponent) getServiceUnit().getComponent(); 
184            Scheduler scheduler = component.getScheduler();
185            jobDetail.getJobDataMap().put(ServiceMixJob.COMPONENT_NAME, component.getComponentName());
186            jobDetail.getJobDataMap().put(ServiceMixJob.ENDPOINT_NAME, EndpointSupport.getKey(this));
187            for (Map.Entry<String, Calendar> e : getCalendars().entrySet()) {
188                scheduler.addCalendar(e.getKey(), e.getValue(), true, true);
189            }
190            scheduler.addJob(getJobDetail(), true);
191            for (Trigger trg : getTriggers()) {
192                boolean triggerExists = scheduler.getTrigger(trg.getName(), trg.getGroup()) != null;
193                if (!triggerExists) {
194                    try {
195                        scheduler.scheduleJob(trg);
196                    } catch (ObjectAlreadyExistsException ex) {
197                        scheduler.rescheduleJob(trg.getName(), trg.getGroup(), trg);
198                    }
199                } else {
200                    scheduler.rescheduleJob(trg.getName(), trg.getGroup(), trg);
201                }
202            }
203            super.start();
204        }
205        
206        public void stop() throws Exception {
207            super.stop();
208            Scheduler scheduler = ((QuartzComponent) getServiceUnit().getComponent()).getScheduler();
209            for (Trigger trg : getTriggers()) {
210                scheduler.unscheduleJob(trg.getName(), trg.getGroup());
211            }
212            scheduler.deleteJob(getJobDetail().getName(), getJobDetail().getGroup());
213            for (Map.Entry<String, Calendar> e : getCalendars().entrySet()) {
214                scheduler.deleteCalendar(e.getKey());
215            }
216        }
217    
218    }