/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.support;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.StaticService;
import org.apache.camel.TimerListener;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A {@link TimerListener} manager which triggers the
* {@link org.apache.camel.TimerListener} listeners once every second.
* <p/>
* Also ensure when adding and remove listeners, that they are correctly removed to avoid
* leaking memory.
*
* @see TimerListener
* @see org.apache.camel.management.ManagedLoadTimer
*/
public class TimerListenerManager extends ServiceSupport implements Runnable, CamelContextAware, StaticService {
private static final Logger LOG = LoggerFactory.getLogger(TimerListenerManager.class);
private final Set<TimerListener> listeners = new LinkedHashSet<TimerListener>();
private CamelContext camelContext;
private ScheduledExecutorService executorService;
private volatile ScheduledFuture<?> task;
private long interval = 1000L;
public TimerListenerManager() {
}
@Override
public void setCamelContext(CamelContext camelContext) {
this.camelContext = camelContext;
}
@Override
public CamelContext getCamelContext() {
return camelContext;
}
/**
* Gets the interval in millis.
* <p/>
* The default interval is 1000 millis.
*
* @return interval in millis.
*/
public long getInterval() {
return interval;
}
/**
* Sets the interval in millis.
*
* @param interval interval in millis.
*/
public void setInterval(long interval) {
this.interval = interval;
}
@Override
public void run() {
LOG.trace("Running scheduled TimerListener task");
if (!isRunAllowed()) {
LOG.debug("TimerListener task cannot run as its not allowed");
return;
}
for (TimerListener listener : listeners) {
try {
LOG.trace("Invoking onTimer on {}", listener);
listener.onTimer();
} catch (Throwable e) {
// ignore
LOG.debug("Error occurred during onTimer for TimerListener: " + listener + ". This exception will be ignored.", e);
}
}
}
/**
* Adds the listener.
* <p/>
* It may be important to implement {@link #equals(Object)} and {@link #hashCode()} for the listener
* to ensure that we can remove the same listener again, when invoking remove.
*
* @param listener listener
*/
public void addTimerListener(TimerListener listener) {
listeners.add(listener);
LOG.debug("Added TimerListener: {}", listener);
}
/**
* Removes the listener.
* <p/>
* It may be important to implement {@link #equals(Object)} and {@link #hashCode()} for the listener
* to ensure that we can remove the same listener again, when invoking remove.
*
* @param listener listener.
*/
public void removeTimerListener(TimerListener listener) {
listeners.remove(listener);
LOG.debug("Removed TimerListener: {}", listener);
}
@Override
protected void doStart() throws Exception {
ObjectHelper.notNull(camelContext, "camelContext", this);
// create scheduled thread pool to trigger the task to run every interval
executorService = camelContext.getExecutorServiceManager().newSingleThreadScheduledExecutor(this, "ManagementLoadTask");
task = executorService.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS);
LOG.debug("Started scheduled TimerListener task to run with interval {} ms", interval);
}
@Override
protected void doStop() throws Exception {
// executor service will be shutdown by CamelContext
if (task != null) {
task.cancel(true);
task = null;
}
}
@Override
protected void doShutdown() throws Exception {
super.doShutdown();
// shutdown thread pool when we are shutting down
camelContext.getExecutorServiceManager().shutdownNow(executorService);
executorService = null;
listeners.clear();
}
}