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