001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.activemq.web;
019
020 import java.io.BufferedReader;
021 import java.io.IOException;
022 import java.util.HashMap;
023 import java.util.Iterator;
024 import java.util.Map;
025
026 import javax.jms.Destination;
027 import javax.jms.JMSException;
028 import javax.jms.TextMessage;
029 import javax.servlet.ServletConfig;
030 import javax.servlet.ServletException;
031 import javax.servlet.http.HttpServlet;
032 import javax.servlet.http.HttpServletRequest;
033
034 import org.apache.activemq.command.ActiveMQDestination;
035 import org.apache.activemq.command.ActiveMQQueue;
036 import org.apache.activemq.command.ActiveMQTopic;
037 import org.apache.commons.logging.Log;
038 import org.apache.commons.logging.LogFactory;
039
040 /**
041 * A useful base class for any JMS related servlet; there are various ways to
042 * map JMS operations to web requests so we put most of the common behaviour in
043 * a reusable base class. This servlet can be configured with the following init
044 * paramters
045 * <dl>
046 * <dt>topic</dt>
047 * <dd>Set to 'true' if the servle should default to using topics rather than
048 * channels</dd>
049 * <dt>destination</dt>
050 * <dd>The default destination to use if one is not specifiied</dd>
051 * <dt></dt>
052 * <dd></dd>
053 * </dl>
054 *
055 * @version $Revision: 1.1.1.1 $
056 */
057 public abstract class MessageServletSupport extends HttpServlet {
058
059 private static final transient Log LOG = LogFactory.getLog(MessageServletSupport.class);
060
061 private boolean defaultTopicFlag = true;
062 private Destination defaultDestination;
063 private String destinationParameter = "destination";
064 private String typeParameter = "type";
065 private String bodyParameter = "body";
066 private boolean defaultMessagePersistent = true;
067 private int defaultMessagePriority = 5;
068 private long defaultMessageTimeToLive;
069 private String destinationOptions;
070
071 public void init(ServletConfig servletConfig) throws ServletException {
072 super.init(servletConfig);
073
074 destinationOptions = servletConfig.getInitParameter("destinationOptions");
075
076 String name = servletConfig.getInitParameter("topic");
077 if (name != null) {
078 defaultTopicFlag = asBoolean(name);
079 }
080
081 if (LOG.isDebugEnabled()) {
082 LOG.debug("Defaulting to use topics: " + defaultTopicFlag);
083 }
084 name = servletConfig.getInitParameter("destination");
085 if (name != null) {
086 if (defaultTopicFlag) {
087 defaultDestination = new ActiveMQTopic(name);
088 } else {
089 defaultDestination = new ActiveMQQueue(name);
090 }
091 }
092
093 // lets check to see if there's a connection factory set
094 WebClient.initContext(getServletContext());
095 }
096
097 public static boolean asBoolean(String param) {
098 return asBoolean(param, false);
099 }
100
101 public static boolean asBoolean(String param, boolean defaultValue) {
102 if (param == null) {
103 return defaultValue;
104 } else {
105 return param.equalsIgnoreCase("true");
106 }
107 }
108
109 protected void appendParametersToMessage(HttpServletRequest request, TextMessage message) throws JMSException {
110 Map parameterMap = request.getParameterMap();
111 if (parameterMap == null) {
112 return;
113 }
114 Map parameters = new HashMap(parameterMap);
115 String correlationID = asString(parameters.remove("JMSCorrelationID"));
116 if (correlationID != null) {
117 message.setJMSCorrelationID(correlationID);
118 }
119 Long expiration = asLong(parameters.remove("JMSExpiration"));
120 if (expiration != null) {
121 message.setJMSExpiration(expiration.longValue());
122 }
123 Destination replyTo = asDestination(parameters.remove("JMSReplyTo"));
124 if (replyTo != null) {
125 message.setJMSReplyTo(replyTo);
126 }
127 String type = (String)asString(parameters.remove("JMSType"));
128 if (correlationID != null) {
129 message.setJMSType(type);
130 }
131
132 for (Iterator iter = parameters.entrySet().iterator(); iter.hasNext();) {
133 Map.Entry entry = (Map.Entry)iter.next();
134 String name = (String)entry.getKey();
135 if (!destinationParameter.equals(name) && !typeParameter.equals(name) && !bodyParameter.equals(name) && !"JMSDeliveryMode".equals(name) && !"JMSPriority".equals(name)
136 && !"JMSTimeToLive".equals(name)) {
137 Object value = entry.getValue();
138 if (value instanceof Object[]) {
139 Object[] array = (Object[])value;
140 if (array.length == 1) {
141 value = array[0];
142 } else {
143 LOG.warn("Can't use property: " + name + " which is of type: " + value.getClass().getName() + " value");
144 value = null;
145 int size = array.length;
146 for (int i = 0; i < size; i++) {
147 LOG.debug("value[" + i + "] = " + array[i]);
148 }
149 }
150 }
151 if (value != null) {
152 message.setObjectProperty(name, value);
153 }
154 }
155 }
156 }
157
158 protected long getSendTimeToLive(HttpServletRequest request) {
159 String text = request.getParameter("JMSTimeToLive");
160 if (text != null) {
161 return asLong(text);
162 }
163 return defaultMessageTimeToLive;
164 }
165
166 protected int getSendPriority(HttpServletRequest request) {
167 String text = request.getParameter("JMSPriority");
168 if (text != null) {
169 return asInt(text);
170 }
171 return defaultMessagePriority;
172 }
173
174 protected boolean isSendPersistent(HttpServletRequest request) {
175 String text = request.getParameter("JMSDeliveryMode");
176 if (text != null) {
177 return text.trim().equalsIgnoreCase("persistent");
178 }
179 return defaultMessagePersistent;
180 }
181
182 protected boolean isSync(HttpServletRequest request) {
183 String text = request.getParameter("sync");
184 if (text != null) {
185 return true;
186 }
187 return false;
188 }
189
190 protected Destination asDestination(Object value) {
191 if (value instanceof Destination) {
192 return (Destination)value;
193 }
194 if (value instanceof String) {
195 String text = (String)value;
196 return ActiveMQDestination.createDestination(text, ActiveMQDestination.QUEUE_TYPE);
197 }
198 if (value instanceof String[]) {
199 String text = ((String[])value)[0];
200 if (text == null) {
201 return null;
202 }
203 return ActiveMQDestination.createDestination(text, ActiveMQDestination.QUEUE_TYPE);
204 }
205 return null;
206 }
207
208 protected Integer asInteger(Object value) {
209 if (value instanceof Integer) {
210 return (Integer)value;
211 }
212 if (value instanceof String) {
213 return Integer.valueOf((String)value);
214 }
215 if (value instanceof String[]) {
216 return Integer.valueOf(((String[])value)[0]);
217 }
218 return null;
219 }
220
221 protected Long asLong(Object value) {
222 if (value instanceof Long) {
223 return (Long)value;
224 }
225 if (value instanceof String) {
226 return Long.valueOf((String)value);
227 }
228 if (value instanceof String[]) {
229 return Long.valueOf(((String[])value)[0]);
230 }
231 return null;
232 }
233
234 protected long asLong(String name) {
235 return Long.parseLong(name);
236 }
237
238 protected int asInt(String name) {
239 return Integer.parseInt(name);
240 }
241
242 protected String asString(Object value) {
243 if (value instanceof String[]) {
244 return ((String[])value)[0];
245 }
246
247 if (value != null) {
248 return value.toString();
249 }
250
251 return null;
252 }
253
254 /**
255 * @return the destination to use for the current request
256 */
257 protected Destination getDestination(WebClient client, HttpServletRequest request) throws JMSException {
258 String destinationName = request.getParameter(destinationParameter);
259 if (destinationName == null || destinationName.equals("")) {
260 if (defaultDestination == null) {
261 return getDestinationFromURI(client, request);
262 } else {
263 return defaultDestination;
264 }
265 }
266
267 return getDestination(client, request, destinationName);
268 }
269
270 /**
271 * @return the destination to use for the current request using the relative
272 * URI from where this servlet was invoked as the destination name
273 */
274 protected Destination getDestinationFromURI(WebClient client, HttpServletRequest request) throws JMSException {
275 String uri = request.getPathInfo();
276 if (uri == null) {
277 return null;
278 }
279
280 // replace URI separator with JMS destination separator
281 if (uri.startsWith("/")) {
282 uri = uri.substring(1);
283 if (uri.length() == 0) {
284 return null;
285 }
286 }
287
288 uri = uri.replace('/', '.');
289 LOG.debug("destination uri=" + uri);
290 return getDestination(client, request, uri);
291 }
292
293 /**
294 * @return the Destination object for the given destination name
295 */
296 protected Destination getDestination(WebClient client, HttpServletRequest request, String destinationName) throws JMSException {
297
298 // TODO cache destinations ???
299
300 boolean isTopic = defaultTopicFlag;
301 if (destinationName.startsWith("topic://")) {
302 isTopic = true;
303 destinationName = destinationName.substring(8);
304 } else if (destinationName.startsWith("channel://")) {
305 isTopic = false;
306 destinationName = destinationName.substring(10);
307 } else {
308 isTopic = isTopic(request);
309 }
310
311 if (destinationOptions != null) {
312 destinationName += "?" + destinationOptions;
313 }
314 LOG.debug(destinationName + " (" + (isTopic ? "topic" : "queue") + ")");
315 if (isTopic) {
316 return client.getSession().createTopic(destinationName);
317 } else {
318 return client.getSession().createQueue(destinationName);
319 }
320 }
321
322 /**
323 * @return true if the current request is for a topic destination, else
324 * false if its for a queue
325 */
326 protected boolean isTopic(HttpServletRequest request) {
327 String typeText = request.getParameter(typeParameter);
328 if (typeText == null) {
329 return defaultTopicFlag;
330 }
331 return typeText.equalsIgnoreCase("topic");
332 }
333
334 /**
335 * @return the text that was posted to the servlet which is used as the body
336 * of the message to be sent
337 */
338 protected String getPostedMessageBody(HttpServletRequest request) throws IOException {
339 String answer = request.getParameter(bodyParameter);
340 if (answer == null && "text/xml".equals(request.getContentType())) {
341 // lets read the message body instead
342 BufferedReader reader = request.getReader();
343 StringBuffer buffer = new StringBuffer();
344 while (true) {
345 String line = reader.readLine();
346 if (line == null) {
347 break;
348 }
349 buffer.append(line);
350 buffer.append("\n");
351 }
352 return buffer.toString();
353 }
354 return answer;
355 }
356 }