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 */
017 package org.apache.camel.impl;
018
019 import java.util.Map;
020
021 import org.apache.camel.CamelContext;
022 import org.apache.camel.Endpoint;
023 import org.apache.camel.Exchange;
024 import org.apache.camel.FailedToCreateConsumerException;
025 import org.apache.camel.IsSingleton;
026 import org.apache.camel.PollingConsumer;
027 import org.apache.camel.support.ServiceSupport;
028 import org.apache.camel.util.CamelContextHelper;
029 import org.apache.camel.util.LRUCache;
030 import org.apache.camel.util.LRUSoftCache;
031 import org.apache.camel.util.ServiceHelper;
032 import org.slf4j.Logger;
033 import org.slf4j.LoggerFactory;
034
035 /**
036 * Cache containing created {@link org.apache.camel.Consumer}.
037 *
038 * @version
039 */
040 public class ConsumerCache extends ServiceSupport {
041 private static final transient Logger LOG = LoggerFactory.getLogger(ConsumerCache.class);
042 private final CamelContext camelContext;
043 private final Map<String, PollingConsumer> consumers;
044 private final Object source;
045
046 public ConsumerCache(Object source, CamelContext camelContext) {
047 this(source, camelContext, CamelContextHelper.getMaximumCachePoolSize(camelContext));
048 }
049
050 public ConsumerCache(Object source, CamelContext camelContext, int cacheSize) {
051 this(source, camelContext, createLRUCache(cacheSize));
052 }
053
054 public ConsumerCache(Object source, CamelContext camelContext, Map<String, PollingConsumer> cache) {
055 this.camelContext = camelContext;
056 this.consumers = cache;
057 this.source = source;
058 }
059
060 /**
061 * Creates the {@link LRUCache} to be used.
062 * <p/>
063 * This implementation returns a {@link org.apache.camel.util.LRUSoftCache} instance.
064
065 * @param cacheSize the cache size
066 * @return the cache
067 */
068 protected static LRUCache<String, PollingConsumer> createLRUCache(int cacheSize) {
069 // We use a soft reference cache to allow the JVM to re-claim memory if it runs low on memory.
070 return new LRUSoftCache<String, PollingConsumer>(cacheSize);
071 }
072
073 public synchronized PollingConsumer getConsumer(Endpoint endpoint) {
074 String key = endpoint.getEndpointUri();
075 PollingConsumer answer = consumers.get(key);
076 if (answer == null) {
077 try {
078 answer = endpoint.createPollingConsumer();
079 answer.start();
080 } catch (Exception e) {
081 throw new FailedToCreateConsumerException(endpoint, e);
082 }
083
084 boolean singleton = true;
085 if (answer instanceof IsSingleton) {
086 singleton = ((IsSingleton) answer).isSingleton();
087 }
088
089 if (singleton) {
090 LOG.debug("Adding to consumer cache with key: {} for consumer: {}", endpoint, answer);
091 consumers.put(key, answer);
092 } else {
093 LOG.debug("Consumer for endpoint: {} is not singleton and thus not added to consumer cache", key);
094 }
095 }
096 return answer;
097 }
098
099 public Exchange receive(Endpoint endpoint) {
100 LOG.debug("<<<< {}", endpoint);
101
102 PollingConsumer consumer = getConsumer(endpoint);
103 return consumer.receive();
104 }
105
106 public Exchange receive(Endpoint endpoint, long timeout) {
107 LOG.debug("<<<< {}", endpoint);
108
109 PollingConsumer consumer = getConsumer(endpoint);
110 return consumer.receive(timeout);
111 }
112
113 public Exchange receiveNoWait(Endpoint endpoint) {
114 LOG.debug("<<<< {}", endpoint);
115
116 PollingConsumer consumer = getConsumer(endpoint);
117 return consumer.receiveNoWait();
118 }
119
120 public CamelContext getCamelContext() {
121 return camelContext;
122 }
123
124 /**
125 * Gets the source which uses this cache
126 *
127 * @return the source
128 */
129 public Object getSource() {
130 return source;
131 }
132
133 /**
134 * Returns the current size of the cache
135 *
136 * @return the current size
137 */
138 public int size() {
139 int size = consumers.size();
140 LOG.trace("size = {}", size);
141 return size;
142 }
143
144 /**
145 * Gets the maximum cache size (capacity).
146 * <p/>
147 * Will return <tt>-1</tt> if it cannot determine this if a custom cache was used.
148 *
149 * @return the capacity
150 */
151 public int getCapacity() {
152 int capacity = -1;
153 if (consumers instanceof LRUCache) {
154 LRUCache<String, PollingConsumer> cache = (LRUCache<String, PollingConsumer>)consumers;
155 capacity = cache.getMaxCacheSize();
156 }
157 return capacity;
158 }
159
160 /**
161 * Gets the cache hits statistic
162 * <p/>
163 * Will return <tt>-1</tt> if it cannot determine this if a custom cache was used.
164 *
165 * @return the hits
166 */
167 public long getHits() {
168 long hits = -1;
169 if (consumers instanceof LRUCache) {
170 LRUCache<String, PollingConsumer> cache = (LRUCache<String, PollingConsumer>)consumers;
171 hits = cache.getHits();
172 }
173 return hits;
174 }
175
176 /**
177 * Gets the cache misses statistic
178 * <p/>
179 * Will return <tt>-1</tt> if it cannot determine this if a custom cache was used.
180 *
181 * @return the misses
182 */
183 public long getMisses() {
184 long misses = -1;
185 if (consumers instanceof LRUCache) {
186 LRUCache<String, PollingConsumer> cache = (LRUCache<String, PollingConsumer>)consumers;
187 misses = cache.getMisses();
188 }
189 return misses;
190 }
191
192 /**
193 * Resets the cache statistics
194 */
195 public void resetCacheStatistics() {
196 if (consumers instanceof LRUCache) {
197 LRUCache<String, PollingConsumer> cache = (LRUCache<String, PollingConsumer>)consumers;
198 cache.resetStatistics();
199 }
200 }
201
202 /**
203 * Purges this cache
204 */
205 public synchronized void purge() {
206 consumers.clear();
207 }
208
209 @Override
210 public String toString() {
211 return "ConsumerCache for source: " + source + ", capacity: " + getCapacity();
212 }
213
214 protected void doStart() throws Exception {
215 ServiceHelper.startServices(consumers.values());
216 }
217
218 protected void doStop() throws Exception {
219 // when stopping we intend to shutdown
220 ServiceHelper.stopAndShutdownServices(consumers.values());
221 consumers.clear();
222 }
223
224 }