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.support;
018
019 import java.util.LinkedHashSet;
020 import java.util.Set;
021 import java.util.concurrent.ScheduledExecutorService;
022 import java.util.concurrent.ScheduledFuture;
023 import java.util.concurrent.TimeUnit;
024
025 import org.apache.camel.TimerListener;
026 import org.apache.camel.util.ObjectHelper;
027 import org.slf4j.Logger;
028 import org.slf4j.LoggerFactory;
029
030 /**
031 * A {@link TimerListener} manager which triggers the
032 * {@link org.apache.camel.TimerListener} listeners once every second.
033 * <p/>
034 * The {@link #setExecutorService(java.util.concurrent.ScheduledExecutorService)} method
035 * must be invoked prior to starting this manager using the {@link #start()} method.
036 * <p/>
037 * Also ensure when adding and remove listeners, that they are correctly removed to avoid
038 * leaking memory.
039 *
040 * @see TimerListener
041 */
042 public class TimerListenerManager extends ServiceSupport implements Runnable {
043
044 private static final Logger LOG = LoggerFactory.getLogger(TimerListenerManager.class);
045 private final Set<TimerListener> listeners = new LinkedHashSet<TimerListener>();
046 private ScheduledExecutorService executorService;
047 private volatile ScheduledFuture<?> task;
048 private long interval = 1000L;
049
050 public TimerListenerManager() {
051 }
052
053 public void setExecutorService(ScheduledExecutorService executorService) {
054 this.executorService = executorService;
055 }
056
057 /**
058 * Gets the interval in millis.
059 * <p/>
060 * The default interval is 1000 millis.
061 *
062 * @return interval in millis.
063 */
064 public long getInterval() {
065 return interval;
066 }
067
068 /**
069 * Sets the interval in millis.
070 *
071 * @param interval interval in millis.
072 */
073 public void setInterval(long interval) {
074 this.interval = interval;
075 }
076
077 @Override
078 public void run() {
079 LOG.trace("Running scheduled TimerListener task");
080
081 if (!isRunAllowed()) {
082 LOG.debug("TimerListener task cannot run as its not allowed");
083 return;
084 }
085
086 for (TimerListener listener : listeners) {
087 try {
088 LOG.trace("Invoking onTimer on {}", listener);
089 listener.onTimer();
090 } catch (Throwable e) {
091 // ignore
092 LOG.debug("Error occurred during onTimer for TimerListener: " + listener + ". This exception will be ignored.", e);
093 }
094 }
095 }
096
097 /**
098 * Adds the listener.
099 * <p/>
100 * It may be important to implement {@link #equals(Object)} and {@link #hashCode()} for the listener
101 * to ensure that we can remove the same listener again, when invoking remove.
102 *
103 * @param listener listener
104 */
105 public void addTimerListener(TimerListener listener) {
106 listeners.add(listener);
107 LOG.debug("Added TimerListener: {}", listener);
108 }
109
110 /**
111 * Removes the listener.
112 * <p/>
113 * It may be important to implement {@link #equals(Object)} and {@link #hashCode()} for the listener
114 * to ensure that we can remove the same listener again, when invoking remove.
115 *
116 * @param listener listener.
117 */
118 public void removeTimerListener(TimerListener listener) {
119 listeners.remove(listener);
120 LOG.debug("Removed TimerListener: {}", listener);
121 }
122
123 @Override
124 protected void doStart() throws Exception {
125 ObjectHelper.notNull(executorService, "executorService", this);
126 task = executorService.scheduleAtFixedRate(this, 1000L, interval, TimeUnit.MILLISECONDS);
127 LOG.debug("Started scheduled TimerListener task to run with interval {} ms", interval);
128 }
129
130 @Override
131 protected void doStop() throws Exception {
132 // executor service will be shutdown by CamelContext
133 if (task != null) {
134 task.cancel(true);
135 task = null;
136 }
137 }
138
139 @Override
140 protected void doShutdown() throws Exception {
141 super.doShutdown();
142 listeners.clear();
143 }
144 }
145