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 }