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 */
017package org.apache.camel.impl;
018
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Locale;
022import java.util.concurrent.ScheduledExecutorService;
023import java.util.concurrent.ScheduledFuture;
024import java.util.concurrent.TimeUnit;
025
026import org.apache.camel.CamelContext;
027import org.apache.camel.Consumer;
028import org.apache.camel.spi.ScheduledPollConsumerScheduler;
029import org.apache.camel.util.ObjectHelper;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033/**
034 * Default {@link org.apache.camel.impl.ScheduledBatchPollingConsumer}.
035 */
036public class DefaultScheduledPollConsumerScheduler extends org.apache.camel.support.ServiceSupport implements ScheduledPollConsumerScheduler {
037
038    private static final Logger LOG = LoggerFactory.getLogger(DefaultScheduledPollConsumerScheduler.class);
039    private CamelContext camelContext;
040    private Consumer consumer;
041    private ScheduledExecutorService scheduledExecutorService;
042    private boolean shutdownExecutor;
043    private volatile List<ScheduledFuture<?>> futures = new ArrayList<ScheduledFuture<?>>();
044    private Runnable task;
045    private int concurrentTasks = 1;
046
047    private long initialDelay = 1000;
048    private long delay = 500;
049    private TimeUnit timeUnit = TimeUnit.MILLISECONDS;
050    private boolean useFixedDelay = true;
051
052    public DefaultScheduledPollConsumerScheduler() {
053    }
054
055    public DefaultScheduledPollConsumerScheduler(ScheduledExecutorService scheduledExecutorService) {
056        this.scheduledExecutorService = scheduledExecutorService;
057    }
058
059    public CamelContext getCamelContext() {
060        return camelContext;
061    }
062
063    public void setCamelContext(CamelContext camelContext) {
064        this.camelContext = camelContext;
065    }
066
067    public long getInitialDelay() {
068        return initialDelay;
069    }
070
071    public void setInitialDelay(long initialDelay) {
072        this.initialDelay = initialDelay;
073    }
074
075    public long getDelay() {
076        return delay;
077    }
078
079    public void setDelay(long delay) {
080        this.delay = delay;
081    }
082
083    public TimeUnit getTimeUnit() {
084        return timeUnit;
085    }
086
087    public void setTimeUnit(TimeUnit timeUnit) {
088        this.timeUnit = timeUnit;
089    }
090
091    public boolean isUseFixedDelay() {
092        return useFixedDelay;
093    }
094
095    public void setUseFixedDelay(boolean useFixedDelay) {
096        this.useFixedDelay = useFixedDelay;
097    }
098
099    public ScheduledExecutorService getScheduledExecutorService() {
100        return scheduledExecutorService;
101    }
102
103    public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
104        this.scheduledExecutorService = scheduledExecutorService;
105    }
106
107    public int getConcurrentTasks() {
108        return concurrentTasks;
109    }
110
111    public void setConcurrentTasks(int concurrentTasks) {
112        this.concurrentTasks = concurrentTasks;
113    }
114
115    @Override
116    public void onInit(Consumer consumer) {
117        this.consumer = consumer;
118    }
119
120    @Override
121    public void scheduleTask(Runnable task) {
122        this.task = task;
123    }
124
125    @Override
126    public void unscheduleTask() {
127        if (isSchedulerStarted()) {
128            for (ScheduledFuture<?> future : futures) {
129                future.cancel(true);
130            }
131            futures.clear();
132        }
133    }
134
135    @Override
136    public void startScheduler() {
137        // only schedule task if we have not already done that
138        if (futures.size() == 0) {
139            if (isUseFixedDelay()) {
140                if (LOG.isDebugEnabled()) {
141                    LOG.debug("Scheduling poll (fixed delay) with initialDelay: {}, delay: {} ({}) for: {}",
142                            new Object[]{getInitialDelay(), getDelay(), getTimeUnit().name().toLowerCase(Locale.ENGLISH), consumer.getEndpoint()});
143                }
144                for (int i = 0; i < concurrentTasks; i++) {
145                    futures.add(scheduledExecutorService.scheduleWithFixedDelay(task, getInitialDelay(), getDelay(), getTimeUnit()));
146                }
147            } else {
148                if (LOG.isDebugEnabled()) {
149                    LOG.debug("Scheduling poll (fixed rate) with initialDelay: {}, delay: {} ({}) for: {}",
150                            new Object[]{getInitialDelay(), getDelay(), getTimeUnit().name().toLowerCase(Locale.ENGLISH), consumer.getEndpoint()});
151                }
152                for (int i = 0; i < concurrentTasks; i++) {
153                    futures.add(scheduledExecutorService.scheduleAtFixedRate(task, getInitialDelay(), getDelay(), getTimeUnit()));
154                }
155            }
156        }
157    }
158
159    @Override
160    public boolean isSchedulerStarted() {
161        return futures != null && futures.size() > 0;
162    }
163
164    @Override
165    protected void doStart() throws Exception {
166        ObjectHelper.notNull(consumer, "Consumer", this);
167        ObjectHelper.notNull(camelContext, "CamelContext", this);
168        ObjectHelper.notNull(task, "Task", this);
169
170        // if no existing executor provided, then create a new thread pool ourselves
171        if (scheduledExecutorService == null) {
172            // we only need one thread in the pool to schedule this task
173            this.scheduledExecutorService = getCamelContext().getExecutorServiceManager()
174                    .newScheduledThreadPool(consumer, consumer.getEndpoint().getEndpointUri(), concurrentTasks);
175            // and we should shutdown the thread pool when no longer needed
176            this.shutdownExecutor = true;
177        }
178    }
179
180    @Override
181    protected void doStop() throws Exception {
182        if (isSchedulerStarted()) {
183            LOG.debug("This consumer is stopping, so cancelling scheduled task: " + futures);
184            for (ScheduledFuture<?> future : futures) {
185                future.cancel(true);
186            }
187            futures.clear();
188        }
189
190        if (shutdownExecutor && scheduledExecutorService != null) {
191            getCamelContext().getExecutorServiceManager().shutdownNow(scheduledExecutorService);
192            scheduledExecutorService = null;
193            futures.clear();
194        }
195    }
196
197}