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.Collections;
021import java.util.EventObject;
022import java.util.HashMap;
023import java.util.HashSet;
024import java.util.List;
025import java.util.Map;
026import java.util.Set;
027
028import org.apache.camel.Endpoint;
029import org.apache.camel.Exchange;
030import org.apache.camel.management.event.ExchangeSendingEvent;
031import org.apache.camel.management.event.RouteAddedEvent;
032import org.apache.camel.management.event.RouteRemovedEvent;
033import org.apache.camel.spi.RouteContext;
034import org.apache.camel.spi.RuntimeEndpointRegistry;
035import org.apache.camel.spi.UnitOfWork;
036import org.apache.camel.support.EventNotifierSupport;
037import org.apache.camel.util.LRUCache;
038
039public class DefaultRuntimeEndpointRegistry extends EventNotifierSupport implements RuntimeEndpointRegistry {
040
041    // route id -> endpoint urls
042    private Map<String, Set<String>> inputs;
043    private Map<String, Map<String, String>> outputs;
044    private int limit = 1000;
045    private boolean enabled = true;
046
047    public boolean isEnabled() {
048        return enabled;
049    }
050
051    public void setEnabled(boolean enabled) {
052        this.enabled = enabled;
053    }
054
055    @Override
056    public List<String> getAllEndpoints(boolean includeInputs) {
057        List<String> answer = new ArrayList<String>();
058        if (includeInputs) {
059            for (Map.Entry<String, Set<String>> entry : inputs.entrySet()) {
060                answer.addAll(entry.getValue());
061            }
062        }
063        for (Map.Entry<String, Map<String, String>> entry : outputs.entrySet()) {
064            answer.addAll(entry.getValue().keySet());
065        }
066        return Collections.unmodifiableList(answer);
067    }
068
069    @Override
070    public List<String> getEndpointsPerRoute(String routeId, boolean includeInputs) {
071        List<String> answer = new ArrayList<String>();
072        if (includeInputs) {
073            Set<String> uris = inputs.get(routeId);
074            if (uris != null) {
075                answer.addAll(uris);
076            }
077        }
078        Map<String, String> uris = outputs.get(routeId);
079        if (uris != null) {
080            answer.addAll(uris.keySet());
081        }
082        return Collections.unmodifiableList(answer);
083    }
084
085    @Override
086    public int getLimit() {
087        return limit;
088    }
089
090    @Override
091    public void setLimit(int limit) {
092        this.limit = limit;
093    }
094
095    @Override
096    public void reset() {
097        inputs.clear();
098        outputs.clear();
099    }
100
101    @Override
102    public int size() {
103        int total = inputs.values().size();
104        total += outputs.values().size();
105        return total;
106    }
107
108    @Override
109    protected void doStart() throws Exception {
110        if (inputs == null) {
111            inputs = new HashMap<String, Set<String>>();
112        }
113        if (outputs == null) {
114            outputs = new HashMap<String, Map<String, String>>();
115        }
116    }
117
118    @Override
119    protected void doStop() throws Exception {
120        reset();
121    }
122
123    @Override
124    public void notify(EventObject event) throws Exception {
125        if (event instanceof RouteAddedEvent) {
126            RouteAddedEvent rse = (RouteAddedEvent) event;
127            Endpoint endpoint = rse.getRoute().getEndpoint();
128            String routeId = rse.getRoute().getId();
129
130            // a HashSet is fine for inputs as we only have a limited number of those
131            Set<String> uris = new HashSet<String>();
132            uris.add(endpoint.getEndpointUri());
133            inputs.put(routeId, uris);
134            // use a LRUCache for outputs as we could potential have unlimited uris if dynamic routing is in use
135            // and therefore need to have the limit in use
136            outputs.put(routeId, new LRUCache<String, String>(limit));
137        } else if (event instanceof RouteRemovedEvent) {
138            RouteRemovedEvent rse = (RouteRemovedEvent) event;
139            String routeId = rse.getRoute().getId();
140            inputs.remove(routeId);
141            outputs.remove(routeId);
142        } else {
143            ExchangeSendingEvent ese = (ExchangeSendingEvent) event;
144            Endpoint endpoint = ese.getEndpoint();
145            String routeId = getRouteId(ese.getExchange());
146            String uri = endpoint.getEndpointUri();
147
148            Map<String, String> uris = outputs.get(routeId);
149            if (uris != null && !uris.containsKey(uri)) {
150                uris.put(uri, uri);
151            }
152        }
153    }
154
155    private String getRouteId(Exchange exchange) {
156        String answer = null;
157        UnitOfWork uow = exchange.getUnitOfWork();
158        RouteContext rc = uow != null ? uow.getRouteContext() : null;
159        if (rc != null) {
160            answer = rc.getRoute().getId();
161        }
162        if (answer == null) {
163            // fallback and get from route id on the exchange
164            answer = exchange.getFromRouteId();
165        }
166        return answer;
167    }
168
169    @Override
170    public boolean isEnabled(EventObject event) {
171        return enabled && event instanceof ExchangeSendingEvent
172                || event instanceof RouteAddedEvent
173                || event instanceof RouteRemovedEvent;
174    }
175}