diff --git a/appengine/.classpath b/appengine/.classpath
new file mode 100644
index 000000000..cc1ca7b80
--- /dev/null
+++ b/appengine/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/appengine/.externalToolBuilders/com.google.appengine.eclipse.core.projectValidator.launch b/appengine/.externalToolBuilders/com.google.appengine.eclipse.core.projectValidator.launch
new file mode 100644
index 000000000..3a3b1b194
--- /dev/null
+++ b/appengine/.externalToolBuilders/com.google.appengine.eclipse.core.projectValidator.launch
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/appengine/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator.launch b/appengine/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator.launch
new file mode 100644
index 000000000..eb4252719
--- /dev/null
+++ b/appengine/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator.launch
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/appengine/.project b/appengine/.project
new file mode 100644
index 000000000..c7fc93149
--- /dev/null
+++ b/appengine/.project
@@ -0,0 +1,43 @@
+
+
+ gridworks appengine
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator.launch
+
+
+
+
+ com.google.appengine.eclipse.core.enhancerbuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/com.google.appengine.eclipse.core.projectValidator.launch
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ com.google.appengine.eclipse.core.gaeNature
+
+
diff --git a/appengine/.settings/com.google.appengine.eclipse.core.prefs b/appengine/.settings/com.google.appengine.eclipse.core.prefs
new file mode 100644
index 000000000..b727dd4d9
--- /dev/null
+++ b/appengine/.settings/com.google.appengine.eclipse.core.prefs
@@ -0,0 +1,3 @@
+#Wed May 26 15:13:15 PDT 2010
+eclipse.preferences.version=1
+validationExclusions=src/com/metaweb/gridworks/appengine/*ClientConnection*.java
diff --git a/appengine/.settings/com.google.gdt.eclipse.core.prefs b/appengine/.settings/com.google.gdt.eclipse.core.prefs
new file mode 100644
index 000000000..a060470b7
--- /dev/null
+++ b/appengine/.settings/com.google.gdt.eclipse.core.prefs
@@ -0,0 +1,5 @@
+#Wed May 26 15:11:38 PDT 2010
+eclipse.preferences.version=1
+jarsExcludedFromWebInfLib=
+warSrcDir=
+warSrcDirIsOutput=true
diff --git a/appengine/lib/slf4j-jdk14-1.5.6.jar b/appengine/lib/slf4j-jdk14-1.5.6.jar
new file mode 100644
index 000000000..1ce0a28e7
Binary files /dev/null and b/appengine/lib/slf4j-jdk14-1.5.6.jar differ
diff --git a/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnection.java b/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnection.java
new file mode 100644
index 000000000..9f0effa08
--- /dev/null
+++ b/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnection.java
@@ -0,0 +1,243 @@
+package com.metaweb.gridworks.appengine;
+
+import static com.google.appengine.api.urlfetch.FetchOptions.Builder.allowTruncate;
+
+import java.io.ByteArrayOutputStream;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.Header;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+
+import com.google.appengine.api.urlfetch.HTTPHeader;
+import com.google.appengine.api.urlfetch.HTTPMethod;
+import com.google.appengine.api.urlfetch.HTTPRequest;
+import com.google.appengine.api.urlfetch.HTTPResponse;
+import com.google.appengine.api.urlfetch.URLFetchService;
+import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
+
+class AppEngineClientConnection implements ManagedClientConnection {
+ // Managed is the composition of ConnectionReleaseTrigger,
+ // HttpClientConnection, HttpConnection, HttpInetConnection
+
+ private HttpRoute _route;
+ private Object _state;
+ private boolean _reuseable;
+
+ public AppEngineClientConnection(HttpRoute route, Object state) {
+ _route = route;
+ _state = state;
+ }
+
+ // ManagedClientConnection methods
+
+ public HttpRoute getRoute() {
+ return _route;
+ }
+
+ public Object getState() {
+ return _state;
+ }
+
+ public SSLSession getSSLSession() {
+ return null;
+ }
+
+ public boolean isSecure() {
+ // XXX maybe parse the url to see if it's https?
+ return false;
+ }
+
+ public boolean isMarkedReusable() {
+ return _reuseable;
+ }
+
+ public void markReusable() {
+ _reuseable = true;
+ }
+
+ public void layerProtocol(HttpContext context, HttpParams params) {
+ return;
+ }
+
+ public void open(HttpRoute route, HttpContext context, HttpParams params) {
+ return;
+ }
+
+ public void setIdleDuration(long duration, TimeUnit unit) {
+ return;
+ }
+
+ public void setState(Object state) {
+ _state = state;
+ }
+
+ public void tunnelProxy(HttpHost next, boolean secure, HttpParams params) {
+ return;
+ }
+
+ public void tunnelTarget(boolean secure, HttpParams params) {
+ return;
+ }
+
+ public void unmarkReusable() {
+ _reuseable = false;
+ }
+
+
+ // ConnectionReleaseTrigger methods
+
+ public void releaseConnection() {
+ return;
+ }
+
+ public void abortConnection() {
+ return;
+ }
+
+ // HttpClientConnection methods
+
+ private HTTPRequest _appengine_hrequest;
+ private HTTPResponse _appengine_hresponse;
+
+ public void flush() {
+ return;
+ }
+
+ public boolean isResponseAvailable(int timeout) {
+ // XXX possibly use Async fetcher
+ return true;
+ }
+
+ public void receiveResponseEntity(org.apache.http.HttpResponse apache_response) {
+ byte[] data = _appengine_hresponse.getContent();
+
+ if (data != null) {
+ apache_response.setEntity(new ByteArrayEntity(data));
+ }
+ }
+
+ public HttpResponse receiveResponseHeader() {
+ URLFetchService ufs = URLFetchServiceFactory.getURLFetchService();
+ try {
+ _appengine_hresponse = ufs.fetch(_appengine_hrequest);
+ } catch (java.io.IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ org.apache.http.HttpResponse apache_response =
+ new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 0),
+ _appengine_hresponse.getResponseCode(),
+ null);
+
+ for (HTTPHeader h : _appengine_hresponse.getHeaders()) {
+ apache_response.addHeader(h.getName(), h.getValue());
+ }
+
+ return apache_response;
+ }
+
+ public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest request) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ org.apache.http.HttpEntity ent = request.getEntity();
+ if (ent != null) {
+ try {
+ ent.writeTo(os);
+ } catch (java.io.IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ _appengine_hrequest.setPayload(os.toByteArray());
+ }
+
+ public void sendRequestHeader(org.apache.http.HttpRequest apache_request) {
+ URL request_url;
+
+ HttpHost host = _route.getTargetHost();
+
+ String protocol = host.getSchemeName();
+ String addr = host.getHostName();
+ int port = host.getPort();
+
+ String path = apache_request.getRequestLine().getUri();
+
+ try {
+ request_url = new URL(protocol, addr, port, path);
+ } catch (java.net.MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+
+ HTTPMethod method = HTTPMethod.valueOf(apache_request.getRequestLine().getMethod());
+ _appengine_hrequest = new HTTPRequest(request_url, method, allowTruncate()
+ .doNotFollowRedirects());
+
+ Header[] apache_headers = apache_request.getAllHeaders();
+ for (int i = 0; i < apache_headers.length; i++) {
+ Header h = apache_headers[i];
+ _appengine_hrequest
+ .setHeader(new HTTPHeader(h.getName(), h.getValue()));
+ }
+ }
+
+ // HttpConnection methods
+
+ public void close() {
+ return;
+ }
+
+ public HttpConnectionMetrics getMetrics() {
+ return null;
+ }
+
+ public int getSocketTimeout() {
+ return -1;
+ }
+
+ public boolean isOpen() {
+ return true;
+ }
+
+ public boolean isStale() {
+ return false;
+ }
+
+ public void setSocketTimeout(int timeout) {
+ return;
+ }
+
+ public void shutdown() {
+ return;
+ }
+
+ // HttpInetConnection methods
+
+ public InetAddress getLocalAddress() {
+ return null;
+ }
+
+ public int getLocalPort() {
+ return -1;
+ }
+
+ public InetAddress getRemoteAddress() {
+ return null;
+ }
+
+ public int getRemotePort() {
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnectionManager.java b/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnectionManager.java
new file mode 100644
index 000000000..9bbc1e9f4
--- /dev/null
+++ b/appengine/src/com/metaweb/gridworks/appengine/AppEngineClientConnectionManager.java
@@ -0,0 +1,83 @@
+package com.metaweb.gridworks.appengine;
+
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ClientConnectionRequest;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.scheme.SocketFactory;
+import org.apache.http.params.HttpParams;
+
+public class AppEngineClientConnectionManager implements ClientConnectionManager {
+ private SchemeRegistry schemes;
+
+ class NoopSocketFactory implements SocketFactory {
+ public Socket connectSocket(Socket sock, String host, int port,
+ InetAddress addr, int lport,
+ HttpParams params) {
+ return null;
+ }
+
+ public Socket createSocket() {
+ return null;
+ }
+
+ public boolean isSecure(Socket sock) {
+ return false;
+ }
+ }
+
+ public AppEngineClientConnectionManager() {
+ SocketFactory noop_sf = new NoopSocketFactory();
+
+ schemes = new SchemeRegistry();
+ schemes.register(new Scheme("http", noop_sf, 80));
+ schemes.register(new Scheme("https", noop_sf, 443));
+ }
+
+ public void closeExpiredConnections() {
+ return;
+ }
+
+ public void closeIdleConnections(long idletime, TimeUnit tunit) {
+ return;
+ }
+
+ public ManagedClientConnection getConnection(HttpRoute route, Object state) {
+ return new AppEngineClientConnection(route, state);
+ }
+
+ public SchemeRegistry getSchemeRegistry() {
+ return schemes;
+ }
+
+ public void releaseConnection(ManagedClientConnection conn,
+ long valid, TimeUnit tuint) {
+ return;
+ }
+
+ public ClientConnectionRequest requestConnection(final HttpRoute route,
+ final Object state) {
+ return new ClientConnectionRequest() {
+ public void abortRequest() {
+ return;
+ }
+
+ public ManagedClientConnection getConnection(long idletime,
+ TimeUnit tunit) {
+
+ return AppEngineClientConnectionManager.this.getConnection(route, state);
+ }
+ };
+ }
+
+ public void shutdown() {
+ return;
+ }
+}
+