Fibonacci Thread
import java.net.*;
import java.io.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.apache.xerces.parsers.*;
import java.util.*;
import java.math.*;
public class FibonacciGenerator implements Runnable {
Socket client;
public FibonacciGenerator(Socket client) {
this.client = client;
}
public void run() {
try {
InputStream in = client.getInputStream();
Writer out = new OutputStreamWriter(client.getOutputStream(), "UTF-8");
// We don't really care about the HTTP header so read and discard it.
// Blank line ends the headers. BufferedReader would be easier
// but I don't want to commit to an encoding just yet.
// Furthermore it's buggy.
boolean done = false;
while (!done) {
int c = in.read();
switch (c) {
case '\r':
c = in.read();
if (c == '\r') {
done = true;
}
else if (c == '\n') {
int c1 = in.read();
int c2 = in.read();
if (c1 == '\r' && c2 == '\n') done = true;
}
continue;
case '\n':
c = in.read();
if (c == '\n') done = true;
continue;
case -1:
fault("Unexpected End of Stream", 2);
return;
default:
continue;
}
}
InputSource source = new InputSource(in);
DOMParser parser = new DOMParser();
parser.parse(source);
Document document = parser.getDocument();
// Example invocation
/*
<?xml version="1.0"?>
<methodCall>
<methodName>getFibonacci</methodName>
<params>
<param>
<value><i4>4</i4></value>
</param>
</params>
</methodCall>
*/
Element methodCall = document.getDocumentElement();
if (!methodCall.getTagName().equals("methodCall")) {
fault("Root element must be methodCall", 1);
return;
}
NodeList methodNames = methodCall.getElementsByTagName("methodName");
if (methodNames.getLength() != 1) {
fault("There must be exactly one method name element", 1);
return;
}
Node methodName = methodNames.item(0).getFirstChild();
if (methodName == null || methodName.getNodeType() != Node.TEXT_NODE ) {
fault("No method name", 1);
return;
}
Text methodNameText = (Text) methodName;
if (!methodNameText.getData().trim().equals("Fibonacci")) {
fault("Unrecognized method name: " + methodNameText.getData(), 1);
return;
}
NodeList paramsList = methodCall.getElementsByTagName("params");
if (paramsList.getLength() != 1) {
fault("There must be exactly one params element", 1);
return;
}
Element params = (Element) paramsList.item(0);
NodeList paramList = params.getElementsByTagName("param");
if (paramList.getLength() != 1) {
fault("There must be exactly one param element", 1);
return;
}
Element param = (Element) paramList.item(0);
NodeList valueList = param.getElementsByTagName("value");
if (valueList.getLength() != 1) {
fault("There must be exactly one value element", 1);
return;
}
Element value = (Element) valueList.item(0);
NodeList intList = value.getChildNodes();
if (intList.getLength() != 1) {
fault("There must be exactly one int or i4 element", 1);
return;
}
String intString = intList.item(0).getFirstChild().getNodeValue();
System.out.println("Int string: " + intString);
int index = 0;
try {
index = Integer.parseInt(intString);
}
catch(NumberFormatException e) {
fault("Contents of " + intList.item(0).getNodeName() + " are not an integer.", 1);
return;
}
// finally we're ready to calculate the Fibonacci number
BigInteger fibonacci = calculateFibonacci(index);
// now write out the result
String result ="<?xml version=\"1.0\"?>\r\n"
+ "<methodResponse>\r\n"
+ " <params>\r\n"
+ " <param>\r\n"
+ " <value><string>" + fibonacci + "</string></value>"
+ " </param>\r\n"
+ " </params>\r\n"
+ "</methodResponse>\r\n";
out.write("HTTP/1.1 200 OK\r\n");
out.write("Connection: close\r\n");
out.write("Content-Type: text/xml\r\n");
out.write("Content-length: " + result.length() + "\r\n");
out.write("Date: " + (new Date()).toString() + "\r\n");
out.write("\r\n");
out.write(result);
out.flush();
client.close();
}
catch (SAXException e) {
System.err.println(e);
}
catch (IOException e) {
System.err.println(e);
}
}
private void fault(String errorMessage, int code)
throws IOException {
System.out.println("Fault: " + errorMessage);
String response = "<?xml version=\"1.0\"?>\r\n"
+ "<methodResponse>\r\n"
+ " <fault>\r\n"
+ " <value>\r\n"
+ " <struct>\r\n"
+ " <member>\r\n"
+ " <name>faultCode</name>\r\n"
+ " <value><int>" + code + "</int></value>\r\n"
+ " </member>\r\n"
+ " <member>\r\n"
+ " <name>faultString</name>\r\n"
+ " <value><string>" + errorMessage + "</string></value>\r\n"
+ " </member>\r\n"
+ " </struct>\r\n"
+ " </value>\r\n"
+ " </fault>\r\n"
+ "</methodResponse>\r\n";
String header = "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: " + response.length() + "\r\n"
+ "Content-Type: text/xml\r\n"
+ "Date: " + new Date() + "\r\n";
System.out.println(header);
System.out.println();
System.out.flush();
Writer out = new OutputStreamWriter(client.getOutputStream(), "UTF-8");
System.out.println(response);
out.write(header);
out.write("\r\n");
out.write(response);
out.flush();
client.close();
}
private static Vector cache = new Vector();
public static BigInteger calculateFibonacci(int index) {
if (index < 0) {
throw new IllegalArgumentException("Index must be non-negative");
}
BigInteger low = BigInteger.ZERO;
BigInteger high = BigInteger.ONE;
for (int i = 0; i <= index; i++) {
BigInteger temp = high;
high = high.add(low);
low = temp;
}
return low;
}
}