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.ArrayList;
020import java.util.Collection;
021import java.util.LinkedHashSet;
022import java.util.Map;
023import java.util.Set;
024import java.util.concurrent.ConcurrentHashMap;
025import java.util.concurrent.ConcurrentMap;
026
027import org.apache.camel.CamelContext;
028import org.apache.camel.Endpoint;
029import org.apache.camel.spi.EndpointRegistry;
030import org.apache.camel.util.CamelContextHelper;
031import org.apache.camel.util.LRUCache;
032import org.apache.camel.util.ServiceHelper;
033
034/**
035 * Default implementation of {@link org.apache.camel.spi.EndpointRegistry}
036 */
037public class DefaultEndpointRegistry extends LRUCache<EndpointKey, Endpoint> implements EndpointRegistry<EndpointKey> {
038    private static final long serialVersionUID = 1L;
039    private ConcurrentMap<EndpointKey, Endpoint> staticMap;
040    private final CamelContext context;
041
042    public DefaultEndpointRegistry(CamelContext context) {
043        // do not stop on eviction, as the endpoint may still be in use
044        super(CamelContextHelper.getMaximumEndpointCacheSize(context), CamelContextHelper.getMaximumEndpointCacheSize(context), false);
045        // static map to hold endpoints we do not want to be evicted
046        this.staticMap = new ConcurrentHashMap<EndpointKey, Endpoint>();
047        this.context = context;
048    }
049
050    public DefaultEndpointRegistry(CamelContext context, Map<EndpointKey, Endpoint> endpoints) {
051        this(context);
052        putAll(endpoints);
053    }
054
055    @Override
056    public void start() throws Exception {
057        resetStatistics();
058    }
059
060    @Override
061    public Endpoint get(Object o) {
062        // try static map first
063        Endpoint answer = staticMap.get(o);
064        if (answer == null) {
065            answer = super.get(o);
066        } else {
067            hits.incrementAndGet();
068        }
069        return answer;
070    }
071
072    @Override
073    public Endpoint put(EndpointKey key, Endpoint endpoint) {
074        // at first we must see if the key already exists and then replace it back, so it stays the same spot
075        Endpoint answer = staticMap.remove(key);
076        if (answer != null) {
077            // replace existing
078            staticMap.put(key, endpoint);
079            return answer;
080        }
081
082        answer = super.remove(key);
083        if (answer != null) {
084            // replace existing
085            super.put(key, endpoint);
086            return answer;
087        }
088
089        // we want endpoints to be static if they are part of setting up or starting routes
090        if (context.isSetupRoutes() || context.isStartingRoutes()) {
091            answer = staticMap.put(key, endpoint);
092        } else {
093            answer = super.put(key, endpoint);
094        }
095
096        return answer;
097    }
098
099    @Override
100    public void putAll(Map<? extends EndpointKey, ? extends Endpoint> map) {
101        // need to use put instead of putAll to ensure the entries gets added to either static or dynamic map
102        for (Map.Entry<? extends EndpointKey, ? extends Endpoint> entry : map.entrySet()) {
103            put(entry.getKey(), entry.getValue());
104        }
105    }
106
107    @Override
108    public boolean containsKey(Object o) {
109        return staticMap.containsKey(o) || super.containsKey(o);
110    }
111
112    @Override
113    public boolean containsValue(Object o) {
114        return staticMap.containsValue(o) || super.containsValue(o);
115    }
116
117    @Override
118    public int size() {
119        return staticMap.size() + super.size();
120    }
121
122    public int staticSize() {
123        return staticMap.size();
124    }
125
126    @Override
127    public int dynamicSize() {
128        return super.size();
129    }
130
131    @Override
132    public boolean isEmpty() {
133        return staticMap.isEmpty() && super.isEmpty();
134    }
135
136    @Override
137    public Endpoint remove(Object o) {
138        Endpoint answer = staticMap.remove(o);
139        if (answer == null) {
140            answer = super.remove(o);
141        }
142        return answer;
143    }
144
145    @Override
146    public void clear() {
147        staticMap.clear();
148        super.clear();
149    }
150
151    @Override
152    public Set<EndpointKey> keySet() {
153        Set<EndpointKey> answer = new LinkedHashSet<EndpointKey>();
154        answer.addAll(staticMap.keySet());
155        answer.addAll(super.keySet());
156        return answer;
157    }
158
159    @Override
160    public Collection<Endpoint> values() {
161        Collection<Endpoint> answer = new ArrayList<Endpoint>();
162        answer.addAll(staticMap.values());
163        answer.addAll(super.values());
164        return answer;
165    }
166
167    @Override
168    public Set<Entry<EndpointKey, Endpoint>> entrySet() {
169        Set<Entry<EndpointKey, Endpoint>> answer = new LinkedHashSet<Entry<EndpointKey, Endpoint>>();
170        answer.addAll(staticMap.entrySet());
171        answer.addAll(super.entrySet());
172        return answer;
173    }
174
175    @Override
176    public int getMaximumCacheSize() {
177        return super.getMaxCacheSize();
178    }
179
180    /**
181     * Purges the cache
182     */
183    @Override
184    public void purge() {
185        // only purge the dynamic part
186        super.clear();
187    }
188
189    @Override
190    public boolean isStatic(String key) {
191        return staticMap.containsKey(new EndpointKey(key));
192    }
193
194    @Override
195    public boolean isDynamic(String key) {
196        return super.containsKey(new EndpointKey(key));
197    }
198
199    @Override
200    public void stop() throws Exception {
201        ServiceHelper.stopServices(staticMap.values());
202        ServiceHelper.stopServices(values());
203        purge();
204    }
205
206    @Override
207    public String toString() {
208        return "EndpointRegistry for " + context.getName() + ", capacity: " + getMaxCacheSize();
209    }
210}