Skip to content

Commit

Permalink
THRIFT-893 JavaScript Tutorial: dynamic part
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1030018 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
bufferoverflow committed Nov 2, 2010
1 parent a8b52c7 commit e5e50de
Show file tree
Hide file tree
Showing 3 changed files with 381 additions and 5 deletions.
77 changes: 77 additions & 0 deletions tutorial/js/build.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<project name="tutorial" default="test" basedir=".">

<description>Thrift JavaScript Tutorial</description>

<property name="src" location="src" />
<property name="javasrc" location="../java/src" />
<property name="gen" location="../gen-java" />
<property name="build" location="build" />

<!-- the root directory, where you unpack thrift distibution (e.g. thrift-0.x.x.tar.gz) -->
<property name="thrift.dir" location="../../" />
<property name="thrift.java.dir" location="${thrift.dir}/lib/java" />

<path id="libs.classpath">
<pathelement path="${thrift.java.dir}/libthrift.jar" />
<fileset dir="${thrift.java.dir}/build/ivy/lib">
<include name="*.jar" />
</fileset>
</path>
<path id="build.classpath">
<path refid="libs.classpath" />
<pathelement path="${gen}" />
<pathelement path="${build}" />
</path>

<target name="init">
<tstamp />
<mkdir dir="${build}"/>
</target>

<target name="compile" depends="init">
<javac srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
<javac srcdir="${javasrc}" destdir="${build}" classpathref="build.classpath">
<exclude name="JavaClient.java"/>
<exclude name="JavaServer.java"/>
<include name="CalculatorHandler.java"/>
</javac>
<javac srcdir="${src}" destdir="${build}" classpathref="build.classpath">
<compilerarg value="-Xlint:all"/>
</javac>
</target>

<target name="tutorial" depends="compile">
<jar jarfile="tutorial-js.jar" basedir="${build}"/>
</target>

<target name="test" description="run the test server" depends="tutorial">
<java classname="Httpd" fork="true"
classpathref="build.classpath" failonerror="true">
<arg value="../../" />
</java>
</target>

<target name="clean">
<delete dir="${build}" />
<delete file="tutorial-js.jar" />
</target>

</project>
299 changes: 299 additions & 0 deletions tutorial/js/src/Httpd.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/

import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.Locale;

import org.apache.http.ConnectionClosedException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpServerConnection;
import org.apache.http.HttpStatus;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.HttpService;
import org.apache.http.util.EntityUtils;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TMemoryBuffer;

// Generated code
import tutorial.*;
import shared.*;

import java.util.HashMap;

/**
* Basic, yet fully functional and spec compliant, HTTP/1.1 file server.
* <p>
* Please note the purpose of this application is demonstrate the usage of
* HttpCore APIs. It is NOT intended to demonstrate the most efficient way of
* building an HTTP file server.
*
*
*/
public class Httpd {

public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Please specify document root directory");
System.exit(1);
}
Thread t = new RequestListenerThread(8088, args[0]);
t.setDaemon(false);
t.start();
}

static class HttpFileHandler implements HttpRequestHandler {

private final String docRoot;

public HttpFileHandler(final String docRoot) {
super();
this.docRoot = docRoot;
}

public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException {

String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
throw new MethodNotSupportedException(method + " method not supported");
}
String target = request.getRequestLine().getUri();

if (request instanceof HttpEntityEnclosingRequest && target.equals("/thrift/service/tutorial/")) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
byte[] entityContent = EntityUtils.toByteArray(entity);
System.out.println("Incoming content: " + new String(entityContent));

final String output = this.thriftRequest(entityContent);

System.out.println("Outgoing content: "+output);

EntityTemplate body = new EntityTemplate(new ContentProducer() {

public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write(output);
writer.flush();
}

});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
} else {
final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
if (!file.exists()) {

response.setStatusCode(HttpStatus.SC_NOT_FOUND);
EntityTemplate body = new EntityTemplate(new ContentProducer() {

public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("File ");
writer.write(file.getPath());
writer.write(" not found");
writer.write("</h1></body></html>");
writer.flush();
}

});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
System.out.println("File " + file.getPath() + " not found");

} else if (!file.canRead() || file.isDirectory()) {

response.setStatusCode(HttpStatus.SC_FORBIDDEN);
EntityTemplate body = new EntityTemplate(new ContentProducer() {

public void writeTo(final OutputStream outstream) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("Access denied");
writer.write("</h1></body></html>");
writer.flush();
}

});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
System.out.println("Cannot read file " + file.getPath());

} else {

response.setStatusCode(HttpStatus.SC_OK);
FileEntity body = new FileEntity(file, "text/html");
response.setEntity(body);
System.out.println("Serving file " + file.getPath());

}
}
}

