View Javadoc

1   /*
2    * Copyright 2005-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.transport.jms.support;
18  
19  import java.net.URI;
20  import java.net.URISyntaxException;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Enumeration;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.regex.Matcher;
27  import java.util.regex.Pattern;
28  import javax.jms.DeliveryMode;
29  import javax.jms.Destination;
30  import javax.jms.JMSException;
31  import javax.jms.Message;
32  import javax.jms.Queue;
33  import javax.jms.Topic;
34  
35  import org.springframework.ws.transport.jms.JmsTransportConstants;
36  
37  /**
38   * Collection of utility methods to work with JMS transports. Includes methods to retrieve JMS properties from an {@link
39   * URI}.
40   *
41   * @author Arjen Poutsma
42   * @since 1.5.0
43   */
44  public abstract class JmsTransportUtils {
45  
46      private static final String[] CONVERSION_TABLE = new String[]{JmsTransportConstants.HEADER_CONTENT_TYPE,
47              JmsTransportConstants.PROPERTY_CONTENT_TYPE, JmsTransportConstants.HEADER_CONTENT_LENGTH,
48              JmsTransportConstants.PROPERTY_CONTENT_LENGTH, JmsTransportConstants.HEADER_SOAP_ACTION,
49              JmsTransportConstants.PROPERTY_SOAP_ACTION, JmsTransportConstants.HEADER_ACCEPT_ENCODING,
50              JmsTransportConstants.PROPERTY_ACCEPT_ENCODING};
51  
52      private static final Pattern DESTINATION_NAME_PATTERN = Pattern.compile("^([^\\?]+)");
53  
54      private static final Pattern DELIVERY_MODE_PATTERN = Pattern.compile("deliveryMode=(PERSISTENT|NON_PERSISTENT)");
55  
56      private static final Pattern MESSAGE_TYPE_PATTERN = Pattern.compile("messageType=(BYTES_MESSAGE|TEXT_MESSAGE)");
57  
58      private static final Pattern TIME_TO_LIVE_PATTERN = Pattern.compile("timeToLive=(\\d+)");
59  
60      private static final Pattern PRIORITY_PATTERN = Pattern.compile("priority=(\\d)");
61  
62      private static final Pattern REPLY_TO_NAME_PATTERN = Pattern.compile("replyToName=([^&]+)");
63  
64      private JmsTransportUtils() {
65      }
66  
67      /**
68       * Converts the given transport header to a JMS property name. Returns the given header name if no match is found.
69       *
70       * @param headerName the header name to transform
71       * @return the JMS property name
72       */
73      public static String headerToJmsProperty(String headerName) {
74          for (int i = 0; i < CONVERSION_TABLE.length; i = i + 2) {
75              if (CONVERSION_TABLE[i].equals(headerName)) {
76                  return CONVERSION_TABLE[i + 1];
77              }
78          }
79          return headerName;
80              }
81  
82      /**
83       * Converts the given JMS property name to a transport header name. Returns the given property name if no match is
84       * found.
85       *
86       * @param propertyName the JMS property name to transform
87       * @return the transport header name
88       */
89      public static String jmsPropertyToHeader(String propertyName) {
90          for (int i = 1; i < CONVERSION_TABLE.length; i = i + 2) {
91              if (CONVERSION_TABLE[i].equals(propertyName)) {
92                  return CONVERSION_TABLE[i - 1];
93              }
94          }
95              return propertyName;
96      }
97  
98      /**
99       * Converts the given JMS destination into a <code>jms</code> URI.
100      *
101      * @param destination the destination
102      * @return a jms URI
103      */
104     public static URI toUri(Destination destination) throws URISyntaxException, JMSException {
105         String destinationName;
106         if (destination instanceof Queue) {
107             destinationName = ((Queue) destination).getQueueName();
108         }
109         else if (destination instanceof Topic) {
110             Topic topic = (Topic) destination;
111             destinationName = topic.getTopicName();
112         }
113         else {
114             throw new IllegalArgumentException("Destination [ " + destination + "] is neither Queue nor Topic");
115         }
116         return new URI(JmsTransportConstants.JMS_URI_SCHEME, destinationName, null);
117     }
118 
119     /** Returns the destination name of the given URI. */
120     public static String getDestinationName(URI uri) {
121         return getStringParameter(DESTINATION_NAME_PATTERN, uri);
122     }
123 
124     /** Adds the given header to the specified message. */
125     public static void addHeader(Message message, String name, String value) throws JMSException {
126         String propertyName = JmsTransportUtils.headerToJmsProperty(name);
127         message.setStringProperty(propertyName, value);
128     }
129 
130     /**
131      * Returns an iterator over all header names in the given message. Delegates to {@link
132      * #jmsPropertyToHeader(String)}.
133      */
134     public static Iterator<String> getHeaderNames(Message message) throws JMSException {
135         Enumeration<?> properties = message.getPropertyNames();
136         List<String> results = new ArrayList<String>();
137         while (properties.hasMoreElements()) {
138             String property = (String) properties.nextElement();
139             if (property.startsWith(JmsTransportConstants.PROPERTY_PREFIX)) {
140                 String header = jmsPropertyToHeader(property);
141                 results.add(header);
142             }
143         }
144         return results.iterator();
145     }
146 
147     /**
148      * Returns an iterator over all the header values of the given message and header name. Delegates to {@link
149      * #headerToJmsProperty(String)}.
150      */
151     public static Iterator<String> getHeaders(Message message, String name) throws JMSException {
152         String propertyName = headerToJmsProperty(name);
153         String value = message.getStringProperty(propertyName);
154         if (value != null) {
155             return Collections.singletonList(value).iterator();
156         }
157         else {
158             return Collections.<String>emptyList().iterator();
159         }
160     }
161 
162     /**
163      * Returns the delivery mode of the given URI.
164      *
165      * @see DeliveryMode#NON_PERSISTENT
166      * @see DeliveryMode#PERSISTENT
167      * @see Message#DEFAULT_DELIVERY_MODE
168      */
169     public static int getDeliveryMode(URI uri) {
170         String deliveryMode = getStringParameter(DELIVERY_MODE_PATTERN, uri);
171         if ("NON_PERSISTENT".equals(deliveryMode)) {
172             return DeliveryMode.NON_PERSISTENT;
173         }
174         else if ("PERSISTENT".equals(deliveryMode)) {
175             return DeliveryMode.PERSISTENT;
176         }
177         else {
178             return Message.DEFAULT_DELIVERY_MODE;
179         }
180     }
181 
182     /**
183      * Returns the message type of the given URI. Defaults to {@link JmsTransportConstants#BYTES_MESSAGE_TYPE}.
184      *
185      * @see JmsTransportConstants#BYTES_MESSAGE_TYPE
186      * @see JmsTransportConstants#TEXT_MESSAGE_TYPE
187      */
188     public static int getMessageType(URI uri) {
189         String deliveryMode = getStringParameter(MESSAGE_TYPE_PATTERN, uri);
190         if ("TEXT_MESSAGE".equals(deliveryMode)) {
191             return JmsTransportConstants.TEXT_MESSAGE_TYPE;
192         }
193         else {
194             return JmsTransportConstants.BYTES_MESSAGE_TYPE;
195         }
196     }
197 
198     /**
199      * Returns the lifetime, in milliseconds, of the given URI.
200      *
201      * @see Message#DEFAULT_TIME_TO_LIVE
202      */
203     public static long getTimeToLive(URI uri) {
204         return getLongParameter(TIME_TO_LIVE_PATTERN, uri, Message.DEFAULT_TIME_TO_LIVE);
205     }
206 
207     /**
208      * Returns the priority of the given URI.
209      *
210      * @see Message#DEFAULT_PRIORITY
211      */
212     public static int getPriority(URI uri) {
213         return getIntParameter(PRIORITY_PATTERN, uri, Message.DEFAULT_PRIORITY);
214     }
215 
216     /**
217      * Returns the reply-to name of the given URI.
218      *
219      * @see Message#setJMSReplyTo(Destination)
220      */
221     public static String getReplyToName(URI uri) {
222         return getStringParameter(REPLY_TO_NAME_PATTERN, uri);
223     }
224 
225     private static String getStringParameter(Pattern pattern, URI uri) {
226         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
227         if (matcher.find() && matcher.groupCount() == 1) {
228             return matcher.group(1);
229         }
230         return null;
231     }
232 
233     private static int getIntParameter(Pattern pattern, URI uri, int defaultValue) {
234         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
235         if (matcher.find() && matcher.groupCount() == 1) {
236             try {
237                 return Integer.parseInt(matcher.group(1));
238             }
239             catch (NumberFormatException ex) {
240                 // fall through to default value
241             }
242         }
243         return defaultValue;
244     }
245 
246     private static long getLongParameter(Pattern pattern, URI uri, long defaultValue) {
247         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
248         if (matcher.find() && matcher.groupCount() == 1) {
249             try {
250                 return Long.parseLong(matcher.group(1));
251             }
252             catch (NumberFormatException ex) {
253                 // fall through to default value
254             }
255         }
256         return defaultValue;
257     }
258 
259 }