/**
* 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.jms;
import java.util.Collection;
import java.util.Enumeration;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.TextMessage;
import javax.jms.Topic;
import com.springsource.insight.intercept.operation.Operation;
import com.springsource.insight.intercept.operation.OperationMap;
import com.springsource.insight.intercept.trace.ObscuredValueMarker;
/**
* Utility class for all JMS plugin operations
*/
final class JMSPluginUtils {
static final String CORRELATION_ID = "correlationId";
static final String DELIVERY_MODE = "deliveryMode";
static final String EXPIRATION = "expiration";
static final String JMS_TYPE = "jmsType";
static final String MESSAGE_PROPERTIES = "messageProperties";
static final String CONNECTION_DATA = "connectionData";
static final String MESSAGE_CONTENT = "messageContent";
static final String MESSAGE_CONTENT_MAP = "messageContentMap";
static final String MESSAGE_DESTINATION = "destination";
static final String MESSAGE_HEADERS = "messageHeaders";
static final String MESSAGE_ID = "messageId";
static final String MESSAGE_TYPE = "messageType";
static final String NAME = "Name";
static final String PRIORITY = "priority";
static final String REDELIVERED = "redelivered";
static final String REPLY_TO = "replyTo";
static final String TIMESTAMP = "timestamp";
static final String TYPE = "Type";
static final String UNKNOWN = "UNKNOWN";
private JMSPluginUtils() {
throw new UnsupportedOperationException("No instance");
}
/**
* Adds destination type and name to a given {@link OperationMap} only if {@code dest}
* is not {@code null}
*
* @param dest jms destination
* @param map The {@link OperationMap} to update
* @param marker The {@link ObscuredValueMarker} to use if a property is marked as sensitive
* @param nameSet The {@link Collection} of properties names marked as sensitive
* @param prefix destination type and name prefix
* @return Same as input map
* @throws JMSException if any occurs by accessing {@code dest} attributes
*/
static OperationMap addDestinationDetailsToMapIfNeeded(Destination dest, OperationMap map, ObscuredValueMarker marker, Collection<String> nameSet, String prefix)
throws JMSException {
if (dest == null) {
return map;
}
DestinationType destinationType = getDestinationType(dest);
String destinationName = getDestinationName(dest, destinationType);
updateAny(map, prefix + TYPE, destinationType.name(), marker, nameSet);
updateAny(map, prefix + NAME, destinationName, marker, nameSet);
return map;
}
/**
* Creates an operation map named {@link #MESSAGE_PROPERTIES} and populates the map with {@code message} properties
*
* @param op insight {@link Operation}
* @param message jms {@link Message}
* @param marker The {@link ObscuredValueMarker} to use if a property is marked as sensitive
* @param nameSet The {@link Collection} of properties names marked as sensitive
* @return Generated attributes {@link OperationMap}
* @throws JMSException if any occurs by accessing {@code message} properties
*/
static OperationMap extractMessageProperties(Operation op, Message message, ObscuredValueMarker marker, Collection<String> nameSet)
throws JMSException {
OperationMap attributesMap = op.createMap(MESSAGE_PROPERTIES);
Enumeration<?> propertyNames = message.getPropertyNames();
if (propertyNames != null) {
Object host = message.getObjectProperty("host");
Object port = message.getObjectProperty("port");
if (host != null && port != null) {
OperationMap connectionData = op.createMap(CONNECTION_DATA);
int _port;
try {
_port = Integer.parseInt(String.valueOf(port));
} catch (NumberFormatException e) {
_port = -1;
}
connectionData.put("port", _port);
connectionData.put("host", String.valueOf(host));
}
for (Enumeration<?> propertyNameEnum = propertyNames; propertyNameEnum.hasMoreElements(); ) {
String propertyName = (String) propertyNameEnum.nextElement();
Object propertyValue = message.getObjectProperty(propertyName);
updateAny(attributesMap, propertyName, propertyValue, marker, nameSet);
}
}
return attributesMap;
}
/**
* Creates an operation map name {@link #MESSAGE_HEADERS} and populates the map
* with {@code message} headers values
*
* @param op insight {@link Operation}
* @param message jms {@link Message}
* @param marker The {@link ObscuredValueMarker} to use if a property is marked as sensitive
* @param nameSet The {@link Collection} of properties names marked as sensitive
* @return The {@link OperationMap} containing the relevant extracted headers
* @throws JMSException if any occurs by accessing {@code message} properties
*/
static OperationMap extractMessageHeaders(Operation op, Message message, ObscuredValueMarker marker, Collection<String> nameSet)
throws JMSException {
OperationMap headersMap = op.createMap(MESSAGE_HEADERS);
addDestinationDetailsToMapIfNeeded(message.getJMSDestination(), headersMap, marker, nameSet, MESSAGE_DESTINATION);
addDestinationDetailsToMapIfNeeded(message.getJMSReplyTo(), headersMap, marker, nameSet, REPLY_TO);
updateAny(headersMap, CORRELATION_ID, message.getJMSCorrelationID(), marker, nameSet);
updateAny(headersMap, DELIVERY_MODE, getDeliveryMode(message.getJMSDeliveryMode()).getLabel(), marker, nameSet);
updateAny(headersMap, EXPIRATION, Long.valueOf(message.getJMSExpiration()), marker, nameSet);
updateAny(headersMap, MESSAGE_ID, message.getJMSMessageID(), marker, nameSet);
updateAny(headersMap, PRIORITY, Integer.valueOf(message.getJMSPriority()), marker, nameSet);
updateAny(headersMap, REDELIVERED, Boolean.valueOf(message.getJMSRedelivered()), marker, nameSet);
long timestamp = message.getJMSTimestamp();
if (timestamp > 0L) {
updateAny(headersMap, TIMESTAMP, Long.valueOf(timestamp), marker, nameSet);
}
updateAny(headersMap, JMS_TYPE, message.getJMSType(), marker, nameSet);
return headersMap;
}
private static OperationMap updateAny(OperationMap map, String name, Object value, ObscuredValueMarker marker, Collection<String> nameSet) {
map.putAny(name, value);
updateSensitiveValues(name, value, marker, nameSet);
return map;
}
private static boolean updateSensitiveValues(String name, Object value, ObscuredValueMarker marker, Collection<String> nameSet) {
if (nameSet.contains(name) && (value != null)) {
marker.markObscured(value);
return true;
}
return false;
}
/**
* Adds the message type ({@link MessageType}) to the {@code message}.<br>
* It also adds the {@code message} content ({@link TextMessage#getText()}) if the {@code message} is a {@link TextMessage}, <br>
* and if the {@code message} is a {@link MapMessage} then the {@code message} content map is added.
*
* @param op insight operation
* @param message jms message
* @throws JMSException if any occurs by accessing {@code message} properties
*/
static void extractMessageTypeAttributes(Operation op, Message message) throws JMSException {
MessageType messageType = MessageType.getType(message);
messageType.handleMessage(message, op);
}
/**
* @param deliveryMode message delivery mode ({@link DeliveryMode})
* @return an enum representation for the {@code message} delivery mode ({@link Message#getJMSDeliveryMode()})
*/
static DeliveryModeType getDeliveryMode(int deliveryMode) {
DeliveryModeType mode;
switch (deliveryMode) {
case DeliveryMode.NON_PERSISTENT:
mode = DeliveryModeType.NON_PERSISTENT;
break;
case DeliveryMode.PERSISTENT:
mode = DeliveryModeType.PERSISTENT;
break;
default:
mode = DeliveryModeType.UNKNOWN;
break;
}
return mode;
}
/**
* @param dest jms destination
* @param type destination type
* @return destination name ({@link Queue#getQueueName()}, {@link Topic#getTopicName()})
* @throws JMSException if any occurs by accessing {@code dest} properties
*/
static String getDestinationName(Destination dest, DestinationType type) throws JMSException {
String name = UNKNOWN;
switch (type) {
case Queue:
case TemporaryQueue:
name = ((Queue) dest).getQueueName();
break;
case Topic:
case TemporaryTopic:
name = ((Topic) dest).getTopicName();
break;
default: // do nothing
}
return name;
}
/**
* @param dest jms destination
* @return {@code dest} type (queue or topic)
*/
static DestinationType getDestinationType(Destination dest) {
DestinationType type = DestinationType.Unknown;
if (dest instanceof TemporaryQueue) {
type = DestinationType.TemporaryQueue;
} else if (dest instanceof Queue) {
type = DestinationType.Queue;
} else if (dest instanceof TemporaryTopic) {
type = DestinationType.TemporaryTopic;
} else if (dest instanceof Topic) {
type = DestinationType.Topic;
}
return type;
}
/**
* Extracts a {@link Message} from a {@code args}
*
* @param args
* @return a {@link Message} or {@code null} if none exists
*/
static Message getMessage(Object[] args) {
Message m = null;
for (Object obj : args) {
if (obj instanceof Message) {
m = (Message) obj;
break;
}
}
return m;
}
}