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          // fall-back
80          StringBuilder builder = new StringBuilder(JmsTransportConstants.PROPERTY_PREFIX);
81          for (int i = 0; i < headerName.length(); i++) {
82              char ch = headerName.charAt(i);
83              if (i == 0) {
84                  builder.append(Character.toLowerCase(ch));
85              }
86              else if (Character.isJavaIdentifierPart(ch)) {
87                  builder.append(ch);
88              }
89          }
90          return builder.toString();
91      }
92  
93      /**
94       * Converts the given JMS property name to a transport header name. Returns the given property name if no match is
95       * found.
96       *
97       * @param propertyName the JMS property name to transform
98       * @return the transport header name
99       */
100     public static String jmsPropertyToHeader(String propertyName) {
101         for (int i = 1; i < CONVERSION_TABLE.length; i = i + 2) {
102             if (CONVERSION_TABLE[i].equals(propertyName)) {
103                 return CONVERSION_TABLE[i - 1];
104             }
105         }
106         // fall-back
107         if (propertyName.startsWith(JmsTransportConstants.PROPERTY_PREFIX)) {
108             StringBuilder builder = new StringBuilder(propertyName.length());
109             int start = JmsTransportConstants.PROPERTY_PREFIX.length();
110             for (int i = start; i < propertyName.length(); i++) {
111                 char ch = propertyName.charAt(i);
112                 if (i == start) {
113                     builder.append(Character.toUpperCase(ch));
114                 }
115                 else {
116                     if (Character.isUpperCase(ch)) {
117                         builder.append('-');
118                     }
119                     builder.append(ch);
120                 }
121             }
122             return builder.toString();
123         }
124         else {
125             return propertyName;
126         }
127     }
128 
129     /**
130      * Converts the given JMS destination into a <code>jms</code> URI.
131      *
132      * @param destination the destination
133      * @return a jms URI
134      */
135     public static URI toUri(Destination destination) throws URISyntaxException, JMSException {
136         String destinationName;
137         if (destination instanceof Queue) {
138             destinationName = ((Queue) destination).getQueueName();
139         }
140         else if (destination instanceof Topic) {
141             Topic topic = (Topic) destination;
142             destinationName = topic.getTopicName();
143         }
144         else {
145             throw new IllegalArgumentException("Destination [ " + destination + "] is neither Queue nor Topic");
146         }
147         return new URI(JmsTransportConstants.JMS_URI_SCHEME, destinationName, null);
148     }
149 
150     /** Returns the destination name of the given URI. */
151     public static String getDestinationName(URI uri) {
152         return getStringParameter(DESTINATION_NAME_PATTERN, uri);
153     }
154 
155     /** Adds the given header to the specified message. */
156     public static void addHeader(Message message, String name, String value) throws JMSException {
157         String propertyName = JmsTransportUtils.headerToJmsProperty(name);
158         message.setStringProperty(propertyName, value);
159     }
160 
161     /**
162      * Returns an iterator over all header names in the given message. Delegates to {@link
163      * #jmsPropertyToHeader(String)}.
164      */
165     public static Iterator<String> getHeaderNames(Message message) throws JMSException {
166         Enumeration<?> properties = message.getPropertyNames();
167         List<String> results = new ArrayList<String>();
168         while (properties.hasMoreElements()) {
169             String property = (String) properties.nextElement();
170             if (property.startsWith(JmsTransportConstants.PROPERTY_PREFIX)) {
171                 String header = jmsPropertyToHeader(property);
172                 results.add(header);
173             }
174         }
175         return results.iterator();
176     }
177 
178     /**
179      * Returns an iterator over all the header values of the given message and header name. Delegates to {@link
180      * #headerToJmsProperty(String)}.
181      */
182     public static Iterator<String> getHeaders(Message message, String name) throws JMSException {
183         String propertyName = headerToJmsProperty(name);
184         String value = message.getStringProperty(propertyName);
185         if (value != null) {
186             return Collections.singletonList(value).iterator();
187         }
188         else {
189             return Collections.<String>emptyList().iterator();
190         }
191     }
192 
193     /**
194      * Returns the delivery mode of the given URI.
195      *
196      * @see DeliveryMode#NON_PERSISTENT
197      * @see DeliveryMode#PERSISTENT
198      * @see Message#DEFAULT_DELIVERY_MODE
199      */
200     public static int getDeliveryMode(URI uri) {
201         String deliveryMode = getStringParameter(DELIVERY_MODE_PATTERN, uri);
202         if ("NON_PERSISTENT".equals(deliveryMode)) {
203             return DeliveryMode.NON_PERSISTENT;
204         }
205         else if ("PERSISTENT".equals(deliveryMode)) {
206             return DeliveryMode.PERSISTENT;
207         }
208         else {
209             return Message.DEFAULT_DELIVERY_MODE;
210         }
211     }
212 
213     /**
214      * Returns the message type of the given URI. Defaults to {@link JmsTransportConstants#BYTES_MESSAGE_TYPE}.
215      *
216      * @see JmsTransportConstants#BYTES_MESSAGE_TYPE
217      * @see JmsTransportConstants#TEXT_MESSAGE_TYPE
218      */
219     public static int getMessageType(URI uri) {
220         String deliveryMode = getStringParameter(MESSAGE_TYPE_PATTERN, uri);
221         if ("TEXT_MESSAGE".equals(deliveryMode)) {
222             return JmsTransportConstants.TEXT_MESSAGE_TYPE;
223         }
224         else {
225             return JmsTransportConstants.BYTES_MESSAGE_TYPE;
226         }
227     }
228 
229     /**
230      * Returns the lifetime, in milliseconds, of the given URI.
231      *
232      * @see Message#DEFAULT_TIME_TO_LIVE
233      */
234     public static long getTimeToLive(URI uri) {
235         return getLongParameter(TIME_TO_LIVE_PATTERN, uri, Message.DEFAULT_TIME_TO_LIVE);
236     }
237 
238     /**
239      * Returns the priority of the given URI.
240      *
241      * @see Message#DEFAULT_PRIORITY
242      */
243     public static int getPriority(URI uri) {
244         return getIntParameter(PRIORITY_PATTERN, uri, Message.DEFAULT_PRIORITY);
245     }
246 
247     /**
248      * Returns the reply-to name of the given URI.
249      *
250      * @see Message#setJMSReplyTo(Destination)
251      */
252     public static String getReplyToName(URI uri) {
253         return getStringParameter(REPLY_TO_NAME_PATTERN, uri);
254     }
255 
256     private static String getStringParameter(Pattern pattern, URI uri) {
257         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
258         if (matcher.find() && matcher.groupCount() == 1) {
259             return matcher.group(1);
260         }
261         return null;
262     }
263 
264     private static int getIntParameter(Pattern pattern, URI uri, int defaultValue) {
265         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
266         if (matcher.find() && matcher.groupCount() == 1) {
267             try {
268                 return Integer.parseInt(matcher.group(1));
269             }
270             catch (NumberFormatException ex) {
271                 // fall through to default value
272             }
273         }
274         return defaultValue;
275     }
276 
277     private static long getLongParameter(Pattern pattern, URI uri, long defaultValue) {
278         Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart());
279         if (matcher.find() && matcher.groupCount() == 1) {
280             try {
281                 return Long.parseLong(matcher.group(1));
282             }
283             catch (NumberFormatException ex) {
284                 // fall through to default value
285             }
286         }
287         return defaultValue;
288     }
289 
290 }