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.components.util;
018    
019    import java.util.Date;
020    
021    import javax.jbi.JBIException;
022    import javax.resource.spi.work.Work;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.apache.servicemix.components.varscheduler.ScheduleIterator;
027    import org.apache.servicemix.components.varscheduler.Scheduler;
028    import org.apache.servicemix.components.varscheduler.SchedulerTask;
029    import org.apache.servicemix.executors.Executor;
030    import org.apache.servicemix.executors.ExecutorFactory;
031    import org.apache.servicemix.jbi.framework.ComponentContextImpl;
032    
033    /**
034     * An implementation inheritence class for a component which polls some resource
035     * at periodic intervals to decide if there is an event to process.
036     * 
037     * @version $Revision: 564374 $
038     */
039    public abstract class PollingComponentSupport extends ComponentSupport implements Work {
040        
041        private static final Log LOG = LogFactory.getLog(PollingComponentSupport.class);
042    
043        private Executor executor;
044        private Scheduler scheduler;
045        private Date firstTime;
046        private long period = 5000;
047        private long delay;
048        private SchedulerTask schedulerTask;
049        private ScheduleIterator scheduleIterator;
050        private boolean started;
051        private boolean scheduleExecutedFlag;
052    
053        /**
054         * Polls the underlying resource to see if some event is required
055         * 
056         * @throws JBIException
057         */
058        public abstract void poll() throws Exception;
059    
060        public void release() {
061        }
062    
063        public void run() {
064            try {
065                poll();
066            } catch (Exception e) {
067                LOG.error("Caught exception while polling: " + e, e);
068            }
069        }
070    
071        // Properties
072        // -------------------------------------------------------------------------
073        public Executor getExecutor() {
074            return executor;
075        }
076    
077        public long getDelay() {
078            return delay;
079        }
080    
081        public void setDelay(long delay) {
082            this.delay = delay;
083        }
084    
085        public Date getFirstTime() {
086            return firstTime;
087        }
088    
089        public void setFirstTime(Date firstTime) {
090            this.firstTime = firstTime;
091        }
092    
093        public long getPeriod() {
094            return period;
095        }
096    
097        public void setPeriod(long period) {
098            this.period = period;
099        }
100    
101        public Scheduler getScheduler() {
102            return scheduler;
103        }
104    
105        public void setScheduler(Scheduler scheduler) {
106            this.scheduler = scheduler;
107        }
108    
109        public synchronized void start() throws JBIException {
110            if (!started) {
111                started = true;
112                if (schedulerTask != null) {
113                    schedulerTask.cancel();
114                }
115                schedulerTask = new PollSchedulerTask();
116                this.scheduler.schedule(schedulerTask, scheduleIterator);
117            }
118            super.start();
119        }
120    
121        public synchronized void stop() throws JBIException {
122            if (schedulerTask != null) {
123                schedulerTask.cancel();
124                schedulerTask = null;
125            }
126            scheduleExecutedFlag = false;
127            started = false;
128            super.stop();
129        }
130    
131        public synchronized void shutDown() throws JBIException {
132            stop();
133            scheduler.cancel();
134            executor.shutdown();
135            scheduler = null;
136            scheduleIterator = null;
137            executor = null;
138            super.shutDown();
139        }
140    
141        // Implementation methods
142        // -------------------------------------------------------------------------
143        protected void init() throws JBIException {
144            if (scheduler == null) {
145                scheduler = new Scheduler(true);
146            }
147            if (scheduleIterator == null) {
148                scheduleIterator = new PollScheduleIterator();
149            }
150            if (executor == null) {
151                ComponentContextImpl context = (ComponentContextImpl) getContext();
152                ExecutorFactory factory = context.getContainer()
153                        .getExecutorFactory();
154                executor = factory.createExecutor("component."
155                        + context.getComponentName());
156            }
157            super.init();
158    
159        }
160    
161        private class PollSchedulerTask extends SchedulerTask {
162            public void run() {
163                try {
164                    // lets run the work inside the JCA worker pools to ensure
165                    // the threads are setup correctly when we actually do stuff
166                    getExecutor().execute(PollingComponentSupport.this);
167                } catch (Throwable e) {
168                    LOG.error("Failed to schedule work: " + e, e);
169                }
170            }
171        }
172    
173        private class PollScheduleIterator implements ScheduleIterator {
174            public Date nextExecution() {
175                long nextTime = System.currentTimeMillis();
176                if (scheduleExecutedFlag) {
177                    nextTime += period;
178                } else {
179                    if (firstTime != null) {
180                        nextTime = firstTime.getTime();
181                    }
182                    nextTime += delay;
183                    scheduleExecutedFlag = true;
184                }
185                return started ? new Date(nextTime) : null;
186            }
187        }
188    }