You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2010/12/02 12:24:54 UTC

svn commit: r1041330 [1/2] - in /openjpa/sandboxes/jest: openjpa-examples/jest/src/main/java/demo/ openjpa-examples/jest/src/main/resources/WEB-INF/ openjpa-examples/jest/src/main/resources/demo/ openjpa-persistence/src/main/java/org/apache/openjpa/per...

Author: ppoddar
Date: Thu Dec  2 11:24:53 2010
New Revision: 1041330

URL: http://svn.apache.org/viewvc?rev=1041330&view=rev
Log:
OPENJPA-1851: Add a client to JEST

Added:
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/IOR.java   (with props)
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/TokenReplacedStream.java   (with props)
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.js   (with props)
Removed:
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DojoFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/HTMLDocument.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/HTMLElement.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/HTMLTableFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/showhide.js
Modified:
    openjpa/sandboxes/jest/openjpa-examples/jest/src/main/java/demo/SimpleApp.java
    openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/WEB-INF/web.xml
    openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/demo/index.html
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Constants.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DomainCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ExceptionFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/FindCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTContext.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTServlet.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JPAServletContext.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONObjectFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ObjectFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ProcessingException.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PrototypeFactory.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/QueryCommand.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLFormatter.java
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/index.html
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.css
    openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties

Modified: openjpa/sandboxes/jest/openjpa-examples/jest/src/main/java/demo/SimpleApp.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-examples/jest/src/main/java/demo/SimpleApp.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-examples/jest/src/main/java/demo/SimpleApp.java (original)
+++ openjpa/sandboxes/jest/openjpa-examples/jest/src/main/java/demo/SimpleApp.java Thu Dec  2 11:24:53 2010
@@ -48,7 +48,7 @@ import javax.servlet.http.HttpServletRes
  */
 @SuppressWarnings("serial")
 public class SimpleApp extends HttpServlet {
-    
+    EntityManagerFactory _emf;
     private static String UNIT_NAME = "jestdemo";
     
     @Override 
@@ -58,14 +58,17 @@ public class SimpleApp extends HttpServl
         try {
             Map<String,Object> props = new HashMap<String, Object>();
             props.put("openjpa.EntityManagerFactoryPool", "true");
-            EntityManagerFactory emf = Persistence.createEntityManagerFactory(UNIT_NAME, props);
-            new DataLoader().populate(emf.createEntityManager());
+            _emf = Persistence.createEntityManagerFactory(UNIT_NAME, props);
+            new DataLoader().populate(_emf.createEntityManager());
         } catch (Exception e) {
             throw new ServletException(e);
         }
         config.getServletContext().log("Initialized with persistence unit [" + UNIT_NAME + "]");
     }
     
+    /**
+     * The only response by this application is an <code>index.html</code> file.
+     */
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         resp.setContentType("text/html");
@@ -75,4 +78,11 @@ public class SimpleApp extends HttpServl
             out.write((char)c);
         }
     }
+    
+    @Override
+    public void destroy() {
+        if (_emf != null) {
+            _emf.close();
+        }
+    }
 }

Modified: openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/WEB-INF/web.xml?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/WEB-INF/web.xml (original)
+++ openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/WEB-INF/web.xml Thu Dec  2 11:24:53 2010
@@ -23,6 +23,9 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
   <display-name>Demo Application with JEST Servlet</display-name>  
+  <welcome-file-list>
+		<welcome-file>index.html</welcome-file>
+  </welcome-file-list>
   <description>
     An example of deploying a simple web application with JEST servlet.
     This descriptor specifies the Demo Application servlet as well as JEST servlet.
@@ -45,7 +48,7 @@
 	</servlet>
 	<servlet-mapping>
 		<servlet-name>demo</servlet-name>
