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