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