/*
* GISToolkit - Geographical Information System Toolkit
* (C) 2002, Ithaqua Enterprises Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package gistoolkit.server.mapservice;
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
import java.util.Date;
import java.util.Properties;
import gistoolkit.server.UTF8Encoder;
import gistoolkit.server.MapRequest;
import gistoolkit.server.Server;
/**
* Used for reading data coming from the input stream from the client, performing some action, and returning
* the data back to the client via the output stream.
*/
public class ResponseThread extends Thread{
/** Holds a reference to the WebMapService so it's additional facilities can be accessed. Facilities such as logging
* and access to the rest of the system.
*/
private WebMapService myService = null;
/** The socket on which to talk. */
private Socket mySocket = null;
/** Creates new ResponseThread */
public ResponseThread(WebMapService inService, Socket inSocket) {
myService = inService;
mySocket = inSocket;
}
/** Read the data in and write the result out. */
public void run(){
try{
// read from the input socket.
InputStream in = mySocket.getInputStream();
InputStreamReader inr = new InputStreamReader(in);
BufferedReader inbr = new BufferedReader(inr);
OutputStream out = mySocket.getOutputStream();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
// read the input line.
String tempInputLine = inbr.readLine();
StringTokenizer tempStringTokenizer = new StringTokenizer(tempInputLine);
//System.out.println("InputLine = "+tempInputLine);
// read the method used to request this document.
String tempMethod = tempStringTokenizer.nextToken().toUpperCase();
// myService.log("Method = "+tempMethod);
// The rest of the urlline is the next token.
String tempURLLine = tempStringTokenizer.nextToken();
// Don't handle any method except GET and HEAD
if (!tempMethod.equals("GET") && !tempMethod.equals("HEAD") && !tempMethod.equals("POST")) {
showNotHandledMessage(bout, "HTTP/1.0 501 Not Implemented", tempMethod);
}
else{
// find the service name.
String tempServiceName = parseGetServiceName(tempURLLine);
// parse the parameters.
Properties tempProperties = new Properties();
if (tempMethod.equals("POST")){
// parse to the blank line
int tempContentLength = 0;
String tempString = inbr.readLine();
while (tempString.trim().length() > 0){
tempString = inbr.readLine();
if (tempString.trim().toUpperCase().startsWith("CONTENT-LENGTH")){
try{
tempContentLength = Integer.parseInt(tempString.substring(15).trim());
}
catch (NumberFormatException e){
}
}
}
char[] tempLine = new char[tempContentLength];
int tempLength = inbr.read(tempLine);
while (tempLength < tempContentLength){
tempLength = tempLength + inbr.read(tempLine, tempLength, tempContentLength-tempLength);
}
tempString = new String(tempLine);
tempProperties = parsePutProperties(tempString);
}
else tempProperties = parseGetProperties(tempURLLine);
// add the called URLParameter
tempProperties.setProperty(CALLED_URL_PARAMETER,"http://"+myService.getHostName()+":"+myService.getPort()+"/"+tempServiceName);
// get the request.
Request tempRequest = new Request(tempProperties);
// get the response
Response tempResponse = new Response(bout);
// look for the service in the extensions.
ExtensionService tempExtensionService = myService.getExtensionService(tempServiceName);
if (tempExtensionService != null){
executeExtension(tempExtensionService, tempRequest, tempResponse);
}
else{
// if the value is DTD, then return the DTD of for the version.
if (tempServiceName.equals("DTD")){
handleDTDRequest(tempRequest, tempResponse);
}
// try to find the Service, and return the response.
else if (myService.hasService(tempServiceName)){
try{
tempProperties.setProperty(SERVICE_NAME_PARAMETER, tempServiceName);
handleMapRequest(tempRequest, tempResponse);
}
catch (Exception e){
showException(tempRequest, tempResponse, e);
}
}
else{
showServiceNotFound(tempRequest, tempResponse, tempServiceName);
}
}
// send the response to the Client
String tempContentType = tempResponse.getContentType();
PrintWriter tempPrintWriter = tempResponse.getWriter();
// tempPrintWriter.flush();
tempPrintWriter.close();
bout.close();
byte[] tempData= bout.toByteArray();
tempPrintWriter = new PrintWriter(out);
tempPrintWriter.println("HTTP/1.0 200 OK");
tempPrintWriter.println("Server: HPHttp 1.0");
tempPrintWriter.println("Date: " + new Date());
tempPrintWriter.println("Content-type: " + tempContentType);
tempPrintWriter.println("Content-length: " + tempData.length);
tempPrintWriter.println();
// tempPrintWriter.flush();
if (tempMethod.equals("GET")||tempMethod.equals("POST")) {
out.write(tempData);
// out.flush();
}
}
// flush the PrintWriter and close.
// out.flush();
out.close();
mySocket.close();
}
catch (Throwable t){
if (myService != null) myService.log(t);
// more than likely the socket was not closed.
if (mySocket != null) try{mySocket.close();}catch(Exception e){}
}
if (myService != null) myService.removeResponseThread(this);
}
public static final String SERVICE_NAME_PARAMETER="SERVICENAME";
public static final String CALLED_URL_PARAMETER="CALLED_URL";
/** Retrieves the name of the service from the get reqest input line. */
private String parseGetServiceName(String inLine){
// if the line is null then return null, garbage in, garbage out.
if (inLine == null) return inLine;
// check for the end of the url string
if (inLine.endsWith("/")) return myService.getDefaultServiceName();
// parse this service name out of the URL.
int tempIndex = inLine.indexOf("?");
if (tempIndex != -1){
if (inLine.charAt(0) == '/') return inLine.substring(1, tempIndex);
return inLine.substring(0, tempIndex);
}
// there are no parameters, so just return the input line.
if (inLine.charAt(0) == '/') return inLine.substring(1);
return inLine;
}
/** Retrieves the parameters from a get request imput line. */
private Properties parseGetProperties(String inLine){
Properties tempProperties = new Properties();
if (inLine != null){
// parse the parameters of the request.
int tempIndex = inLine.indexOf("?");
if (tempIndex != -1){
StringTokenizer st = new StringTokenizer(inLine.substring(tempIndex+1));
String tempServiceName = inLine.substring(0, tempIndex);
while (st.hasMoreElements()){
String tempGroup = st.nextToken("&");
tempIndex = tempGroup.indexOf('=');
if (tempIndex != -1){
String tempName = UTF8Encoder.decode(tempGroup.substring(0, tempIndex));
String tempValue = UTF8Encoder.decode(tempGroup.substring(tempIndex+1));
tempProperties.setProperty(tempName.toUpperCase(), tempValue);
//myService.log("Key = "+tempName+" Value = "+tempValue);
}
}
}
}
return tempProperties;
}
/** Retrieves the parameters from a put request imput line. */
private Properties parsePutProperties(String inLine){
Properties tempProperties = new Properties();
if (inLine != null){
// parse the parameters of the request.
StringTokenizer st = new StringTokenizer(inLine);
while (st.hasMoreElements()){
String tempGroup = st.nextToken("&");
int tempIndex = tempGroup.indexOf('=');
if (tempIndex != -1){
String tempName = UTF8Encoder.decode(tempGroup.substring(0, tempIndex));
String tempValue = UTF8Encoder.decode(tempGroup.substring(tempIndex+1));
tempProperties.setProperty(tempName.toUpperCase(), tempValue);
//myService.log("Key = "+tempName+" Value = "+tempValue);
}
}
}
return tempProperties;
}
/** Execute the extension services. */
private void executeExtension(ExtensionService inExtensionService, Request inRequest, Response inResponse){
// call the service
try{
inExtensionService.setServer(myService.getServer());
inExtensionService.doGet(inRequest, inResponse);
}
catch (Throwable e){
System.out.println(""+e);
inResponse.setContentType("text/plain");
PrintWriter out = inResponse.getWriter();
out.println(e);
e.printStackTrace(out);
}
}
/** Handle the map request. */
private void handleMapRequest(Request inRequest, Response inResponse) throws Exception{
// find the version
String tempVersion = inRequest.getParameter("VERSION");
if (tempVersion == null) tempVersion = inRequest.getParameter("WMTVER");
// check for the 1.1.1 version
OGCParser tempParser = null;
if ((tempVersion == null) || (tempVersion.equalsIgnoreCase("1.1.1"))){
tempParser = new OGC1_1_1Parser();
}
else if (tempVersion.equalsIgnoreCase("1.1.0")){
tempParser = new OGC1_1_0Parser();
}
else if (tempVersion.equalsIgnoreCase("1.0.0")){
tempParser = new OGC1_0_0Parser();
}
else tempParser = new OGC1_1_1Parser();
// find the service within the server.
Server tempServer = myService.getServer();
// generate the result.
tempParser.getRequest(inRequest, inResponse, tempServer);
}
/** Handle the DTD request. */
private void handleDTDRequest(Request inRequest, Response inResponse) throws Exception{
// find the version
String tempVersion = inRequest.getParameter("VERSION");
if (tempVersion == null) tempVersion = inRequest.getParameter("WMTVER");
// check for the 1.1.1 version
OGCParser tempParser = null;
String tempName = "capabilities_1_1_1.dtd";
if ((tempVersion == null) || (tempVersion.equalsIgnoreCase("1.1.1"))){
tempName = "capabilities_1_1_1.dtd";
}
else if (tempVersion.equalsIgnoreCase("1.1.0")){
tempName = "capabilities_1_1_0.dtd";
}
else if (tempVersion.equalsIgnoreCase("1.0.0")){
tempName = "capabilities_1_0_0.dtd";
}
InputStream in = getResourceStream(tempName);
if (in == null) return;
inResponse.setContentType("text/xml");
try {
int bufflen = 100;
byte[] buff = new byte[bufflen];
OutputStream out = inResponse.getOutputStream();
int length = 0;
do {
length = in.read(buff);
if (length != -1)
out.write(buff, 0, length);
}
while (length != -1);
}
catch (Exception exc) {
System.out.println(exc + " getting resource " + tempName);
}
in.close();
}
private InputStream getResourceStream(String inFileName){
InputStream in = getClass().getResourceAsStream(inFileName);
if (in == null) {
String tempClass = this.getClass().getPackage().getName();
tempClass = tempClass.replace('.','/');
in = ClassLoader.getSystemResourceAsStream(tempClass+"/"+inFileName);
if (in == null) System.out.println("Resource "+inFileName+" Not Found");
}
return in;
}
/**
* Get a HTTP response for this message.
* This method is called before any of the support stuff is in place, so it has to have the other data as well.
*/
private void showNotHandledMessage(OutputStream inOut, String inMessage, String inMethod) throws Exception{
StringBuffer sb = new StringBuffer(inMessage);
sb.append("Server: HPHttp 1.0");
sb.append("\n");
sb.append("Date: ");
sb.append(new Date().toString());
sb.append("\n");
sb.append("Content-Type: text/html");
sb.append("\n");
sb.append("<HTML>");
sb.append("\n");
sb.append("<HEAD><TITLE>Not Implemented</TITLE>");
sb.append("</HEAD>");
sb.append("\n");
sb.append("<BODY>");
sb.append("\n");
sb.append("<H2>");
sb.append(inMessage);
sb.append(": ");
sb.append(inMethod);
sb.append(" method. </H2>");
sb.append("\n");
sb.append("</BODY></HTML>");
String tempData = sb.toString();
inOut.write(tempData.getBytes());
inOut.flush();
}
/** Show the error message "Service not found" to the client.*/
private void showServiceNotFound(Request inRequest, Response inResponse, String inServiceName){
PrintWriter out = inResponse.getWriter();
out.println("<HTML>");
out.println("<HEAD>");
out.println("<TITLE>Service Not Found</TITLE>");
out.println("</HEAD>");
out.println("<BODY>");
out.println("<H2>");
out.println("The service "+inServiceName+" was not found on this server.");
out.println("</H2>");
out.println("</BODY>");
out.println("</HTML>");
}
/** An exception occured, show the nasty exception information to the client. */
private void showException(Request inRequest, Response inResponse, Exception e){
PrintWriter out = inResponse.getWriter();
out.println("<HTML>");
out.println("<HEAD>");
out.println("<TITLE> Error:"+e.getMessage()+"</TITLE>");
out.println("</HEAD>");
out.println("<BODY>");
out.print(" <H2>");
if ((e.getMessage() == null) || (e.getMessage().trim().length() == 0)){
out.print(e.toString());
}
else{
out.print(e.getMessage());
}
out.println("</H2>");
e.printStackTrace(out);
out.println("");
out.println("</BODY>");
out.println("</HTML>");
}
/** Create the map request given the request, and return it. */
public static MapRequest getMapRequest(Request inRequest) throws Exception{
// find the version
String tempVersion = inRequest.getParameter("VERSION");
if (tempVersion == null) tempVersion = inRequest.getParameter("WMTVER");
MapRequest tempRequest = null;
// check for the 1.1.1 version
if ((tempVersion == null) || (tempVersion.equalsIgnoreCase("1.1.1"))){
OGCParser tempParser = new OGC1_1_1Parser();
tempRequest = tempParser.getMapRequest(inRequest);
}
else if (tempVersion.equalsIgnoreCase("1.1.0")){
OGCParser tempParser = new OGC1_1_0Parser();
tempRequest = tempParser.getMapRequest(inRequest);
}
else if (tempVersion.equalsIgnoreCase("1.0.0")){
OGCParser tempParser = new OGC1_0_0Parser();
tempRequest = tempParser.getMapRequest(inRequest);
}
if (tempRequest == null) throw new Exception ("VERSION or WMTVER Is not found");
else return tempRequest;
}
}