| /* |
| * 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 |
| ); |
| |
| } |
| } |