001: /* Copyright 2002, 2003 Elliotte Rusty Harold
002:
003: This library is free software; you can redistribute it and/or modify
004: it under the terms of version 2.1 of the GNU Lesser General Public
005: License as published by the Free Software Foundation.
006:
007: This library is distributed in the hope that it will be useful,
008: but WITHOUT ANY WARRANTY; without even the implied warranty of
009: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: GNU Lesser General Public License for more details.
011:
012: You should have received a copy of the GNU Lesser General Public
013: License along with this library; if not, write to the
014: Free Software Foundation, Inc., 59 Temple Place, Suite 330,
015: Boston, MA 02111-1307 USA
016:
017: You can contact Elliotte Rusty Harold by sending e-mail to
018: elharo@metalab.unc.edu. Please include the word "XOM" in the
019: subject line. The XOM home page is located at http://www.xom.nu/
020: */
021:
022: package nu.xom.samples;
023:
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.math.BigInteger;
028:
029: import javax.servlet.ServletException;
030: import javax.servlet.SingleThreadModel;
031: import javax.servlet.http.HttpServlet;
032: import javax.servlet.http.HttpServletRequest;
033: import javax.servlet.http.HttpServletResponse;
034:
035: import nu.xom.Builder;
036: import nu.xom.Document;
037: import nu.xom.Element;
038: import nu.xom.Serializer;
039: import nu.xom.XMLException;
040:
041: /**
042: * <p>
043: * Demonstrates a servlet that receives and
044: * responds to XML-RPC requests.
045: * </p>
046: *
047: * @author Elliotte Rusty Harold
048: * @version 1.0
049: *
050: */
051: public class FibonacciXOMXMLRPCServlet extends HttpServlet implements
052: SingleThreadModel {
053:
054: // Fault codes
055: public final static int MALFORMED_REQUEST_DOCUMENT = 1;
056: public final static int INVALID_REQUEST_DOCUMENT = 2;
057: public final static int INDEX_MISSING = 3;
058: public final static int NON_POSITIVE_INDEX = 4;
059: public final static int BAD_INTEGER_FORMAT = 5;
060: public final static int UNEXPECTED_PROBLEM = 255;
061:
062: private transient Builder parser;
063:
064: // Load a parser, transformer, and implementation
065: public void init() throws ServletException {
066:
067: try {
068: this .parser = new Builder();
069: } catch (Exception ex) {
070: throw new ServletException(
071: "Could not locate a JAXP parser", ex);
072: }
073:
074: }
075:
076: // Respond to an XML-RPC request
077: public void doPost(HttpServletRequest servletRequest,
078: HttpServletResponse servletResponse)
079: throws ServletException, IOException {
080:
081: servletResponse
082: .setContentType("application/xml; charset=UTF-8");
083: OutputStream out = servletResponse.getOutputStream();
084: InputStream in = servletRequest.getInputStream();
085:
086: Document request;
087: Document response;
088: try {
089: request = parser.build(in);
090: Element methodCall = request.getRootElement();
091: Element params = methodCall.getFirstChildElement("params");
092: String generations = params.getValue().trim();
093: int numberOfGenerations = Integer.parseInt(generations);
094: BigInteger result = calculateFibonacci(numberOfGenerations);
095: response = makeResponseDocument(result);
096: } catch (XMLException ex) {
097: response = makeFaultDocument(MALFORMED_REQUEST_DOCUMENT, ex
098: .getMessage());
099: } catch (NullPointerException ex) {
100: response = makeFaultDocument(INDEX_MISSING, ex.getMessage());
101: } catch (NumberFormatException ex) {
102: response = makeFaultDocument(BAD_INTEGER_FORMAT, ex
103: .getMessage());
104: } catch (Exception ex) {
105: response = makeFaultDocument(UNEXPECTED_PROBLEM, ex
106: .getMessage());
107: }
108:
109: // Transform onto the OutputStream
110: try {
111: Serializer output = new Serializer(out, "US-ASCII");
112: output.write(response);
113: servletResponse.flushBuffer();
114: out.flush();
115: } catch (Exception ex) {
116: // If we get an exception at this point, it's too late to
117: // switch over to an XML-RPC fault.
118: throw new ServletException(ex);
119: }
120:
121: }
122:
123: // If performance is an issue, this could be pre-built in the
124: // init() method and then cached. You'd just change one text
125: // node each time. This would only work in a SingleThreadModel
126: // servlet.
127: public Document makeResponseDocument(BigInteger result) {
128:
129: Element methodResponse = new Element("methodResponse");
130: Element params = new Element("params");
131: Element param = new Element("param");
132: Element value = new Element("value");
133: Element doubleElement = new Element("double");
134:
135: methodResponse.appendChild(params);
136: params.appendChild(param);
137: param.appendChild(value);
138: value.appendChild(doubleElement);
139: doubleElement.appendChild(result.toString());
140:
141: return new Document(methodResponse);
142:
143: }
144:
145: public Document makeFaultDocument(int faultCode, String faultString) {
146:
147: Element methodResponse = new Element("methodResponse");
148:
149: Element fault = new Element("fault");
150: Element value = new Element("value");
151: Element struct = new Element("struct");
152: Element memberCode = new Element("member");
153: Element nameCode = new Element("name");
154: Element valueCode = new Element("value");
155: Element intCode = new Element("int");
156: Element memberString = new Element("member");
157: Element valueString = new Element("value");
158: Element stringString = new Element("string");
159:
160: methodResponse.appendChild(fault);
161: fault.appendChild(value);
162: value.appendChild(struct);
163: struct.appendChild(memberCode);
164: struct.appendChild(memberString);
165: memberCode.appendChild(nameCode);
166: memberCode.appendChild(valueCode);
167: memberString.appendChild("name");
168: memberString.appendChild(valueString);
169: nameCode.appendChild("faultCode");
170: valueCode.appendChild(intCode);
171: valueString.appendChild(stringString);
172: intCode.appendChild(String.valueOf(faultCode));
173: stringString.appendChild(faultString);
174:
175: Document faultDoc = new Document(methodResponse);
176:
177: return faultDoc;
178:
179: }
180:
181: public static BigInteger calculateFibonacci(int generations)
182: throws IndexOutOfBoundsException {
183:
184: if (generations < 1) {
185: throw new IndexOutOfBoundsException(
186: "Fibonacci numbers are not defined for "
187: + generations
188: + "or any other number less than one.");
189: }
190: BigInteger low = BigInteger.ONE;
191: BigInteger high = BigInteger.ONE;
192: for (int i = 2; i <= generations; i++) {
193: BigInteger temp = high;
194: high = high.add(low);
195: low = temp;
196: }
197: return low;
198:
199: }
200:
201: }
|