/*
* 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.jmeter.protocol.jms;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.NamingException;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.jms.sampler.JMSProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods for JMS protocol.
* WARNING - the API for this class is likely to change!
*/
public final class Utils {
// By default priority is 4
// http://docs.oracle.com/javaee/6/tutorial/doc/bncfu.html
public static final String DEFAULT_PRIORITY_4 = "4"; // $NON-NLS-1$
// By default a message never expires
// http://docs.oracle.com/javaee/6/tutorial/doc/bncfu.html
public static final String DEFAULT_NO_EXPIRY = "0"; // $NON-NLS-1$
private static final Logger log = LoggerFactory.getLogger(Utils.class);
public static void close(MessageConsumer closeable, Logger log){
if (closeable != null){
try {
closeable.close();
} catch (JMSException e) {
log.error("Error during close: ", e);
}
}
}
public static void close(Session closeable, Logger log) {
if (closeable != null){
try {
closeable.close();
} catch (JMSException e) {
log.error("Error during close: ", e);
}
}
}
public static void close(Connection closeable, Logger log) {
if (closeable != null){
try {
closeable.close();
} catch (JMSException e) {
log.error("Error during close: ", e);
}
}
}
/**
* @param closeable {@link MessageProducer}
* @param log {@link Logger}
*/
public static void close(MessageProducer closeable, Logger log) {
if (closeable != null){
try {
closeable.close();
} catch (JMSException e) {
log.error("Error during close: ", e);
}
}
}
public static String messageProperties(Message msg){
return messageProperties(new StringBuilder(), msg).toString();
}
public static StringBuilder messageProperties(StringBuilder sb, Message msg){
requestHeaders(sb, msg);
sb.append("Properties:\n");
Enumeration<?> rme;
try {
rme = msg.getPropertyNames();
while(rme.hasMoreElements()){
String name=(String) rme.nextElement();
sb.append(name).append('\t');
String value=msg.getStringProperty(name);
sb.append(value).append('\n');
}
} catch (JMSException e) {
sb.append("\nError: "+e.toString());
}
return sb;
}
public static StringBuilder requestHeaders(StringBuilder sb, Message msg){
try {
sb.append("JMSCorrelationId ").append(msg.getJMSCorrelationID()).append('\n');
sb.append("JMSMessageId ").append(msg.getJMSMessageID()).append('\n');
sb.append("JMSTimestamp ").append(msg.getJMSTimestamp()).append('\n');
sb.append("JMSType ").append(msg.getJMSType()).append('\n');
sb.append("JMSExpiration ").append(msg.getJMSExpiration()).append('\n');
sb.append("JMSPriority ").append(msg.getJMSPriority()).append('\n');
sb.append("JMSDestination ").append(msg.getJMSDestination()).append('\n');
} catch (JMSException e) {
sb.append("\nError: "+e.toString());
}
return sb;
}
/**
* Method will lookup a given destination (topic/queue) using JNDI.
*
* @param context
* context to use for lookup
* @param name
* the destination name
* @return the destination, never null
* @throws NamingException
* if the name cannot be found as a Destination
*/
public static Destination lookupDestination(Context context, String name) throws NamingException {
Object o = context.lookup(name);
if (o instanceof Destination){
return (Destination) o;
}
throw new NamingException("Found: "+name+"; expected Destination, but was: "+(o!=null ? o.getClass().getName() : "null"));
}
/**
* Get value from Context environment taking into account non fully
* compliant JNDI implementations
*
* @param context
* context to use
* @param key
* key to lookup in contexts environment
* @return String or <code>null</code> if context.getEnvironment() is not compliant
* @throws NamingException
* if a naming problem occurs while getting the environment
*/
public static String getFromEnvironment(Context context, String key) throws NamingException {
try {
Hashtable<?,?> env = context.getEnvironment();
if(env != null) {
return (String) env.get(key);
} else {
log.warn("context.getEnvironment() returned null (should not happen according to javadoc but non compliant implementation can return this)");
return null;
}
} catch (javax.naming.OperationNotSupportedException ex) {
// Some JNDI implementation can return this
log.warn("context.getEnvironment() not supported by implementation ");
return null;
}
}
/**
* Obtain the queue connection from the context and factory name.
*
* @param ctx
* context to use
* @param factoryName
* name of the object factory to look up in <code>context</code>
* @return the queue connection
* @throws JMSException
* when creation of the connection fails
* @throws NamingException
* when lookup in context fails
*/
public static Connection getConnection(Context ctx, String factoryName) throws JMSException, NamingException {
Object objfac = null;
try {
objfac = ctx.lookup(factoryName);
} catch (NoClassDefFoundError e) {
throw new NamingException("Lookup failed: "+e.toString());
}
if (objfac instanceof javax.jms.ConnectionFactory) {
String username = getFromEnvironment(ctx, Context.SECURITY_PRINCIPAL);
if(username != null) {
String password = getFromEnvironment(ctx, Context.SECURITY_CREDENTIALS);
return ((javax.jms.ConnectionFactory) objfac).createConnection(username, password);
}
else {
return ((javax.jms.ConnectionFactory) objfac).createConnection();
}
}
throw new NamingException("Expected javax.jms.ConnectionFactory, found "+(objfac != null ? objfac.getClass().getName(): "null"));
}
/**
* Set JMS Properties to msg
* @param msg Message to operate on
* @param map Map of Properties to be set on the message
* @throws JMSException when <code>msg</code> throws a {@link JMSException} while the properties get set
*/
public static void addJMSProperties(Message msg, Map<String, Object> map) throws JMSException {
if (map == null) {
return;
}
for (Map.Entry<String, Object> me : map.entrySet()) {
String name = me.getKey();
Object value = me.getValue();
if (log.isDebugEnabled()) {
log.debug("Adding property [" + name + "=" + value + "]");
}
// WebsphereMQ does not allow corr. id. to be set using setStringProperty()
if ("JMSCorrelationID".equalsIgnoreCase(name)) { // $NON-NLS-1$
msg.setJMSCorrelationID((String)value);
} else {
msg.setObjectProperty(name, value);
}
}
}
/**
* Converts {@link Arguments} to {@link JMSProperties} defaulting to String type
* Used to convert version <= 2.10 test plans
* @param args {@link Arguments} to be converted
* @return jmsProperties The converted {@link JMSProperties}
*/
public static JMSProperties convertArgumentsToJmsProperties(Arguments args) {
JMSProperties jmsProperties = new JMSProperties();
Map<String,String> map = args.getArgumentsAsMap();
for (Map.Entry<String, String> entry : map.entrySet()) {
jmsProperties.addJmsProperty(entry.getKey(), entry.getValue());
}
return jmsProperties;
}
}