package org.jboss.soa.esb.addressing.eprs;
/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
* @author mark.little@jboss.com
*/
/**
* This class represents the endpoint reference for services.
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.jms.Session;
import javax.naming.Context;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.addressing.EPR;
import org.jboss.soa.esb.addressing.PortReference;
import org.jboss.soa.esb.addressing.XMLUtil;
import org.jboss.soa.esb.addressing.PortReference.Extension;
import org.jboss.soa.esb.common.Configuration;
import org.jboss.soa.esb.util.JndiUtil;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* A helper class for using JMS style EPRs. Simply create and use instances of
* this type.
*
* @author marklittle
*
*/
public class JMSEpr extends EPR
{
@SuppressWarnings("unused")
private Logger log = Logger.getLogger( JMSEpr.class );
public static final String JMS_PROTOCOL = "jms";
public static final String PROTOCOL_SEPARATOR = "://";
public static final String ONE_ONE_PROTOCOL = "1.1";
public static final String ONE_ZERO_TWO_PROTOCOL = "1.0.2b";
public static final String SPECIFICATION_VERSION_TAG = "specification-version";
public static final String DESTINATION_TYPE_TAG = "destination-type";
public static final String DESTINATION_NAME_TAG = "destination-name";
public static final String CONNECTION_FACTORY_TAG = "connection-factory";
public static final String MAX_SESSIONS_PER_CONNECTION = "max-sessions-per-connection";
public static final String MAX_XA_SESSIONS_PER_CONNECTION = "max-xa-sessions-per-connection";
public static final String JNDI_PKG_PREFIX_TAG = "jndi-pkg-prefix";
public static final String JNDI_URL_TAG = "jndi-URL";
public static final String JNDI_CONTEXT_FACTORY_TAG = "jndi-context-factory";
public static final String MESSAGE_SELECTOR_TAG = "message-selector";
public static final String QUEUE_TYPE = "queue";
public static final String TOPIC_TYPE = "topic";
public static final String DEFAULT_REPLY_TO_DESTINATION_SUFFIX = "_reply";
public static final String PERSISTENT_TAG = "persistent";
public static final String TRANSACTED_TAG = "transacted";
public static final String JNDI_PREFIXES = "jndi-prefixes";
public static final String CLIENT_ID = "client-id";
public static final String DURABLE_SUBSCRIPTION_NAME = "durable-subscription-name";
/**
* JMS Client acknowledgment mode configuration tag
*/
public static final String ACKNOWLEDGE_MODE_TAG = "acknowledge-mode";
/**
* JMS Destination username. This is the username in the call to
* {@link javax.jms.ConnectionFactory#createConnection(String, String) }
*/
public static final String JMS_SECURITY_PRINCIPAL_TAG = "jms-security-principal";
/**
* JMS Destination password. This is the password in the call to
* {@link javax.jms.ConnectionFactory#createConnection(String, String) }
*/
public static final String JMS_SECURITY_CREDENTIAL_TAG = "jms-security-credential";
/**
* Enum to type-safe JMS Client Acknowledgement mode string
* mappings to JMS Session's integers.
*/
public enum AcknowledgeMode
{
CLIENT_ACKNOWLEDGE(Session.CLIENT_ACKNOWLEDGE),
AUTO_ACKNOWLEDGE(Session.AUTO_ACKNOWLEDGE),
DUPS_OK_ACKNOWLEDGE(Session.DUPS_OK_ACKNOWLEDGE);
private static Logger log = Logger.getLogger(AcknowledgeMode.class);
private int jmsAckModeInt;
AcknowledgeMode(final int jmsAckModeInt)
{
this.jmsAckModeInt = jmsAckModeInt;
}
public int getAcknowledgeModeInt()
{
return jmsAckModeInt;
}
static public AcknowledgeMode getAckMode(final String ackMode)
{
if(ackMode != null)
try
{
return AcknowledgeMode.valueOf(ackMode);
}
catch (IllegalArgumentException e)
{
log.warn("' " + ackMode + "' is invalid : " + ".Will use default '" + AcknowledgeMode.AUTO_ACKNOWLEDGE);
}
return AcknowledgeMode.AUTO_ACKNOWLEDGE;
}
}
private static final String DEFAULT_ACKNOWLEDGE_MODE = AcknowledgeMode.AUTO_ACKNOWLEDGE.toString();
public JMSEpr(EPR epr)
{
super(epr);
}
public JMSEpr(EPR epr, Element header)
{
super(epr);
NodeList nl = header.getChildNodes();
String uri = null;
String name = null;
String jndiPrefixesValue = null ;
final Map<String, String> extensions = new TreeMap<String, String>() ;
for (int i = 0; i < nl.getLength(); i++)
{
String prefix = nl.item(i).getPrefix();
String tag = nl.item(i).getLocalName();
if ((prefix != null) && (prefix.equals(XMLUtil.JBOSSESB_PREFIX)))
{
if (tag != null)
{
final String value = nl.item(i).getTextContent();
if (tag.startsWith("java.naming.")) {
getAddr().addExtension(tag, value);
} else if (tag.equals(SPECIFICATION_VERSION_TAG)) {
getAddr().addExtension(SPECIFICATION_VERSION_TAG, value);
} else if (tag.equals(DESTINATION_NAME_TAG)) {
name = value;
} else if (tag.equals(CONNECTION_FACTORY_TAG)) {
getAddr().addExtension(CONNECTION_FACTORY_TAG, value);
} else if (tag.equals(JNDI_CONTEXT_FACTORY_TAG)) {
getAddr().addExtension(Context.INITIAL_CONTEXT_FACTORY, value);
} else if (tag.equals(JNDI_PKG_PREFIX_TAG)) {
getAddr().addExtension(Context.URL_PKG_PREFIXES, value);
} else if (tag.equals(JNDI_URL_TAG)) {
uri = value;
// remember to add this extension!
getAddr().addExtension(Context.PROVIDER_URL, uri);
} else if (tag.equals(MESSAGE_SELECTOR_TAG)) {
getAddr().addExtension(MESSAGE_SELECTOR_TAG, value);
} else if (tag.equals(PERSISTENT_TAG)) {
boolean persistent = true;
final String persistentStr = value;
if ( persistentStr != null )
persistent = Boolean.parseBoolean(persistentStr);
getAddr().addExtension(PERSISTENT_TAG, String.valueOf(persistent));
} else if (tag.equals(ACKNOWLEDGE_MODE_TAG)) {
String ackMode = value;
getAddr().addExtension(ACKNOWLEDGE_MODE_TAG, String.valueOf(ackMode));
} else if (tag.equals(JMS_SECURITY_PRINCIPAL_TAG)) {
String username = value;
getAddr().addExtension(JMS_SECURITY_PRINCIPAL_TAG, String.valueOf(username));
} else if (tag.equals(JMS_SECURITY_CREDENTIAL_TAG)) {
String password = value;
getAddr().addExtension(JMS_SECURITY_CREDENTIAL_TAG, String.valueOf(password));
} else if (tag.equals(DESTINATION_TYPE_TAG)) {
getAddr().addExtension(DESTINATION_TYPE_TAG, value);
} else if (tag.equals(TRANSACTED_TAG)) {
boolean transacted = false;
final String transactedStr = value;
if ( transactedStr != null )
transacted = Boolean.parseBoolean(transactedStr);
getAddr().addExtension(TRANSACTED_TAG, String.valueOf(transacted));
} else if (tag.equals(JNDI_PREFIXES)) {
jndiPrefixesValue = value ;
getAddr().addExtension(JNDI_PREFIXES, value);
} else {
extensions.put(tag, value);
}
}
}
}
if (jndiPrefixesValue != null) {
final String[] jndiPrefixes = JndiUtil.getJndiPrefixes(jndiPrefixesValue) ;
for(Map.Entry<String, String> entry: extensions.entrySet()) {
for(String jndiPrefix: jndiPrefixes) {
final String tag = entry.getKey() ;
if (tag.startsWith(jndiPrefix)) {
getAddr().addExtension(tag, entry.getValue()) ;
break ;
}
}
}
}
if (uri != null) {
final String address = getJmsAddress(uri, name) ;
setAddr(new PortReference(address));
}
}
/**
* Create a new JMS EPR. The protocol version is assumed to be 1.1. ,
* jndi_type="", jndi_url="", messageSelector=null
*
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
*/
public JMSEpr(String destinationType, String destinationName,
String connection)
{
this(ONE_ONE_PROTOCOL, destinationType, destinationName, connection,
null, null, true);
}
/**
* Create a new JMS EPR. The protocol version is assumed to be 1.1.
*
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
*/
public JMSEpr(String destinationType, String destinationName,
String connection, Properties environment, String messageSelector)
{
this(ONE_ONE_PROTOCOL, destinationType, destinationName, connection,
environment, messageSelector, true);
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector)
{
this(protocol,destinationType, destinationName,connection,environment,messageSelector, true);
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent)
{
this(protocol, destinationType, destinationName, connection, environment, messageSelector, peristent, DEFAULT_ACKNOWLEDGE_MODE);
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent,
boolean transacted)
{
this(protocol, destinationType, destinationName, connection, environment, messageSelector, peristent, DEFAULT_ACKNOWLEDGE_MODE, transacted);
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
* @param acknowledgeModeStr
* JMS client acknowledgement mode
* @param transacted
* true if the jms session should be transaction aware
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent, String acknowledgeModeStr,
boolean transacted)
{
this( protocol, destinationType, destinationName, connection, environment,
messageSelector, peristent, acknowledgeModeStr, null, null, transacted );
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
* @param acknowledgeModeStr
* JMS client acknowledgement mode
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent, String acknowledgeModeStr)
{
this( protocol, destinationType, destinationName, connection, environment,
messageSelector, peristent, acknowledgeModeStr, null, null, false );
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
* @param acknowledgeModeStr
* JMS client acknowledgement mode
* @param username
* username to use when creating JMS connections
* @param password
* password to use when creating JMS connections
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent, String acknowledgeModeStr,
String username, String password)
{
this( protocol, destinationType, destinationName, connection, environment,
messageSelector, peristent, acknowledgeModeStr, username, password, false );
}
/**
* Create a new JMS EPR.
*
* @param protocol
* the protocol version.
* @param destinationType
* the type of destination (queue/topic).
* @param destinationName
* name of the queue/topic.
* @param connection
* reference to the connection factory.
* @param environment
* reference to the jndi properties
* @param messageSelector
* the selector to filter the messages on.
* @param peristent
* true if messages should be sent persistently
* @param acknowledgeModeStr
* JMS client acknowledgement mode
* @param username
* JMS destination username
* @param password
* JMS destination password
* @param transacted
* true if the jms session should be transaction aware
*
*/
public JMSEpr(String protocol, String destinationType,
String destinationName, String connection, Properties environment,
String messageSelector, boolean peristent, String acknowledgeModeStr,
String username, String password,
boolean transacted)
{
// how many of these do we really need? modify accordingly.
if ((protocol == null) || (destinationType == null)
|| (destinationName == null) || (connection == null))
throw new IllegalArgumentException();
if (protocol.equals(ONE_ONE_PROTOCOL)
|| (protocol.equals(ONE_ZERO_TWO_PROTOCOL)))
{
if (destinationType.equals(QUEUE_TYPE)
|| destinationType.equals(TOPIC_TYPE))
{
String uri = null;
String name = null;
PortReference addr = new PortReference();
if (environment!=null) {
for (Object key : environment.keySet()) {
if (key.toString().equals(JNDI_URL_TAG))
uri = environment.getProperty(key.toString());
else
{
if (key.toString().equals(DESTINATION_NAME_TAG))
{
name = environment.getProperty(key.toString());
if ((destinationName != null) && !name.equals(destinationName))
throw new IllegalArgumentException("Destination name inconsistency: < "+name+", "+destinationName+" >");
}
else
addr.addExtension(key.toString(), environment.getProperty(key.toString()));
}
}
}
if (uri == null) {
uri = addr.getExtensionValue(Context.PROVIDER_URL) ;
}
if (uri == null) {
uri = Configuration.getJndiServerURL() ;
}
if (name == null)
name = destinationName;
addr.setAddress(getJmsAddress(uri, name));
addr.addExtension(DESTINATION_TYPE_TAG, destinationType);
addr.addExtension(DESTINATION_NAME_TAG, destinationName);
addr.addExtension(SPECIFICATION_VERSION_TAG, protocol);
if (connection != null)
addr.addExtension(CONNECTION_FACTORY_TAG, connection);
if (messageSelector != null)
addr.addExtension(MESSAGE_SELECTOR_TAG, messageSelector);
addr.addExtension(PERSISTENT_TAG, String.valueOf(peristent));
addr.addExtension(ACKNOWLEDGE_MODE_TAG, String.valueOf(AcknowledgeMode.getAckMode(acknowledgeModeStr)));
setAddr(addr);
if(username != null)
addr.addExtension(JMS_SECURITY_PRINCIPAL_TAG, username);
if(password != null)
addr.addExtension(JMS_SECURITY_CREDENTIAL_TAG, password);
addr.addExtension(TRANSACTED_TAG, String.valueOf(transacted));
}
else
throw new IllegalArgumentException("Invalid destination type! "+destinationType);
}
else
throw new IllegalArgumentException("Invalid specification version!");
}
/*
* There are deliberately no setters for the values once the EPR is created.
*/
/**
* @return the destination type used.
*/
public final String getDestinationType()
{
return getAddr().getExtensionValue(DESTINATION_TYPE_TAG);
}
/**
* @return the specification version used.
*/
public final String getVersion()
{
return getAddr().getExtensionValue(SPECIFICATION_VERSION_TAG);
}
/**
* @return the destination name used.
*/
public final String getDestinationName()
{
final String name = getAddr().getExtensionValue(DESTINATION_NAME_TAG);
if (name != null)
{
return name ;
}
try
{
URI uri = new URI(getAddr().getAddress());
return uri.getPath().substring(1);
}
catch (URISyntaxException ex)
{
_logger.warn("Unexpected parsing exception!", ex);
return null;
}
}
/**
* @return the connection factory for this EPR, or <code>null</code> if
* none is set.
*/
public final String getConnectionFactory()
{
return getAddr().getExtensionValue(CONNECTION_FACTORY_TAG);
}
public final String getClientId()
{
return getAddr().getExtensionValue(CLIENT_ID);
}
public final String getDurableSubscriptionName()
{
return getAddr().getExtensionValue(DURABLE_SUBSCRIPTION_NAME);
}
/**
* @return the jndi context factory for this EPR, or <code>null</code> if
* none is set.
*/
public final Properties getJndiEnvironment()
{
final Properties properties = new Properties();
final String jndiPrefixesValue = getAddr().getExtensionValue(JNDI_PREFIXES) ;
if (jndiPrefixesValue != null)
{
properties.put(JNDI_PREFIXES, jndiPrefixesValue) ;
}
final String[] jndiPrefixes = JndiUtil.getJndiPrefixes(jndiPrefixesValue) ;
Iterator<Extension> iter = getAddr().getExtensions();
while (iter.hasNext()) {
Extension extension = iter.next();
String tag = extension.getTag();
if(tag.equals(JMSEpr.MAX_SESSIONS_PER_CONNECTION) || tag.equals(JMSEpr.MAX_XA_SESSIONS_PER_CONNECTION)) {
properties.put(tag, extension.getValue());
} else if(tag.equals(JMSEpr.CLIENT_ID)) {
properties.put(tag, extension.getValue());
} else {
for(String jndiPrefix: jndiPrefixes)
{
if (tag.startsWith(jndiPrefix) && extension.getValue()!=null) {
properties.put(tag, extension.getValue());
break ;
}
}
}
}
if(!properties.containsKey(Context.INITIAL_CONTEXT_FACTORY)) {
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, Configuration.getJndiServerContextFactory());
}
if(!properties.containsKey(Context.PROVIDER_URL)) {
properties.setProperty(Context.PROVIDER_URL, Configuration.getJndiServerURL());
}
return properties;
}
/**
* Get the list of JNDI extension prefixes.
* @param jndiPrefixesValue The JNDI prefix list or null if default.
* @return The list of JNDI extension prefixes.
* @deprecated Use {@link JndiUtil#getJndiPrefixes(String)}.
*/
public static String[] getJndiPrefixes(final String jndiPrefixesValue)
{
return JndiUtil.getJndiPrefixes(jndiPrefixesValue);
}
/**
* @return the message selector for this EPR, or <code>null</code> if none
* is set.
*/
public final String getMessageSelector()
{
return getAddr().getExtensionValue(MESSAGE_SELECTOR_TAG);
}
/**
* @return the delivery mode
*/
public final boolean getPersistent()
{
return Boolean.parseBoolean(getAddr().getExtensionValue(PERSISTENT_TAG));
}
/**
*
* @return <code>int</code> JMS Acknowledge mode, one of:
* <lu>
* <li>{@link Session#AUTO_ACKNOWLEDGE}</li>
* <li>{@link Session#CLIENT_ACKNOWLEDGE}</li>
* <li>{@link Session#DUPS_OK_ACKNOWLEDGE}</li>
* </lu>
*/
public final int getAcknowledgeMode()
{
AcknowledgeMode ackMode = AcknowledgeMode.getAckMode(getAddr().getExtensionValue(ACKNOWLEDGE_MODE_TAG));
return ackMode.getAcknowledgeModeInt();
}
/**
* The JMS Security principal which is indended to be used as the username
* argument to:
* {@link javax.jms.ConnectionFactory}.createConnection(String username, String password) }
* @return
*/
public final String getJMSSecurityPrincipal()
{
final String username = getAddr().getExtensionValue(JMS_SECURITY_PRINCIPAL_TAG);
return username == null || username.equals("null") ? null : username;
}
/**
* The JMS Security credential which is indended to be used as the password
* argument to:
* {@link javax.jms.ConnectionFactory}.createConnection(String username, String password) }
* @return
*/
public final String getJMSSecurityCredential()
{
final String password = getAddr().getExtensionValue(JMS_SECURITY_CREDENTIAL_TAG);
return password == null || password.equals("null") ? null : password;
}
/**
* @return the delivery mode
*/
public final boolean getTransacted()
{
return Boolean.parseBoolean(getAddr().getExtensionValue(TRANSACTED_TAG));
}
public EPR copy ()
{
return new JMSEpr(this);
}
private String getJmsAddress(final String uri, final String name)
{
try {
final URI result = new URI(JMS_PROTOCOL, uri, name) ;
return result.toString();
} catch (final URISyntaxException urise) {}
return JMS_PROTOCOL + PROTOCOL_SEPARATOR + uri + "/" + name;
}
public String toString ()
{
return "JMSEpr [ "+super.getAddr().extendedToString()+" ]";
}
public static final URI type()
{
return _type;
}
private static URI _type;
static
{
try
{
_type = new URI("urn:jboss/esb/epr/type/jms");
}
catch (Exception ex)
{
ex.printStackTrace();
throw new ExceptionInInitializerError(ex.toString());
}
}
}