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 018package org.apache.activemq.web; 019 020import java.io.BufferedReader; 021import java.io.IOException; 022import java.io.InputStreamReader; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.Map; 026 027import javax.jms.Destination; 028import javax.jms.JMSException; 029import javax.jms.TextMessage; 030import javax.servlet.ServletConfig; 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServlet; 033import javax.servlet.http.HttpServletRequest; 034 035import org.apache.activemq.command.ActiveMQDestination; 036import org.apache.activemq.command.ActiveMQQueue; 037import org.apache.activemq.command.ActiveMQTopic; 038import org.apache.commons.io.input.BoundedInputStream; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042/** 043 * A useful base class for any JMS related servlet; there are various ways to 044 * map JMS operations to web requests so we put most of the common behaviour in 045 * a reusable base class. This servlet can be configured with the following init 046 * parameters 047 * <dl> 048 * <dt>topic</dt> 049 * <dd>Set to 'true' if the servlet should default to using topics rather than 050 * channels</dd> 051 * <dt>destination</dt> 052 * <dd>The default destination to use if one is not specifiied</dd> 053 * <dt></dt> 054 * <dd></dd> 055 * </dl> 056 * 057 * 058 */ 059@SuppressWarnings("serial") 060public abstract class MessageServletSupport extends HttpServlet { 061 062 private static final transient Logger LOG = LoggerFactory.getLogger(MessageServletSupport.class); 063 /** 064 * A configuration tag to specify the maximum message size (in bytes) for the servlet. The default 065 * is given by DEFAULT_MAX_MESSAGE_SIZE below. 066 */ 067 private static final String MAX_MESSAGE_SIZE_TAG = "maxMessageSize"; 068 private static final Long DEFAULT_MAX_MESSAGE_SIZE = 100000L; 069 070 private boolean defaultTopicFlag = true; 071 private Destination defaultDestination; 072 private String destinationParameter = "destination"; 073 private String typeParameter = "type"; 074 private String bodyParameter = "body"; 075 private boolean defaultMessagePersistent = true; 076 private int defaultMessagePriority = 5; 077 private long defaultMessageTimeToLive; 078 private String destinationOptions; 079 private long maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE; 080 081 public void init(ServletConfig servletConfig) throws ServletException { 082 super.init(servletConfig); 083 084 destinationOptions = servletConfig.getInitParameter("destinationOptions"); 085 086 String name = servletConfig.getInitParameter("topic"); 087 if (name != null) { 088 defaultTopicFlag = asBoolean(name); 089 } 090 091 if (LOG.isDebugEnabled()) { 092 LOG.debug("Defaulting to use topics: " + defaultTopicFlag); 093 } 094 name = servletConfig.getInitParameter("destination"); 095 if (name != null) { 096 if (defaultTopicFlag) { 097 defaultDestination = new ActiveMQTopic(name); 098 } else { 099 defaultDestination = new ActiveMQQueue(name); 100 } 101 } 102 103 String maxMessageSizeConfigured = servletConfig.getInitParameter(MAX_MESSAGE_SIZE_TAG); 104 if (maxMessageSizeConfigured != null) { 105 maxMessageSize = Long.parseLong(maxMessageSizeConfigured); 106 } 107 108 // lets check to see if there's a connection factory set 109 WebClient.initContext(getServletContext()); 110 } 111 112 public static boolean asBoolean(String param) { 113 return asBoolean(param, false); 114 } 115 116 public static boolean asBoolean(String param, boolean defaultValue) { 117 if (param == null) { 118 return defaultValue; 119 } else { 120 return param.equalsIgnoreCase("true"); 121 } 122 } 123 124 @SuppressWarnings({ "rawtypes", "unchecked" }) 125 protected void appendParametersToMessage(HttpServletRequest request, TextMessage message) throws JMSException { 126 Map parameterMap = request.getParameterMap(); 127 if (parameterMap == null) { 128 return; 129 } 130 Map parameters = new HashMap(parameterMap); 131 String correlationID = asString(parameters.remove("JMSCorrelationID")); 132 if (correlationID != null) { 133 message.setJMSCorrelationID(correlationID); 134 } 135 Long expiration = asLong(parameters.remove("JMSExpiration")); 136 if (expiration != null) { 137 message.setJMSExpiration(expiration.longValue()); 138 } 139 Destination replyTo = asDestination(parameters.remove("JMSReplyTo")); 140 if (replyTo != null) { 141 message.setJMSReplyTo(replyTo); 142 } 143 String type = (String)asString(parameters.remove("JMSType")); 144 if (type != null) { 145 message.setJMSType(type); 146 } 147 148 for (Iterator iter = parameters.entrySet().iterator(); iter.hasNext();) { 149 Map.Entry entry = (Map.Entry)iter.next(); 150 String name = (String)entry.getKey(); 151 if (!destinationParameter.equals(name) && !typeParameter.equals(name) && !bodyParameter.equals(name) && !"JMSDeliveryMode".equals(name) && !"JMSPriority".equals(name) 152 && !"JMSTimeToLive".equals(name)) { 153 Object value = entry.getValue(); 154 if (value instanceof Object[]) { 155 Object[] array = (Object[])value; 156 if (array.length == 1) { 157 value = array[0]; 158 } else { 159 LOG.warn("Can't use property: " + name + " which is of type: " + value.getClass().getName() + " value"); 160 value = null; 161 int size = array.length; 162 for (int i = 0; i < size; i++) { 163 LOG.debug("value[" + i + "] = " + array[i]); 164 } 165 } 166 } 167 if (value != null) { 168 message.setObjectProperty(name, value); 169 } 170 } 171 } 172 } 173 174 protected long getSendTimeToLive(HttpServletRequest request) { 175 String text = request.getParameter("JMSTimeToLive"); 176 if (text != null) { 177 return asLong(text); 178 } 179 return defaultMessageTimeToLive; 180 } 181 182 protected int getSendPriority(HttpServletRequest request) { 183 String text = request.getParameter("JMSPriority"); 184 if (text != null) { 185 return asInt(text); 186 } 187 return defaultMessagePriority; 188 } 189 190 protected boolean isSendPersistent(HttpServletRequest request) { 191 String text = request.getParameter("JMSDeliveryMode"); 192 if (text != null) { 193 return text.trim().equalsIgnoreCase("persistent"); 194 } 195 return defaultMessagePersistent; 196 } 197 198 protected boolean isSync(HttpServletRequest request) { 199 String text = request.getParameter("sync"); 200 if (text != null) { 201 return true; 202 } 203 return false; 204 } 205 206 protected Destination asDestination(Object value) { 207 if (value instanceof Destination) { 208 return (Destination)value; 209 } 210 if (value instanceof String) { 211 String text = (String)value; 212 return ActiveMQDestination.createDestination(text, ActiveMQDestination.QUEUE_TYPE); 213 } 214 if (value instanceof String[]) { 215 String text = ((String[])value)[0]; 216 if (text == null) { 217 return null; 218 } 219 return ActiveMQDestination.createDestination(text, ActiveMQDestination.QUEUE_TYPE); 220 } 221 return null; 222 } 223 224 protected Integer asInteger(Object value) { 225 if (value instanceof Integer) { 226 return (Integer)value; 227 } 228 if (value instanceof String) { 229 return Integer.valueOf((String)value); 230 } 231 if (value instanceof String[]) { 232 return Integer.valueOf(((String[])value)[0]); 233 } 234 return null; 235 } 236 237 protected Long asLong(Object value) { 238 if (value instanceof Long) { 239 return (Long)value; 240 } 241 if (value instanceof String) { 242 return Long.valueOf((String)value); 243 } 244 if (value instanceof String[]) { 245 return Long.valueOf(((String[])value)[0]); 246 } 247 return null; 248 } 249 250 protected long asLong(String name) { 251 return Long.parseLong(name); 252 } 253 254 protected int asInt(String name) { 255 return Integer.parseInt(name); 256 } 257 258 protected String asString(Object value) { 259 if (value instanceof String[]) { 260 return ((String[])value)[0]; 261 } 262 263 if (value != null) { 264 return value.toString(); 265 } 266 267 return null; 268 } 269 270 /** 271 * @return the destination to use for the current request 272 */ 273 protected Destination getDestination(WebClient client, HttpServletRequest request) throws JMSException { 274 String destinationName = request.getParameter(destinationParameter); 275 if (destinationName == null || destinationName.equals("")) { 276 if (defaultDestination == null) { 277 return getDestinationFromURI(client, request); 278 } else { 279 return defaultDestination; 280 } 281 } 282 283 return getDestination(client, request, destinationName); 284 } 285 286 /** 287 * @return the destination to use for the current request using the relative 288 * URI from where this servlet was invoked as the destination name 289 */ 290 protected Destination getDestinationFromURI(WebClient client, HttpServletRequest request) throws JMSException { 291 String uri = request.getPathInfo(); 292 if (uri == null) { 293 return null; 294 } 295 296 // replace URI separator with JMS destination separator 297 if (uri.startsWith("/")) { 298 uri = uri.substring(1); 299 if (uri.length() == 0) { 300 return null; 301 } 302 } 303 304 uri = uri.replace('/', '.'); 305 LOG.debug("destination uri=" + uri); 306 return getDestination(client, request, uri); 307 } 308 309 /** 310 * @return the Destination object for the given destination name 311 */ 312 protected Destination getDestination(WebClient client, HttpServletRequest request, String destinationName) throws JMSException { 313 314 // TODO cache destinations ??? 315 316 boolean isTopic = defaultTopicFlag; 317 if (destinationName.startsWith("topic://")) { 318 isTopic = true; 319 } else if (destinationName.startsWith("channel://") || destinationName.startsWith("queue://")) { 320 isTopic = false; 321 } else { 322 isTopic = isTopic(request); 323 } 324 if (destinationName.indexOf("://") != -1) { 325 destinationName = destinationName.substring(destinationName.indexOf("://") + 3); 326 } 327 328 if (destinationOptions != null) { 329 destinationName += "?" + destinationOptions; 330 } 331 LOG.debug(destinationName + " (" + (isTopic ? "topic" : "queue") + ")"); 332 if (isTopic) { 333 return client.getSession().createTopic(destinationName); 334 } else { 335 return client.getSession().createQueue(destinationName); 336 } 337 } 338 339 /** 340 * @return true if the current request is for a topic destination, else 341 * false if its for a queue 342 */ 343 protected boolean isTopic(HttpServletRequest request) { 344 String typeText = request.getParameter(typeParameter); 345 if (typeText == null) { 346 return defaultTopicFlag; 347 } 348 return typeText.equalsIgnoreCase("topic"); 349 } 350 351 /** 352 * @return the text that was posted to the servlet which is used as the body 353 * of the message to be sent 354 */ 355 protected String getPostedMessageBody(HttpServletRequest request) throws IOException { 356 String answer = request.getParameter(bodyParameter); 357 String contentType = request.getContentType(); 358 if (answer == null && contentType != null) { 359 LOG.debug("Content-Type={}", contentType); 360 // lets read the message body instead 361 BoundedInputStream boundedInputStream = new BoundedInputStream(request.getInputStream(), maxMessageSize); 362 BufferedReader reader = new BufferedReader(new InputStreamReader(boundedInputStream)); 363 StringBuilder buffer = new StringBuilder(); 364 while (true) { 365 String line = reader.readLine(); 366 if (line == null) { 367 break; 368 } 369 buffer.append(line); 370 buffer.append("\n"); 371 } 372 return buffer.toString(); 373 } 374 return answer; 375 } 376 377 protected String getSelector(HttpServletRequest request) throws IOException { 378 return request.getHeader(WebClient.selectorName); 379 } 380}