-		<url-pattern>/app/*</url-pattern>
+		<url-pattern>/*</url-pattern>
 	</servlet-mapping>
   
     <!-- Deployment descriptor for JESTServlet.                                           -->
@@ -66,6 +69,10 @@
 			<param-name>persistence.unit</param-name>
 			<param-value>jestdemo</param-value>
 		</init-param>
+		<init-param>
+			<param-name>debug</param-name>
+			<param-value>true</param-value>
+		</init-param>
 	</servlet>
 	<servlet-mapping>
 		<servlet-name>jest</servlet-name>

Modified: openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/demo/index.html
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/demo/index.html?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/demo/index.html (original)
+++ openjpa/sandboxes/jest/openjpa-examples/jest/src/main/resources/demo/index.html Thu Dec  2 11:24:53 2010
@@ -19,7 +19,6 @@ under the License.
 <html>
 <head>
 <style type="text/css">
-hr {color:sienna;}
 p {margin-left:20px;}
 body {background-image:url("images/back40.gif");
 .tag {
@@ -31,7 +30,10 @@ body {background-image:url("images/back4
 <body>
   <h1>DNA: Do-Nothing Application</h1>  
   <hr>
-  This DNA application is deployed as a HTTP Servlet.<br>
+  <span style="font-size:1.2em;color:green;font-weight:bold">DNA application is used to demonstrate </span> 
+  <A HREF="./jest/">JEST</A>.
+  <br>
+  DNA application is deployed as a HTTP Servlet.<br>
   
   The servlet creates an OpenJPA persistence unit at initialization.<br>
   
@@ -39,13 +41,10 @@ body {background-image:url("images/back4
   The fact that you are reading this page means the persistence unit has been initialized. 
   <p>
   
-  <span style="font-size:1.2em;color:green;font-weight:bold">DNA application is used to demonstrate </span> 
-  <A HREF="./jest/">JEST</A>.
-  <br>
   
-  <h2>Requirement for JEST</h2>
+  <h2>Requirement for enabling JEST</h2>
   
-  The only requirements for an application to enable JEST are
+  The requirements for an application to enable JEST are
   
   <p>
   &#9658; JEST Servlet must be <A href="#web.xml">deployed</A> within the same module scope of the application.  <br>
@@ -72,7 +71,7 @@ body {background-image:url("images/back4
  &lt;/servlet>
    &lt;servlet-mapping>
    &lt;servlet-name></span><span style="color:blue;">demo</span><span style="color:gray;font-weight:bold;">&lt;/servlet-name>
- &lt;url-pattern></span><span style="color:blue;">/app/*</span><span style="color:gray;font-weight:bold;">&lt;/url-pattern>
+ &lt;url-pattern></span><span style="color:blue;">/*</span><span style="color:gray;font-weight:bold;">&lt;/url-pattern>
  &lt;/servlet-mapping>
   
  <span style="color:green;font-weight:bold;">&lt;!-- Deployment descriptor for JESTServlet. --></span>

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/AbstractCommand.java Thu Dec  2 11:24:53 2010
@@ -20,10 +20,8 @@
 package org.apache.openjpa.persistence.jest;
 
 import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
-import static org.apache.openjpa.persistence.jest.Constants.*;
-import static org.apache.openjpa.persistence.jest.Constants.EQUAL;
-import static org.apache.openjpa.persistence.jest.Constants.FORMAT_DEFAULT;
-import static org.apache.openjpa.persistence.jest.Constants.PATH_SEPARATOR;
+import static org.apache.openjpa.persistence.jest.Constants.QUALIFIER_FORMAT;
+import static org.apache.openjpa.persistence.jest.Constants._loc;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -49,20 +47,26 @@ import org.apache.openjpa.kernel.OpenJPA
  *
  */
 abstract class AbstractCommand implements JESTCommand {
-    protected ObjectFormatter _formatter;
-    protected static PrototypeFactory<ObjectFormatter> _ff = new PrototypeFactory<ObjectFormatter>();
+    public static final char EQUAL = '=';
+    public static final String PATH_SEPARATOR = "/";
+    public static final Collection<String> EMPTY_LIST = Collections.emptySet();
+    protected ObjectFormatter<?> _formatter;
+    protected static PrototypeFactory<Format,ObjectFormatter<?>> _ff = 
+        new PrototypeFactory<Format,ObjectFormatter<?>>();
 
     private Map<String, String> _qualifiers = new HashMap<String, String>();
     private Map<String, String> _args = new HashMap<String, String>();
     private Map<String, String> _margs = new HashMap<String, String>();
+    protected final JPAServletContext ctx;
     
     static {
-        _ff.register(FORMAT_XML,  XMLFormatter.class);
-        _ff.register(FORMAT_JSON, JSONObjectFormatter.class);
-        _ff.register(FORMAT_DOJO, DojoFormatter.class);
-        _ff.register(FORMAT_HTML, HTMLTableFormatter.class);
-
+        _ff.register(Format.xml,  XMLFormatter.class);
+        _ff.register(Format.json, JSONObjectFormatter.class);
+    }
+    protected AbstractCommand(JPAServletContext ctx) {
+        this.ctx = ctx;
     }
+    
     public String getMandatoryArgument(String key) {
         return get(key, _margs);
     }
@@ -108,7 +112,8 @@ abstract class AbstractCommand implement
      * <br>
      * The qualifiers and arguments are immutable after parse.
      */
-    public void parse(HttpServletRequest request) throws ProcessingException {
+    public void parse() throws ProcessingException {
+        HttpServletRequest request = ctx.getRequest();
         String path = request.getPathInfo();
         if (path != null) {
             path = path.substring(1);
@@ -130,12 +135,13 @@ abstract class AbstractCommand implement
         
         while (names.hasMoreElements()) {
             String key = names.nextElement().toString();
+            if (key.startsWith("dojo.")) continue;
             put(key, request.getParameter(key), mandatoryArgs.contains(key) ? _margs : _args);
         }
         _args = Collections.unmodifiableMap(_args);
         _margs = Collections.unmodifiableMap(_margs);
         
-        validate(request);
+        validate();
     }
     
     /**
@@ -157,6 +163,19 @@ abstract class AbstractCommand implement
     }
     
     /**
+     * Gets the maximum number of arguments excluding the mandatory arguments.
+     * 
+     * @return Integer.MAX_VALUE by default.
+     */
+    protected int getMaximumArguments() {
+        return Integer.MAX_VALUE;
+    }
+    
+    protected Format getDefaultFormat() {
+        return Format.xml;
+    }
+    
+    /**
      * Gets the valid qualifiers.
      * 
      * @return empty list by default.
@@ -168,23 +187,28 @@ abstract class AbstractCommand implement
     /**
      * Called post-parse to validate this command has requisite qualifiers and arguments.
      */
-    protected void validate(HttpServletRequest request) {
+    protected void validate() {
+        HttpServletRequest request = ctx.getRequest();
         Collection<String> validQualifiers = getValidQualifiers();
         for (String key : _qualifiers.keySet()) {
             if (!validQualifiers.contains(key)) {
-                throw new ProcessingException(_loc.get("parse-invalid-qualifier", this, key, validQualifiers),
+                throw new ProcessingException(ctx,_loc.get("parse-invalid-qualifier", this, key, validQualifiers),
                     HTTP_BAD_REQUEST);
             }
         }
         Collection<String> mandatoryArgs = getMandatoryArguments();
         for (String key : mandatoryArgs) {
             if (request.getParameter(key) == null) {
-                throw new ProcessingException(_loc.get("parse-missing-mandatory-argument", this, key,  
+                throw new ProcessingException(ctx, _loc.get("parse-missing-mandatory-argument", this, key,  
                     request.getParameterMap().keySet()), HTTP_BAD_REQUEST);
             }
         }
         if (_args.size() < getMinimumArguments()) {
-            throw new ProcessingException(_loc.get("parse-less-argument", this, _args.keySet(),  
+            throw new ProcessingException(ctx, _loc.get("parse-less-argument", this, _args.keySet(),  
+                getMinimumArguments()), HTTP_BAD_REQUEST);
+        }
+        if (_args.size() > getMaximumArguments()) {
+            throw new ProcessingException(ctx, _loc.get("parse-less-argument", this, _args.keySet(),  
                 getMinimumArguments()), HTTP_BAD_REQUEST);
         }
     }
@@ -201,17 +225,23 @@ abstract class AbstractCommand implement
         return map.containsKey(key);
     }
     
-    public ObjectFormatter<?> getObjectFormatter(JPAServletContext ctx) {
+    public ObjectFormatter<?> getObjectFormatter() {
         if (_formatter == null) {
-            String format = getQualifier(QUALIFIER_FORMAT);
-            if (format == null) {
-                format = ctx.getRequest().getSession().getServletContext().getInitParameter(INIT_PARA_FORMAT);
-                if (format == null)
-                    format = FORMAT_DEFAULT;
+            String rformat = getQualifier(QUALIFIER_FORMAT);
+            Format format = null;
+            if (rformat == null) {
+                format = getDefaultFormat();
+            } else {
+                try {
+                    format = Format.valueOf(rformat);
+                } catch (Exception e) {
+                    throw new ProcessingException(ctx, _loc.get("format-not-supported", new Object[]{format, 
+                        ctx.getRequest().getPathInfo(), _ff.getRegisteredKeys()}), HTTP_BAD_REQUEST);
+                }
             }
             _formatter = _ff.newInstance(format);
             if (_formatter == null) {
-                throw new ProcessingException(_loc.get("format-not-supported", new Object[]{format, 
+                throw new ProcessingException(ctx, _loc.get("format-not-supported", new Object[]{format, 
                     ctx.getRequest().getPathInfo(), _ff.getRegisteredKeys()}), HTTP_BAD_REQUEST);
             }
         }
@@ -240,7 +270,7 @@ abstract class AbstractCommand implement
 
     protected void debug(HttpServletRequest request, HttpServletResponse response, JPAServletContext ctx) 
         throws IOException {
-        response.setContentType(MIME_TYPE_PLAIN);
+        response.setContentType(Constants.MIME_TYPE_PLAIN);
         PrintWriter writer = response.getWriter();
         
         writer.println("URI             = [" + request.getRequestURI() + "]");

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Constants.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Constants.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Constants.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/Constants.java Thu Dec  2 11:24:53 2010
@@ -19,12 +19,7 @@
 
 package org.apache.openjpa.persistence.jest;
 
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-
 import org.apache.openjpa.lib.util.Localizer;
-import org.apache.openjpa.persistence.jest.HTMLElement.Tag;
 
 /**
  * Static String constants
@@ -34,24 +29,6 @@ import org.apache.openjpa.persistence.je
  */
 public interface Constants {
     /**
-     * Character constants
-     */
-    public static final char EQUAL = '=';
-    public static final char START = '<';
-    public static final char END   = '>';
-    public static final char SLASH = '/';
-    public static final char QUOTE = '"';
-    public static final char DOT = '.';
-    public static final char UNDERSCORE = '_';
-    public static final char DASH = '-';
-    public static final char HASH = '#';
-    public static final String EMPTY = "";
-    public static final String SPACE = " ";
-    public static final String NEWLINE = "\r\n";
-    public static final String PATH_SEPARATOR = "/";
-    public static final String KEY_VALUE_SEPARATOR = " : ";
-
-    /**
      * Command Qualifiers
      */
     public static final String QUALIFIER_FORMAT      = "format";
@@ -67,14 +44,6 @@ public interface Constants {
     public static final String ARG_QUERY    = "q";
     public static final String ARG_TYPE     = "type";
 
-    /**
-     * Supported format monikers.
-     */
-    public static final String FORMAT_XML     = "xml";
-    public static final String FORMAT_JSON    = "json";
-    public static final String FORMAT_DOJO    = "dojo";
-    public static final String FORMAT_HTML    = "html";
-    public static final String FORMAT_DEFAULT = "html";
     
     /**
      * Mime Types
@@ -82,58 +51,66 @@ public interface Constants {
     public static final String MIME_TYPE_PLAIN = "text/plain";
     public static final String MIME_TYPE_JS    = "text/javascript";
     public static final String MIME_TYPE_CSS   = "text/css";
-    public static final String MIME_TYPE_HTML  = "text/html";
     public static final String MIME_TYPE_XML   = "text/xml";
     public static final String MIME_TYPE_JSON  = "application/json";
      
     public static final String CONTEXT_ROOT  = "/";
+    public static final String JEST_TEMPLATE  = "jest.html";
     
     /**
      * Servlet initialization parameters
      */
-    public static final String INIT_PARA_FORMAT  = "response.format";
-    public static final String INIT_PARA_UNIT    = "persistence.unit";
+    public static final String INIT_PARA_UNIT       = "persistence.unit";
+    public static final String INIT_PARA_STANDALONE = "standalone";
    
     /**
      * Dojo Toolkit URL and Themes
      */
-    public static final String DOJO_URL     = "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js";
-    public static final String DOJO_CSS_URL = "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/"; 
-    public static final String DOJO_THEME   = "claro";
+    public static final String DOJO_BASE_URL = "http://ajax.googleapis.com/ajax/libs/dojo/1.5";
+    public static final String DOJO_THEME    = "claro";
     
-    /**
-     * HTML divisions used by Dojo JavaScript
-     */
-    public static final String HTML_DIV_CANVAS = "canvas";
-    public static final String HTML_DIV_DATA   = "data";
     
+      
     /**
-     * CSS styles
+     * Root element of XML instances. Must match the name defined in <A href="jest-instance.xsd>jest-instance.xsd</A>.
      */
-    public static final String CSS_INVISIBLE      = "display:none;";
-    public static final String CSS_ERROR_MESSSAGE = "error-message";
-    public static final String CSS_ERROR_HEADER   = "error-header";
-    public static final String CSS_EVEN_ROW       = "even";
-    public static final String CSS_ODD_ROW        = "odd";
-    public static final String CSS_DATA_TABLE     = "data";
-      
+    public static final String ROOT_ELEMENT_INSTANCE   = "instances";
+    public static final String ATTR_ID      = "id";
     public static final String ATTR_REL     = "rel";
     public static final String ATTR_SRC     = "src";
     public static final String ATTR_TYPE    = "type";
     public static final String ATTR_NAME    = "name";
     public static final String ATTR_VERSION = "version";
     public static final String ATTR_CLASS   = "class";
-    public static final String HREF         = "href";
-    public static final String STYLESHEET   = "stylesheet";
-    public static final String STYLE        = "style";
-    public static final String REL          = "rel";
-    public static final String ATTR_ID      = "id";
+    public static final String ATTR_HREF    = "href";
+    public static final String ATTR_STYLE   = "style";
+    public static final String ATTR_NULL           = "null";
+    public static final String ATTR_MEMBER_TYPE    = "member-type";
+    public static final String ATTR_KEY_TYPE       = "key-type";
+    public static final String ATTR_VALUE_TYPE     = "value-type";
     
     /**
-     * Root element of XML instances. Must match the name defined in <A href="jest-instance.xsd>jest-instance.xsd</A>.
+     * Elements and attributes in properties XML.
      */
-    public static final String ELEMENT_ROOT_INSTANCE = "instances";
+    public static final String ROOT_ELEMENT_PROPERTIES = "properties";
+    public static final String ELEMENT_PROPERTY     = "property";
+    public static final String ATTR_PROPERTY_KEY     = "name";
+    public static final String ATTR_PROPERTY_VALUE     = "value";
+    
+    
+    public static final String ROOT_ELEMENT_ERROR      = "error";
+    public static final String ELEMENT_ERROR_HEADER    = "error-code";
+    public static final String ELEMENT_ERROR_MESSAGE   = "error-message";
+    public static final String ELEMENT_ERROR_TRACE     = "stacktrace";
+    
+    /**
+     * Root element of XML meta-model. Must match the name defined in <A href="jest-model.xsd>jest-model.xsd</A>.
+     */
+    public static final String ROOT_ELEMENT_MODEL      = "metamodel";
+    
     public static final String ELEMENT_INSTANCE      = "instance";
+    public static final String ELEMENT_URI           = "uri";
+    public static final String ELEMENT_DESCRIPTION   = "description";
     public static final String ELEMENT_REF           = "ref";
     public static final String ELEMENT_NULL_REF      = "null";
     public static final String ELEMENT_MEMBER        = "member";
@@ -141,64 +118,24 @@ public interface Constants {
     public static final String ELEMENT_ENTRY_KEY     = "key";
     public static final String ELEMENT_ENTRY_VALUE   = "value";
 
-    /**
-     * Root element of XML meta-model. Must match the name defined in <A href="jest-instance.xsd>jest-model.xsd</A>.
-     */
-    public static final String ELEMENT_DOMAIN      = "metamodel";
     
-    public static final String NULL_VALUE          = EMPTY;
-    public static final String ATTR_NULL           = "null";
-    public static final String ATTR_MEMBER_TYPE    = "member-type";
-    public static final String ATTR_KEY_TYPE       = "key-type";
-    public static final String ATTR_VALUE_TYPE     = "value-type";
     
     /**
      * JEST resources
      */
-    public static final String JEST_ROOT_RESOURCE      = "index.html";
-    public static final String JEST_STYLESHEET         = "jest.css";
-    public static final String JEST_SCRIPT_INSTANCES   = "instances.js";
-    public static final String JEST_SCRIPT_DOMAIN      = "domain.js";
+//    public static final String JEST_STYLESHEET         = "jest.css";
+//    public static final String JEST_SCRIPT_INSTANCES   = "instances.js";
+//    public static final String JEST_SCRIPT_DOMAIN      = "model.js";
     public static final String JEST_INSTANCE_XSD       = "jest-instance.xsd";
     
-    /**
-     * JEST Cascaded StyleSheet.
-     */
-    public static final HTMLElement CSS_JEST = new HTMLElement(Tag.link).set(
-        ATTR_REL, STYLESHEET, 
-        ATTR_TYPE, MIME_TYPE_CSS, 
-        HREF, JEST_STYLESHEET).createTemplate();
-    
-    /**
-     * JavaScript to render object graph using dojo widgets.
-     */
-    static HTMLElement JEST_INSTANCE_SCRIPT = new HTMLElement(Tag.script).set(
-        ATTR_SRC, JEST_SCRIPT_INSTANCES, 
-        ATTR_TYPE, MIME_TYPE_JS).createTemplate();
-    
-    /**
-     * JavaScript to render domain model using dojo widgets.
-     */
-    static HTMLElement JEST_DOMAIN_SCRIPT = new HTMLElement(Tag.script).set(
-        ATTR_SRC, JEST_SCRIPT_DOMAIN, 
-        ATTR_TYPE, MIME_TYPE_JS).createTemplate();
-
-
-
-    /**
-     * XML constants
-     */
-    public static final String DOCTYPE_STRICT = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
-        + " \"http://www.w3.org/TR/html4/strict.dtd\">";
     static final String JAXP_SCHEMA_SOURCE      = "http://java.sun.com/xml/jaxp/properties/schemaSource";
     static final String JAXP_SCHEMA_LANGUAGE    = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
     
     /**
      * Common instances
      */
-    public static final Collection<String> EMPTY_LIST = Collections.emptySet();
-    public static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy");
     public static final Localizer _loc = Localizer.forPackage(JESTContext.class);
+    public static final String NULL_VALUE          = "null";
 
 
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DomainCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DomainCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DomainCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/DomainCommand.java Thu Dec  2 11:24:53 2010
@@ -20,7 +20,12 @@
 package org.apache.openjpa.persistence.jest;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
 
+import static org.apache.openjpa.persistence.jest.Constants.ARG_TYPE;
+import static org.apache.openjpa.persistence.jest.Constants._loc;
 
 /**
  * Marshals a JPA meta-model in the configured format to the response output stream.
@@ -29,12 +34,27 @@ import java.io.IOException;
  *
  */
 class DomainCommand extends AbstractCommand {
+    private static final List<String> _validQualifiers = Arrays.asList("format");
+    
+    public DomainCommand(JPAServletContext ctx) {
+        super(ctx);
+    }
+    
+    protected Collection<String> getValidQualifiers() {
+        return _validQualifiers;
+    }
+    
+    protected int getMaximumArguments() {
+        return 0;
+    }    
     
     public String getAction() {
         return "domain";
     }
     
-    public void process(JPAServletContext ctx) throws ProcessingException, IOException {
-        getObjectFormatter(ctx).writeOut(ctx.getPersistenceContext().getMetamodel(), ctx.getResponse().getWriter());
+    public void process() throws ProcessingException, IOException {
+        getObjectFormatter().writeOut(ctx.getPersistenceContext().getMetamodel(), 
+            _loc.get("domain-title").toString(), _loc.get("domain-desc").toString(), ctx.getRequestURI(), 
+            ctx.getResponse().getOutputStream());
     }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ExceptionFormatter.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ExceptionFormatter.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ExceptionFormatter.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ExceptionFormatter.java Thu Dec  2 11:24:53 2010
@@ -19,15 +19,12 @@
 
 package org.apache.openjpa.persistence.jest;
 
-import static org.apache.openjpa.persistence.jest.Constants.CSS_JEST;
-import static org.apache.openjpa.persistence.jest.Constants.ATTR_CLASS;
-import static org.apache.openjpa.persistence.jest.Constants.CSS_ERROR_HEADER;
-import static org.apache.openjpa.persistence.jest.Constants.CSS_ERROR_MESSSAGE;
-
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
-import org.apache.openjpa.persistence.jest.HTMLElement.Tag;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
 
 /**
  * Formats error stack trace.
@@ -35,24 +32,31 @@ import org.apache.openjpa.persistence.je
  * @author Pinaki Poddar
  *
  */
-class ExceptionFormatter {
+class ExceptionFormatter extends XMLFormatter {
     /**
-     * Creates a HTML Document with given header and stack trace of the given error.
+     * Creates a XML Document with given header and stack trace of the given error.
      * @param header
      * @param e
      */
-    public HTMLDocument createHTML(String header, Throwable e) {
-        HTMLDocument html = new HTMLDocument();
-        html.getHead().add(CSS_JEST);
+    public Document createXML(String code, String message, Throwable e) {
+        Element root = newDocument(Constants.ROOT_ELEMENT_ERROR);
+        Document doc = root.getOwnerDocument();
+        Element errorCode    = doc.createElement(Constants.ELEMENT_ERROR_HEADER);
+        Element errorMessage = doc.createElement(Constants.ELEMENT_ERROR_MESSAGE);
+        Element stackTrace   = doc.createElement(Constants.ELEMENT_ERROR_TRACE);
+
+        errorCode.setTextContent(code);
+        errorMessage.appendChild(doc.createCDATASection(e.getMessage()));
         
         StringWriter buf = new StringWriter();
         e.printStackTrace(new PrintWriter(buf, true));
-        html.getBody()
-               .add(new HTMLElement(Tag.p).set(ATTR_CLASS, CSS_ERROR_HEADER).setBody(header), 
-                    new HTMLElement(Tag.p).set(ATTR_CLASS, CSS_ERROR_MESSSAGE).setBody(e.getLocalizedMessage()), 
-                    new HTMLElement(Tag.p).setBody("Error Stack Trace:"), 
-                    new HTMLElement(Tag.pre).setBody(buf.toString()));
-        return html;
+        stackTrace.appendChild(doc.createCDATASection(buf.toString()));
+        
+        root.appendChild(errorCode);
+        root.appendChild(errorMessage);
+        root.appendChild(stackTrace);
+        
+        return doc;
     }
 
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/FindCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/FindCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/FindCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/FindCommand.java Thu Dec  2 11:24:53 2010
@@ -44,6 +44,10 @@ class FindCommand extends AbstractComman
     private static final List<String> _mandatoryArgs   = Arrays.asList(ARG_TYPE);
     private static final List<String> _validQualifiers = Arrays.asList("format", "plan");
     
+    public FindCommand(JPAServletContext ctx) {
+        super(ctx);
+    }
+    
     @Override
     protected Collection<String> getMandatoryArguments() {
         return _mandatoryArgs;
@@ -59,7 +63,7 @@ class FindCommand extends AbstractComman
     }
 
     @Override
-    public void process(JPAServletContext ctx) throws ProcessingException {
+    public void process() throws ProcessingException {
         EntityManager em = ctx.getPersistenceContext();
         String type = getMandatoryArgument(ARG_TYPE);
         ClassMetaData meta = ctx.resolve(type);
@@ -73,15 +77,17 @@ class FindCommand extends AbstractComman
         Object pc = em.find(meta.getDescribedType(), oid); 
         if (pc != null) {
             OpenJPAStateManager sm = toStateManager(pc);
-            ObjectFormatter<?> formatter = getObjectFormatter(ctx);
+            ObjectFormatter<?> formatter = getObjectFormatter();
             ctx.getResponse().setContentType(formatter.getMimeType());
             try {
-                formatter.writeOut(Collections.singleton(sm), em.getMetamodel(), ctx.getResponse().getWriter());
+                formatter.writeOut(Collections.singleton(sm), em.getMetamodel(), 
+                    _loc.get("find-title").toString(), _loc.get("find-desc").toString(), ctx.getRequestURI(), 
+                    ctx.getResponse().getOutputStream());
             } catch (IOException e) {
-                throw new ProcessingException(e);
+                throw new ProcessingException(ctx, e);
             }
         } else {
-            throw new ProcessingException(_loc.get("entity-not-found", type, Arrays.toString(pks)), 
+            throw new ProcessingException(ctx, _loc.get("entity-not-found", type, Arrays.toString(pks)), 
                 HttpURLConnection.HTTP_NOT_FOUND);
         }
     }

Added: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/IOR.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/IOR.java?rev=1041330&view=auto
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/IOR.java (added)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/IOR.java Thu Dec  2 11:24:53 2010
@@ -0,0 +1,45 @@
+/*
+ * 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 static org.apache.openjpa.persistence.jest.Constants.NULL_VALUE;
+
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+/**
+ * String reference of a managed object.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class IOR {
+    public static final char DASH = '-';
+    /**
+     * Stringified representation of a managed instance identity.
+     * The simple Java type name and the persistent identity separated by a {@link Constants#DASH dash}.
+     *  
+     * @param sm a managed instance.
+     * @return
+     */
+    public static String toString(OpenJPAStateManager sm) {
+        if (sm == null) return NULL_VALUE;
+        return sm.getMetaData().getDescribedType().getSimpleName() + DASH + sm.getObjectId();
+    }
+}

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

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

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTCommand.java Thu Dec  2 11:24:53 2010
@@ -57,6 +57,10 @@ import javax.servlet.http.HttpServletReq
  *
  */
 public interface JESTCommand {
+    /**
+     * Supported format monikers.
+     */
+    public static enum Format {xml, json};
     
     /**
      * Parse the given request to populate qualifiers and parameters of this command.
@@ -64,10 +68,8 @@ public interface JESTCommand {
      * original request. During {@link #process(ServletRequest, ServletResponse, JPAServletContext) processing}
      * phase, the parameters and qualifiers are accessed from the parsed command itself rather than
      * from the 
-     * 
-     * @param request a HTTP request
      */
-    public void parse(HttpServletRequest request) throws ProcessingException;
+    public void parse() throws ProcessingException;
     
     /**
      * Accessors for this command's arguments and qualifiers. 
@@ -83,9 +85,8 @@ public interface JESTCommand {
     
     /**
      * Process the given request and write the output on to the given response in the given context.
-     * @param ctx the operational context.
      * @throws ProcessingException 
      * 
      */
-    public void process(JPAServletContext ctx) throws ProcessingException, IOException;
+    public void process() throws ProcessingException, IOException;
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTContext.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTContext.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTContext.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTContext.java Thu Dec  2 11:24:53 2010
@@ -19,11 +19,18 @@
 
 package org.apache.openjpa.persistence.jest;
 
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
 import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static org.apache.openjpa.persistence.jest.Constants.CONTEXT_ROOT;
 
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Calendar;
 import java.util.Date;
 
@@ -37,7 +44,6 @@ import org.apache.openjpa.meta.ClassMeta
 import org.apache.openjpa.meta.MetaDataRepository;
 import org.apache.openjpa.persistence.OpenJPAEntityManager;
 import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
-import static org.apache.openjpa.persistence.jest.Constants.*;
 
 /**
  * An operational context combines a {@link OpenJPAEntityManager persistence context} and a HTTP execution
@@ -56,10 +62,12 @@ public class JESTContext implements JPAS
     private final HttpServletRequest   _request;
     private final HttpServletResponse  _response;
     protected MetaDataRepository       _repos;
+    private String _rootResource;
     protected Log _log;
-    protected static PrototypeFactory<JESTCommand> _cf = new PrototypeFactory<JESTCommand>();
+    protected static PrototypeFactory<String,JESTCommand> _cf = new PrototypeFactory<String,JESTCommand>();
     public static final Localizer _loc = Localizer.forPackage(JESTContext.class);
     private static final String ONE_YEAR_FROM_NOW; 
+    public static final char QUERY_SEPARATOR = '?'; 
     
     /**
      * Registers known commands in a {@link PrototypeFactory registry}.
@@ -113,6 +121,23 @@ public class JESTContext implements JPAS
     }
     
     /**
+     * 
+     */
+    public URI getRequestURI() {
+        StringBuffer buf = _request.getRequestURL();
+        String query = _request.getQueryString();
+        if (query != null) {
+            buf.append(QUERY_SEPARATOR).append(query);
+        }
+        try {
+            return new URI(buf.toString());
+        } catch (URISyntaxException e) {
+            throw new ProcessingException(this, _loc.get("bad-uri", _request.getRequestURL()), HTTP_INTERNAL_ERROR);
+        }
+        
+    }
+    
+    /**
      * Gets the response.
      */
     public HttpServletResponse getResponse() {
@@ -127,7 +152,7 @@ public class JESTContext implements JPAS
      * if a action with the given key is registered then the control is delegated to the command.
      * The command parses the entire {@link HttpServletRequest request} for requisite qualifiers and
      * arguments and if the parse is successful then the command is 
-     * {@linkplain JESTCommand#process(JPAServletContext) executed} in this context.
+     * {@linkplain JESTCommand#process() executed} in this context.
      * <br>
      * If path is null, or no  command is registered for the action or the command can not parse
      * the request, then a last ditch attempt is made to {@linkplain #findResource(String) find} a resource. 
@@ -148,26 +173,27 @@ public class JESTContext implements JPAS
      * @throws Exception
      */
     public void execute() throws Exception {
-        debug(_request);
         String path = _request.getPathInfo();
-        if (path == null || CONTEXT_ROOT.equals(path)) {
-            findResource(JEST_ROOT_RESOURCE);
+        if (isContextRoot(path)) {
+            getRootResource();
             return;
         }
         String action = getAction(path);
-        JESTCommand command = _cf.newInstance(action);
+        JESTCommand command = _cf.newInstance(action, this);
         if (command == null) {
             findResource(path.substring(1));
             return;
         }
         try {
-            command.parse(_request);
-            command.process(this);
-        } catch (Exception e) {
+            command.parse();
+            command.process();
+        } catch (ProcessingException e1) {
+            throw e1;
+        } catch (Exception e2) {
             try {
                 findResource(path.substring(action.length()+1));
-            } catch (ProcessingException e2) {
-                throw e;
+            } catch (ProcessingException e3) {
+                throw e2;
             }
         }
     }
@@ -204,14 +230,14 @@ public class JESTContext implements JPAS
      * @throws ProcessingException
      */
     void findResource(String rsrc) throws ProcessingException {
-        _response.setHeader("Cache-Control", "public");
-        _response.setHeader("Expires", ONE_YEAR_FROM_NOW);
+//        _response.setHeader("Cache-Control", "public");
+//        _response.setHeader("Expires", ONE_YEAR_FROM_NOW);
         InputStream in = getClass().getResourceAsStream(rsrc);
         if (in == null) { // try again as a relative path
             if (rsrc.startsWith(CONTEXT_ROOT)) {
                 in = getClass().getResourceAsStream(rsrc.substring(1));
                 if (in == null) {
-                    throw new ProcessingException(_loc.get("resource-not-found", rsrc), HTTP_NOT_FOUND);
+                    throw new ProcessingException(this, _loc.get("resource-not-found", rsrc), HTTP_NOT_FOUND);
                 }
             }
         }
@@ -233,9 +259,10 @@ public class JESTContext implements JPAS
                 }
             }
         } catch (IOException e) {
-            throw new ProcessingException(e, _loc.get("resource-not-found", rsrc), HTTP_NOT_FOUND);
+            throw new ProcessingException(this, e, _loc.get("resource-not-found", rsrc), HTTP_NOT_FOUND);
         }
     }
+    
 
     
     private void log(String s) {
@@ -255,14 +282,49 @@ public class JESTContext implements JPAS
         }
     }
     
-    private void debug(HttpServletRequest request) {
-        log("-----------------------------------------------------------");
-        log("Request URL    = [" + request.getRequestURL() + "]");
-        log("Request URI    = [" + request.getRequestURI() + "]");
-        log("Servlet Path   = [" + request.getServletPath() + "]");
-        log("Context Path   = [" + request.getContextPath() + "]");
-        log("Path Info      = [" + request.getPathInfo() + "]");
-        log("Path Translated = [" + request.getPathTranslated() + "]");
+    /**
+     * Is this path a context root?
+     * @param path
+     * @return
+     */
+    boolean isContextRoot(String path) {
+        return (path == null || CONTEXT_ROOT.equals(path));
     }
     
+    /**
+     * Root resource is a HTML template with deployment specific tokens such as name of the persistence unit
+     * or base url. On first request for this resource, the tokens in the templated HTML file gets replaced  
+     * by the actual deployment specific value into a string. This string (which is an entire HTML file)
+     * is then written to the response.
+     * 
+     * @see TokenReplacedStream
+     * @throws IOException
+     */
+    private void getRootResource() throws IOException {
+        _response.setHeader("Cache-Control", "public");
+        _response.setHeader("Expires", ONE_YEAR_FROM_NOW);
+        if (_rootResource == null) {
+            String[] tokens = {
+                "${persistence.unit}", getPersistenceUnitName(),
+                "${jest.uri}",         _request.getRequestURL().toString(),
+                "${webapp.name}",     _request.getContextPath().startsWith(CONTEXT_ROOT) 
+                                    ? _request.getContextPath().substring(1)
+                                    : _request.getContextPath(),
+                "${servlet.name}",     _request.getServletPath().startsWith(CONTEXT_ROOT) 
+                                    ? _request.getServletPath().substring(1)
+                                    : _request.getServletPath(),
+                "${server.name}",     _request.getServerName(),
+                "${server.port}",     ""+_request.getServerPort(),
+                
+                "${dojo.base}",     Constants.DOJO_BASE_URL,
+                "${dojo.theme}",    Constants.DOJO_THEME,
+                
+            };
+            InputStream in = getClass().getResourceAsStream(Constants.JEST_TEMPLATE);
+            CharArrayWriter out = new CharArrayWriter();
+            new TokenReplacedStream().replace(in, out, tokens);
+            _rootResource = out.toString();
+        }
+        _response.getOutputStream().write(_rootResource.getBytes());
+    }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTServlet.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTServlet.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTServlet.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JESTServlet.java Thu Dec  2 11:24:53 2010
@@ -19,8 +19,15 @@
 
 package org.apache.openjpa.persistence.jest;
 
+import static org.apache.openjpa.persistence.jest.Constants.INIT_PARA_UNIT;
+import static org.apache.openjpa.persistence.jest.Constants.INIT_PARA_STANDALONE;
+import static org.apache.openjpa.persistence.jest.Constants._loc;
+
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
+import javax.persistence.Persistence;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -29,10 +36,9 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.openjpa.kernel.AbstractBrokerFactory;
 import org.apache.openjpa.kernel.BrokerFactory;
-import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.persistence.JPAFacadeHelper;
 import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
-import static org.apache.openjpa.persistence.jest.Constants.*;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
 
 /**
  * A specialized HTTP servlet to interpret HTTP requests as Java Persistent API commands
@@ -60,17 +66,24 @@ import static org.apache.openjpa.persist
  *
  */
 @SuppressWarnings("serial")
-public class JESTServlet extends HttpServlet {
+public class JESTServlet extends HttpServlet  {
     private String _unit;
+    private boolean _debug;
     private OpenJPAEntityManagerFactory _emf;
     
     @Override
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
+        _debug = "true".equalsIgnoreCase(config.getInitParameter("debug"));
         _unit = config.getInitParameter(INIT_PARA_UNIT);
         if (_unit == null) {
             throw new ServletException(_loc.get("no-persistence-unit-param").toString());
-        } else if (findPersistenceUnit()){
+        }
+        boolean standalone = "true".equalsIgnoreCase(config.getInitParameter(INIT_PARA_STANDALONE));
+        if (standalone) {
+            createPersistenceUnit();
+        }
+        if (findPersistenceUnit()) {
             config.getServletContext().log(_loc.get("servlet-init", _unit).toString());
         } else {
             config.getServletContext().log(_loc.get("servlet-not-init", _unit).toString());
@@ -83,19 +96,29 @@ public class JESTServlet extends HttpSer
      */
     @Override
     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        debug(request);
         if (findPersistenceUnit()) {
+            JESTContext ctx = new JESTContext(_unit, _emf, request, response);
             try {
-                JESTContext ctx = new JESTContext(_unit, _emf, request, response);
                 ctx.execute();
             } catch (Exception e) {
-                handleError(e, response);
+                handleError(ctx, e);
             }
         } else {
-            handleError(new RuntimeException(_loc.get("no-persistence-unit", _unit).toString()), response);
+            throw new ServletException(_loc.get("no-persistence-unit", _unit).toString());
         } 
     }
     
-    protected boolean findPersistenceUnit()  throws ServletException {
+    protected void createPersistenceUnit() throws ServletException {
+        try {
+            Map<String, Object> map = new HashMap<String, Object>();
+            map.put("openjpa.EntityManagerFactoryPool", true);
+            _emf = OpenJPAPersistence.cast(Persistence.createEntityManagerFactory(_unit, map));
+        } catch (Exception e) {
+            throw new ServletException(_loc.get("no-persistence-unit").toString(), e);
+        } 
+    }
+    protected boolean findPersistenceUnit() {
         if (_emf == null) {
             BrokerFactory bf = AbstractBrokerFactory.getPooledFactoryForKey(_unit);
             if (bf != null) {
@@ -105,11 +128,33 @@ public class JESTServlet extends HttpSer
         return _emf != null;
     }
     
-    protected void handleError(Throwable t, HttpServletResponse response) throws IOException {
+    protected void handleError(JPAServletContext ctx, Throwable t) throws IOException {
         if (t instanceof ProcessingException) {
-            ((ProcessingException)t).printStackTrace(response);
+            ((ProcessingException)t).printStackTrace();
         } else {
-            new ProcessingException(t).printStackTrace(response);
+            new ProcessingException(ctx, t).printStackTrace();
         }
     }
+
+    @Override
+    public void destroy() {
+        _emf = null;
+        _unit = null;;
+    }
+    
+    private void debug(HttpServletRequest request) {
+        if (!_debug) return;
+        log("-----------------------------------------------------------");
+        log("Request URL    = [" + request.getRequestURL() + "]");
+        log("Request URI    = [" + request.getRequestURI() + "]");
+        log("Servlet Path   = [" + request.getServletPath() + "]");
+        log("Context Path   = [" + request.getContextPath() + "]");
+        log("Path Info      = [" + request.getPathInfo() + "]");
+        log("Path Translated = [" + request.getPathTranslated() + "]");
+    }
+    
+    public void log(String s) {
+        System.err.println(s);
+        super.log(s);
+    }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JPAServletContext.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JPAServletContext.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JPAServletContext.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JPAServletContext.java Thu Dec  2 11:24:53 2010
@@ -19,6 +19,8 @@
 
 package org.apache.openjpa.persistence.jest;
 
+import java.net.URI;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -55,6 +57,12 @@ public interface JPAServletContext {
     public HttpServletResponse getResponse();
     
     /**
+     * Get the requested URI. 
+     * @return
+     */
+    public URI getRequestURI();
+    
+    /**
      * Resolve the given alias to meta-data of the persistent type.
      * @param alias a moniker for the Java type. It can be fully qualified type name or entity name
      * or simple name of the actual persistent Java class.

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONObjectFormatter.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONObjectFormatter.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONObjectFormatter.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/JSONObjectFormatter.java Thu Dec  2 11:24:53 2010
@@ -24,8 +24,10 @@ import java.io.CharArrayWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.Reader;
+import java.net.URI;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collection;
@@ -66,7 +68,7 @@ public class JSONObjectFormatter impleme
                 PrintWriter writer = ctx.getResponse().getWriter();
                 writer.println(result.toString());
             } catch (Exception e) {
-                throw new ProcessingException(e);
+                throw new ProcessingException(ctx, e);
             }
         } else {
             throw new RuntimeException(this + " does not know how to encode " + obj);
@@ -74,8 +76,11 @@ public class JSONObjectFormatter impleme
         return;
     }
     
-    public void writeOut(Collection<OpenJPAStateManager> sms, Metamodel model, PrintWriter writer) throws IOException {
-        writer.println(encode(sms,model));
+    public JSON writeOut(Collection<OpenJPAStateManager> sms, Metamodel model, String title, String desc, 
+        URI uri, OutputStream out) throws IOException {
+        JSON json = encode(sms,model);
+        out.write(json.toString().getBytes());
+        return json;
     }
     
     public JSON encode(Collection<OpenJPAStateManager> sms, Metamodel model) {
@@ -278,21 +283,14 @@ public class JSONObjectFormatter impleme
         return writer.toString();
     }
 
-    /* (non-Javadoc)
-     * @see org.apache.openjpa.persistence.jest.ObjectFormatter#encode(javax.persistence.metamodel.Metamodel)
-     */
     @Override
     public JSON encode(Metamodel model) {
         // TODO Auto-generated method stub
         return null;
     }
 
-    /* (non-Javadoc)
-     * @see org.apache.openjpa.persistence.jest.ObjectFormatter#writeOut(javax.persistence.metamodel.Metamodel, java.io.PrintWriter)
-     */
     @Override
-    public void writeOut(Metamodel model, PrintWriter writer) throws IOException {
-        // TODO Auto-generated method stub
-        
+    public JSON writeOut(Metamodel model, String title, String desc, URI uri, OutputStream out) throws IOException {
+        throw new UnsupportedOperationException();
     }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/MetamodelHelper.java Thu Dec  2 11:24:53 2010
@@ -26,7 +26,9 @@ import java.util.List;
 
 import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.ManagedType;
+import javax.persistence.metamodel.MapAttribute;
 import javax.persistence.metamodel.Metamodel;
+import javax.persistence.metamodel.PluralAttribute;
 import javax.persistence.metamodel.SingularAttribute;
 
 import org.apache.openjpa.meta.ClassMetaData;
@@ -39,6 +41,8 @@ import static org.apache.openjpa.persist
  *
  */
 public class MetamodelHelper {
+    public static final char DASH = '-';
+    public static final char UNDERSCORE = '_';
     
     /**
      * Attribute Category makes a finer distinction over PersistentAttributeType declared in
@@ -139,6 +143,33 @@ public class MetamodelHelper {
     }
     
     /**
+     * Gets name of the attribute type. For collection and map type attribute, the name is
+     * appended with generic type argument names.
+     * @param attr
+     * @return
+     */
+    public static String getAttributeTypeName(Attribute<?, ?> attr) {
+        StringBuilder name = new StringBuilder(attr.getJavaType().getSimpleName());
+        switch (attr.getPersistentAttributeType()) {
+            case ONE_TO_MANY:
+            case ELEMENT_COLLECTION:
+                name.append("&lt;")
+                    .append(((PluralAttribute<?,?,?>)attr).getBindableJavaType().getSimpleName())
+                    .append("&gt;");
+                break;
+            case MANY_TO_MANY:
+                name.append("&lt;")
+                .append(((MapAttribute<?,?,?>)attr).getKeyJavaType().getSimpleName())
+                .append(',')
+                .append(((MapAttribute<?,?,?>)attr).getBindableJavaType().getSimpleName())
+                .append("&gt;");
+            break;
+            default:
+        }
+        return name.toString();
+    }
+    
+    /**
      * Compares attribute by their category and within the same category by name.
      *
      */

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ObjectFormatter.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ObjectFormatter.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ObjectFormatter.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ObjectFormatter.java Thu Dec  2 11:24:53 2010
@@ -20,7 +20,9 @@
 package org.apache.openjpa.persistence.jest;
 
 import java.io.IOException;
-import java.io.PrintWriter;
+import java.io.OutputStream;
+import java.net.URI;
+import java.text.SimpleDateFormat;
 import java.util.Collection;
 
 import javax.persistence.metamodel.Metamodel;
@@ -50,6 +52,7 @@ import org.apache.openjpa.kernel.OpenJPA
  *
  */
 public interface ObjectFormatter<T> {
+    public static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy");
     
     /**
      * Gets the mime type produced by this formatter.
@@ -83,12 +86,14 @@ public interface ObjectFormatter<T> {
      * 
      * @param objs the collection of objects to be formatted.
      * @param model a meta-model of managed types, provided for easier introspection if necessary
+     * @param title TODO
+     * @param desc TODO
+     * @param uri TODO
      * @param writer a text-oriented output stream
-     *  
      * @throws IOException
      */
-    public void writeOut(Collection<OpenJPAStateManager> objs, Metamodel model, 
-        PrintWriter writer) throws IOException;
+    public T writeOut(Collection<OpenJPAStateManager> objs, Metamodel model,
+        String title, String desc, URI uri, OutputStream out) throws IOException;
     
     /**
      * Encodes the given domain model, then write it into the given output stream.
@@ -98,5 +103,5 @@ public interface ObjectFormatter<T> {
      * 
      * @throws IOException
      */
-    public void writeOut(Metamodel model, PrintWriter writer) throws IOException;
+    public T writeOut(Metamodel model, String title, String desc, URI uri, OutputStream out) throws IOException;
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ProcessingException.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ProcessingException.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ProcessingException.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/ProcessingException.java Thu Dec  2 11:24:53 2010
@@ -19,17 +19,16 @@
 
 package org.apache.openjpa.persistence.jest;
 
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static org.apache.openjpa.persistence.jest.Constants.MIME_TYPE_XML;
+
 import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.HttpURLConnection;
+import java.net.URLDecoder;
 
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.openjpa.lib.util.Localizer.Message;
-import org.apache.openjpa.persistence.jest.HTMLElement.Tag;
-
-import static org.apache.openjpa.persistence.jest.Constants.*;
-import static java.net.HttpURLConnection.*;
+import org.w3c.dom.Document;
 
 /**
  * Specialized RuntimException thrown by JEST commands.
@@ -40,28 +39,32 @@ import static java.net.HttpURLConnection
  */
 @SuppressWarnings("serial")
 public class ProcessingException extends RuntimeException {
+    private final JPAServletContext ctx;
     private final int _errorCode;
     
-    public ProcessingException(Throwable error) {
-        this(error, HTTP_INTERNAL_ERROR);
+    public ProcessingException(JPAServletContext ctx, Throwable error) {
+        this(ctx, error, HTTP_INTERNAL_ERROR);
     }
     
-    public ProcessingException(Throwable error, int errorCode) {
+    public ProcessingException(JPAServletContext ctx, Throwable error, int errorCode) {
         super(error);
+        this.ctx = ctx;
         this._errorCode = errorCode;
     }
 
-    public ProcessingException(Message message, int errorCode) {
+    public ProcessingException(JPAServletContext ctx, Message message, int errorCode) {
         super(message.toString());
+        this.ctx = ctx;
         this._errorCode = errorCode;
     }
     
-    public ProcessingException(Throwable error, Message message) {
-        this(error, message, HTTP_INTERNAL_ERROR);
+    public ProcessingException(JPAServletContext ctx, Throwable error, Message message) {
+        this(ctx, error, message, HTTP_INTERNAL_ERROR);
     }
     
-    public ProcessingException(Throwable error, Message message, int errorCode) {
+    public ProcessingException(JPAServletContext ctx, Throwable error, Message message, int errorCode) {
         super(message.toString(), error);
+        this.ctx = ctx;
         this._errorCode = errorCode;
     }
     
@@ -71,13 +74,19 @@ public class ProcessingException extends
      * @param response
      * @throws IOException
      */
-    public void printStackTrace(HttpServletResponse response) throws IOException {
-        response.setContentType(MIME_TYPE_HTML);
-        response.setStatus(_errorCode);
-        PrintWriter writer = response.getWriter();
-        Throwable t = this.getCause() == null ? this : getCause();
-        HTMLDocument html = new ExceptionFormatter().createHTML("HTTP Error " + _errorCode, t);
-        writer.println(html);
+    public void printStackTrace() {
+        try {
+            HttpServletResponse response = ctx.getResponse();
+            response.setContentType(MIME_TYPE_XML);
+            response.setStatus(_errorCode);
+            Throwable t = this.getCause() == null ? this : getCause();
+            String uri = "URI: " + URLDecoder.decode(ctx.getRequestURI().toString(), "UTF-8");
+            ExceptionFormatter formatter = new ExceptionFormatter();
+            Document xml = formatter.createXML("HTTP Error: " + _errorCode, uri, t);
+            formatter.write(xml, response.getOutputStream(), false);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
     
 

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesCommand.java Thu Dec  2 11:24:53 2010
@@ -29,6 +29,8 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletResponse;
 
+import org.w3c.dom.Document;
+
 
 /**
  * Represents configuration properties in HTML.
@@ -37,19 +39,27 @@ import javax.servlet.http.HttpServletRes
  *
  */
 public class PropertiesCommand extends AbstractCommand {
+    private static final char DOT = '.';
+    
+    public PropertiesCommand(JPAServletContext ctx) {
+        super(ctx);
+    }
     
+    protected int getMaximumArguments() {
+        return 0;
+    }    
+
     @Override
-    public void process(JPAServletContext ctx) throws ProcessingException, IOException {
+    public void process() throws ProcessingException, IOException {
         HttpServletResponse response = ctx.getResponse();
-        response.setContentType(MIME_TYPE_HTML);
-        PrintWriter writer = response.getWriter();
+        response.setContentType(MIME_TYPE_XML);
         
         Map<String,Object> properties = ctx.getPersistenceContext().getProperties();
         removeBadEntries(properties);
         PropertiesFormatter formatter = new PropertiesFormatter();
         String caption = _loc.get("properties-caption", ctx.getPersistenceUnitName()).toString();
-        HTMLElement html = formatter.createHTML(caption, "", "", properties);
-        writer.println(html);
+        Document xml = formatter.createXML(caption, "", "", properties);
+        formatter.write(xml, response.getOutputStream(), false);
         response.setStatus(HttpURLConnection.HTTP_OK);
     }
     
@@ -59,4 +69,9 @@ public class PropertiesCommand extends A
             if (keys.next().indexOf(DOT) == -1) keys.remove();
         }
     }
+
+    @Override
+    protected Format getDefaultFormat() {
+        return Format.xml;
+    }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesFormatter.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesFormatter.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesFormatter.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PropertiesFormatter.java Thu Dec  2 11:24:53 2010
@@ -22,8 +22,8 @@ package org.apache.openjpa.persistence.j
 import java.util.Arrays;
 import java.util.Map;
 
-import org.apache.openjpa.persistence.jest.HTMLElement.Tag;
-import static org.apache.openjpa.persistence.jest.Constants.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 /**
  * Formats a key-value pair in a HTML Document.
@@ -31,28 +31,19 @@ import static org.apache.openjpa.persist
  * @author Pinaki Poddar
  *
  */
-class PropertiesFormatter {
-    public HTMLDocument createHTML(String title, String tkey, String tvalue, Map<String,Object> properties) {
-        HTMLDocument html = new HTMLDocument();
-        html.getHead().add(CSS_JEST);
-
-        HTMLElement table = new HTMLElement(Tag.table).add(new HTMLElement(Tag.caption).setBody(title));
-        HTMLElement header = new HTMLElement(Tag.tr).add(
-            new HTMLElement(Tag.th).set(STYLE, "width:35%").setBody(tkey), 
-            new HTMLElement(Tag.th).set(STYLE, "width:65%").setBody(tvalue));
-        table.add(header);
-        html.getBody().add(table);
-        int i = 0;
+class PropertiesFormatter extends XMLFormatter {
+    public Document createXML(String title, String tkey, String tvalue, Map<String,Object> properties) {
+        Element root = newDocument(Constants.ROOT_ELEMENT_PROPERTIES);
         for (Map.Entry<String,Object> entry : properties.entrySet()) {
-            HTMLElement row = new HTMLElement(Tag.tr).set(ATTR_CLASS, ++i%2 == 0 ?  CSS_EVEN_ROW : CSS_ODD_ROW);
+            Element property = root.getOwnerDocument().createElement("property");
             Object value = entry.getValue();
             String v = value == null 
                      ? Constants.NULL_VALUE 
                      : value.getClass().isArray() ? Arrays.toString((Object[])value) : value.toString();
-            table.add(row.add(
-                new HTMLElement(Tag.td).setBody(entry.getKey()), 
-                new HTMLElement(Tag.td).setBody(v)));
+                     property.setAttribute(Constants.ATTR_PROPERTY_KEY, entry.getKey());
+                     property.setAttribute(Constants.ATTR_PROPERTY_VALUE, v);
+            root.appendChild(property);
         }
-        return html;
+        return root.getOwnerDocument();
     }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PrototypeFactory.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PrototypeFactory.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PrototypeFactory.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/PrototypeFactory.java Thu Dec  2 11:24:53 2010
@@ -19,44 +19,108 @@
 
 package org.apache.openjpa.persistence.jest;
 
+import java.lang.reflect.Constructor;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
+import org.apache.openjpa.kernel.Filters;
+
 /**
  * A factory for a specific type of objects registered by a key.
- * The client registers a type indexed by name. The type must have a no-argument constructor.
+ * The client registers a type indexed by name. 
  * The client can get a new instance of the registered type. 
+ * The requested registered type <em>not</em> necessarily have to have a no-arg
+ * constructor. The constructor arguments can be passed during 
+ * {@link #newInstance(Class, Object...) new instance} request. Based on the
+ * arguments, a matching constructor, if any, is located and invoked.
+ * 
+ * <K> type of key for this registry
+ * <T> base type of the objects to construct 
  * 
  * @author Pinaki Poddar
  *
  */
-public class PrototypeFactory<T> {
-    private Map<String, Class<? extends T>> _registry = new TreeMap<String, Class<? extends T>>();
+public class PrototypeFactory<K,T> {
+    private Map<K, Class<? extends T>> _registry = new TreeMap<K, Class<? extends T>>();
     
     /**
-     * Register
-     * @param key
-     * @param prototype
+     * Register the given class with the given key.
+     * 
+     * @param key a non-null key.
+     * @param prototype a type.
      */
-    public void register(String key, Class<? extends T> prototype) {
+    public void register(K key, Class<? extends T> prototype) {
         _registry.put(key, prototype);
     }
     
-    public T newInstance(String name) {
-        return _registry.containsKey(name) ? newInstance(_registry.get(name)) : null;
+    /**
+     * Create a new instance of the type {@linkplain #register(Object, Class) registered} before
+     * with the given key, if any.
+     * The given arguments are used to identify a constructor of the registered type and 
+     * passed to the constructor of the registered type.
+     * 
+     * @param key a key to identify a registered type.
+     * @param args arguments to pass to the constructor of the type.
+     * 
+     * @return null if no type has been registered against the given key.  
+     */
+    public T newInstance(K key, Object... args) {
+        return _registry.containsKey(key) ? newInstance(_registry.get(key), args) : null;
     }
     
-    public Set<String> getRegisteredKeys() {
+    /**
+     * Gets the keys registered in this factory.
+     * 
+     * @return immutable set of registered keys.
+     */
+    public Set<K> getRegisteredKeys() {
         return Collections.unmodifiableSet(_registry.keySet());
     }
     
-    private T newInstance(Class<? extends T> type) {
+    private T newInstance(Class<? extends T> type, Object... args) {
         try {
-            return type.newInstance();
+            return findConstructor(type, getConstructorParameterTypes(args)).newInstance(args);
         } catch (Exception e) {
             throw new RuntimeException();
         }
     }
+    
+    Class<?>[] getConstructorParameterTypes(Object... args) {
+        if (args == null || args.length == 0) {
+            return new Class<?>[0];
+        }
+        Class<?>[] types = new Class<?>[args.length];
+        for (int i = 0; i < args.length; i++) {
+            types[i] = args[i] == null ? Object.class : args[i].getClass();
+        }
+        return types;
+    }
+    
+    /**
+     * Finds a constructor of the given class with given argument types.
+     */
+    Constructor<? extends T> findConstructor(Class<? extends T> cls, Class<?>[] types) {
+        try {
+            return cls.getConstructor(types);
+        } catch (Exception e) {
+            Constructor<?>[] constructors = cls.getConstructors();
+            for (Constructor<?> cons : constructors) {
+                Class<?>[] paramTypes = cons.getParameterTypes();
+                boolean match = false;
+                if (paramTypes.length == types.length) {
+                    for (int i = 0; i < paramTypes.length; i++) {
+                        match = paramTypes[i].isAssignableFrom(Filters.wrap(types[i]));
+                        if (!match)
+                            break;
+                        }
+                    }
+                    if (match) {
+                        return (Constructor<? extends T>)cons;
+                    }
+            }
+        }
+        throw new RuntimeException();//_loc.get("fill-ctor-none", cls, Arrays.toString(types)).getMessage());
+    }
 }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/QueryCommand.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/QueryCommand.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/QueryCommand.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/QueryCommand.java Thu Dec  2 11:24:53 2010
@@ -41,6 +41,10 @@ class QueryCommand extends AbstractComma
         QUALIFIER_FORMAT, QUALIFIER_PLAN, QUALIFIER_NAMED, QUALIFIER_SINGLE, 
         QUALIFIER_FIRSTRESULT, QUALIFIER_MAXRESULT);
     
+    public QueryCommand(JPAServletContext ctx) {
+        super(ctx);
+    }
+
     @Override
     protected Collection<String> getMandatoryArguments() {
         return _mandatoryArgs;
@@ -56,7 +60,7 @@ class QueryCommand extends AbstractComma
     }
 
     @Override
-    public void process(JPAServletContext ctx) throws ProcessingException {
+    public void process() throws ProcessingException {
         String spec = getMandatoryArgument(ARG_QUERY);
         try {
             EntityManager em = ctx.getPersistenceContext();
@@ -70,12 +74,14 @@ class QueryCommand extends AbstractComma
             for (Map.Entry<String, String> entry : args.entrySet()) {
                 query.setParameter(entry.getKey(), entry.getValue());
             }
-            getObjectFormatter(ctx)
+            getObjectFormatter()
                 .writeOut(toStateManager(isBooleanQualifier(QUALIFIER_SINGLE) 
                  ? Collections.singleton(query.getSingleResult()) : query.getResultList()), 
-                 em.getMetamodel(), ctx.getResponse().getWriter());
+                 em.getMetamodel(), 
+                 _loc.get("query-title").toString(), _loc.get("query-desc").toString(), ctx.getRequestURI(), 
+                 ctx.getResponse().getOutputStream());
         } catch (Exception e) {
-            throw new ProcessingException(e, _loc.get("query-execution-error", spec));
+            throw new ProcessingException(ctx, e, _loc.get("query-execution-error", spec));
         }
     }
 }

Added: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/TokenReplacedStream.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/TokenReplacedStream.java?rev=1041330&view=auto
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/TokenReplacedStream.java (added)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/TokenReplacedStream.java Thu Dec  2 11:24:53 2010
@@ -0,0 +1,180 @@
+/*
+ * 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.InputStream;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Reads from an input stream and writes to an output stream after replacing matched tokens
+ * by their counterpart.
+ * 
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class TokenReplacedStream {
+    /**
+     * Read the given input stream and replaces the tokens as it reads. The replaced stream is written to the
+     * given output stream.
+     * 
+     * @param in a non-null input stream
+     * @param out a character oriented writer
+     * @param replacements an even number of Strings. Any occurrence of the even-indexed i-th String in the
+     * input stream will be replaced by the (i+1)-th String in the output writer. 
+     */
+    public void replace(InputStream in, Writer out, String... prs) throws IOException {
+        if (prs.length%2 != 0) 
+            throw new IllegalArgumentException("Even number of pattern/string pairs: " + Arrays.toString(prs) 
+                + ". Must be even number of arguments.");
+        Pattern[] patterns = new Pattern[prs.length/2];
+        for (int i = 0; i < prs.length; i += 2) {
+            patterns[i/2] = new Pattern(prs[i], prs[i+1]);
+        }
+        
+        StringBuilder tmp = new StringBuilder();
+        for (int c = 0; (c = in.read()) != -1;) {
+            int cursor = match((char)c, patterns);
+            if (cursor < 0) { // no pattern recognized at all
+                if (tmp.length() > 0) { // append  partial match then discard partial memory
+                    for (int j = 0; j < tmp.length(); j++) {
+                        out.write(tmp.charAt(j));
+                    }
+                    tmp.delete(0, tmp.length());
+                } 
+                out.write((char)c); // directly output
+            } else {
+                Pattern p = matched(patterns); // has any pattern matched completely
+                if (p != null) { // a pattern matched completely
+                    char[] replace = p.replace().toCharArray();
+                    for (int j = 0; j < replace.length; j++) {
+                        out.write(replace[j]);
+                    }
+                    reset(patterns);
+                    tmp.delete(0, tmp.length());
+                } else {
+                    tmp.append((char)c); // remember partial match
+                }
+            }
+        }
+    }
+
+    /**
+     * Match the given character to all patterns and return the index of highest match. 
+     * @param c a character to match
+     * @param patterns an array of patterns
+     * @return -1 if character matched no pattern 
+     */
+    int match(char c, Pattern...patterns) {
+        if (patterns == null)
+            return -1;
+        int result = -1;
+        for (Pattern p : patterns) {
+            result = Math.max(result, p.match(c));
+        }
+        return result;
+    }
+    
+    /**
+     * Gets the pattern if any in matched state
+     * @param patterns
+     * @return
+     */
+    Pattern matched(Pattern...patterns) {
+        if (patterns == null)
+            return null;
+        for (Pattern p : patterns) {
+            if (p.isMatched()) return p;
+        }
+        return null;
+    }
+    
+    /**
+     * Resets all the patterns.
+     * @param patterns
+     */
+    void reset(Pattern...patterns) {
+        if (patterns == null)
+            return;
+        for (Pattern p : patterns) {
+            p.reset();
+        }
+    }
+    
+    public static class Pattern {
+        private final char[] chars;
+        private final String _replace;
+        private int _cursor;
+        
+        /**
+         * Construct a pattern and its replacement.
+         */
+        public Pattern(String s, String replace) {
+            if (s == null || s.length() == 0)
+                throw new IllegalArgumentException("Pattern [" + s + "] can not be empty or null ");
+            if (replace == null)
+                throw new IllegalArgumentException("Replacement [" + replace + "] is null for pattern [" + s + "]");
+            chars = s.toCharArray();
+            _cursor = -1;
+            _replace = replace;
+        }
+        
+        /**
+         * Match the given character with the current cursor and advance the matching length.
+         * @param c
+         * @return the matching length. -1 denotes the pattern did not match the character.
+         */
+        public int match(char c) {
+            if (c != chars[++_cursor]) {
+                reset();
+            }
+            return _cursor;
+        }
+        
+        /**
+         * Reset the cursor. Subsequent matching will begin at start.
+         */
+        public void reset() {
+            _cursor = -1;
+        }    
+        
+        /**
+         * Is this pattern matched fully?
+         * A pattern is fully matched when the matching length is equal to the length of the pattern string.
+         */
+        public boolean isMatched() {
+            return _cursor == chars.length-1;
+        }
+        
+        /**
+         * Gets the string to be replaced.
+         */
+        public String replace() {
+            return _replace;
+        }
+        
+        public String toString() {
+            return new String(chars) + ":" + _cursor;
+        }
+    }
+
+}

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

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