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.impl; 018 019import java.util.concurrent.ArrayBlockingQueue; 020import java.util.concurrent.BlockingQueue; 021import java.util.concurrent.LinkedBlockingQueue; 022import java.util.concurrent.RejectedExecutionException; 023import java.util.concurrent.TimeUnit; 024 025import org.apache.camel.Consumer; 026import org.apache.camel.Endpoint; 027import org.apache.camel.Exchange; 028import org.apache.camel.PollingConsumerPollingStrategy; 029import org.apache.camel.Processor; 030import org.apache.camel.spi.ExceptionHandler; 031import org.apache.camel.util.ServiceHelper; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035/** 036 * A default implementation of the {@link org.apache.camel.PollingConsumer} which uses the normal 037 * asynchronous consumer mechanism along with a {@link BlockingQueue} to allow 038 * the caller to pull messages on demand. 039 * 040 * @version 041 */ 042public class EventDrivenPollingConsumer extends PollingConsumerSupport implements Processor { 043 private static final Logger LOG = LoggerFactory.getLogger(EventDrivenPollingConsumer.class); 044 private final BlockingQueue<Exchange> queue; 045 private ExceptionHandler interruptedExceptionHandler; 046 private Consumer consumer; 047 private boolean blockWhenFull = true; 048 private final int queueCapacity; 049 050 public EventDrivenPollingConsumer(Endpoint endpoint) { 051 this(endpoint, 1000); 052 } 053 054 public EventDrivenPollingConsumer(Endpoint endpoint, int queueSize) { 055 super(endpoint); 056 this.queueCapacity = queueSize; 057 if (queueSize <= 0) { 058 this.queue = new LinkedBlockingQueue<Exchange>(); 059 } else { 060 this.queue = new ArrayBlockingQueue<Exchange>(queueSize); 061 } 062 this.interruptedExceptionHandler = new LoggingExceptionHandler(endpoint.getCamelContext(), EventDrivenPollingConsumer.class); 063 } 064 065 public EventDrivenPollingConsumer(Endpoint endpoint, BlockingQueue<Exchange> queue) { 066 super(endpoint); 067 this.queue = queue; 068 this.queueCapacity = queue.remainingCapacity(); 069 this.interruptedExceptionHandler = new LoggingExceptionHandler(endpoint.getCamelContext(), EventDrivenPollingConsumer.class); 070 } 071 072 public boolean isBlockWhenFull() { 073 return blockWhenFull; 074 } 075 076 public void setBlockWhenFull(boolean blockWhenFull) { 077 this.blockWhenFull = blockWhenFull; 078 } 079 080 /** 081 * Gets the queue capacity. 082 */ 083 public int getQueueCapacity() { 084 return queueCapacity; 085 } 086 087 /** 088 * Gets the current queue size (no of elements in the queue). 089 */ 090 public int getQueueSize() { 091 return queue.size(); 092 } 093 094 public Exchange receiveNoWait() { 095 return receive(0); 096 } 097 098 public Exchange receive() { 099 // must be started 100 if (!isRunAllowed() || !isStarted()) { 101 throw new RejectedExecutionException(this + " is not started, but in state: " + getStatus().name()); 102 } 103 104 while (isRunAllowed()) { 105 try { 106 beforePoll(0); 107 // take will block waiting for message 108 return queue.take(); 109 } catch (InterruptedException e) { 110 handleInterruptedException(e); 111 } finally { 112 afterPoll(); 113 } 114 } 115 LOG.trace("Consumer is not running, so returning null"); 116 return null; 117 } 118 119 public Exchange receive(long timeout) { 120 // must be started 121 if (!isRunAllowed() || !isStarted()) { 122 throw new RejectedExecutionException(this + " is not started, but in state: " + getStatus().name()); 123 } 124 125 try { 126 // use the timeout value returned from beforePoll 127 timeout = beforePoll(timeout); 128 return queue.poll(timeout, TimeUnit.MILLISECONDS); 129 } catch (InterruptedException e) { 130 handleInterruptedException(e); 131 return null; 132 } finally { 133 afterPoll(); 134 } 135 } 136 137 public void process(Exchange exchange) throws Exception { 138 if (isBlockWhenFull()) { 139 try { 140 queue.put(exchange); 141 } catch (InterruptedException e) { 142 // ignore 143 log.debug("Put interrupted, are we stopping? {}", isStopping() || isStopped()); 144 } 145 } else { 146 queue.add(exchange); 147 } 148 } 149 150 public ExceptionHandler getInterruptedExceptionHandler() { 151 return interruptedExceptionHandler; 152 } 153 154 public void setInterruptedExceptionHandler(ExceptionHandler interruptedExceptionHandler) { 155 this.interruptedExceptionHandler = interruptedExceptionHandler; 156 } 157 158 protected void handleInterruptedException(InterruptedException e) { 159 getInterruptedExceptionHandler().handleException(e); 160 } 161 162 protected long beforePoll(long timeout) { 163 if (consumer instanceof PollingConsumerPollingStrategy) { 164 PollingConsumerPollingStrategy strategy = (PollingConsumerPollingStrategy) consumer; 165 try { 166 timeout = strategy.beforePoll(timeout); 167 } catch (Exception e) { 168 LOG.debug("Error occurred before polling " + consumer + ". This exception will be ignored.", e); 169 } 170 } 171 return timeout; 172 } 173 174 protected void afterPoll() { 175 if (consumer instanceof PollingConsumerPollingStrategy) { 176 PollingConsumerPollingStrategy strategy = (PollingConsumerPollingStrategy) consumer; 177 try { 178 strategy.afterPoll(); 179 } catch (Exception e) { 180 LOG.debug("Error occurred after polling " + consumer + ". This exception will be ignored.", e); 181 } 182 } 183 } 184 185 protected void doStart() throws Exception { 186 // lets add ourselves as a consumer 187 consumer = getEndpoint().createConsumer(this); 188 189 // if the consumer has a polling strategy then invoke that 190 if (consumer instanceof PollingConsumerPollingStrategy) { 191 PollingConsumerPollingStrategy strategy = (PollingConsumerPollingStrategy) consumer; 192 strategy.onInit(); 193 } else { 194 ServiceHelper.startService(consumer); 195 } 196 } 197 198 protected void doStop() throws Exception { 199 ServiceHelper.stopService(consumer); 200 } 201 202 protected void doShutdown() throws Exception { 203 ServiceHelper.stopAndShutdownService(consumer); 204 queue.clear(); 205 } 206}