openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r1028093 [1/2] - in /openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence: ./ jest/
Date Wed, 27 Oct 2010 20:42:45 GMT
Author: ppoddar
Date: Wed Oct 27 20:42:44 2010
New Revision: 1028093

URL: http://svn.apache.org/viewvc?rev=1028093&view=rev
Log:
OPENJPA-1851: First version of JEST (REST on OpenJPA)

Added:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ServerContext.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLEncoder.java   (with props)
Modified:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java?rev=1028093&r1=1028092&r2=1028093&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java Wed Oct 27 20:42:44 2010
@@ -45,10 +45,10 @@ import org.apache.openjpa.lib.util.Close
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
 import org.apache.openjpa.persistence.criteria.OpenJPACriteriaBuilder;
+import org.apache.openjpa.persistence.jest.Server;
 import org.apache.openjpa.persistence.meta.MetamodelImpl;
 import org.apache.openjpa.persistence.query.OpenJPAQueryBuilder;
 import org.apache.openjpa.persistence.query.QueryBuilderImpl;
-import org.apache.openjpa.util.UserException;
 
 /**
  * Implementation of {@link EntityManagerFactory} that acts as a
@@ -70,7 +70,8 @@ public class EntityManagerFactoryImpl
     private transient StoreCache _cache = null;
     private transient QueryResultCache _queryCache = null;
     private transient MetamodelImpl _metaModel;
-    
+    private transient Server _remoteAccess = null;
+
     /**
      * Default constructor provided for auto-instantiation.
      */
@@ -93,10 +94,11 @@ public class EntityManagerFactoryImpl
 
     /**
      * Delegate must be provided before use.
+     * Configures for Remote Access, if appropriate. 
      */
     public void setBrokerFactory(BrokerFactory factory) {
-        _factory = new DelegatingBrokerFactory(factory,
-            PersistenceExceptions.TRANSLATOR);
+        _factory = new DelegatingBrokerFactory(factory, PersistenceExceptions.TRANSLATOR);
+        configureRemoteAccess(getConfiguration());
     }
 
     public OpenJPAConfiguration getConfiguration() {
@@ -271,6 +273,10 @@ public class EntityManagerFactoryImpl
         if (log.isTraceEnabled()) {
             log.trace(this + ".close() invoked.");
         }
+        if (_remoteAccess != null) {
+            _remoteAccess.stop();
+            _remoteAccess = null;
+        }
         _factory.close();
     }
 
@@ -396,4 +402,40 @@ public class EntityManagerFactoryImpl
             }
         }
     }
+    
+    /**
+     * Configures this unit for remote access.
+     */
+    protected void configureRemoteAccess(OpenJPAConfiguration conf) {
+        Value value = conf.getValue("RemoteAccess");
+        if (value == null) {
+            return;
+        }
+        String props = value.getString();
+        if (props == null)
+            return;
+        try {
+            _remoteAccess = new Server();
+            _remoteAccess.setContext(this);
+            Configurations.configureInstance(_remoteAccess, conf, props);
+            conf.removeValue(value);
+            if (!_remoteAccess.start()) {
+                _remoteAccess = null;
+            }
+        } catch (Exception ex) {
+            Log log = _factory.getConfiguration().getLog(OpenJPAConfiguration.LOG_RUNTIME);
+            if (log != null) {
+                log.error(_loc.get("remote-start-error"), ex);
+            }
+        }
+    }
+    
+    /**
+     * Affirms if this unit is accessible remotely.
+     */
+    public boolean allowsRemoteAccess() {
+        return _remoteAccess != null;
+    }
+    
+
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java?rev=1028093&r1=1028092&r2=1028093&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java Wed Oct 27 20:42:44 2010
@@ -188,6 +188,7 @@ public class PersistenceProductDerivatio
         conf.metaFactoryPlugin.setAlias(SPEC_JPA.getName(),  PersistenceMetaDataFactory.class.getName());
         
         conf.addValue(new EntityManagerFactoryValue());
