001 /** 002 * 003 * Copyright 2004 Protique Ltd 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * 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 019 package org.activemq.web; 020 021 import org.activemq.message.ActiveMQDestination; 022 import org.apache.commons.logging.Log; 023 import org.apache.commons.logging.LogFactory; 024 025 import javax.jms.Destination; 026 import javax.jms.JMSException; 027 import javax.jms.Message; 028 import javax.jms.MessageConsumer; 029 import javax.jms.ObjectMessage; 030 import javax.jms.TextMessage; 031 import javax.servlet.ServletConfig; 032 import javax.servlet.ServletException; 033 import javax.servlet.http.HttpServletRequest; 034 import javax.servlet.http.HttpServletResponse; 035 036 import java.io.IOException; 037 import java.io.PrintWriter; 038 039 /** 040 * A servlet for sending and receiving messages to/from JMS destinations using 041 * HTTP POST for sending and HTTP GET for receiving. <p/> You can specify the 042 * destination and whether it is a topic or queue via configuration details on 043 * the servlet or as request parameters. <p/> For reading messages you can 044 * specify a readTimeout parameter to determine how long the servlet should 045 * block for. 046 * 047 * @version $Revision: 1.1.1.1 $ 048 */ 049 public class MessageServlet extends MessageServletSupport { 050 private static final Log log = LogFactory.getLog(MessageServlet.class); 051 052 private String readTimeoutParameter = "readTimeout"; 053 private long defaultReadTimeout = -1; 054 private long maximumReadTimeout = 1200; 055 056 public void init() throws ServletException { 057 ServletConfig servletConfig = getServletConfig(); 058 String name = servletConfig.getInitParameter("defaultReadTimeout"); 059 if (name != null) { 060 defaultReadTimeout = asLong(name); 061 } 062 name = servletConfig.getInitParameter("maximumReadTimeout"); 063 if (name != null) { 064 maximumReadTimeout = asLong(name); 065 } 066 } 067 068 /** 069 * Sends a message to a destination 070 * 071 * @param request 072 * @param response 073 * @throws ServletException 074 * @throws IOException 075 */ 076 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, 077 IOException { 078 // lets turn the HTTP post into a JMS Message 079 try { 080 WebClient client = getWebClient(request); 081 082 String text = getPostedMessageBody(request); 083 084 // lets create the destination from the URI? 085 Destination destination = getDestination(client, request); 086 087 if (log.isInfoEnabled()) { 088 log.info("Sending message to: " + ActiveMQDestination.inspect(destination) + " with text: " + text); 089 } 090 091 TextMessage message = client.getSession().createTextMessage(text); 092 appendParametersToMessage(request, message); 093 client.send(destination, message); 094 095 // lets return a unique URI for reliable messaging 096 response.setHeader("messageID", message.getJMSMessageID()); 097 response.setStatus(HttpServletResponse.SC_OK); 098 } 099 catch (JMSException e) { 100 throw new ServletException("Could not post JMS message: " + e, e); 101 } 102 } 103 104 /** 105 * Reads a message from a destination up to some specific timeout period 106 * 107 * @param request 108 * @param response 109 * @throws ServletException 110 * @throws IOException 111 */ 112 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 113 try { 114 WebClient client = getWebClient(request); 115 116 // lets create the destination from the URI? 117 Destination destination = getDestination(client, request); 118 119 long timeout = getReadTimeout(request); 120 121 if (log.isInfoEnabled()) { 122 log.info("Receiving message from: " + ActiveMQDestination.inspect(destination) + " with timeout: " 123 + timeout); 124 } 125 126 MessageConsumer consumer = client.getConsumer(destination); 127 128 Message message = null; 129 // ensure that only one thread uses the consumer at once 130 synchronized (consumer) { 131 if (timeout == 0) { 132 message = consumer.receiveNoWait(); 133 } 134 else { 135 message = consumer.receive(timeout); 136 } 137 } 138 139 if (log.isInfoEnabled()) { 140 log.info("HTTP GET servlet done! message: " + message); 141 } 142 143 sendMessageResponse(request, response, message); 144 } 145 catch (JMSException e) { 146 throw new ServletException("Could not post JMS message: " + e, e); 147 } 148 149 } 150 151 /** 152 * Supports a HTTP DELETE to be equivlanent of consuming a message from a 153 * queue 154 */ 155 protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, 156 IOException { 157 try { 158 WebClient client = getWebClient(request); 159 160 // lets create the destination from the URI? 161 Destination destination = getDestination(client, request); 162 163 MessageConsumer consumer = client.getConsumer(destination); 164 165 Message message = null; 166 // ensure that only one thread uses the consumer at once 167 synchronized (consumer) { 168 message = consumer.receiveNoWait(); 169 } 170 171 sendMessageResponse(request, response, message); 172 } 173 catch (JMSException e) { 174 throw new ServletException("Could not post JMS message: " + e, e); 175 } 176 } 177 178 protected void sendMessageResponse(HttpServletRequest request, HttpServletResponse response, Message message) 179 throws JMSException, IOException { 180 response.setContentType("text/xml"); 181 boolean ajax = isRicoAjax(request); 182 PrintWriter writer = response.getWriter(); 183 if (ajax) { 184 writer.print("<ajax-response><response type='object' id='"); 185 writer.print(request.getParameter("id")); 186 writer.println("'>"); 187 } 188 if (message == null) { 189 if (ajax) { 190 writer.println("</response></ajax-response>"); 191 response.setStatus(HttpServletResponse.SC_OK); 192 } 193 else { 194 response.setStatus(HttpServletResponse.SC_NO_CONTENT); 195 } 196 } 197 else { 198 String type = getContentType(request); 199 if (type != null) { 200 response.setContentType(type); 201 } 202 setResponseHeaders(response, message); 203 204 if (message instanceof TextMessage) { 205 TextMessage textMsg = (TextMessage) message; 206 writer.print(textMsg.getText()); 207 } 208 else if (message instanceof ObjectMessage) { 209 ObjectMessage objectMsg = (ObjectMessage) message; 210 Object object = objectMsg.getObject(); 211 writer.print(object.toString()); 212 } 213 if (ajax) { 214 writer.println("</response></ajax-response>"); 215 } 216 response.setStatus(HttpServletResponse.SC_OK); 217 } 218 } 219 220 protected boolean isRicoAjax(HttpServletRequest request) { 221 String rico = request.getParameter("rico"); 222 return rico != null && rico.equals("true"); 223 } 224 225 protected String getContentType(HttpServletRequest request) { 226 /* 227 * log("Params: " + request.getParameterMap()); Enumeration iter = 228 * request.getHeaderNames(); while (iter.hasMoreElements()) { String 229 * name = (String) iter.nextElement(); log("Header: " + name + " = " + 230 * request.getHeader(name)); } 231 */ 232 String value = request.getParameter("xml"); 233 if (value != null && "true".equalsIgnoreCase(value)) { 234 return "text/xml"; 235 } 236 return null; 237 } 238 239 protected void setResponseHeaders(HttpServletResponse response, Message message) throws JMSException { 240 response.setHeader("destination", message.getJMSDestination().toString()); 241 response.setHeader("id", message.getJMSMessageID()); 242 } 243 244 /** 245 * @return the timeout value for read requests which is always >= 0 and <= 246 * maximumReadTimeout to avoid DoS attacks 247 */ 248 protected long getReadTimeout(HttpServletRequest request) { 249 long answer = defaultReadTimeout; 250 251 String name = request.getParameter(readTimeoutParameter); 252 if (name != null) { 253 answer = asLong(name); 254 } 255 if (answer < 0 || answer > maximumReadTimeout) { 256 answer = maximumReadTimeout; 257 } 258 return answer; 259 } 260 261 }