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