private String thriftRequest(byte[] input){
try{

//Input
TMemoryBuffer inbuffer = new TMemoryBuffer(input.length);
inbuffer.write(input);
TProtocol inprotocol = new TJSONProtocol(inbuffer);

//Output
TMemoryBuffer outbuffer = new TMemoryBuffer(100);
TProtocol outprotocol = new TJSONProtocol(outbuffer);

TProcessor processor = new Calculator.Processor(new CalculatorHandler());
processor.process(inprotocol, outprotocol);

byte[] output = new byte[outbuffer.length()];
outbuffer.readAll(output, 0, output.length);

return new String(output,"UTF-8");
}catch(Throwable t){
return "Error:"+t.getMessage();
}


}

}

static class RequestListenerThread extends Thread {

private final ServerSocket serversocket;
private final HttpParams params;
private final HttpService httpService;

public RequestListenerThread(int port, final String docroot) throws IOException {
this.serversocket = new ServerSocket(port);
this.params = new BasicHttpParams();
this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");

// Set up the HTTP protocol processor
HttpProcessor httpproc = new BasicHttpProcessor();

// Set up request handlers
HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
reqistry.register("*", new HttpFileHandler(docroot));

// Set up the HTTP service
this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory());
this.httpService.setParams(this.params);
this.httpService.setHandlerResolver(reqistry);
}

public void run() {
System.out.println("Listening on port " + this.serversocket.getLocalPort());
System.out.println("Point your browser to http://localhost:8088/tutorial/js/tutorial.html");

while (!Thread.interrupted()) {
try {
// Set up HTTP connection
Socket socket = this.serversocket.accept();
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
System.out.println("Incoming connection from " + socket.getInetAddress());
conn.bind(socket, this.params);

// Start worker thread
Thread t = new WorkerThread(this.httpService, conn);
t.setDaemon(true);
t.start();
} catch (InterruptedIOException ex) {
break;
} catch (IOException e) {
System.err.println("I/O error initialising connection thread: " + e.getMessage());
break;
}
}
}
}

static class WorkerThread extends Thread {

private final HttpService httpservice;
private final HttpServerConnection conn;

public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) {
super();
this.httpservice = httpservice;
this.conn = conn;
}

public void run() {
System.out.println("New connection thread");
HttpContext context = new BasicHttpContext(null);
try {
while (!Thread.interrupted() && this.conn.isOpen()) {
this.httpservice.handleRequest(this.conn, context);
}
} catch (ConnectionClosedException ex) {
System.err.println("Client closed connection");
} catch (IOException ex) {
System.err.println("I/O error: " + ex.getMessage());
} catch (HttpException ex) {
System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
} finally {
try {
this.conn.shutdown();
} catch (IOException ignore) {
}
}
}

}

}
10 changes: 5 additions & 5 deletions tutorial/js/tutorial.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Thrift Javascript Bindings - Tutorial Example</title>

<script src="thrift.js" type="text/javascript"></script>
<script src="gen-js/tutorial_types.js" type="text/javascript"></script>
<script src="gen-js/shared_types.js" type="text/javascript"></script>
<script src="gen-js/SharedService.js" type="text/javascript"></script>
<script src="gen-js/Calculator.js" type="text/javascript"></script>
<script src="../../lib/js/thrift.js" type="text/javascript"></script>
<script src="../gen-js/tutorial_types.js" type="text/javascript"></script>
<script src="../gen-js/shared_types.js" type="text/javascript"></script>
<script src="../gen-js/SharedService.js" type="text/javascript"></script>
<script src="../gen-js/Calculator.js" type="text/javascript"></script>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

Expand Down

0 comments on commit e5e50de

Please sign in to comment.