001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mq.il.http.servlet;
023:
024: import java.io.IOException;
025: import java.io.ObjectInputStream;
026: import java.io.ObjectOutputStream;
027: import java.lang.reflect.InvocationTargetException;
028: import java.lang.reflect.Method;
029:
030: import javax.management.MBeanServer;
031: import javax.management.ObjectName;
032: import javax.servlet.ServletConfig;
033: import javax.servlet.ServletException;
034: import javax.servlet.http.HttpServlet;
035: import javax.servlet.http.HttpServletRequest;
036: import javax.servlet.http.HttpServletResponse;
037: import javax.transaction.xa.Xid;
038:
039: import org.jboss.logging.Logger;
040: import org.jboss.mq.ConnectionToken;
041: import org.jboss.mq.SpyMessage;
042: import org.jboss.mq.il.http.HTTPClientILStorageQueue;
043: import org.jboss.mq.il.http.HTTPILRequest;
044: import org.jboss.mq.il.http.HTTPILResponse;
045: import org.jboss.mq.server.JMSServerInvoker;
046: import org.jboss.mx.util.MBeanServerLocator;
047:
048: /**
049: * This Servlet acts as a proxy to the JMS Server for the HTTP IL clients.
050: * It receives posts from the HTTPServerIL in the form of HTTPILRequests,
051: * invokes the approprate method on the server, and returns a HTTPILResponse.
052: *
053: * This also acts as a delegate for the HTTPClientILService, by receiving
054: * POSTS, looking in HTTPILStorageQueue, retrieving HTTPRequests bound for the
055: * client, packaging them in a HTTPILResponse. These requests are generally
056: * long lived to simulate asynch messaging. When the HTTPClientILService POSTS
057: * a HTTPILRequest the payload of the request includes timeout value which represents
058: * the max time the request will last, before returning to the client.
059: *
060: * @author Nathan Phelps (nathan@jboss.org)
061: * @version $Revision: 57210 $
062: * @created January 15, 2003
063: */
064: public class HTTPServerILServlet extends HttpServlet {
065:
066: private static final String RESPONSE_CONTENT_TYPE = "application/x-java-serialized-object; class=org.jboss.mq.il.http.HTTPILResponse";
067:
068: private static Logger log = Logger
069: .getLogger(HTTPServerILServlet.class);
070: private MBeanServer server;
071: private JMSServerInvoker invoker;
072:
073: public void init(ServletConfig config) throws ServletException {
074: super .init(config);
075: if (log.isTraceEnabled()) {
076: log.trace("init(ServletConfig " + config.toString() + ")");
077: }
078: this .server = MBeanServerLocator.locateJBoss();
079: if (this .server == null) {
080: throw new ServletException(
081: "Failed to locate the MBeanServer");
082: }
083: String invokerName = config.getInitParameter("Invoker");
084: if (invokerName == null) {
085: throw new ServletException(
086: "Invoker must be specified as servlet init parameter");
087: }
088: if (log.isDebugEnabled()) {
089: log.debug("Invoker set to '" + invokerName + ".'");
090: }
091: try {
092: this .invoker = (JMSServerInvoker) server.getAttribute(
093: new ObjectName(invokerName), "Invoker");
094: } catch (Exception exception) {
095: throw new ServletException(
096: "Failed to locate the JBossMQ invoker.");
097: }
098: }
099:
100: public void destroy() {
101: if (log.isTraceEnabled()) {
102: log.trace("destroy()");
103: }
104: }
105:
106: protected void processRequest(HttpServletRequest request,
107: HttpServletResponse response) throws ServletException,
108: IOException {
109: if (log.isTraceEnabled()) {
110: log.trace("processRequest(HttpServletRequest "
111: + request.toString() + ", HttpServletResponse "
112: + response.toString() + ")");
113: }
114: response.setContentType(RESPONSE_CONTENT_TYPE);
115: ObjectOutputStream outputStream = new ObjectOutputStream(
116: response.getOutputStream());
117: try {
118: ObjectInputStream inputStream = new ObjectInputStream(
119: request.getInputStream());
120: HTTPILRequest httpIlRequest = (HTTPILRequest) inputStream
121: .readObject();
122: String methodName = httpIlRequest.getMethodName();
123: if (methodName.equals("clientListening")) {
124: if (log.isTraceEnabled()) {
125: log.trace("clientListening(HTTPILRequest "
126: + httpIlRequest.toString() + ")");
127: }
128: String clientIlId = (String) httpIlRequest
129: .getArguments()[0];
130: long timeout = ((Long) httpIlRequest.getArguments()[1])
131: .longValue();
132: if (log.isDebugEnabled()) {
133: log.debug("Listening on behalf of a ClientIL #"
134: + clientIlId + " for "
135: + String.valueOf(timeout)
136: + " milliseconds.");
137: }
138: HTTPILRequest[] responseRequest = HTTPClientILStorageQueue
139: .getInstance().get(clientIlId, timeout);
140: if (log.isDebugEnabled()) {
141: log
142: .debug("The following lines reflect the HTTPILRequest object to be packaged and returned to ClientIL #"
143: + clientIlId
144: + " as an HTTPILResponse.");
145: for (int i = 0; i < responseRequest.length; i++) {
146: log.debug("Response for ClientIL #"
147: + clientIlId + " contains '"
148: + responseRequest[i].toString() + ".'");
149: }
150: }
151: outputStream.writeObject(new HTTPILResponse(
152: responseRequest));
153: } else if (methodName.equals("getClientILIdentifer")) {
154: if (log.isTraceEnabled()) {
155: log.trace("getClientILIdentifer(HTTPILRequest "
156: + httpIlRequest.toString() + ")");
157: }
158: String id = HTTPClientILStorageQueue.getInstance()
159: .getID();
160: if (log.isDebugEnabled()) {
161: log.debug("Provided ClientIL Id #" + id + ".");
162: }
163: outputStream.writeObject(new HTTPILResponse(id));
164: } else if (methodName.equals("stopClientListening")) {
165: if (log.isTraceEnabled()) {
166: log.trace("stopClientListening(HTTPILRequest "
167: + httpIlRequest.toString() + ")");
168: }
169: String clientIlId = (String) httpIlRequest
170: .getArguments()[0];
171: if (clientIlId != null) {
172: HTTPClientILStorageQueue.getInstance().purgeEntry(
173: clientIlId);
174: }
175: outputStream.writeObject(new HTTPILResponse(
176: "Storage queue was purged."));
177: }
178: /* The following four 'else ifs' are special ServerIL cases where we can't
179: * simply pass the invocation through due to the way the primitives
180: * must be stored as objects. In JDK 1.4, you can specify the primitive
181: * class (i.e. Long.TYPE or long.class) and it works, however, this
182: * is NOT the case with JDK 1.3. Therefore, in order to support both
183: * we've got to pass the primitive class type in its object form
184: * (i.e. Long.class), and then--in cases where they target object
185: * expects a primitive--handle the unboxing manually.
186: */
187: else if (methodName.equals("ping")) {
188: if (log.isTraceEnabled()) {
189: log.trace("ping(HTTPILRequest "
190: + httpIlRequest.toString() + ")");
191: }
192: ConnectionToken connectionToken = (ConnectionToken) httpIlRequest
193: .getArguments()[0];
194: long clientTime = ((Long) httpIlRequest.getArguments()[1])
195: .longValue();
196: this .invoker.ping(connectionToken, clientTime);
197: outputStream.writeObject(new HTTPILResponse());
198: } else if (methodName.equals("receive")) {
199: if (log.isTraceEnabled()) {
200: log.trace("receive(HTTPILRequest "
201: + httpIlRequest.toString() + ")");
202: }
203: ConnectionToken connectionToken = (ConnectionToken) httpIlRequest
204: .getArguments()[0];
205: int subscriberId = ((Integer) httpIlRequest
206: .getArguments()[1]).intValue();
207: long wait = ((Long) httpIlRequest.getArguments()[2])
208: .longValue();
209: SpyMessage message = this .invoker.receive(
210: connectionToken, subscriberId, wait);
211: outputStream.writeObject(new HTTPILResponse(message));
212: if (message != null && log.isDebugEnabled()) {
213: log.debug("Returned an instance of '"
214: + message.getClass().toString()
215: + "' with value of '" + message.toString()
216: + "'");
217: }
218: } else if (methodName.equals("setEnabled")) {
219: if (log.isTraceEnabled()) {
220: log.trace("setEnabled(HTTPILRequest "
221: + httpIlRequest.toString() + ")");
222: }
223: ConnectionToken connectionToken = (ConnectionToken) httpIlRequest
224: .getArguments()[0];
225: boolean enabled = ((Boolean) httpIlRequest
226: .getArguments()[1]).booleanValue();
227: this .invoker.setEnabled(connectionToken, enabled);
228: outputStream.writeObject(new HTTPILResponse());
229: } else if (methodName.equals("unsubscribe")) {
230: if (log.isTraceEnabled()) {
231: log.trace("unsubscribe(HTTPILRequest "
232: + httpIlRequest.toString() + ")");
233: }
234: ConnectionToken connectionToken = (ConnectionToken) httpIlRequest
235: .getArguments()[0];
236: int subscriberId = ((Integer) httpIlRequest
237: .getArguments()[1]).intValue();
238: this .invoker.unsubscribe(connectionToken, subscriberId);
239: outputStream.writeObject(new HTTPILResponse());
240: } else if (methodName.equals("recover")) {
241: if (log.isTraceEnabled())
242: log.trace("recover(HTTPILRequest "
243: + httpIlRequest.toString() + ")");
244: ConnectionToken connectionToken = (ConnectionToken) httpIlRequest
245: .getArguments()[0];
246: int flags = ((Integer) httpIlRequest.getArguments()[1])
247: .intValue();
248: Xid[] xids = this .invoker.recover(connectionToken,
249: flags);
250: outputStream.writeObject(new HTTPILResponse(xids));
251: } else {
252: if (log.isTraceEnabled()) {
253: log.trace("HTTPILRequest recieved: "
254: + httpIlRequest.toString());
255: }
256: Method method = this .invoker.getClass().getMethod(
257: methodName, httpIlRequest.getArgumentTypes());
258: Object returnValue = method.invoke(this .invoker,
259: httpIlRequest.getArguments());
260: if (log.isDebugEnabled()) {
261: log.debug("Invoked method '" + methodName + ".'");
262: }
263: outputStream
264: .writeObject(new HTTPILResponse(returnValue));
265: if (returnValue != null && log.isDebugEnabled()) {
266: log.debug("Returned an instance of '"
267: + returnValue.getClass().toString()
268: + "' with value of '"
269: + returnValue.toString() + "'");
270: }
271: }
272: } catch (InvocationTargetException invocatonTargetException) {
273: Throwable targetException = invocatonTargetException
274: .getTargetException();
275: if (log.isDebugEnabled()) {
276: log
277: .debug("The underlying invoker (i.e. The JMS Server itself) threw in exception of type '"
278: + targetException.getClass().getName()
279: + "' and a message of '"
280: + targetException.getMessage()
281: + ".' This exception is being propogated to the client as a HTTPILResponse.");
282: }
283: outputStream
284: .writeObject(new HTTPILResponse(targetException));
285: } catch (Exception exception) {
286: if (log.isDebugEnabled()) {
287: log
288: .debug("Threw an exception of type '"
289: + exception.getClass().getName()
290: + "' with a message of '"
291: + exception.getMessage()
292: + ".' This exception is being propogated to the client as a HTTPILResponse.");
293: }
294: outputStream.writeObject(new HTTPILResponse(exception));
295: }
296: outputStream.close();
297: }
298:
299: protected void doGet(HttpServletRequest request,
300: HttpServletResponse response) throws ServletException,
301: IOException {
302: if (log.isTraceEnabled()) {
303: log.trace("doGet(HttpServletRequest " + request.toString()
304: + ", HttpServletResponse " + response.toString()
305: + ")");
306: }
307: response
308: .getWriter()
309: .print(
310: "<html><head><title>JBossMQ HTTP-IL Servlet</title><head><body><h1>This is the JBossMQ HTTP-IL</h1></body></html>");
311: }
312:
313: protected void doPost(HttpServletRequest request,
314: HttpServletResponse response) throws ServletException,
315: IOException {
316: if (log.isTraceEnabled()) {
317: log
318: .trace("doPost() defers to processRequest, see the parameters in its trace.");
319: }
320: processRequest(request, response);
321: }
322:
323: public String getServletInfo() {
324: return "Provides an HTTP/S interface to JBossMQ";
325: }
326: }
|