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 }