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.component.timer; 018 019import java.util.Date; 020import java.util.Timer; 021import java.util.TimerTask; 022import java.util.concurrent.atomic.AtomicLong; 023 024import org.apache.camel.AsyncCallback; 025import org.apache.camel.CamelContext; 026import org.apache.camel.Endpoint; 027import org.apache.camel.Exchange; 028import org.apache.camel.Processor; 029import org.apache.camel.StartupListener; 030import org.apache.camel.impl.DefaultConsumer; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034/** 035 * The timer consumer. 036 * 037 * @version 038 */ 039public class TimerConsumer extends DefaultConsumer implements StartupListener { 040 private static final Logger LOG = LoggerFactory.getLogger(TimerConsumer.class); 041 private final TimerEndpoint endpoint; 042 private volatile TimerTask task; 043 private volatile boolean configured; 044 045 public TimerConsumer(TimerEndpoint endpoint, Processor processor) { 046 super(endpoint, processor); 047 this.endpoint = endpoint; 048 } 049 050 @Override 051 public TimerEndpoint getEndpoint() { 052 return (TimerEndpoint) super.getEndpoint(); 053 } 054 055 @Override 056 protected void doStart() throws Exception { 057 task = new TimerTask() { 058 // counter 059 private final AtomicLong counter = new AtomicLong(); 060 061 @Override 062 public void run() { 063 if (!isTaskRunAllowed()) { 064 // do not run timer task as it was not allowed 065 LOG.debug("Run now allowed for timer: {}", endpoint); 066 return; 067 } 068 069 try { 070 long count = counter.incrementAndGet(); 071 072 boolean fire = endpoint.getRepeatCount() <= 0 || count <= endpoint.getRepeatCount(); 073 if (fire) { 074 sendTimerExchange(count); 075 } else { 076 // no need to fire anymore as we exceeded repeat count 077 LOG.debug("Cancelling {} timer as repeat count limit reached after {} counts.", endpoint.getTimerName(), endpoint.getRepeatCount()); 078 cancel(); 079 } 080 } catch (Throwable e) { 081 // catch all to avoid the JVM closing the thread and not firing again 082 LOG.warn("Error processing exchange. This exception will be ignored, to let the timer be able to trigger again.", e); 083 } 084 } 085 }; 086 087 // only configure task if CamelContext already started, otherwise the StartupListener 088 // is configuring the task later 089 if (!configured && endpoint.getCamelContext().getStatus().isStarted()) { 090 Timer timer = endpoint.getTimer(this); 091 configureTask(task, timer); 092 } 093 } 094 095 @Override 096 protected void doStop() throws Exception { 097 if (task != null) { 098 task.cancel(); 099 } 100 task = null; 101 configured = false; 102 103 // remove timer 104 endpoint.removeTimer(this); 105 } 106 107 @Override 108 public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception { 109 if (task != null && !configured) { 110 Timer timer = endpoint.getTimer(this); 111 configureTask(task, timer); 112 } 113 } 114 115 /** 116 * Whether the timer task is allow to run or not 117 */ 118 protected boolean isTaskRunAllowed() { 119 // only allow running the timer task if we can run and are not suspended, 120 // and CamelContext must have been fully started 121 return endpoint.getCamelContext().getStatus().isStarted() && isRunAllowed() && !isSuspended(); 122 } 123 124 protected void configureTask(TimerTask task, Timer timer) { 125 if (endpoint.isFixedRate()) { 126 if (endpoint.getTime() != null) { 127 timer.scheduleAtFixedRate(task, endpoint.getTime(), endpoint.getPeriod()); 128 } else { 129 timer.scheduleAtFixedRate(task, endpoint.getDelay(), endpoint.getPeriod()); 130 } 131 } else { 132 if (endpoint.getTime() != null) { 133 if (endpoint.getPeriod() > 0) { 134 timer.schedule(task, endpoint.getTime(), endpoint.getPeriod()); 135 } else { 136 timer.schedule(task, endpoint.getTime()); 137 } 138 } else { 139 if (endpoint.getPeriod() > 0) { 140 timer.schedule(task, endpoint.getDelay(), endpoint.getPeriod()); 141 } else { 142 timer.schedule(task, endpoint.getDelay()); 143 } 144 } 145 } 146 configured = true; 147 } 148 149 protected void sendTimerExchange(long counter) { 150 final Exchange exchange = endpoint.createExchange(); 151 exchange.setProperty(Exchange.TIMER_COUNTER, counter); 152 exchange.setProperty(Exchange.TIMER_NAME, endpoint.getTimerName()); 153 exchange.setProperty(Exchange.TIMER_TIME, endpoint.getTime()); 154 exchange.setProperty(Exchange.TIMER_PERIOD, endpoint.getPeriod()); 155 156 Date now = new Date(); 157 exchange.setProperty(Exchange.TIMER_FIRED_TIME, now); 158 // also set now on in header with same key as quartz to be consistent 159 exchange.getIn().setHeader("firedTime", now); 160 161 if (LOG.isTraceEnabled()) { 162 LOG.trace("Timer {} is firing #{} count", endpoint.getTimerName(), counter); 163 } 164 165 if (!endpoint.isSynchronous()) { 166 getAsyncProcessor().process(exchange, new AsyncCallback() { 167 @Override 168 public void done(boolean doneSync) { 169 // handle any thrown exception 170 if (exchange.getException() != null) { 171 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException()); 172 } 173 } 174 }); 175 } else { 176 try { 177 getProcessor().process(exchange); 178 } catch (Exception e) { 179 exchange.setException(e); 180 } 181 182 // handle any thrown exception 183 if (exchange.getException() != null) { 184 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException()); 185 } 186 } 187 } 188}