+        conf.addString("RemoteAccess");
         
         conf.readLockLevel.setAlias("optimistic", String.valueOf(MixedLockLevels.LOCK_OPTIMISTIC));
         conf.readLockLevel.setAlias("optimistic-force-increment", String

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java Wed Oct 27 20:42:44 2010
@@ -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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Abstract implementation of a stream-based response.
+ * Every response is result of a {@linkplain Request} and operates within a {@linkplain ServerContext}.
+ * This fact is enforced by the constructor argument of an abstract response.
+ * <p>
+ * Besides, this implementation provides common utility to write HTTP response or extract useful information
+ * from the request.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractResponse extends PrintStream implements Response {
+    protected final Request _request;
+    protected final ServerContext _ctx;
+    
+    /**
+     * Construct a response for the given request and server context.
+     * 
+     * @param request the request for this response. Can be null if the response is for server error.
+     * @param ctx the processing context 
+     * @param out the output stream where the response is targeted.
+     */
+    protected AbstractResponse(Request request, ServerContext ctx, OutputStream out) {
+        super(out);
+        _request = request;
+        _ctx = ctx;
+    }
+    
+    /**
+     * Write a HTTP header to the stream.
+     * <br> 
+     * The format of HTTP header is <code>key: [value]* NEWLINE</code>
+     * 
+     * @param key the key of the header
+     * @param values one of more value of the header fields.
+     */
+    protected void printHeader(String key, String...values) {
+        if (key == null)
+            return;
+        print(key);
+        print(" :");
+        if (values == null || values.length == 0)
+            return;
+        int n = values.length-1;
+        for (int i = 0; i < n-1; i++) {
+            print(values[i]);
+            print(";");
+        }
+        println(values[n]);
+    }
+    
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractResponse.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,68 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+
+/**
+ * A HTTP response for something gone wrong.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class ErrorResponse extends AbstractResponse {
+    private final Exception _error;
+    private final int _code;
+    /**
+     * Construct a response to describe a error.
+     * 
+     * @param request a request that produced this response. VCan be null to denote that the request can not
+     * be created.
+     * @param ctx the processing context
+     * @param ex the error
+     * @param code HTTP error code
+     * @param out the stream where the response is written
+     * 
+     */
+    public ErrorResponse(Request request, ServerContext ctx, Exception ex, int code, OutputStream out)  {
+        super(request, ctx, out);
+        _error = ex;
+        _code = code;
+    }
+
+    /**
+     * Writes the response. 
+     * The response is always a HTTP response with the error stack trace.
+     */
+    public void writeOut() throws Exception {
+        println("HTTP/1.1"); print(" " + _code); println("Error");
+        printHeader("Connection",  "close");
+        printHeader("Content-Type", "text/html", "charset=UTF-8");
+        println();
+        println("<html><body><pre>");
+        _error.printStackTrace(this);
+        println("Response from JEST");
+        
+        println("</pre></body></html>");
+        close();
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ErrorResponse.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,147 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityNotFoundException;
+import javax.persistence.Query;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.StoreContext;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.util.ApplicationIds;
+import org.apache.openjpa.util.ObjectNotFoundException;
+
+/**
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class GETRequest extends JESTRequest {
+    public Response process(ServerContext server, OutputStream out) throws Exception {
+        String action = getAction();
+        try {
+            if ("find".equals(action)) {
+                return find(server, out);
+            } else {
+                return resource(server, out);
+            }
+        } catch (Exception e) {
+            return new ErrorResponse(this, server, new RuntimeException("bad action " + action), 
+                HttpURLConnection.HTTP_BAD_REQUEST, out);
+        }
+    }
+    
+    Response find(ServerContext server, OutputStream out)  throws Exception {
+        EntityManager em = server.getPersistenceUnit().createEntityManager();
+        Map<String, String> qualifiers = getQualifiers();
+        Map<String, String> parameters = getParameters();
+        if (parameters.size() < 2)
+            throw new IllegalArgumentException("find must have at least two parameters");
+        Object[] pks = new Object[parameters.size()-1];
+        Iterator<Map.Entry<String,String>> params = parameters.entrySet().iterator();
+        String alias = null;
+        for (int i = 0; i < parameters.size(); i++) {
+            if (i == 0) {
+                alias = params.next().getKey();
+            } else {
+                pks[i-1] = params.next().getKey();
+            }
+        }
+        ClassMetaData meta = server.resolve(alias);
+        Object oid = ApplicationIds.fromPKValues(pks, meta);
+        Object pc = em.find(meta.getDescribedType(), oid); 
+        if (pc != null) {
+            OpenJPAStateManager sm = ((StoreContext)JPAFacadeHelper.toBroker(em)).getStateManager(pc);
+            return new JESTResponse(this, server, sm, out);
+        } else {
+            return new ErrorResponse(this, server, new EntityNotFoundException("not found!"), 
+                HttpURLConnection.HTTP_NOT_FOUND, out);
+        }
+    }
+    
+    Response query(ServerContext server, OutputStream out)  throws Exception {
+        EntityManager em = server.getPersistenceUnit().createEntityManager();
+        Map<String, String> qualifiers = getQualifiers();
+        boolean named = isBooleanQualifier("named");
+        boolean single = isBooleanQualifier("single");
+        Map<String, String> parameters = getParameters();
+        if (parameters.size() < 1)
+            throw new IllegalArgumentException("find must have at least one parameter");
+        Iterator<Map.Entry<String,String>> params = parameters.entrySet().iterator();
+        Query query = null;
+        int i = 0;
+        for (Map.Entry<String, String> param : parameters.entrySet()) {
+            if (i == 0) {
+                query = named ? em.createQuery(param.getKey()) : em.createNamedQuery(param.getKey());
+            } else {
+                query.setParameter(param.getKey(), param.getValue());
+            }
+        }
+        if (single) {
+            Object result = query.getSingleResult();
+            OpenJPAStateManager sm = ((StoreContext)JPAFacadeHelper.toBroker(em)).getStateManager(result);
+            return new JESTResponse(this, server, sm, out);
+        } else {
+            List<Object> result = query.getResultList();
+            return new ErrorResponse(this, server, new EntityNotFoundException("not found!"), 404, out);
+        }
+    }
+    
+    Response resource(ServerContext server, OutputStream out)  throws Exception {
+        String resource = getAction();
+        if (resource.length() == 0)
+            resource = "index.html";
+        String mimeType = getMimeType(resource);
+//        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
+        InputStream in = getClass().getResourceAsStream(resource);
+        if (in == null) {
+            return new ErrorResponse(this, server, new ObjectNotFoundException(resource), 404, out);
+        }
+        if (server.getLog().isTraceEnabled())
+            server.getLog().trace("Found resource " + resource);
+        return mimeType.startsWith("image") 
+          ? new ImageResponse(this, server, in, mimeType, out)
+          : new ResourceResponse(this, server, in, mimeType, out);
+    }
+    
+    boolean isBooleanQualifier(String key) {
+        String q = getQualifier(key);
+        return hasQualifier(key) && (q == null || "true".equals(q));
+    }
+    
+    String getMimeType(String resource) {
+        int index = resource.lastIndexOf('.');
+        String ext = (index != -1) ? resource.substring(index+1) : ""; 
+        if (ext.equalsIgnoreCase("html") || ext.equalsIgnoreCase(".html")) return "text/html";
+        if (ext.equalsIgnoreCase(".png") || ext.equalsIgnoreCase(".ico") || ext.equalsIgnoreCase("jpeg")) 
+            return "image/"+ext;
+        return "text/html";
+    }
+    
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/GETRequest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,61 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Sends an image as response.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class ImageResponse extends AbstractResponse {
+    private final InputStream _in;
+    private final String _mimeType;
+    
+    public ImageResponse(Request request, ServerContext ctx, InputStream resource, String mimeType,
+        OutputStream out) throws Exception {
+        super(request, ctx, out);
+        _in = resource;
+        _mimeType = mimeType;
+    }
+
+    public void writeOut() throws Exception {
+        print(_request.getProtocol()); println("200 OK");
+        printHeader("Connection",  "close");
+        printHeader("Content-Type", _mimeType);
+        println();
+        byte[] b = new byte[1024];
+        int i = 0;
+        for (int l = 0; (l = _in.read(b)) != -1;) {
+            write(b, 0, l);
+            i += l;
+        }
+        printHeader("Content-Length", ""+i);
+        _in.close();
+        close();
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ImageResponse.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,386 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+/**
+ * A request carries requisite data for a JPA operation to be performed. 
+ * The request is populated by parsing an input data stream.
+ * 
+ * 
+ * @author Pinaki Poddar
+ * 
+ */
+@SuppressWarnings("serial")
+public abstract class JESTRequest implements Request {
+    private String _method;
+    private String _protocol;
+    private String _action;
+    private String _body;
+    private LinkedHashMap<String, String> _qualifiers = new LinkedHashMap<String, String>();
+    private LinkedHashMap<String, String> _params = new LinkedHashMap<String, String>();
+    private Map<String, List<String>> _headers = new HashMap<String, List<String>>();
+    private ParseState _state;
+    private StringBuffer buf = new StringBuffer();
+    private LinkedList<Token> _stack = new LinkedList<Token>();
+    
+    public static final List<String> METHODS = Arrays.asList(new String[]{"GET","POST","PUT","DELETE"});
+    
+    /**
+     * Parse States.
+     */
+    static enum ParseState {
+        INIT, ACTION, QUALIFIER_KEY, QUALIFIER_VALUE, PARAM_KEY, PARAM_VALUE, END
+    };
+
+
+    public String getMethod() {
+        return _method;
+    }
+
+    void setMethod(String method) {
+        if (_method == null) {
+            if (method != null && METHODS.contains(method.toUpperCase())) {
+                _method = method.toUpperCase();
+            } else {
+                throw new IllegalArgumentException("Unsupported method " + method);
+            }
+        } else if (!_method.equalsIgnoreCase(method)) {
+            throw new IllegalStateException("Method can not be changed to [" + method + "]. " +
+                "Current method [" + _method + "]");
+        }
+    }
+
+    public String getProtocol() {
+        return _protocol == null ? "HTTP/1.1" : _protocol;
+    }
+
+    void setProtocol(String protocol) {
+        if (_protocol == null) {
+            if (protocol != null && protocol.toUpperCase().startsWith("HTTP")) {
+                _protocol = protocol.toUpperCase();
+            } else {
+                throw new IllegalArgumentException("Unsupported protocol " + protocol);
+            }
+        } else if (!_protocol.equalsIgnoreCase(protocol)) {
+            throw new IllegalStateException("Protocol can not be changed to [" + protocol + "]. " +
+                "Current protocol [" + _protocol + "]");
+        }
+    }
+
+    /**
+     * Sets an action. Once set, an action can not be modified.
+     * 
+     * @param action
+     */
+    private void setAction(String action) {
+        if (_action == null) {
+            _action = action;
+        } else if (!_action.equals(action)) {
+            throw new IllegalStateException("Action can not be [" + action + "]. Already set to [" + _action + "]");
+        }
+    }
+
+    public String getAction() {
+        return _action == null ? "" : _action;
+    }
+
+    public String getBody() {
+        return _body;
+    }
+
+    private void setQualifier(String key, String value) {
+        _qualifiers.put(key, value);
+    }
+
+    public String getQualifier(String key) {
+        return _qualifiers.get(key);
+    }
+
+    public Map<String, String> getQualifiers() {
+        return Collections.unmodifiableMap(_qualifiers);
+    }
+
+    public boolean hasQualifier(String key) {
+        return _qualifiers.containsKey(key);
+    }
+
+    private void setParameter(String key, String value) {
+        _params.put(key, value);
+    }
+
+    public String getParameter(String key) {
+        return _params.get(key);
+    }
+
+    public boolean hasParameter(String key) {
+        return _params.containsKey(key);
+    }
+
+    public Map<String, String> getParameters() {
+        return Collections.unmodifiableMap(_params);
+    }
+    
+    public Map.Entry<String, String> getParameter(int n) {
+        if (n >= _params.size())
+            throw new NoSuchElementException("Index " + n + " size " + _params.size());
+        int i = 0;
+        for (Map.Entry<String, String> entry : _params.entrySet()) {
+            if (i == n) {
+                return entry;
+            }
+            i++;
+        }
+        return null;
+    }
+
+    public Map<String, List<String>> getHeaders() {
+        return Collections.unmodifiableMap(_headers);
+    }
+
+    public List<String> getHeader(String key) {
+        return _headers.get(key);
+    }
+    
+    
+    public void read(List<String> lines) throws IOException {
+        parse(lines.get(0));
+        int i = 1;
+        for (; i < lines.size(); i++) {
+            String line = lines.get(i);
+            if (line.length() == 0) {
+                break;
+            } else {
+                parseHeader(line);
+            }
+        }
+        parseBody(lines.subList(i, lines.size()));
+    }
+
+    protected void parseHeader(String line) throws IOException {
+        String key = null;
+        StringBuilder token = new StringBuilder();
+        int N = line.length();
+        for (int i = 0; i < N; i++) {
+            char c = line.charAt(i);
+            if (c == ':' && key == null) {
+                key = token.toString().trim();
+                token.delete(0, token.length());
+            } else {
+                token.append(c);
+            }
+        }
+        if (key != null) {
+            _headers.put(key, Collections.singletonList(token.toString().trim()));
+        }
+    }
+
+    protected void parseBody(List<String> lines) {
+        if (lines == null || lines.isEmpty())
+            return;
+        for (String line : lines) {
+            if (_body == null) {
+                _body = line;
+            } else {
+                _body = _body + line;
+            }
+        }
+    }
+
+    /**
+     * Parses JEST stream and populates a request.
+     * 
+     */
+     protected void parse(String s) {
+            char[] chars = s.toCharArray();
+            _state = ParseState.INIT;
+            _stack.clear();
+
+            for (int i = 0; i < chars.length; i++) {
+                char ch = chars[i];
+                switch (_state) {
+                    case INIT:
+                        if (ch == '/') {
+                            transit(ParseState.ACTION);
+                        } else if (!Character.isWhitespace(ch)) {
+                            parseError(ch, i, s, true, ' ');
+                        }
+                        break;
+
+                    case ACTION:
+                        if (ch == '/') {
+                            transit(ParseState.QUALIFIER_KEY);
+                        } else if (ch == '?') {
+                            transit(ParseState.PARAM_KEY);
+                        } else {
+                            buf.append(ch);
+                        }
+                        break;
+
+                    case QUALIFIER_KEY:
+                        if (Character.isJavaIdentifierPart(ch)) {
+                            buf.append(ch);
+                        } else if (ch == '=') {
+                            transit(ParseState.QUALIFIER_VALUE);
+                        } else if (ch == '/') {
+                            transit(ParseState.QUALIFIER_KEY);
+                        } else if (ch == '?') {
+                            transit(ParseState.PARAM_KEY);
+                        } else {
+                            parseError(ch, i, s, true, '/', '?', '=');
+                        }
+                        break;
+
+                    case QUALIFIER_VALUE:
+                        if (Character.isJavaIdentifierPart(ch)) {
+                            buf.append(ch);
+                        } else if (ch == '/') {
+                            transit(ParseState.QUALIFIER_KEY);
+                        } else if (ch == '?') {
+                            transit(ParseState.PARAM_KEY);
+                        } else {
+                            parseError(ch, i, s, true, '/', '?');
+                        }
+                        break;
+
+                    case PARAM_KEY:
+                        if (Character.isJavaIdentifierPart(ch)) {
+                            buf.append(ch);
+                        } else if (ch == '=') {
+                            if (isQueryKey())
+                                buf.append(ch);
+                            else
+                                transit(ParseState.PARAM_VALUE);
+                        } else if (ch == ';') {
+                            transit(ParseState.PARAM_KEY);
+                        } else if (isQueryKey() && isQueryChar(ch)) {
+                            buf.append(ch);
+                        } else {
+                            parseError(ch, i, s, true, ';', '=');
+                        }
+                        break;
+
+                    case PARAM_VALUE:
+                        if (Character.isJavaIdentifierPart(ch)) {
+                            buf.append(ch);
+                        } else if (ch == ';') {
+                            transit(ParseState.PARAM_KEY);
+                        } else {
+                            parseError(ch, i, s, true, ';');
+                        }
+                        break;
+                    default:
+                        throw new RuntimeException("ParseError: '" + ch + "' at " + i + " in [" + s + "]. "
+                            + "Unknown state " + _state);
+                }
+            }
+            if (buf.length() > 0) {
+                transit(ParseState.END);
+            }
+        }
+
+        /**
+         * Affirms if parsing a query string.
+         */
+        private boolean isQueryKey() {
+            return "query".equals(_action) && _stack.size() == 1;
+        }
+        
+        /**
+         * Affirms if the given character is valid in a query string 
+         */
+        private boolean isQueryChar(char c) {
+            return c == ' ' || c == '.' || c == ':' || c == '?' || c == '\'';
+        }
+
+        /**
+         * Transitions to a new parse state.
+         * 
+         * @param to target parse state
+         */
+        void transit(ParseState to) {
+            String token = buf.toString();
+            switch (_state) {
+                case ACTION:
+                    setAction(token);
+                    break;
+                case QUALIFIER_KEY:
+                    setQualifier(token, null);
+                    break;
+                case QUALIFIER_VALUE:
+                    setQualifier(_stack.peekLast().getValue(), token);
+                    break;
+                case PARAM_KEY:
+                    setParameter(token, null);
+                    break;
+                case PARAM_VALUE:
+                    setParameter(_stack.peekLast().getValue(), token);
+                    break;
+
+            }
+            if (_state != ParseState.INIT && to != ParseState.END) {
+                _stack.add(new Token(_state, token));
+            }
+            buf.delete(0, buf.length());
+            _state = to;
+        }
+
+        protected void parseError(char ch, int pos, String line, boolean java, char... expected) {
+            throw new RuntimeException("ParseError: Encountered '" + ch + "' at " + pos + " in [" + line + "] while "
+                + "parsing " + _state + ". Expected " + Arrays.toString(expected) + (java ? " or Java identifer" : ""));
+
+        }
+
+        /**
+         * Token in a JEST stream.
+         * 
+         */
+        static class Token {
+            final ParseState _type;
+            final String _value;
+
+            public Token(ParseState type, String value) {
+                _type = type;
+                _value = value;
+            }
+
+            public ParseState getType() {
+                return _type;
+            }
+
+            public String getValue() {
+                return _value;
+            }
+
+            public String toString() {
+                return _value + "[" + _type + "]";
+            }
+        }
+    
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTRequest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,71 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Response of a JEST Request.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class JESTResponse extends AbstractResponse {
+    private final OpenJPAStateManager _sm;
+    
+    public JESTResponse(Request request, ServerContext ctx, OpenJPAStateManager sm, OutputStream out) throws Exception {
+        super(request, ctx, out);
+        _sm = sm;
+    }
+    
+    public String getContentType() {
+        return "text/html";
+    }
+    
+    public void writeOut() throws Exception {
+        print(_request.getProtocol()); println("200 OK");
+        printHeader("Connection",  "close");
+        printHeader("Content-Type", "text/html", "charset=UTF-8");
+        println();
+        println("<html><body><pre>");
+        XMLEncoder encoder = new XMLEncoder(_ctx.getPersistenceUnit().getMetamodel());
+        Document doc = encoder.encode(_sm);
+        encoder.writeDoc(doc, this);
+        println("Response from JEST");
+        
+        println("</pre></body></html>");
+        close();
+    }
+    
+}
+
+

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTResponse.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,316 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.BufferedReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.metamodel.Attribute;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.StoreContext;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.ValueMetaData;
+import org.apache.openjpa.persistence.meta.Members;
+import org.apache.openjpa.persistence.meta.MetamodelImpl;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Marshals a root instance and its persistent closure as JSON object.
+ * The closure is resolved against the persistence context that contains the root instance.
+ * The JSON format introduces a $id and $ref to address reference that pure JSON does not. 
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class JSONEncoder {
+    /**
+     * The element/attribute tags declared in <code>jest-instance.xsd</code> XML schema.
+     */
+    public static final String ELEMENT_NULL_REF    = "null";
+    public static final String ELEMENT_INSTANCE    = "instance";
+    public static final String ELEMENT_REF         = "ref";
+        
+    
+    private MetamodelHelper _model;
+    
+    public JSONEncoder(MetamodelImpl model) {
+        _model = new MetamodelHelper(model);
+    }
+    
+    /**
+     * Encodes the given managed instance into a new XML element as a child of the given parent node.
+     * 
+     * @param sm a managed instance, can be null.
+     * @param parent the parent node to which the new node be attached.
+     */
+    public StringBuilder encode(final OpenJPAStateManager sm) {
+        return encode(sm, new HashSet<OpenJPAStateManager>(), 0, false);
+    }
+    StringBuilder indent(StringBuilder buf, int indent) {
+        if (indent <= 0)
+            return buf;
+        char[] spaces = new char[indent*4];
+        Arrays.fill(spaces, ' ');
+        buf.insert(0, spaces);
+        return buf;
+    }
+    StringBuilder end(StringBuilder buf, char ch, int indent) {
+        char[] spaces = new char[indent*4];
+        Arrays.fill(spaces, ' ');
+        return buf.append("\r\n").append(spaces).append(ch);
+    }
+    
+    /**
+     * Encodes the closure of a persistent instance into a XML element.
+     * 
+     * @param sm the managed instance to be encoded. Can be null.
+     * @param parent the parent XML element to which the new XML element be added. Must not be null. Must be
+     * owned by a document. 
+     * @param visited the persistent instances that had been encoded already. Must not be null or immutable.
+     * 
+     * @return the new element. The element has been appended as a child to the given parent in this method.  
+     */
+    private StringBuilder encode(final OpenJPAStateManager sm, final Set<OpenJPAStateManager> visited, 
+        int indent, boolean indentPara) {
+        if (visited == null) {
+            throw new IllegalArgumentException("null closure for encoder");
+        }
+        StringBuilder root =  indent(new StringBuilder("{"), indentPara ? indent : 0);
+        if (sm == null) {
+            return root.append("null}");
+        }
+        boolean ref = !visited.add(sm);
+        if (ref) {
+            return indent(root.append(quoted("$ref")).append(": ").append(ior(sm)).append('}'), 
+                indentPara ? indent : 0);
+        } else {
+            indent(root.append(quoted("$id")).append(": ").append(ior(sm)), indentPara ? indent : 0);
+        }
+        
+        StringBuilder child = new StringBuilder();
+        BitSet loaded = sm.getLoaded();
+        StoreContext ctx = (StoreContext)sm.getGenericContext();
+        List<Attribute<?, ?>> attrs = _model.getAttributesInOrder(sm.getMetaData());
+        for (int i = 0; i < attrs.size(); child = new StringBuilder(), i++) {
+            FieldMetaData fmd = ((Members.Member<?, ?>) attrs.get(i)).fmd;
+            if (!loaded.get(fmd.getIndex())) 
+                continue;
+            Object value = sm.fetch(fmd.getIndex());
+            child.append(quoted(fmd.getName())).append(": ");
+            switch (fmd.getDeclaredTypeCode()) {
+                case JavaTypes.BOOLEAN:
+                case JavaTypes.BYTE:
+                case JavaTypes.CHAR:
+                case JavaTypes.DOUBLE:
+                case JavaTypes.FLOAT:
+                case JavaTypes.INT:
+                case JavaTypes.LONG:
+                case JavaTypes.SHORT:
+
+                case JavaTypes.BOOLEAN_OBJ:
+                case JavaTypes.BYTE_OBJ:
+                case JavaTypes.CHAR_OBJ:
+                case JavaTypes.DOUBLE_OBJ:
+                case JavaTypes.FLOAT_OBJ:
+                case JavaTypes.INT_OBJ:
+                case JavaTypes.LONG_OBJ:
+                case JavaTypes.SHORT_OBJ:
+
+                case JavaTypes.BIGDECIMAL:
+                case JavaTypes.BIGINTEGER:
+                case JavaTypes.DATE:
+                case JavaTypes.NUMBER:
+                case JavaTypes.CALENDAR:
+                case JavaTypes.LOCALE:
+                case JavaTypes.STRING:
+                case JavaTypes.ENUM:
+                         child.append(quoted(value));
+                break;
+                
+                case JavaTypes.PC:
+                    if (value == null) {
+                        child.append("null");
+                    } else {
+                        child.append(encode(ctx.getStateManager(value), visited, indent+1, false));
+                    }
+                    break;
+                    
+                case JavaTypes.ARRAY:
+                    Object[] values = (Object[])value;
+                    value = Arrays.asList(values);
+                // no break;
+                case JavaTypes.COLLECTION:
+                    if (value == null) {
+                        child.append("null");
+                        break;
+                    }
+                    child.append("[");
+                    Collection<?> members = (Collection<?>)value;
+                    boolean basic = fmd.getElement().getTypeMetaData() == null;
+                    int k = 0;
+                    for (Object o : members) {
+                        child.append("\r\n");
+                        if (o == null) {
+                            child.append(indent(new StringBuilder("null"), indent+1)); 
+                        } else {
+                            if (basic) {
+                                child.append(indent(new StringBuilder(quoted(o)), indent+1));
+                            } else {
+                                child.append(encode(ctx.getStateManager(o), visited, indent+1, true));
+                            }
+                        }
+                    }
+                    end(child, ']', indent+1);
+                    break;
+                case JavaTypes.MAP:
+                    if (value == null) {
+                        child.append("null");
+                        break;
+                    }
+                    child.append("[");
+                    Set<Map.Entry> entries = ((Map)value).entrySet();
+                    boolean basicKey   = fmd.getElement().getTypeMetaData() == null;
+                    boolean basicValue = fmd.getValue().getTypeMetaData() == null;
+                    for (Map.Entry<?,?> e : entries) {
+                        if (e.getKey() == null) {
+                            child.append("null:");
+                        } else {
+                            if (basicKey) {
+                                child.append(quoted(e.getKey())).append(":");
+                            } else {
+                                child.append(encode(ctx.getStateManager(e.getKey()), visited, indent+1, true));
+                            }
+                        }
+                        if (e.getValue() == null) {
+                            child.append("null");
+                        } else {
+                            if (basicValue) {
+                                child.append(quoted(e.getValue()));
+                            } else {
+                                child.append(encode(ctx.getStateManager(e.getValue()), visited, indent+1, false));
+                            }
+                        }
+                    }
+                    break;
+                    
+                case JavaTypes.INPUT_STREAM:
+                case JavaTypes.INPUT_READER:
+                    child = new StringBuilder(fmd.getName());
+                    if (value == null) {
+                        child.append("null");
+                    } else { 
+                        child.append(streamToString(value));
+                    }
+                    break;
+                    
+                case JavaTypes.PC_UNTYPED:
+                case JavaTypes.OBJECT:
+                case JavaTypes.OID:
+                    System.err.println("Not handled " + fmd.getName() + " of type " + fmd.getDeclaredType());
+            }
+            
+            if (child != null) {
+                root.append("\r\n");
+                root.append(indent(child, indent+1));
+                if (loaded.length()-1 != i)
+                    root.append(",");
+           }
+        }
+        return end(root, '}', indent);
+    }
+    
+    
+    String ior(OpenJPAStateManager sm) {
+        return quoted(typeOf(sm)+"-"+sm.getObjectId().toString());
+    }
+    
+    String typeOf(OpenJPAStateManager sm) {
+        return sm.getMetaData().getDescribedType().getSimpleName();
+    }
+    
+    String typeOf(Class<?> cls) {
+        return cls.getSimpleName();
+    }
+    
+    String typeOf(ClassMetaData meta) {
+        return meta.getDescribedType().getSimpleName();
+    }
+    
+    String typeOf(ValueMetaData vm) {
+        if (vm.getTypeMetaData() == null)
+            return typeOf(vm.getType()); 
+        return typeOf(vm.getTypeMetaData());
+    }
+    
+    String typeOf(FieldMetaData fmd) {
+        return fmd.getType().getSimpleName();
+    }
+    
+    
+    /**
+     * Convert the given stream (either an InutStream or a Reader) to a String
+     * to be included in CDATA section of a XML document.
+     * 
+     * @param value the field value to be converted. Can not be null 
+     * @return
+     */
+    String streamToString(Object value) {
+        Reader reader = null;
+        if (value instanceof InputStream) {
+            reader = new BufferedReader(new InputStreamReader((InputStream)value));
+        } else if (value instanceof Reader) {
+            reader = (Reader)value;
+        } else {
+            throw new RuntimeException();
+        }
+        CharArrayWriter writer = new CharArrayWriter();
+        try {
+            for (int c; (c = reader.read()) != -1;) {
+                writer.write(c);
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+        return writer.toString();
+    }
+    
+    String quoted(Object o) {
+        if (o == null) return "null";
+        if (o instanceof Number)
+            return o.toString();
+        return "\"" + o.toString() + "\"";
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONEncoder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,127 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.ManagedType;
+import javax.persistence.metamodel.Metamodel;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.persistence.meta.MetamodelImpl;
+
+/**
+ * @author Pinaki Poddar
+ *
+ */
+public class MetamodelHelper {
+    private MetamodelImpl _model;
+    private Map<ManagedType<?>, List<Attribute<?, ?>>> _attrs = new HashMap<ManagedType<?>, List<Attribute<?,?>>>();
+    
+    public MetamodelHelper(MetamodelImpl model) {
+        _model = model;
+    }
+    
+    public List<Attribute<?,?>> getAttributesInOrder(Class<?> cls) {
+        return getAttributesInOrder(_model.managedType(cls));
+    }
+    
+    public List<Attribute<?,?>> getAttributesInOrder(ClassMetaData meta) {
+        return getAttributesInOrder(meta.getDescribedType());
+    }
+    
+    /**
+     * Gets the attributes of the given type in defined order.
+     * @param type
+     * @return
+     */
+    public List<Attribute<?,?>> getAttributesInOrder(ManagedType<?> type) {
+        List<Attribute<?,?>> attrs = _attrs.get(type);
+        if (attrs != null)
+            return attrs;
+        List<Attribute<?,?>> list = new ArrayList<Attribute<?,?>>(type.getAttributes());
+        Collections.sort(list, new AttributeComparator());
+        _attrs.put(type, list);
+        return list;
+    }
+
+    public static boolean isId(Attribute<?,?> a) {
+        if (a instanceof SingularAttribute)
+            return ((SingularAttribute<?,?>)a).isId();
+        return false;
+    }
+    
+    public static boolean isVersion(Attribute<?,?> a) {
+        if (a instanceof SingularAttribute)
+            return ((SingularAttribute<?,?>)a).isVersion();
+        return false;
+    }
+
+    public static Integer getAttributeTypeCode(Attribute<?,?> attr) {
+        if (isId(attr))
+            return 0;
+        if (isVersion(attr))
+            return 1;
+        
+      switch (attr.getPersistentAttributeType()) {
+      case BASIC : 
+      case EMBEDDED:
+          return 2;
+      case ONE_TO_ONE: 
+      case MANY_TO_ONE:
+          return 3;
+      case ONE_TO_MANY:
+      case MANY_TO_MANY:
+      case ELEMENT_COLLECTION: return 4;
+      default: return 5;
+      }
+    }
+    
+    /**
+     * Compares attribute by their qualification.
+     * Identity 
+     * Version
+     * Basic
+     * Singular association
+     * Plural association
+     *
+     */
+    public static class AttributeComparator implements Comparator<Attribute<?,?>> {
+        @Override
+        public int compare(Attribute<?, ?> a1, Attribute<?, ?> a2) {
+            Integer t1 = getAttributeTypeCode(a1);
+            Integer t2 = getAttributeTypeCode(a2);
+            if (t1.equals(t2)) {
+                return a1.getName().compareTo(a2.getName());
+            } else {
+                return t1.compareTo(t2);
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,138 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A request from a remote client to a server to do something.
+ * The request arrives as stream of bytes from a remote location
+ * and if the server can interpret the protocol from the stream, 
+ * then  make a concrete request object.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public interface Request extends Serializable {
+    /**
+     * Get the HTTP verb such as GET, POST
+     * 
+     * @return uppercase string
+     */
+    String getMethod();
+    
+    /**
+     * Get the first path segment as intended persistence action such as <code>find</code> or <code>query</code>
+     *   
+     * @return lowercase action name. Can be empty.
+     */
+    String getAction();
+    
+    /**
+     * Get the protocol such as HTTP/1.1
+     * 
+     * @return upper-case string
+     */
+    String getProtocol();
+    
+    /**
+     * Get the body, if any.
+     * 
+     * @return body of the request. null if no body.
+     */
+    String getBody();
+    
+    /**
+     * Get the headers indexed by the keys.
+     * Header values are list of Strings.
+     * 
+     * @return empty map if there is no header
+     */
+    Map<String, List<String>> getHeaders();
+    
+    /**
+     * Get the header values for the given key.
+     * @param key a key
+     * @return null if no header value for the given key
+     */
+    List<String> getHeader(String key);
+    
+    /**
+     * Affirm if the the given qualifier is available in this request.
+     *  
+     * @param key case-sensitive qualifier
+     * @return true if the key is present.
+     */
+    boolean hasQualifier(String key);
+    
+    /**
+     * Gets the value for the given qualifier key.
+     * 
+     * @param key case-sensitive qualifier
+     * @return value of the qualifier. null if the key is absent.
+     */
+    String getQualifier(String key);
+    
+    /**
+     * Get all the qualifiers available in this request.
+     * 
+     * @return key-value pairs of the qualifiers. Empty map if no qualifier is present.
+     */
+    Map<String,String> getQualifiers();
+    
+    
+    /**
+     * Affirm if the the given parameter is available in this request.
+     *  
+     * @param key case-sensitive parameter
+     * @return true if the key is present.
+     */
+    boolean hasParameter(String key);
+    
+    
+    /**
+     * Gets the value for the given parameter key.
+     * 
+     * @param key case-sensitive parameter
+     * @return value of the parameter. null if the key is absent.
+     */
+    String getParameter(String key);
+    
+    /**
+     * Get all the parameters available in this request.
+     * 
+     * @return key-value pairs of the parameters. Empty map if no parameter is present.
+     */
+    Map<String,String> getParameters();
+    
+    /**
+     * Parse the request represented as a list of strings.
+     *
+     * @param lines each line of the request.
+     * @throws IOException
+     */
+    void read(List<String> lines) throws IOException;
+    
+    Response process(ServerContext server, OutputStream stream) throws Exception;
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Request.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,63 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A factory to create a specific type of request.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class RequestFactory {
+    private final String _protocol;
+    private static Map<String, RequestFactory> _registered = new HashMap<String, RequestFactory>();
+    static {
+        _registered.put("HTTP/1.0", new RequestFactory("HTTP/1.0"));
+        _registered.put("HTTP/1.1", new RequestFactory("HTTP/1.1"));
+    }
+    
+    public static void register(String protocol, RequestFactory factory) {
+        _registered.put(protocol, factory);
+    }
+    
+    private RequestFactory(String proto) {
+        _protocol = proto;
+    }
+    
+    public static RequestFactory getFactory(String protocol) {
+        return _registered.get(protocol);
+    }
+    
+    Request createRequest(String method) {
+        JESTRequest request = null;
+        if ("GET".equalsIgnoreCase(method)) {
+            request = new GETRequest();
+        } else {
+            throw new UnsupportedOperationException();
+        }
+        request.setProtocol(_protocol);
+        request.setMethod(method.toUpperCase());
+        return request;
+        
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,147 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityNotFoundException;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.StoreContext;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.util.ApplicationIds;
+
+/**
+ * Handles a request from a remote client.
+ * Reads the socket data.
+ * Populates the request.
+ * Determines the processor based on request method and action.
+ * Delegates to the processor.
+ * Processor generates the response.
+ * Writes the response to the stream.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class RequestHandler implements Callable<Void> {
+    private static final int SPACE = ' ';
+    private final Socket _socket;
+    private final ServerContext _server;
+    private final Log _log;
+    private static final Localizer _loc = Localizer.forPackage(RequestHandler.class);
+    
+    public RequestHandler(Socket socket, ServerContext server) {
+        _socket = socket;
+        _server = server;
+        _log = _server.getLog();
+    }
+    
+    public Void call() throws Exception {
+        Request request = null;
+        Response response = null;
+        try {
+            request = readRequest(_socket.getInputStream());
+            response = request.process(_server, _socket.getOutputStream());
+        } catch (Exception e) {
+            response = new ErrorResponse(request, _server, e, HttpURLConnection.HTTP_INTERNAL_ERROR, 
+                _socket.getOutputStream());
+        }
+        response.writeOut();
+        return null;
+    }
+    
+
+
+    /**
+     * Reads the given CR-LF delimited stream. 
+     * The first line is scanned for the method (first space-delimited String) and protocol (the last
+     * space-delimited String). Accordingly a request is created and rest of the input stream content
+     * is parsed by the request itself. 
+     * 
+     * @param input
+     * @throws IOException
+     */
+    public Request readRequest(InputStream input) throws IOException {
+        if (_log.isTraceEnabled())
+            _log.trace("Reading request from the input stream ");
+        
+        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+        String status = reader.readLine();
+        if (_log.isInfoEnabled())
+            _log.info("Status Line [" + status + "]");
+        int spaceFirst = status.indexOf(SPACE);
+        if (spaceFirst == -1) 
+            throw new IOException("HTTP Method could not be determined from [" + status + "]");
+        int spaceLast = status.lastIndexOf(SPACE);
+        if (spaceLast == -1) 
+            throw new IOException("HTTP Protocol could not be determined from [" + status + "]");
+        String method = status.substring(0, spaceFirst);
+        String protocol = status.substring(spaceLast+1);
+        String path = status.substring(spaceFirst+1, spaceLast);
+        Request request = RequestFactory.getFactory(protocol).createRequest(method);
+        List<String> lines = new ArrayList<String>();
+        if (path.equals("/")) {
+            lines.add(path);
+        } else {
+            lines = readlines(reader);
+            lines.add(0, path);
+        }
+        if (lines.isEmpty()) {
+            throw new IOException("No CR-LF delimited lines could be read from " + input);
+        }
+        request.read(lines);
+        return request;
+    }
+    
+
+    List<String> readlines(BufferedReader reader) throws IOException {
+        List<String> buffers = new ArrayList<String>();
+        String line;
+        while ((line = reader.readLine()) != null && line.length() > 0) {
+            buffers.add(line);
+        }
+        return buffers;
+    }
+    
+    
+    public String toString() {
+        return _socket.getInetAddress()+":"+_socket.getPort();
+    }    
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/RequestHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,54 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import javax.imageio.ImageIO;
+
+/**
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class ResourceResponse extends AbstractResponse {
+    private final InputStream _in;
+    private final String _mimeType;
+    public ResourceResponse(Request request, ServerContext ctx, InputStream resource, String mimeType,
+        OutputStream out) throws Exception {
+        super(request, ctx, out);
+        _in = resource;
+        _mimeType = mimeType;
+    }
+
+    public void writeOut() throws Exception {
+        print(_request.getProtocol()); println("200 OK");
+        printHeader("Connection",  "close");
+        printHeader("Content-Type", _mimeType, "charset=UTF-8");
+        println();
+        for (int c = 0; (c = _in.read()) != -1;) {
+           print((char)c);
+        }
+        _in.close();
+        close();
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ResourceResponse.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,31 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.Serializable;
+
+/**
+ * @author Pinaki Poddar
+ *
+ */
+public interface Response extends Serializable {
+//    void setHeader(String key, String value);
+    void writeOut() throws Exception;
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Response.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java?rev=1028093&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java Wed Oct 27 20:42:44 2010
@@ -0,0 +1,230 @@
+/*
+ * 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.    
+ */
+
+package org.apache.openjpa.persistence.jest;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.lib.conf.Configurable;
+import org.apache.openjpa.lib.conf.Configuration;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.persistence.EntityManagerFactoryImpl;
+
+
+/**
+ * A server running on an independent thread that allows a remote, language-neutral client to access OpenJPA runtime.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class Server implements ServerContext, Configurable, Runnable {
+    private ServerSocket _listenSocket;
+    protected ExecutorService _executors;
+    public final static int DEFAULT_PORT = 6789;
+    protected int _port = DEFAULT_PORT;
+    protected int _range = 1;
+    protected String _format = "xml";
+    protected Log _log;
+    protected Thread _thread;
+    private EntityManagerFactoryImpl _ctx;
+    private static Localizer _loc = Localizer.forPackage(Server.class);
+    
+    /**
+     * Sets the persistence unit context in which this server will serve requests.
+     * The context must be set before operation.
+     * 
+     * @param emf an implementation of OpenJPA Persistence Unit. Must not be null.
+     */
+    public void setContext(EntityManagerFactoryImpl emf) {
+        if (emf == null)
+            throw new NullPointerException();
+        _ctx = emf;
+    }
+    
+    /**
+     * Gets the persistence unit context in which this server serves requests.
+     * 
+     * @param emf an implementation of OpenJPA Persistence Unit. 
+     */
+    public EntityManagerFactoryImpl getPersistenceUnit() {
+        return _ctx;
+    }
+    
+    public Log getLog() {
+        return _log;
+    }
+    
+    /**
+     * Start the server in a daemon thread.
+     * This method is idempotent.
+     * 
+     * @return true if the server has started by this call or already running. 
+     */
+    public synchronized boolean start() {
+        try {
+            if (_thread != null)
+                return true;
+            if (createServerSocket()) {
+                _thread = new Thread(this);
+                _thread.setDaemon(true);
+                _thread.start();
+                return true;
+            }
+            return false;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return false;
+        }
+    }
+    
+    /**
+     * Stops the server.
+     */
+    public synchronized void stop() {
+        _thread.interrupt();
+        _thread = null;
+        _executors.shutdownNow();
+    }
+    
+    /**
+     * Sets the port in which the server will listen.
+     * 
+     * @param port a positive integer.
+     */
+    public void setPort(int port) {
+        _port = port;
+    }
+    
+    /**
+     * Gets the current port.
+     * 
+     * @return the port number. Defaults to default HTTP port.
+     */
+    public int getPort() {
+        return _port;
+    }
+    
+    /**
+     * Sets the range of ports the server will attempt at start.
+     * 
+     * @param range a positive integer.
+     */
+    public void setRange(int range) {
+        if (range > 0) 
+            _range = range;
+    }
+    
+    public void setFormat(String format) {
+        _format = format;
+    }
+    
+    public String getFormat() {
+        return _format;
+    }
+    
+    /**
+     * Sets the range of ports the server will attempt at start.
+     * @return  a positive integer. Defaults to 1.
+     */
+    public int getRange() {
+        return _range;
+    }
+    
+    public void run() {
+        _log.info(_loc.get("server-starting", this));
+        
+        _executors = Executors.newCachedThreadPool();
+        while (!Thread.interrupted()) {
+            try {
+                Socket socket = _listenSocket.accept();
+                if (_log.isTraceEnabled())
+                    _log.trace(_loc.get("server-request", socket));
+                RequestHandler request = new RequestHandler(socket, this); 
+                _executors.submit(request);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private boolean createServerSocket() {
+        int p = _port;
+        int p2 = p + _range;
+        Exception error = null;
+        for (; _listenSocket == null && p < p2; ) {
+            try {
+                _listenSocket = new ServerSocket(p);
+            } catch (IOException ex) {
+                p++;
+                error = ex;
+            }
+        }
+        if (_listenSocket != null) {
+            if (p != _port) {
+                _port = p;
+                _log.warn(_loc.get("server-reconfigured", _port));
+            }
+        } else {
+            if (error != null) {
+                _log.warn(_loc.get("server-failed", this, _port, error));
+            }
+        }
+        return _listenSocket != null;
+    }
+    
+    // Configurable contract
+    public void setConfiguration(Configuration conf) {
+        _log = conf.getLog("Remote");
+    }
+
+    public void startConfiguration() {
+    }
+
+    public void endConfiguration() {
+    }
+    
+    
+    // Server side utilities 
+    
+    /**
+     * Resolves the given alias to a persistent class meta data.
+     * 
+     * @exception if no meta data available for the given alias 
+     */
+    public ClassMetaData resolve(String alias) {
+        MetaDataRepository repos = _ctx.getConfiguration().getMetaDataRepositoryInstance();
+        return repos.getMetaData(alias, Thread.currentThread().getContextClassLoader(), true);
+    }
+    
+    public String toString() {
+        if (_listenSocket == null) return "JEST Server [not strated]";
+        return "JEST Server " + _listenSocket.getInetAddress()+":"+_listenSocket.getLocalPort();
+    }
+
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Server.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message