/* * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. 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.wso2.carbon.inbound.endpoint.protocol.jms; import org.apache.axiom.om.OMElement; import org.apache.axis2.context.MessageContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.jms.BytesMessage; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.ObjectMessage; import javax.jms.StreamMessage; import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import javax.naming.Reference; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; /** * * Maintain the common methods used by inbound JMS protocol * */ public class JMSUtils { private static final Log log = LogFactory.getLog(JMSUtils.class); public static String inferJMSMessageType(Message msg) { if(inferTextMessage(msg)) { return TextMessage.class.getName(); } else if(inferByteMessage(msg)) { return BytesMessage.class.getName(); } else if(inferObjectMessage(msg)) { return ObjectMessage.class.getName(); } else if(inferStreamMessage(msg)) { return StreamMessage.class.getName(); } else { return null; } } public static void convertXMLtoJMSMap(OMElement element, MapMessage message) throws JMSException{ Iterator itr = element.getChildElements(); while (itr.hasNext()){ OMElement elem = (OMElement)itr.next(); message.setString(elem.getLocalName(),elem.getText()); } } /** * Set transport headers from the axis message context, into the JMS message * * @param msgContext the axis message context * @param message the JMS Message * @throws JMSException on exception */ public static void setTransportHeaders(MessageContext msgContext, Message message) throws JMSException { Map<?,?> headerMap = (Map<?,?>) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS); if (headerMap == null) { return; } for (Object headerName : headerMap.keySet()) { String name = (String) headerName; if (name.startsWith(JMSConstants.JMSX_PREFIX) && !(name.equals(JMSConstants.JMSX_GROUP_ID) || name.equals(JMSConstants.JMSX_GROUP_SEQ))) { continue; } if (JMSConstants.JMS_COORELATION_ID.equals(name)) { message.setJMSCorrelationID( (String) headerMap.get(JMSConstants.JMS_COORELATION_ID)); } else if (JMSConstants.JMS_DELIVERY_MODE.equals(name)) { Object o = headerMap.get(JMSConstants.JMS_DELIVERY_MODE); if (o instanceof Integer) { message.setJMSDeliveryMode((Integer) o); } else if (o instanceof String) { try { message.setJMSDeliveryMode(Integer.parseInt((String) o)); } catch (NumberFormatException nfe) { log.warn("Invalid delivery mode ignored : " + o, nfe); } } else { log.warn("Invalid delivery mode ignored : " + o); } } else if (JMSConstants.JMS_EXPIRATION.equals(name)) { message.setJMSExpiration( Long.parseLong((String) headerMap.get(JMSConstants.JMS_EXPIRATION))); } else if (JMSConstants.JMS_MESSAGE_ID.equals(name)) { message.setJMSMessageID((String) headerMap.get(JMSConstants.JMS_MESSAGE_ID)); } else if (JMSConstants.JMS_PRIORITY.equals(name)) { message.setJMSPriority( Integer.parseInt((String) headerMap.get(JMSConstants.JMS_PRIORITY))); } else if (JMSConstants.JMS_TIMESTAMP.equals(name)) { message.setJMSTimestamp( Long.parseLong((String) headerMap.get(JMSConstants.JMS_TIMESTAMP))); } else if (JMSConstants.JMS_MESSAGE_TYPE.equals(name)) { message.setJMSType((String) headerMap.get(JMSConstants.JMS_MESSAGE_TYPE)); } else { Object value = headerMap.get(name); if (value instanceof String) { if (name.contains("-")) { if (isHyphenReplaceMode(msgContext)) { // we replace message.setStringProperty(transformHyphenatedString(name), (String) value); } else if (isHyphenDeleteMode(msgContext)) { // we skip continue; } else { message.setStringProperty(name, (String) value); } } else { message.setStringProperty(name, (String) value); } } else if (value instanceof Boolean) { message.setBooleanProperty(name, (Boolean) value); } else if (value instanceof Integer) { message.setIntProperty(name, (Integer) value); } else if (value instanceof Long) { message.setLongProperty(name, (Long) value); } else if (value instanceof Double) { message.setDoubleProperty(name, (Double) value); } else if (value instanceof Float) { message.setFloatProperty(name, (Float) value); } } } } /** * Return the JMS destination with the given destination name looked up from the context * * @param context the Context to lookup * @param destinationName name of the destination to be looked up * @param destinationType type of the destination to be looked up * @return the JMS destination, or null if it does not exist */ public static Destination lookupDestination(Context context, String destinationName, String destinationType) throws NamingException { if (destinationName == null) { return null; } try { return JMSUtils.lookup(context, Destination.class, destinationName); } catch (NameNotFoundException e) { try { Properties initialContextProperties = new Properties(); if (context.getEnvironment() != null) { if (context.getEnvironment().get(JMSConstants.NAMING_FACTORY_INITIAL) != null) { initialContextProperties.put(JMSConstants.NAMING_FACTORY_INITIAL, context.getEnvironment().get(JMSConstants.NAMING_FACTORY_INITIAL)); } if (context.getEnvironment().get(JMSConstants.CONNECTION_STRING) != null) { initialContextProperties.put(JMSConstants.CONNECTION_STRING, context.getEnvironment().get(JMSConstants.CONNECTION_STRING)); } if (context.getEnvironment().get(JMSConstants.PROVIDER_URL) != null) { initialContextProperties.put(JMSConstants.PROVIDER_URL, context.getEnvironment().get(JMSConstants.PROVIDER_URL)); } } if (JMSConstants.DESTINATION_TYPE_TOPIC.equalsIgnoreCase(destinationType)) { initialContextProperties.put(JMSConstants.TOPIC_PREFIX + destinationName, destinationName); } else if (JMSConstants.DESTINATION_TYPE_QUEUE.equalsIgnoreCase(destinationType) || JMSConstants.DESTINATION_TYPE_GENERIC.equalsIgnoreCase(destinationType)) { initialContextProperties.put(JMSConstants.QUEUE_PREFIX + destinationName, destinationName); } InitialContext initialContext = new InitialContext(initialContextProperties); try { return JMSUtils.lookup(initialContext, Destination.class, destinationName); } catch (NamingException e1) { return JMSUtils.lookup(context, Destination.class, (JMSConstants.DESTINATION_TYPE_TOPIC.equalsIgnoreCase(destinationType) ? "dynamicTopics/" : "dynamicQueues/") + destinationName); } } catch (NamingException x) { log.warn("Cannot locate destination : " + destinationName); throw x; } } catch (NamingException e) { log.warn("Cannot locate destination : " + destinationName, e); throw e; } } private static <T> T lookup(Context context, Class<T> clazz, String name) throws NamingException { Object object = context.lookup(name); try { return clazz.cast(object); } catch (ClassCastException ex) { // Instead of a ClassCastException, throw an exception with some // more information. if (object instanceof Reference) { Reference ref = (Reference)object; handleException("JNDI failed to de-reference Reference with name " + name + "; is the factory " + ref.getFactoryClassName() + " in your classpath?"); return null; } else { handleException("JNDI lookup of name " + name + " returned a " + object.getClass().getName() + " while a " + clazz + " was expected"); return null; } } } protected static void handleException(String s) throws NamingException{ log.error(s); throw new NamingException(s); } /** * Extract transport level headers from JMS message into a Map * @param message JMS message * @param msgContext axis2 message context * @return a Map of the transport headers */ public static Map<String, Object> getTransportHeaders(Message message, MessageContext msgContext) { // create a Map to hold transport headers Map<String, Object> map = new HashMap<>(); try { Enumeration<?> propertyNamesEnm = message.getPropertyNames(); while (propertyNamesEnm.hasMoreElements()) { String headerName = (String) propertyNamesEnm.nextElement(); Object headerValue = message.getObjectProperty(headerName); if (headerValue instanceof String) { if (isHyphenReplaceMode(msgContext)) { map.put(inverseTransformHyphenatedString(headerName), message.getStringProperty(headerName)); } else { map.put(headerName, message.getStringProperty(headerName)); } } else if (headerValue instanceof Integer) { map.put(headerName, message.getIntProperty(headerName)); } else if (headerValue instanceof Boolean) { map.put(headerName, message.getBooleanProperty(headerName)); } else if (headerValue instanceof Long) { map.put(headerName, message.getLongProperty(headerName)); } else if (headerValue instanceof Double) { map.put(headerName, message.getDoubleProperty(headerName)); } else if (headerValue instanceof Float) { map.put(headerName, message.getFloatProperty(headerName)); } else { map.put(headerName, headerValue); } } } catch (JMSException e) { log.error("Error while reading the Transport Headers from JMS Message", e); } return map; } private static boolean isHyphenReplaceMode(MessageContext msgContext) { if (msgContext == null) { return false; } String hyphenSupport = (String) msgContext.getProperty(JMSConstants.PARAM_JMS_HYPHEN_MODE); if (hyphenSupport != null && hyphenSupport.equals(JMSConstants.HYPHEN_MODE_REPLACE)) { return true; } return false; } /** * This method is to fix ESBJAVA-3687 - certain brokers do not support '-' in JMS property name, in such scenarios * we will replace the dash with a special character sequence. This support is configurable and is turned off by * default. * @return modified string name if broker does not support name format */ private static String transformHyphenatedString(String name) { return name.replaceAll("-", JMSConstants.HYPHEN_REPLACEMENT_STR); } private static boolean isHyphenDeleteMode(MessageContext msgContext) { if (msgContext == null) { return false; } String hyphenSupport = (String) msgContext.getProperty(JMSConstants.PARAM_JMS_HYPHEN_MODE); if (hyphenSupport != null && hyphenSupport.equals(JMSConstants.HYPHEN_MODE_DELETE)) { return true; } return false; } private static boolean inferTextMessage(Message msg) { if (msg instanceof TextMessage) { return true; } return false; } private static boolean inferStreamMessage(Message msg) { if (msg instanceof StreamMessage) { return true; } return false; } private static boolean inferObjectMessage(Message msg) { if (msg instanceof ObjectMessage) { return true; } return false; } private static boolean inferByteMessage(Message msg) { if (msg instanceof BytesMessage) { return true; } return false; } private static String inverseTransformHyphenatedString(String name) { return name.replaceAll(JMSConstants.HYPHEN_REPLACEMENT_STR, "-"); } }