public class

HttpBridge

extends Object
/*
 * Copyright (C) 2010 Stanford University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package edu.stanford.junction.addon;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
/*
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
*/

// temporary to avoid errors, without including HttpServlet as dependency
class ServletInputStream extends InputStream {

	@Override
	public int read() throws IOException {
		// TODO Auto-generated method stub
		return 0;
	}
}

class ServletOutputStream extends OutputStream {

	@Override
	public void write(int b) throws IOException {
		// TODO Auto-generated method stub
		
	}
	
	public void print(String s) {}
	
}

class HttpServletRequest {
	public String getRequestURI() { return null; }
	public String getContentType() { return null; }
	public ServletInputStream getInputStream () { return null; }
}

class HttpServletResponse {
	public void setContentType(String type) {}
	
	
	public ServletOutputStream getOutputStream () { return null; }
}

class HttpServlet {
	protected void doPost(HttpServletRequest req,
			HttpServletResponse resp) {}
	
	protected void doGet(HttpServletRequest req,
			HttpServletResponse resp) {}
	
}

public class HttpBridge extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	// static makes the same hashmap available
	// to all connecting threads.
	
	// remember that a thread is created every time
	// a client connects to our socket.
	static HashMap<String,HttpBridgePair> bridge = 
		new HashMap<String,HttpBridgePair>();

	
	@Override
	protected void doPost(HttpServletRequest req,
			HttpServletResponse resp) {
	
		String uri = req.getRequestURI();
		HttpBridgePair pair;
		if (!bridge.containsKey(uri)) {
			pair = new HttpBridgePair();
			bridge.put(uri, pair);
		} else {
			pair = bridge.get(uri);
		}
		
		if (pair.hasPoster()) {
			// throw error
			return;
		}
		
		pair.setPoster(req, resp);
	}

	@Override
	protected void doGet(HttpServletRequest req,
			HttpServletResponse resp) {
		
		String uri = req.getRequestURI();
		HttpBridgePair pair;
		if (!bridge.containsKey(uri)) {
			pair = new HttpBridgePair();
			bridge.put(uri, pair);
		} else {
			pair = bridge.get(uri);
		}
		
		if (pair.hasGetter()) {
			// throw error
			return;
		}
		
		pair.setGetter(req, resp);
		bridge.remove(uri);
	}
}

class HttpBridgePair {
	final private int BUFFER_SIZE = 2048; // bytes
	private HTTPClientConnection mPoster;
	private HTTPClientConnection mGetter;
	
	public boolean hasGetter() {
		return (mGetter != null);
	}
	
	public boolean hasPoster() {
		return (mPoster != null);
	}
	
	
	public synchronized void setPoster(HttpServletRequest req,
				HttpServletResponse resp) {

		/*
		the req object has an input stream; use getInputStream() to get it.
		Also get the content length as: getContentLength() and type as getContentType().
		*/

		mPoster = new HTTPClientConnection(req,resp);

		System.out.println("Set Poster");
		if(hasGetter()) {
			System.out.println("Poster notifying...");
			this.notify();
		} else {
			while (null == mGetter){
				try {
					System.out.println("Poster waiting...");
					this.wait();
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}
			}
		}

		System.out.println("Poster done waiting");
		// only one side bridges connection:
		bridgeConnections();
	}

	public synchronized void setGetter(HttpServletRequest req,
				HttpServletResponse resp) {
		
		System.out.println("Set Getter");
		mGetter = new HTTPClientConnection(req,resp);
		
		if(hasPoster()) {
			System.out.println("Getter notifying...");
			this.notify();
		} else {
			while (null == mPoster){
				try {
					System.out.println("Getter waiting...");
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		System.out.println("Getter done waiting");
	}

	/**
	 * Does the work of actually bridging our connections,
	 * given a GET and POST request.
	 */
	private void bridgeConnections() {
		// bridge poster.req.getInputStream()
			
		// and
		// getter.resp.getOutputStream()

		//need to get header
		//send other header

		//get InputStream
		//send InputStream

		try{
			String postType = mPoster.request.getContentType();
			//int postLength = mPoster.request.getContentLength();			
						
			ServletInputStream in = mPoster.request.getInputStream();		
			ServletOutputStream out = mGetter.response.getOutputStream();

			if(postType.indexOf("multipart/form-data") == -1){
				//mGetter.response.setContentType("application/pdf");
				int i;
				byte[] buf = new byte[BUFFER_SIZE];
				while(-1 != (i = in.read(buf))) {
					out.write(buf,0,i);
				}
			}
			else{
				StringBuffer line = new StringBuffer();
				StringBuffer preamble = new StringBuffer();
				int i = in.read();
				while(i != -1){
					if((char)i == '\n'){
						String s = line.toString();	
						String CONTENT_TYPE = "Content-Type: ";
						if(s.indexOf(CONTENT_TYPE) != -1){
							String type = s.substring(CONTENT_TYPE.length());
							if(!type.equals("multipart/form-data")){
								mGetter.response.setContentType(type);
								preamble.append((char)i);
								break;
							}
						}
						line = new StringBuffer();
					}
					line.append((char)i);
					preamble.append((char)i);
					i = in.read();
				}
				out.print(preamble.toString());
				
				byte[] buf = new byte[BUFFER_SIZE];
				while(-1 != (i = in.read(buf))) {
					out.write(buf,0,i);
				}
			}
			
			
			
			in.close();
			out.close();

		}
		catch (Exception e)
		{
		//print some type of error here.
		}	
	}
	
	class HTTPClientConnection {
		public HttpServletRequest request;
		public HttpServletResponse response;
		
		public HTTPClientConnection(HttpServletRequest req, HttpServletResponse resp) {
			this.request = req;
			this.response = resp;
		}
	}
}