/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.MessageHistory;
import org.apache.camel.spi.InflightRepository;
import org.apache.camel.support.ServiceSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Default {@link org.apache.camel.spi.InflightRepository}.
*
* @version
*/
public class DefaultInflightRepository extends ServiceSupport implements InflightRepository {
private static final Logger LOG = LoggerFactory.getLogger(DefaultInflightRepository.class);
private final ConcurrentMap<String, Exchange> inflight = new ConcurrentHashMap<String, Exchange>();
private final ConcurrentMap<String, AtomicInteger> routeCount = new ConcurrentHashMap<String, AtomicInteger>();
public void add(Exchange exchange) {
inflight.put(exchange.getExchangeId(), exchange);
}
public void remove(Exchange exchange) {
inflight.remove(exchange.getExchangeId());
}
public void add(Exchange exchange, String routeId) {
AtomicInteger existing = routeCount.putIfAbsent(routeId, new AtomicInteger(1));
if (existing != null) {
existing.incrementAndGet();
}
}
public void remove(Exchange exchange, String routeId) {
AtomicInteger existing = routeCount.get(routeId);
if (existing != null) {
existing.decrementAndGet();
}
}
public int size() {
return inflight.size();
}
@Deprecated
public int size(Endpoint endpoint) {
return 0;
}
@Override
public void removeRoute(String routeId) {
routeCount.remove(routeId);
}
@Override
public int size(String routeId) {
AtomicInteger existing = routeCount.get(routeId);
return existing != null ? existing.get() : 0;
}
@Override
public Collection<InflightExchange> browse() {
return browse(null, -1, false);
}
@Override
public Collection<InflightExchange> browse(String fromRouteId) {
return browse(fromRouteId, -1, false);
}
@Override
public Collection<InflightExchange> browse(int limit, boolean sortByLongestDuration) {
return browse(null, limit, sortByLongestDuration);
}
@Override
public Collection<InflightExchange> browse(String fromRouteId, int limit, boolean sortByLongestDuration) {
List<InflightExchange> answer = new ArrayList<InflightExchange>();
List<Exchange> values;
if (fromRouteId == null) {
// all values
values = new ArrayList<Exchange>(inflight.values());
} else {
// only if route match
values = new ArrayList<Exchange>();
for (Exchange exchange : inflight.values()) {
String exchangeRouteId = exchange.getFromRouteId();
if (fromRouteId.equals(exchangeRouteId)) {
values.add(exchange);
}
}
}
if (sortByLongestDuration) {
values.sort(new Comparator<Exchange>() {
@Override
public int compare(Exchange e1, Exchange e2) {
long d1 = getExchangeDuration(e1);
long d2 = getExchangeDuration(e2);
return Long.compare(d1, d2);
}
});
} else {
// else sort by exchange id
values.sort(new Comparator<Exchange>() {
@Override
public int compare(Exchange e1, Exchange e2) {
return e1.getExchangeId().compareTo(e2.getExchangeId());
}
});
}
for (Exchange exchange : values) {
answer.add(new InflightExchangeEntry(exchange));
if (limit > 0 && answer.size() >= limit) {
break;
}
}
return Collections.unmodifiableCollection(answer);
}
@Override
protected void doStart() throws Exception {
}
@Override
protected void doStop() throws Exception {
int count = size();
if (count > 0) {
LOG.warn("Shutting down while there are still " + count + " inflight exchanges.");
} else {
LOG.debug("Shutting down with no inflight exchanges.");
}
routeCount.clear();
}
private static long getExchangeDuration(Exchange exchange) {
long duration = 0;
Date created = exchange.getProperty(Exchange.CREATED_TIMESTAMP, Date.class);
if (created != null) {
duration = System.currentTimeMillis() - created.getTime();
}
return duration;
}
private static final class InflightExchangeEntry implements InflightExchange {
private final Exchange exchange;
private InflightExchangeEntry(Exchange exchange) {
this.exchange = exchange;
}
@Override
public Exchange getExchange() {
return exchange;
}
@Override
public long getDuration() {
return DefaultInflightRepository.getExchangeDuration(exchange);
}
@Override
@SuppressWarnings("unchecked")
public long getElapsed() {
LinkedList<MessageHistory> list = exchange.getProperty(Exchange.MESSAGE_HISTORY, LinkedList.class);
if (list == null || list.isEmpty()) {
return 0;
}
// get latest entry
MessageHistory history = list.getLast();
if (history != null) {
return history.getElapsed();
} else {
return 0;
}
}
@Override
@SuppressWarnings("unchecked")
public String getNodeId() {
LinkedList<MessageHistory> list = exchange.getProperty(Exchange.MESSAGE_HISTORY, LinkedList.class);
if (list == null || list.isEmpty()) {
return null;
}
// get latest entry
MessageHistory history = list.getLast();
if (history != null) {
return history.getNode().getId();
} else {
return null;
}
}
@Override
public String getFromRouteId() {
return exchange.getFromRouteId();
}
@Override
public String getRouteId() {
return getAtRouteId();
}
@Override
@SuppressWarnings("unchecked")
public String getAtRouteId() {
LinkedList<MessageHistory> list = exchange.getProperty(Exchange.MESSAGE_HISTORY, LinkedList.class);
if (list == null || list.isEmpty()) {
return null;
}
// get latest entry
MessageHistory history = list.getLast();
if (history != null) {
return history.getRouteId();
} else {
return null;
}
}
@Override
public String toString() {
return "InflightExchangeEntry[exchangeId=" + exchange.getExchangeId() + "]";
}
}
}