001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package echo2example.chatserver;
031:
032: import java.io.IOException;
033: import java.io.InputStream;
034:
035: import javax.servlet.ServletException;
036: import javax.servlet.http.HttpServlet;
037: import javax.servlet.http.HttpServletRequest;
038: import javax.servlet.http.HttpServletResponse;
039: import javax.xml.parsers.DocumentBuilder;
040: import javax.xml.parsers.DocumentBuilderFactory;
041: import javax.xml.parsers.ParserConfigurationException;
042: import javax.xml.transform.Transformer;
043: import javax.xml.transform.TransformerException;
044: import javax.xml.transform.TransformerFactory;
045: import javax.xml.transform.dom.DOMSource;
046: import javax.xml.transform.stream.StreamResult;
047:
048: import org.w3c.dom.Document;
049: import org.w3c.dom.Element;
050: import org.w3c.dom.NodeList;
051: import org.w3c.dom.Text;
052: import org.xml.sax.SAXException;
053:
054: /**
055: * Chat Server Servlet
056: */
057: public class ChatServerServlet extends HttpServlet {
058:
059: private static final Server server = new Server();
060:
061: /**
062: * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
063: */
064: protected void doPost(HttpServletRequest request,
065: HttpServletResponse response) throws ServletException,
066: IOException {
067: Document requestDocument = loadRequestDocument(request);
068: Document responseDocument = createResponseDocument();
069: processUserAdd(requestDocument, responseDocument);
070: processUserRemove(requestDocument, responseDocument);
071: processPostMessage(requestDocument, responseDocument);
072: processGetMessages(requestDocument, responseDocument);
073: renderResponseDocument(response, responseDocument);
074: }
075:
076: /**
077: * Creates the response DOM document, containing a 'chat-server-response'
078: * document element.
079: *
080: * @return the response document
081: */
082: private Document createResponseDocument() throws IOException {
083: try {
084: DocumentBuilderFactory factory = DocumentBuilderFactory
085: .newInstance();
086: factory.setNamespaceAware(true);
087: DocumentBuilder builder = factory.newDocumentBuilder();
088: Document document = builder.newDocument();
089: document.appendChild(document
090: .createElement("chat-server-response"));
091: return document;
092: } catch (ParserConfigurationException ex) {
093: throw new IOException("Cannot create document: " + ex);
094: }
095: }
096:
097: /**
098: * Retrieves the request DOM document from an incoming
099: * <code>httpServletRequest</code>.
100: *
101: * @param request the <code>HttpServletRequest</code>
102: * @return the request DOM document
103: */
104: private Document loadRequestDocument(HttpServletRequest request)
105: throws IOException {
106: InputStream in = null;
107: try {
108: request.setCharacterEncoding("UTF-8");
109: in = request.getInputStream();
110: DocumentBuilderFactory factory = DocumentBuilderFactory
111: .newInstance();
112: factory.setNamespaceAware(true);
113: DocumentBuilder builder = factory.newDocumentBuilder();
114: return builder.parse(in);
115: } catch (ParserConfigurationException ex) {
116: throw new IOException(
117: "Provided InputStream cannot be parsed: " + ex);
118: } catch (SAXException ex) {
119: throw new IOException(
120: "Provided InputStream cannot be parsed: " + ex);
121: } catch (IOException ex) {
122: throw new IOException(
123: "Provided InputStream cannot be parsed: " + ex);
124: } finally {
125: if (in != null) {
126: try {
127: in.close();
128: } catch (IOException ex) {
129: }
130: }
131: }
132: }
133:
134: /**
135: * Retrieves new messages posted with id values higher than the
136: * request document's specified 'last-retrieved-id' value.
137: *
138: * @param requestDocument the request DOM document
139: * @param responseDocument the response DOM document
140: */
141: private void processGetMessages(Document requestDocument,
142: Document responseDocument) {
143: String lastRetrievedIdString = requestDocument
144: .getDocumentElement().getAttribute("last-retrieved-id");
145: Message[] messages;
146: if (lastRetrievedIdString == null
147: || lastRetrievedIdString.trim().length() == 0) {
148: messages = server.getRecentMessages();
149: } else {
150: long lastRetrievedId = Long
151: .parseLong(lastRetrievedIdString);
152: messages = server.getMessages(lastRetrievedId);
153: }
154: for (int i = 0; i < messages.length; ++i) {
155: Element messageElement = responseDocument
156: .createElement("message");
157: messageElement.setAttribute("id", Long.toString(messages[i]
158: .getId()));
159: if (messages[i].getUserName() != null) {
160: messageElement.setAttribute("user-name", messages[i]
161: .getUserName());
162: }
163: messageElement.setAttribute("time", Long
164: .toString(messages[i].getPostTime()));
165: messageElement.appendChild(responseDocument
166: .createTextNode(messages[i].getContent()));
167: responseDocument.getDocumentElement().appendChild(
168: messageElement);
169: }
170: }
171:
172: /**
173: * Processes a request (if applicable) to post a message to the chat
174: * server.
175: *
176: * @param requestDocument the request DOM document
177: * @param responseDocument the response DOM document
178: */
179: private void processPostMessage(Document requestDocument,
180: Document responseDocument) {
181: NodeList postMessageNodes = requestDocument
182: .getDocumentElement().getElementsByTagName(
183: "post-message");
184: if (postMessageNodes.getLength() == 0) {
185: // Posting not requested.
186: return;
187: }
188:
189: String remoteHost = requestDocument.getDocumentElement()
190: .getAttribute("remote-host");
191:
192: Element postMessageElement = (Element) postMessageNodes.item(0);
193: String userName = postMessageElement.getAttribute("user-name");
194: String authToken = postMessageElement
195: .getAttribute("auth-token");
196: NodeList postMessageContentNodes = postMessageElement
197: .getChildNodes();
198: int length = postMessageContentNodes.getLength();
199: for (int i = 0; i < length; ++i) {
200: if (postMessageContentNodes.item(i) instanceof Text) {
201: server.postMessage(userName, authToken, remoteHost,
202: ((Text) postMessageContentNodes.item(i))
203: .getNodeValue());
204: }
205: }
206: }
207:
208: /**
209: * Process a request (if applicable) to add a user to the chat.
210: *
211: * @param requestDocument the request DOM document
212: * @param responseDocument the response DOM document
213: */
214: private void processUserAdd(Document requestDocument,
215: Document responseDocument) {
216: NodeList userAddNodes = requestDocument.getDocumentElement()
217: .getElementsByTagName("user-add");
218: if (userAddNodes.getLength() == 0) {
219: // User add not requested.
220: return;
221: }
222:
223: String remoteHost = requestDocument.getDocumentElement()
224: .getAttribute("remote-host");
225:
226: // Attempt to authenticate.
227: Element userAddElement = (Element) userAddNodes.item(0);
228: String userName = userAddElement.getAttribute("name");
229: String authToken = server.addUser(userName, remoteHost);
230:
231: Element userAuthElement = responseDocument
232: .createElement("user-auth");
233: if (authToken == null) {
234: userAuthElement.setAttribute("failed", "true");
235: } else {
236: userAuthElement.setAttribute("auth-token", authToken);
237: }
238: responseDocument.getDocumentElement().appendChild(
239: userAuthElement);
240: }
241:
242: /**
243: * Process a request (if applicable) to remove a user from the chat.
244: *
245: * @param requestDocument the request DOM document
246: * @param responseDocument the response DOM document
247: */
248: private void processUserRemove(Document requestDocument,
249: Document responseDocument) {
250: NodeList userRemoveNodes = requestDocument.getDocumentElement()
251: .getElementsByTagName("user-remove");
252: if (userRemoveNodes.getLength() == 0) {
253: // User remove not requested.
254: return;
255: }
256:
257: Element userRemoveElement = (Element) userRemoveNodes.item(0);
258: String userName = userRemoveElement.getAttribute("name");
259: String authToken = userRemoveElement.getAttribute("auth-token");
260:
261: String remoteHost = requestDocument.getDocumentElement()
262: .getAttribute("remote-host");
263:
264: server.removeUser(userName, authToken, remoteHost);
265: }
266:
267: /**
268: * Renders the response DOM document to the
269: * <code>HttpServletResponse</code>.
270: *
271: * @param response the outgoing <code>HttpServletResponse</code>
272: * @param responseDocument the response DOM document
273: */
274: private void renderResponseDocument(HttpServletResponse response,
275: Document responseDocument) throws IOException {
276: response.setContentType("text/xml; charset=UTF-8");
277: try {
278: TransformerFactory tFactory = TransformerFactory
279: .newInstance();
280: Transformer transformer = tFactory.newTransformer();
281: DOMSource source = new DOMSource(responseDocument);
282: StreamResult result = new StreamResult(response.getWriter());
283: transformer.transform(source, result);
284: } catch (TransformerException ex) {
285: throw new IOException(
286: "Unable to write document to OutputStream: "
287: + ex.toString());
288: }
289: }
290: }
|