/**
* Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved.
*
* Licensed 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 com.springsource.insight.plugin.rabbitmqClient;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.springsource.insight.intercept.color.ColorManager;
import com.springsource.insight.intercept.endpoint.EndPointAnalysis;
import com.springsource.insight.intercept.metrics.AbstractMetricsGenerator;
import com.springsource.insight.intercept.operation.Operation;
import com.springsource.insight.intercept.operation.OperationType;
import com.springsource.insight.intercept.topology.ExternalResourceAnalyzer;
import com.springsource.insight.intercept.topology.ExternalResourceDescriptor;
import com.springsource.insight.intercept.topology.ExternalResourceType;
import com.springsource.insight.intercept.topology.MD5NameGenerator;
import com.springsource.insight.intercept.trace.Frame;
import com.springsource.insight.intercept.trace.Trace;
import com.springsource.insight.util.ListUtil;
import com.springsource.insight.util.StringUtil;
public abstract class AbstractRabbitMQResourceAnalyzer implements ExternalResourceAnalyzer {
public static final String RABBIT = "RabbitMQ";
/**
* Placeholder string used if no exchange name specified
*/
public static final String NO_EXCHANGE = "AMQP default";
public static final String NO_ROUTING_KEY = "no routing key";
/**
* The <U>static</U> score value assigned to endpoints - <B>Note:</B>
* we return a score of {@link EndPointAnalysis#CEILING_LAYER_SCORE} so as
* to let other endpoints "beat" this one
*/
public static final int DEFAULT_SCORE = EndPointAnalysis.CEILING_LAYER_SCORE;
public static final String UNNAMED_TEMP_QUEUE_KEY_PREFIX = "amq.gen-";
public static final String UNNAMED_TEMP_QUEUE_LABEL = "AMQP internal routing";
public static final String UNNAMED_RPC_QUEUE_KEY_PREFIX = "amqp.gen-";
public static final String UNNAMED_RPC_QUEUE_LABEL = "RPC internal routing";
private final RabbitPluginOperationType operationType;
private final boolean isIncoming;
protected AbstractRabbitMQResourceAnalyzer(RabbitPluginOperationType type, boolean incoming) {
this.operationType = type;
this.isIncoming = incoming;
}
public final boolean isIncomingResource() {
return isIncoming;
}
public final RabbitPluginOperationType getRabbitPluginOperationType() {
return operationType;
}
protected abstract String getExchange(Operation op);
protected abstract String getRoutingKey(Operation op);
public OperationType getOperationType() {
return operationType.getOperationType();
}
public Collection<ExternalResourceDescriptor> locateExternalResourceName(Trace trace) {
return locateExternalResourceName(trace, locateFrames(trace));
}
public Collection<Frame> locateFrames(Trace trace) {
return AbstractMetricsGenerator.locateDefaultMetricsFrames(trace, getOperationType());
}
public Collection<ExternalResourceDescriptor> locateExternalResourceName(Trace trace, Collection<Frame> queueFrames) {
if (ListUtil.size(queueFrames) <= 0) {
return Collections.emptyList();
}
List<ExternalResourceDescriptor> queueDescriptors = new ArrayList<ExternalResourceDescriptor>(queueFrames.size());
ColorManager colorManager = ColorManager.getInstance();
for (Frame queueFrame : queueFrames) {
Operation op = queueFrame.getOperation();
String host = op.get("host", String.class);
int port = op.getInt("port", (-1));
String connectionUrl = op.get("connectionUrl", String.class);
String vhost = getVirtualHost(port, connectionUrl);
String color = colorManager.getColor(op);
String finalExchange = getFinalExchangeName(getExchange(op));
String finalRoutingKey = getFinalRoutingKey(getRoutingKey(op));
String exchangeResourceName = buildExternalResourceName(finalExchange, finalRoutingKey, vhost);
ExternalResourceDescriptor externalResourceExchangeDescriptor =
new ExternalResourceDescriptor(queueFrame,
exchangeResourceName,
buildExternalResourceLabel(buildLabel(finalExchange, finalRoutingKey)),
ExternalResourceType.QUEUE.name(),
RABBIT,
host,
port,
color, isIncoming);
queueDescriptors.add(externalResourceExchangeDescriptor);
}
return queueDescriptors;
}
private String getVirtualHost(int port, String connectionUrl) {
// The connectionURL returned from rabbit AMQConnection looks like this:
// "amqp://" + this.username + "@" + getHostAddress() + ":" + getPort() + _virtualHost;
// So we need to parse it carefully :-)
int i = connectionUrl.lastIndexOf(':');
if (i < 0)
return "";
String portvhost = connectionUrl.substring(i+1);
if (port == -1)
return portvhost;
String portStr = Integer.toString(port);
if (portStr.length() < portvhost.length())
return portvhost.substring(portStr.length());
return "";
}
public static String getFinalExchangeName(String exchange) {
boolean hasExchange = !isTrimEmpty(exchange);
if (hasExchange) {
return exchange;
} else {
return NO_EXCHANGE;
}
}
public static String getFinalRoutingKey(String routingKey) {
boolean hasRoutingKey = !isTrimEmpty(routingKey);
if (hasRoutingKey) {
if (routingKey.startsWith(UNNAMED_TEMP_QUEUE_KEY_PREFIX)) {
return UNNAMED_TEMP_QUEUE_LABEL;
} else if (routingKey.startsWith(UNNAMED_RPC_QUEUE_KEY_PREFIX)) {
return UNNAMED_RPC_QUEUE_LABEL;
}
}
return routingKey;
}
public static String buildExternalResourceName(String finalExchange, String finalRoutingKey, String vhost) {
return RABBIT + ":" + finalExchange + ":" + (finalRoutingKey != null ? finalRoutingKey : "") + ":" + vhost;
}
public static String buildExternalResourceLabel(String label) {
return label;
}
public static String buildLabel(String finalExchange, String finalRoutingKey) {
StringBuilder sb = new StringBuilder(StringUtil.getSafeLength(finalExchange)
+ StringUtil.getSafeLength(finalRoutingKey)
+ 2);
boolean hasExchange = !isTrimEmpty(finalExchange);
if (hasExchange) {
sb.append(finalExchange);
}
boolean hasRoutingKey = !isTrimEmpty(finalRoutingKey);
if (hasRoutingKey) {
if (hasExchange) {
sb.append('-');
}
sb.append(finalRoutingKey);
}
return sb.toString();
}
private static boolean isTrimEmpty(String str) {
return (str == null) || (str.trim().length() <= 0);
}
@Override
public String toString() {
return getRabbitPluginOperationType().name() + "[incoming=" + isIncomingResource() + "]";
}
}