blob: 864c0571586111e9c4bd81dca3a95779fc9c97bb [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* 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 org.apache.axis2.transport.jms;
import org.apache.axis2.transport.OutTransportInfo;
import org.apache.axis2.transport.base.BaseUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
/**
* The JMS OutTransportInfo is a holder of information to send an outgoing message
* (e.g. a Response) to a JMS destination. Thus at a minimum a reference to a
* ConnectionFactory and a Destination are held
*/
public class JMSOutTransportInfo implements OutTransportInfo {
private static final Log log = LogFactory.getLog(JMSOutTransportInfo.class);
/** The naming context */
private Context context;
/**
* this is a reference to the underlying JMS ConnectionFactory when sending messages
* through connection factories not defined at the TransportSender level
*/
private ConnectionFactory connectionFactory = null;
/**
* this is a reference to a JMS Connection Factory instance, which has a reference
* to the underlying actual connection factory, an open connection to the JMS provider
* and optionally a session already available for use
*/
private JMSConnectionFactory jmsConnectionFactory = null;
/** the Destination queue or topic for the outgoing message */
private Destination destination = null;
/** the Destination queue or topic for the outgoing message
* i.e. JMSConstants.DESTINATION_TYPE_QUEUE, DESTINATION_TYPE_TOPIC or DESTINATION_TYPE_GENERIC
*/
private String destinationType = JMSConstants.DESTINATION_TYPE_GENERIC;
/** the Reply Destination queue or topic for the outgoing message */
private Destination replyDestination = null;
/** the Reply Destination name */
private String replyDestinationName = null;
/** the Reply Destination queue or topic for the outgoing message
* i.e. JMSConstants.DESTINATION_TYPE_QUEUE, DESTINATION_TYPE_TOPIC or DESTINATION_TYPE_GENERIC
*/
private String replyDestinationType = JMSConstants.DESTINATION_TYPE_GENERIC;
/** the EPR properties when the out-transport info is generated from a target EPR */
private Hashtable<String,String> properties = null;
/** the target EPR string where applicable */
private String targetEPR = null;
/** the message property name that stores the content type of the outgoing message */
private String contentTypeProperty;
/**
* Creates an instance using the given JMS connection factory and destination
*
* @param jmsConnectionFactory the JMS connection factory
* @param dest the destination
* @param contentTypeProperty the content type
*/
JMSOutTransportInfo(JMSConnectionFactory jmsConnectionFactory, Destination dest,
String contentTypeProperty) {
this.jmsConnectionFactory = jmsConnectionFactory;
this.destination = dest;
destinationType = dest instanceof Topic ? JMSConstants.DESTINATION_TYPE_TOPIC
: JMSConstants.DESTINATION_TYPE_QUEUE;
this.contentTypeProperty = contentTypeProperty;
}
/**
* Creates and instance using the given URL
*
* @param targetEPR the target EPR
*/
JMSOutTransportInfo(String targetEPR) {
this.targetEPR = targetEPR;
if (!targetEPR.startsWith(JMSConstants.JMS_PREFIX)) {
handleException("Invalid prefix for a JMS EPR : " + targetEPR);
} else {
properties = BaseUtils.getEPRProperties(targetEPR);
String destinationType = properties.get(JMSConstants.PARAM_DEST_TYPE);
if (destinationType != null) {
setDestinationType(destinationType);
}
String replyDestinationType = properties.get(JMSConstants.PARAM_REPLY_DEST_TYPE);
if (replyDestinationType != null) {
setReplyDestinationType(replyDestinationType);
}
replyDestinationName = properties.get(JMSConstants.PARAM_REPLY_DESTINATION);
contentTypeProperty = properties.get(JMSConstants.CONTENT_TYPE_PROPERTY_PARAM);
try {
context = new InitialContext(properties);
} catch (NamingException e) {
handleException("Could not get an initial context using " + properties, e);
}
destination = getDestination(context, targetEPR);
replyDestination = getReplyDestination(context, targetEPR);
}
}
/**
* Provides a lazy load when created with a target EPR. This method performs actual
* lookup for the connection factory and destination
*/
public void loadConnectionFactoryFromProperies() {
if (properties != null) {
connectionFactory = getConnectionFactory(context, properties);
}
}
/**
* Get the referenced ConnectionFactory using the properties from the context
*
* @param context the context to use for lookup
* @param props the properties which contains the JNDI name of the factory
* @return the connection factory
*/
private ConnectionFactory getConnectionFactory(Context context, Hashtable<String,String> props) {
try {
String conFacJndiName = props.get(JMSConstants.PARAM_CONFAC_JNDI_NAME);
if (conFacJndiName != null) {
return JMSUtils.lookup(context, ConnectionFactory.class, conFacJndiName);
} else {
handleException("Connection Factory JNDI name cannot be determined");
}
} catch (NamingException e) {
handleException("Failed to look up connection factory from JNDI", e);
}
return null;
}
/**
* Get the JMS destination specified by the given URL from the context
*
* @param context the Context to lookup
* @param url URL
* @return the JMS destination, or null if it does not exist
*/
private Destination getDestination(Context context, String url) {
String destinationName = JMSUtils.getDestination(url);
if (log.isDebugEnabled()) {
log.debug("Lookup the JMS destination " + destinationName + " of type "
+ destinationType + " extracted from the URL " + url);
}
try {
return JMSUtils.lookupDestination(context, destinationName, destinationType);
} catch (NamingException e) {
handleException("Couldn't locate the JMS destination " + destinationName
+ " of type " + destinationType + " extracted from the URL " + url, e);
}
// never executes but keeps the compiler happy
return null;
}
/**
* Get the JMS reply destination specified by the given URL from the context
*
* @param context the Context to lookup
* @param url URL
* @return the JMS destination, or null if it does not exist
*/
private Destination getReplyDestination(Context context, String url) {
String replyDestinationName = properties.get(JMSConstants.PARAM_REPLY_DESTINATION);
if (log.isDebugEnabled()) {
log.debug("Lookup the JMS destination " + replyDestinationName + " of type "
+ replyDestinationType + " extracted from the URL " + url);
}
try {
return JMSUtils.lookupDestination(context, replyDestinationName, replyDestinationType);
} catch (NamingException e) {
handleException("Couldn't locate the JMS destination " + replyDestinationName
+ " of type " + replyDestinationType + " extracted from the URL " + url, e);
}
// never executes but keeps the compiler happy
return null;
}
/**
* Look up for the given destination
* @param replyDest the JNDI name to lookup Destination required
* @return Destination for the JNDI name passed
*/
public Destination getReplyDestination(String replyDest) {
if (log.isDebugEnabled()) {
log.debug("Lookup the JMS destination " + replyDest + " of type "
+ replyDestinationType);
}
try {
return JMSUtils.lookupDestination(
jmsConnectionFactory.getContext(), replyDest, replyDestinationType);
} catch (NamingException e) {
handleException("Couldn't locate the JMS destination " + replyDest
+ " of type " + replyDestinationType, e);
}
// never executes but keeps the compiler happy
return null;
}
private void handleException(String s) {
log.error(s);
throw new AxisJMSException(s);
}
private void handleException(String s, Exception e) {
log.error(s, e);
throw new AxisJMSException(s, e);
}
public Destination getDestination() {
return destination;
}
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
public JMSConnectionFactory getJmsConnectionFactory() {
return jmsConnectionFactory;
}
public void setContentType(String contentType) {
// this is a useless Axis2 method imposed by the OutTransportInfo interface :(
}
public Hashtable<String,String> getProperties() {
return properties;
}
public String getTargetEPR() {
return targetEPR;
}
public String getDestinationType() {
return destinationType;
}
public void setDestinationType(String destinationType) {
if (destinationType != null) {
this.destinationType = destinationType;
}
}
public Destination getReplyDestination() {
return replyDestination;
}
public void setReplyDestination(Destination replyDestination) {
this.replyDestination = replyDestination;
}
public String getReplyDestinationType() {
return replyDestinationType;
}
public void setReplyDestinationType(String replyDestinationType) {
this.replyDestinationType = replyDestinationType;
}
public String getReplyDestinationName() {
return replyDestinationName;
}
public void setReplyDestinationName(String replyDestinationName) {
this.replyDestinationName = replyDestinationName;
}
public String getContentTypeProperty() {
return contentTypeProperty;
}
public void setContentTypeProperty(String contentTypeProperty) {
this.contentTypeProperty = contentTypeProperty;
}
/**
* Create a one time MessageProducer for this JMS OutTransport information.
* For simplicity and best compatibility, this method uses only JMS 1.0.2b API.
* Please be cautious when making any changes
*
* @return a JMSSender based on one-time use resources
* @throws JMSException on errors, to be handled and logged by the caller
*/
public JMSMessageSender createJMSSender() throws JMSException {
// digest the targetAddress and locate CF from the EPR
loadConnectionFactoryFromProperies();
// create a one time connection and session to be used
String user = properties != null ? properties.get(JMSConstants.PARAM_JMS_USERNAME) : null;
String pass = properties != null ? properties.get(JMSConstants.PARAM_JMS_PASSWORD) : null;
QueueConnectionFactory qConFac = null;
TopicConnectionFactory tConFac = null;
int destType = -1;
// TODO: there is something missing here for destination type generic
if (JMSConstants.DESTINATION_TYPE_QUEUE.equals(destinationType)) {
destType = JMSConstants.QUEUE;
qConFac = (QueueConnectionFactory) connectionFactory;
} else if (JMSConstants.DESTINATION_TYPE_TOPIC.equals(destinationType)) {
destType = JMSConstants.TOPIC;
tConFac = (TopicConnectionFactory) connectionFactory;
} else{
//treat jmsdestination type=queue(default is queue)
destType = JMSConstants.QUEUE;
qConFac = (QueueConnectionFactory) connectionFactory;
}
Connection connection = null;
if (user != null && pass != null) {
if (qConFac != null) {
connection = qConFac.createQueueConnection(user, pass);
} else if (tConFac != null) {
connection = tConFac.createTopicConnection(user, pass);
}
} else {
if (qConFac != null) {
connection = qConFac.createQueueConnection();
} else if (tConFac != null) {
connection = tConFac.createTopicConnection();
}
}
if (connection == null) {
connection = jmsConnectionFactory != null ? jmsConnectionFactory.getConnection() : null;
}
Session session = null;
MessageProducer producer = null;
if (connection != null) {
if (destType == JMSConstants.QUEUE) {
session = ((QueueConnection) connection).
createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
producer = ((QueueSession) session).createSender((Queue) destination);
} else {
session = ((TopicConnection) connection).
createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
producer = ((TopicSession) session).createPublisher((Topic) destination);
}
}
return new JMSMessageSender(
connection,
session,
producer,
destination,
jmsConnectionFactory == null ?
JMSConstants.CACHE_NONE : jmsConnectionFactory.getCacheLevel(),
false,
destType == -1 ?
null : destType == JMSConstants.QUEUE ? Boolean.TRUE : Boolean.FALSE
);
}
}