openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r1041330 [2/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...
Date Thu, 02 Dec 2010 11:24:54 GMT
Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLFormatter.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLFormatter.java?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLFormatter.java (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/jest/XMLFormatter.java Thu Dec  2 11:24:53 2010
@@ -26,9 +26,11 @@ import java.io.CharArrayWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.PrintWriter;
+import java.io.OutputStream;
 import java.io.Reader;
 import java.io.Writer;
+import java.net.URI;
+import java.net.URLEncoder;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -42,7 +44,9 @@ import java.util.Set;
 
 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 javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
@@ -83,6 +87,7 @@ public class XMLFormatter implements Obj
     public static final  Schema          _xsd;
     private static final DocumentBuilder _builder;
     private static final Transformer     _transformer;
+    private static final String EMPTY_TEXT = " ";
     
     static {
         try {
@@ -115,12 +120,12 @@ public class XMLFormatter implements Obj
      * @param parent the parent node to which the new node be attached.
      */
     public Document encode(final Collection<OpenJPAStateManager> sms, Metamodel model) {
-        Document doc = newDocument(ELEMENT_ROOT_INSTANCE);
+        Element root = newDocument(ROOT_ELEMENT_INSTANCE);
         Closure closure = new Closure(sms);
         for (OpenJPAStateManager sm : closure) {
-            encodeManagedInstance(sm, doc.getDocumentElement(), false, model);
+            encodeManagedInstance(sm, root, false, model);
         }
-        return doc;
+        return root.getOwnerDocument();
     }
     
     /**
@@ -129,21 +134,21 @@ public class XMLFormatter implements Obj
      * @param model a persistent domain model. Must not be null.
      */
     public Document encode(Metamodel model) {
-        Document doc = newDocument(ELEMENT_DOMAIN);
+        Element root = newDocument(ROOT_ELEMENT_MODEL);
         for (ManagedType<?> t : model.getManagedTypes()) {
-            encodeManagedType(t, doc.getDocumentElement());
+            encodeManagedType(t, root);
         }
-        return doc;
+        return root.getOwnerDocument();
     }
     
     /**
-     * Create a new document with the given root.
+     * Create a new document with the given tag as the root element. 
      * 
      * @param rootTag the tag of the root element
      * 
-     * @return a new XML document
+     * @return the document element of a new document
      */
-    private Document newDocument(String rootTag) {
+    public Element newDocument(String rootTag) {
         Document doc = _builder.newDocument();
         Element root = doc.createElement(rootTag);
         doc.appendChild(root);
@@ -155,21 +160,50 @@ public class XMLFormatter implements Obj
         for (int i = 0; i < nvpairs.length; i += 2) {
             root.setAttribute(nvpairs[i], nvpairs[i+1]);
         }
-        return doc;
+        return root;
     }
 
     
     @Override
-    public void writeOut(Collection<OpenJPAStateManager> objs, Metamodel model, PrintWriter writer) throws IOException {
-        write(encode(objs, model), writer, true);
+    public Document writeOut(Collection<OpenJPAStateManager> objs, Metamodel model, String title, String desc, 
+        URI uri, OutputStream out) throws IOException {
+        Document doc = encode(objs, model);
+        decorate(doc, title, desc, uri);
+        write(doc, out, true);
+        return doc;
     }
     
     @Override
-    public void writeOut(Metamodel model, PrintWriter writer) throws IOException {
-        write(encode(model), writer, true);
+    public Document writeOut(Metamodel model, String title, String desc, URI uri, OutputStream out) 
+        throws IOException {
+        Document doc = encode(model);
+        decorate(doc, title, desc, uri);
+        write(doc, out, true);
+        return doc;
     }
     
-    protected void write(Document doc, Writer writer, boolean standalone) throws IOException {
+    Document decorate(Document doc, String title, String desc, URI uri) {
+        Element root = doc.getDocumentElement();
+        Element instance = (Element)root.getElementsByTagName(ELEMENT_INSTANCE).item(0);
+        Element uriElement = doc.createElement(ELEMENT_URI);
+        uriElement.setTextContent(uri == null ? NULL_VALUE : uri.toString());
+        Element descElement = doc.createElement(ELEMENT_DESCRIPTION);
+        descElement.setTextContent(desc == null ? NULL_VALUE : desc);
+        root.insertBefore(uriElement, instance);
+        root.insertBefore(descElement, instance);
+        return doc;
+    }
+    
+    public void write(Document doc, OutputStream out, boolean standalone) throws IOException {
+        try {
+            _transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, standalone ? "yes" : "no");
+            _transformer.transform(new DOMSource(doc), new StreamResult(out));
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+    
+    public void write(Document doc, Writer writer, boolean standalone) throws IOException {
         try {
             _transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, standalone ? "yes" : "no");
             _transformer.transform(new DOMSource(doc), new StreamResult(writer));
@@ -375,8 +409,8 @@ public class XMLFormatter implements Obj
         Element ref = parent.getOwnerDocument().createElement(sm == null ? ELEMENT_NULL_REF : ELEMENT_REF);
         if (sm != null)
             ref.setAttribute(ATTR_ID, ior(sm));
-     // IMPORTANT: for xml transformer not to omit the closing tag otherwise dojo is confused
-        ref.setTextContent(SPACE); 
+     // IMPORTANT: for xml transformer not to omit the closing tag, otherwise dojo is confused
+        ref.setTextContent(EMPTY_TEXT); 
         parent.appendChild(ref);
         return ref;
     }
@@ -394,7 +428,7 @@ public class XMLFormatter implements Obj
         if (obj instanceof Date)
             element.setTextContent(dateFormat.format(obj));
         else 
-            element.setTextContent(obj.toString());
+            element.setTextContent(obj == null ? NULL_VALUE : obj.toString());
     }
     
     
@@ -434,22 +468,19 @@ public class XMLFormatter implements Obj
         root.setAttribute(ATTR_NAME, type.getJavaType().getSimpleName());
         List<Attribute<?,?>> attributes = MetamodelHelper.getAttributesInOrder(type);
         for (Attribute<?,?> a : attributes) {
-            String tag = null;
-            if (a instanceof SingularAttribute) {
-                SingularAttribute<?, ?> sa = (SingularAttribute<?, ?>)a;
-                if (sa.isId()) {
-                    tag = ATTR_ID;
-                } else if (sa.isVersion()) {
-                    tag = ATTR_VERSION;
-                } 
-            } 
-            if (tag == null) {
-                tag = a.getPersistentAttributeType().toString().toLowerCase().replace(UNDERSCORE, DASH);
-            }
+            String tag = MetamodelHelper.getTagByAttributeType(a);
             
             Element child = doc.createElement(tag);
             root.appendChild(child);
-            child.setAttribute(ATTR_TYPE, a.getJavaType().getSimpleName());
+            child.setAttribute(ATTR_TYPE, typeOf(a.getJavaType()));
+            if (a instanceof PluralAttribute) {
+                if (a instanceof MapAttribute) {
+                    child.setAttribute(ATTR_KEY_TYPE,   typeOf(((MapAttribute)a).getKeyJavaType()));
+                    child.setAttribute(ATTR_VALUE_TYPE, typeOf(((MapAttribute)a).getBindableJavaType()));
+                } else {
+                    child.setAttribute(ATTR_MEMBER_TYPE, typeOf(((PluralAttribute)a).getBindableJavaType()));
+                }
+            }
             child.setTextContent(a.getName());
         }
     }

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/index.html
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/index.html?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/index.html (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/index.html Thu Dec  2 11:24:53 2010
@@ -61,17 +61,17 @@ The documentation on JEST is available i
 	You can deploy JEST as a servlet in a web application.
 	<hr>
 	Following <code>WEB-INF/web.xml</code> descriptor will enable JEST to
-	operate on a persistence unit named <code>jestdemo</code>. Of course, JEST servlet
+	operate on a persistence unit named <code>${persistence.unit}</code>. Of course, JEST servlet
 	must be in the same module scope of the application that is using 
-	using <code>jestdemo</code> as its persistence unit.  
+	using <code>${persistence.unit}</code> as its persistence unit.  
 	<br>
 <pre>
 <code class="tag">&lt;servlet&gt;</code>
-  <code class="tag">&lt;servlet-name&gt;</code>jest<code class="tag">&lt;/servlet-name&gt;</code>
+  <code class="tag">&lt;servlet-name&gt;</code>${webapp.name}<code class="tag">&lt;/servlet-name&gt;</code>
   <code class="tag">&lt;servlet-class&gt;</code><span style="color:blue">org.apache.openjpa.persistence.jest.JESTServlet</span><code class="tag">&lt;/servlet-class&gt;</code>
 	<code class="tag">&lt;init-param&gt;</code>
 	  <code class="tag">&lt;param-name&gt;</code><span style="color:red;">persistence.unit</span><code class="tag">&lt;/param-name&gt;</code>
-	  <code class="tag">&lt;param-value&gt;</code><span style="color:red">jestdemo</span><code class="tag">&lt;/param-value&gt;</code>
+	  <code class="tag">&lt;param-value&gt;</code><span style="color:red">${persistence.unit}</span><code class="tag">&lt;/param-value&gt;</code>
 	<code class="tag">&lt;/init-param&gt;</code>
 <code class="tag">&lt;/servlet&gt;</code>
 <code class="tag">&lt;servlet-mapping&gt;</code>
@@ -80,10 +80,10 @@ The documentation on JEST is available i
 <code class="tag">&lt;/servlet-mapping&gt;</code>
 
 </pre>
-	If you deploy an application named <code>demo</code> containing the above JEST servlet 
-	in a servlet container running on <code>localhost</code> at port 8080, then the JEST servlet
+	If you deploy an application named <code>${webapp.name}</code> containing the above JEST servlet 
+	in a servlet container running on <code>${server.name}</code> at port ${server.port}, then the JEST servlet
 	can be accessed at (<span style="color:red">do not miss the the trailing / character</span>) <br>
-	<code class="url">http://localhost:8080/demo/jest/</code> 
+	<code class="url">${jest.uri}</code> 
 	<br>
 	<p>
 		<a href="http://openjpa.apache.org/jest-usage.html" target="_blank">more...</a>
@@ -93,9 +93,9 @@ The documentation on JEST is available i
 	You can find persistent objects by simple or compound primary key.
 	<hr>
 	
-	<code class="url">http://www.jpa.com/demo/jest/find?type=Person&12345</code>
+	<code class="url">${jest.uri}find?type=${entity.name}&12345</code>
 	<br>
-	will find a <code>Person</code> with primary key <code>12345</code>.
+	will find a <code>${entity.name}</code> with primary key <code>12345</code>.
 	<p>
        <a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">more...</a>
 </div>
@@ -103,13 +103,15 @@ The documentation on JEST is available i
 <div id="query"  class="highlight" style="display:none;">
 		 You can execute JPQL or named query with parameters.
 		 <hr>
-		 <code class="url">http://www.jpa.com/demo/jest/query?q=select p from Person p where p.name=:x&x=John</code>
+		 <code class="url">${jest.uri}query?q=select p from ${entity.name} p where p.name=:x&x=John</code>
 		 <br>
-		 will find a <code>Person</code> whose name is <code>John</code>.
+		 will find a <code>${entity.name}</code> whose name is <code>John</code>, assuming, of course, that
+		 ${persistent.unit} persistent unit contains persistent entity ${entity.name} and ${entity.name}
+		 has declared <code>name</code>code> as its persistent property.
 		 <br>
-		 <code class="url">http://www.jpa.com/demo/jest/query/named?q=SelectPersonByName&x=John</code>
+		 <code class="url">${jest.uri}query/named?q=SelectByNamedQuery&x=John</code>
 		 <br>
-		 will do the same with an equivalent named query <code>SelectPersonByName</code>.
+		 will do the same with an equivalent named query <code>SelectByNamedQuery</code>.
 		 <p> 
 		 
 		 <a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">more...</a>
@@ -118,7 +120,7 @@ The documentation on JEST is available i
 <div id="browse"  class="highlight" style="display:none;">
 		 You can display the persistent domain model.
 		 <hr>
-		 <code class="url">http://www.jpa.com/demo/jest/domain</code>
+		 <code class="url">${jest.uri}domain</code>
 		 <br>
 		 will display the persistent domain model.
 		 <p>
@@ -128,7 +130,7 @@ The documentation on JEST is available i
 <div id="properties"  class="highlight" style="display:none;">
 		 You can view the configuration properties of the persistence unit.
 		 <hr>
-		 <code class="url">http://www.jpa.com/demo/jest/properties</code>
+		 <code class="url">${jest.uri}properties</code>
 		 <br>
 		 will display the configuration properties of the persistence unit.
 		 <p>

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd Thu Dec  2 11:24:53 2010
@@ -32,7 +32,9 @@
 	<xsd:element name="instances">
 		<xsd:complexType>
 			<xsd:sequence>
-				<xsd:element name="instance" maxOccurs="unbounded" type="instance-type" />
+			    <xsd:element name="uri"         minOccurs="1" maxOccurs="1" type="xsd:anyURI"/>
+			    <xsd:element name="description" minOccurs="0" maxOccurs="1" type="xsd:string"/>
+				<xsd:element name="instance"    minOccurs="0" maxOccurs="unbounded" type="instance-type" />
 			</xsd:sequence>
 			<xsd:attribute name="version" type="xsd:string" />
 		</xsd:complexType>

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.css
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.css?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.css (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.css Thu Dec  2 11:24:53 2010
@@ -27,14 +27,62 @@
 	display:none;
 }
 /** -----------------------------------------------------------------------
- * Highlighted blocks
+ *  div section containing the command menu.
+ *  Lodged on the top-left corner
+ *  -------------------------------------------------------------------- */
+.menu {
+	position:absolute;
+	left:0em;
+	top:4em;
+	width:10em;
+}
+/** -----------------------------------------------------------------------
+ * Highlighted blocks appear relative to the menu. The same top position
+ * of the menu and shifted to left of the menu by the menu's width+padding. 
  * --------------------------------------------------------------------- */
 .highlight {
-	background-color:#F9F9F9;
+	position:relative;
+	left:10em;
+	top:0em;
+//	background-color:#F9F9F9;
 	width:60em;
+
+//	border:1px solid black;
+//	padding:0em 1em 1em 1em; // top, right, bottom, left
+
+}
+
+/** -----------------------------------------------------------------------
+ * Canvas section appears relative to the menu and the highlighted section. 
+ * The top position is relative to the highlighted section and left position
+ * is relative to the menu section.
+ * --------------------------------------------------------------------- */
+.canvas {
+	position:relative;
+	left:10em;
+	top:1em;
 	border:1px solid black;
-	padding:2em 4em 2em 2em;
+	padding:0em 1em 1em 1em; // top, right, bottom, left
 }
+
+/** -----------------------------------------------------------------------
+ * Hyperlinks
+ * --------------------------------------------------------------------- */
+.url {
+	color:blue;
+	font-size:1.1em;
+	font-family:"Courier New", Arial;
+	border:0px;
+	cursor:pointer;
+}
+
+.url-invalid {
+	color:red;
+	font-size:0.9em;
+	font-family:"Courier New", Arial;
+}
+
+
 /** -----------------------------------------------------------------------
  * XML Tag 
  * --------------------------------------------------------------------- */
@@ -42,6 +90,7 @@
 	color:green;
 	font-family:"Courier New";
 	font-weight:bold;
+	border:0px;
 }
 /** -----------------------------------------------------------------------
  * Data Table used for Tabular HTML
@@ -82,21 +131,12 @@ tr.odd td {
    border:2px solid black;
 	vertical-align:top;
 }
-
-/** -----------------------------------------------------------------------
- * Hyperlinks
- * --------------------------------------------------------------------- */
-a {
-	target:_blank;
+td.mandatory {
+	font-weight:bold;
+	color:red;
 }
 
 
-.url {
-	color:blue;
-	font-size:1.1em;
-	font-family:"Courier New", Arial;
-}
-
 /** -----------------------------------------------------------------------
  * Paragraph with smaller line breaks 
  * --------------------------------------------------------------------- */

Added: openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.js
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.js?rev=1041330&view=auto
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.js (added)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/jest.js Thu Dec  2 11:24:53 2010
@@ -0,0 +1,972 @@
+/*
+ * 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.    
+ */
+
+dojo.require("dijit.form.Button");
+dojo.require("dijit.TitlePane");
+dojo.require("dojox.xml.parser");
+
+
+/** -----------------------------------------------------------------------------------------
+ *                        Navigation functions
+ *
+ * Available commands appear on left menu. Clicking on any command makes a corresponding 
+ * highlighted section to appear at a fixed position. These command windows are identified 
+ * and these identifiers are used to make only one of the section to be visible while 
+ * hiding the rest.
+ *
+ * The jest.html document will use these same identifiers in their command section. 
+ * ------------------------------------------------------------------------------------------
+ *
+ * The identifiers of every element to be shown or hidden.
+ * --------------------------------------------------------------------------------------- */ 
+/**
+ * Show the division identified by the given id, and hide all others
+ */
+function switchid(/*string*/id, /*string[]*/highlightedSections) {	
+    for (var i=0; i < highlightedSections.length; i++){
+    	var section = document.getElementById(highlightedSections[i]);
+    	if (section != null) {
+             section.style.display = 'none';
+    	}
+    }
+    var div  = document.getElementById(id);
+    if (div != null) {
+        div.style.display = 'block';
+    }
+}
+
+/** -----------------------------------------------------------------------------------------
+ *    Generic Command handling functions
+ *    
+ *  All available JEST commands are enumerated by their qualifiers and arguments.
+ *  
+ *  Specification of a JEST Command requires the following:
+ *     a) a name
+ *     b) zero or more Qualifiers. Qualifiers are not ordered. All Qualifiers are optional. 
+ *     c) zero or more Arguments. Arguments are ordered. Some Arguments can be mandatory. 
+ *     
+ *  Command, Qualifier and Argument are 'objects' -- in a curious JavaScript sense. They
+ *  are responsible to harvest their state value from the HTML element such as a input
+ *  text box or a check box etc. The aim of harvesting the values is to construct a 
+ *  relative URI that can be passed to the server via a HTTP get request.
+ *  
+ *  jest.html attaches change event handlers to all input elements and the on change
+ *  event handler updates the URI.
+ *  
+ *  The complexity is added because some commands may take variable number of arguments.
+ *  Hence the input text boxes to enter arbitrary number of key-value pair can be created 
+ *  or removed by the user.
+ *  
+ *  A lot of implicit naming convention for the element identifiers are used in this 
+ *  script. These naming conventions are documented in jest.html.     
+ * --------------------------------------------------------------------------------------- */
+var findCommand = new Command('find', 
+		new Array( // 
+		   new Qualifier("plan",        "plan",        false),
+		   new Qualifier("format",      "format",      false),
+		   new Qualifier("ignoreCache", "ignoreCache", true)
+		), 
+		new Array( // Order of arguments is significant
+		   new Argument("type", "type", true),
+		   new Argument("pk",   null,   true)
+		));
+
+var queryCommand = new Command('query', 
+		new Array( // Qualifiers are not ordered
+		   new Qualifier("plan",        "plan",        false),
+		   new Qualifier("format",      "format",      false),
+		   new Qualifier("single",      "single",      true),
+		   new Qualifier("named",       "named",       true),
+		   new Qualifier("ignoreCache", "ignoreCache", true)
+		), 
+		new Array( // Order of arguments is significant
+		   new Argument("q", "q", true)
+		));
+var domainCommand = new Command('domain', 
+		new Array(), 
+		new Array());
+var propertiesCommand = new Command('properties', 
+		new Array(), 
+		new Array());
+
+var commands = new Array(findCommand, queryCommand, domainCommand, propertiesCommand);
+
+/** -----------------------------------------------------------------------------------------
+ * Creates a relative URI for the given commandName by reading the content of the given HTML 
+ * element and its children.
+ * The URI is written to the HTML anchor element identified by {commandName} + '.uri'.
+ * 
+ * @param commandName name of the command. All source HTML element are identified by this 
+ * command name as prefix. 
+ * --------------------------------------------------------------------------------------- */
+function toURI(commandName) {
+	var command = null;
+	switch (commandName) {
+	  case 'find'       : command = findCommand;        break;
+	  case 'query'      : command = queryCommand;       break;
+	  case 'domain'     : command = domainCommand;      break;
+	  case 'properties' : command = propertiesCommand;  break;
+	}
+	if (command != null)
+		command.toURI();
+}
+
+/** -----------------------------------------------------------------------------------------
+ * Adds columns to the given row for entering a variable argument key-value pair.
+ * A remove button is created as well to remove the row.
+ * A new row is created to invoke this function again to add another new row. 
+ * 
+ * @param rowIdPrefix a string such as query.vararg or find.vararg
+ * @param index a integer appended to the prefix to identify the row such as query.vararg.3
+ * @param message the label on the new button 
+ * --------------------------------------------------------------------------------------- */
+function addVarArgRow(rowIdPrefix, index, message) {
+	var rowId = rowIdPrefix + '.' + index;
+	var row = document.getElementById(rowId);
+	if (row == null) {
+		console.log("*ERROR: Variable argument row id [" + rowId + "] not found in the document");
+		return;
+    }
+	
+	// remove the current columns from this row
+	while (row.childNodes.length > 0) {
+		row.removeChild(row.firstChild);
+	}
+	
+	// New input column for parameter name. Element id is rowId + '.key'
+	var argNameColumn  = document.createElement('td');
+	var argNameInput   = document.createElement('input');
+	argNameInput.setAttribute('type', 'text');
+	argNameInput.setAttribute('id', rowId + '.key');
+	argNameInput.setAttribute('onchange', 'javascript:toURI("' + rowIdPrefix.split('.')[0] + '");');
+	argNameColumn.appendChild(argNameInput);
+	
+	// New input column for parameter value Element id is rowId + '.value'
+	var argValueColumn = document.createElement('td');
+	var argValueInput  = document.createElement('input');
+	argValueInput.setAttribute('type', 'text');
+	argValueInput.setAttribute('id', rowId + '.value');
+	argValueInput.setAttribute('onchange', 'javascript:toURI("' + rowIdPrefix.split('.')[0] + '");');
+	argValueColumn.appendChild(argValueInput);
+	
+	// New column for remove button. Will remove this row.
+	var removeColumn   = document.createElement('td');
+	var removeColumnInput  = document.createElement('input');
+	removeColumnInput.setAttribute('type', 'button');
+	removeColumnInput.setAttribute('value', 'Remove');
+	removeColumnInput.setAttribute('onclick', 'javascript:removeVarArgRow("' + rowId + '");');
+	removeColumn.appendChild(removeColumnInput);
+	
+	// Empty column as the first column
+	var emptyColumn = document.createElement('td');
+	
+	
+	// Add the new instruction column, input columns and remove button to the current row
+	row.appendChild(emptyColumn); 
+	row.appendChild(argNameColumn);
+	row.appendChild(argValueColumn);
+	row.appendChild(removeColumn);
+	
+	// create a new row with a single column to add another parameter.
+	// This new row looks similar to the original state of the modified column
+	var newIndex = index + 1;
+	var newRowId = rowIdPrefix + '.' + newIndex;
+	var newRow = document.createElement('tr');
+	newRow.setAttribute('id', newRowId);
+	var newColumn      = document.createElement('td');
+	var newColumnInput = document.createElement('input');
+	newColumnInput.setAttribute('type', 'button');
+	newColumnInput.setAttribute('value', message);
+	newColumnInput.setAttribute('onclick', 'javascript:addVarArgRow("' + rowIdPrefix + '",' + newIndex + ',"'
+			+ message + '");');
+	newColumn.appendChild(newColumnInput);
+	
+	newRow.appendChild(newColumn);
+	row.parentNode.appendChild(newRow);
+}
+
+/** -----------------------------------------------------------------------------------------
+ * Removes a variable argument row.
+ * The URI is updated.
+ * 
+ * @param rowId the identifier of the row to be removed. The identifier follows the
+ * naming convention of the variable argument row i.e. {commandName}.varargs.{n}
+ * --------------------------------------------------------------------------------------- */
+function removeVarArgRow(rowId) {
+	var row = document.getElementById(rowId);
+	row.parentNode.removeChild(row);
+	toURI(rowId.split('.')[0]);
+}
+
+/** -----------------------------------------------------------------------------------------
+ * Definition of Command as a JavScript object.
+ * 
+ * @param name name of the command. Used to identify the command, or identify input elements.
+ * @param qualifiers zero or more Qualifier objects 
+ * @param arguments zero or more Argument objects
+ * 
+ * 
+ * --------------------------------------------------------------------------------------- */
+function Command(name, qualifiers, arguments) {
+	this.name       = name;
+	this.qualifiers = qualifiers;
+	this.arguments  = arguments;
+	this.toURI      = Command_toURI;
+}
+
+/** -----------------------------------------------------------------------------------------
+ * Harvests the input HTML elements for a commands qualifiers and arguments and builds up
+ * a URI.
+ * Uses several naming convention that are documented in jest.html to identify the input
+ * elements.
+ * The naming of the function and its capitalization follows JavaScript convention for it
+ * to behave as a faux object method.
+ * 
+ * @returns a string form of URI
+ * --------------------------------------------------------------------------------------- */
+function Command_toURI() {
+	console.log("Rewriting URI for " + this.name + " command");
+	var uri = this.name;
+	for (var i = 0; i < this.qualifiers.length; i++) {
+		var id = this.name + '.' + this.qualifiers[i].name;
+		var inode = document.getElementById(id);
+		var path = this.qualifiers[i].toURI(inode);
+		if (path != null) {
+			uri = uri.concat('/').concat(path);
+		}
+	}
+	var args = "";
+	var invalid = null;
+	for (var i = 0; i < this.arguments.length; i++) {
+		var id = this.name + '.' + this.arguments[i].name;
+		var inode = document.getElementById(id);
+		var arg = this.arguments[i].toURI(inode);
+		if (arg != null) {
+			args = args.concat(args.length == 0 ? '' : '&').concat(arg);
+		} else if (this.arguments[i].mandatory) {
+			invalid = 'Missing mandatory ' + this.arguments[i].name + ' argument';
+		}
+	}
+
+	// Variable argument processing
+	var children = document.getElementById(this.name + '.command').getElementsByTagName('tr');
+	for (var i = 0; i < children.length; i++) {
+		var child = children[i];
+		if (isVarArgRow(child, this.name)) {
+			var varargRow = child;
+			var pair  = varargRow.getElementsByTagName('input');
+			var key   = getNodeValue(pair[0]);
+			var value = getNodeValue(pair[1]);
+			if (key != null && value != null) {
+				args = args.concat(args.length == 0 ? '' : '&').concat(key).concat('=').concat(value);
+			}
+		}
+	}
+	if (args.length > 0) {
+		uri = uri.concat('?').concat(args);
+	}
+	
+	// update the command URI element
+	console.log("New URI is " + uri);
+	var uriNode  = document.getElementById(this.name + ".uri");
+	if (invalid == null) {
+		uriNode.setAttribute('class', 'url');
+		var contentType = getContentTypeForCommand(this.name);
+		uriNode.setAttribute('onclick', 
+				'javascript:render("' 
+				   + uri 
+				   + '", "canvas"' + ',"' 
+				   + contentType   + '",' 
+				   + '"xml", "xml"); event.returnValue = false; return false;');
+		uriNode.innerHTML = uri;
+	} else {
+		uriNode.setAttribute('class', 'url-invalid');
+		uriNode.removeAttribute('onclick');
+		uriNode.innerHTML = uri + ' (' + invalid + ')';
+	}
+	return uri;
+}
+
+function getContentTypeForCommand(/*string*/ commandName) {
+	if (commandName == 'find' || commandName == 'query') return 'instances';
+	if (commandName == 'domain') return 'domain';
+	if (commandName == 'properties') return 'properties';
+	
+}
+
+/** -----------------------------------------------------------------------------------------
+ *  Definition of Qualifier JavaScript object.
+ *  
+ *  A qualifier decorates a Command. For example, a query command can be decorated with 
+ *  'single' qualifier to return a single result. A 'plan' qualifier can decorate a find or 
+ *  query command to use a named fetch plan etc. 
+ *  A qualifier is encoded in the path segment of JEST URI followed by the
+ *  command name e.g. /query/single or /find/plan=myFetchPlan etc.
+ * 
+ * 
+ * @param name a name when prefixed by the name of the command identifies the HTML element 
+ * that carries the value of this qualifier.
+ * @param key  the identifier for this qualifier used in the JEST URI
+ * @param isBoolean is this qualifier carries a boolean value?
+ * 
+ * @returns {Qualifier}
+ * -------------------------------------------------------------------------------------- */
+function Qualifier(name, key, isBoolean) {
+	this.name = name;
+	this.key  = key;
+	this.isBoolean = isBoolean;
+	this.toURI = Qualifier_toURI;
+}
+
+/** -----------------------------------------------------------------------------------------
+ *  Generates a string for this qualifier to appear in the command URI.
+ *  
+ *  A qualifier is translated to a URI fragment as a key=value pair. A boolean
+ *  qualifier is translated to a URI fragment only if the corresponding HTML
+ *  element is checked. And even then, only the key is sufficient.
+ * 
+ * @returns a string
+ * --------------------------------------------------------------------------------------- */
+function Qualifier_toURI(inode) {
+	var value = getNodeValue(inode);
+	if (isEmpty(value) || (this.isBoolean && !inode.checked)) { 
+		return null;
+	}
+	if (this.isBoolean) {
+		return this.key + (value == 'true' ? '' : '=' + value);
+	}
+	return this.key + '=' + value;
+}
+
+/** -----------------------------------------------------------------------------------------
+ *  Definition of Argument JavaScript object.
+ *  
+ *  An argument for a command. Some argument can be mandatory. <br>
+ *  Each argument is encoded as key=value pair in JEST URI in query parameters
+ *  separated by '&' character.
+ * 
+ * @param name a name when prefixed by the name of the command identifies the HTML element 
+ * that carries the value of this argument.
+ * @param key the identifier for this argument used in the JEST URI
+ * @param mandatory is this argument mandatory?
+ * 
+ * @returns {Argument}
+ * -------------------------------------------------------------------------------------- */
+function Argument(name, key, mandatory) {
+	this.name = name;
+	this.key  = key;
+	this.mandatory = mandatory;
+	this.toURI = Argument_toURI;
+}
+
+/** -----------------------------------------------------------------------------------------
+ *  Generates a string for this argument to appear in the command URI.
+ *  
+ *  An argument is translated to a URI fragment as a key=value pair. 
+ * 
+ * @returns a string
+ * --------------------------------------------------------------------------------------- */
+function Argument_toURI(inode) {
+	var value = getNodeValue(inode);
+	if (isEmpty(value))
+		return null;
+	if (this.key == null) {
+		return value;
+	} else {
+		return this.key + '=' + value;
+	}
+}
+
+/**  ----------------------------------------------------------------------------------------
+ *      Utility functions
+ *   ------------------------------------------------------------------------------------- */
+/**
+ * Trims a String.
+ */
+String.prototype.trim = function () {
+    return this.replace(/^\s*/, "").replace(/\s*$/, "");
+};
+
+/**
+ * Affirms if the given string appears at the start of this string.
+ */
+String.prototype.startsWith = function(s) {
+	return this.indexOf(s, 0) == 0;
+};
+
+/**
+ * Affirms if the given string is null or zero-length or trimmed to zero-length.
+ * 
+ * @param str a string to test for 'emptiness'
+ * @returns {Boolean}
+ */
+function isEmpty(str) {
+	return str == null || str.length == 0 || str.trim().length == 0;
+}
+
+/**
+ * Gets the string value of the given node.
+ * 
+ * @param inode a HTML element
+ * @returns null if given node is null or its value is an empty string. 
+ *          Otherwise, trimmed string.
+ */
+function getNodeValue(inode) {
+	if (inode == null) {
+		return null;
+	}
+	if (isEmpty(inode.value)) {
+		return null;
+	} else {
+		return inode.value.trim();
+	}
+}
+
+/**
+ * Affirms if the given HTML row element represents a variable argument row
+ * for the given commandName.
+ * @param row a HTML row element
+ * @param commandName name of a command 
+ * 
+ * @returns true if row identifer starts with commandName + '.vararg.'
+ */
+function isVarArgRow(row, commandName) {
+	return row != null && row.nodeName != '#text' 
+		&& row.hasAttribute("id") 
+		&& row.getAttribute("id").startsWith(commandName + '.vararg.');
+}
+
+/**
+ * Removes all children of the given element.
+ */
+function clearElement(/* HTML element */ element) {
+	while (element.childNodes.length > 0) {
+		element.removeChild(element.firstChild);
+	}
+}
+
+/**
+ * Prints and alerts with the given message string.
+ * @param message a warning message
+ */
+function warn(/*string*/message) {
+	console.log(message);
+	alert(message);
+}
+
+/** -----------------------------------------------------------------------------------------
+ *     Rendering functions
+ *     
+ *  Several rendering functions to display server response in the canvas section.
+ *  The server responds in either 
+ *      1a) XML 
+ *   or 1b) JSON 
+ *  format. The response can be rendered as
+ *      2a) raw XML text
+ *      2b) HTML table
+ *      2c) Dojo Widgets
+ *      2d) JSON as text
+ *  The content can be one of the following
+ *      3a) instances from find() or query() command
+ *      3b) domain model from domain() command
+ *      3c) configuration properties from properties() command
+ *      3d) error stack trace
+ *      
+ *  Thus there are 2x4x4 = 32 possible combinations. However, response format for
+ *  certain content type is fixed e.g. server always sends domain/properties/error 
+ *  stack trace in XML format. Moreover certain content-response format-display format
+ *  combinations are not supported. The following matrix describes the supported 
+ *  display format for content-response format combinations.
+ *  [y] : supported
+ *  [x] : not supported
+ *  n/a : not available
+ *  --------------------------------------------------------------------------------
+ *  Response                              Content
+ *  --------------------------------------------------------------------------------
+ *               instances         domain            properties            error
+ *  --------------------------------------------------------------------------------               
+ *  XML          [y] XML text      [y] XML text      [y] XML text      [x] XML text
+ *               [y] HTML Table    [y] HTML Table    [y] HTML Table    [y] HTML Table
+ *               [y] Dojo Widgets  [y] Dojo Widgets  [x] Dojo Widgets  [x] Dojo Widgets
+ *               [x] JSON          [x] JSON          [x] JSON          [x] JSON
+ *                  
+ *  JSON         [x] XML text      n/a               n/a               n/a
+ *               [x] HTML Table    n/a               n/a               n/a
+ *               [x] Dojo Widgets  n/a               n/a               n/a
+ *               [y] JSON          n/a               n/a               n/a
+ *  ---------------------------------------------------------------------------------
+ *  The above matrix shows that there are 10 supported combinations.    
+ *   ------------------------------------------------------------------------------------- */
+var supportedResponseFormats = new Array('xml', 'json');
+var supportedContentTypes    = new Array('instances', 'domain', 'properties', 'error');
+var renderingCombo = new Array(
+		                                                              
+/*XML*/ new Array(new Array('xml', 'html', 'dojo'), // instances
+		          new Array('xml', 'html', 'dojo'), // domain
+		          new Array('xml','html'),          // properties
+		          new Array('html')),               // error
+/*JSON*/new Array(new Array('json'),                // instances
+		          new Array('xml', 'html', 'dojo'), // domain
+		          new Array('xml', 'html'),         // properties
+		          new Array('html')));              // error 
+/**
+ * Gets the ordinal index of the given key in the given array
+ * @param array an array of enumerated strings.
+ * @param key a key to search for.
+ * 
+ * @returns {Number} 0-based index of the key in the array.
+ */
+function getOrdinal(/*Array*/array, /*string*/key) {
+	for (var i = 0; i < array.length; i++) {
+		if (key == array[i]) return i;
+	}
+	console.log(key + " is not a valid enum in " + array);
+	return 0;
+}
+/**
+ * Gets ordinal number for enumerated response format.
+ * 
+ * @param iformat response format. one of 'xml', 'json'
+ * 
+ * @returns {Number} ordinal number 0 for 'xml', 
+ */
+function getOrdinalResponseFormat(/*enum*/iformat) {
+	return getOrdinal(supportedResponseFormats, iformat);
+}
+
+/**
+ * Gets ordinal number of the enumerated content types.
+ * @param contentType type of content. One of 'instances', 'domain', 'properties', 'error'
+ * @returns
+ */
+function getOrdinalContentType(/*enum*/contentType) {
+	return getOrdinal(supportedContentTypes, contentType);
+}
+
+/**
+ * Gets the array of enumerated strings of display format for the given response format and content type.
+ * @param iformat
+ * @param contentType
+ * @returns
+ */
+function getSupportedDisplayFormat(/*enum*/iformat,/*enum*/contentType) {
+	var displayFormats = renderingCombo[getOrdinalResponseFormat(iformat)][getOrdinalContentType(contentType)];
+	if (displayFormats == null) {
+		warn("No display format for response format [" + iformat + "] and content type [" + contentType + "]");
+	}
+	return displayFormats;
+} 
+
+/**
+ * Render the response from the given URI on to the given HTML element identified by targetId.
+ * 
+ * The URI is requested from server in an asynchronous call. Then the server response is rendered
+ * in all supported display format but only the given display format is made visible. 
+ *  
+ * @param uri the request URI
+ * @param targetId identifier of the HTML element that will display the data
+ * @param contentType type of the content, one of 'instances', 'domain', 'properties', 'error'
+ * @param iformat format of the server response, one of 'xml' or 'json'
+ * @param oformat format for display, one of 'xml', 'json', 'dojo', 'html'
+ * 
+ * The combination of iformat-contentType-oformat must be compatiable as described in above matrix.
+ * 
+ * @returns {Boolean} to prevent default event propagation
+ */
+function render(/* string */ uri, /* id */ targetId, /* enum */contentType, /* enum */iformat) {
+    var targetNode = dojo.byId(targetId);
+    clearElement(targetNode);
+     
+    //The parameters to pass to xhrGet, the url, how to handle it, and the callbacks.
+    var xhrArgs = {
+        url: uri,
+        handleAs: (iformat == 'json' && contentType == 'instances') ? 'json' : 'xml',
+        preventCache: true,
+        timeout : 1000,
+        load: function(data, ioargs) {
+    		var displayFormats = getSupportedDisplayFormat(iformat, contentType);
+    		var newDivs = null;
+        	if (iformat == 'json') {
+        		newDivs = renderJSONResponse(data, contentType);
+        	} else {
+        		newDivs = renderXMLResponse(data, contentType);
+        	} 
+        	var displayNode = document.createElement("table");
+        	targetNode.appendChild(displayNode);
+        	for (var row = 0; row < 2; row++) {
+        		var tr = document.createElement("tr");
+        		var td = document.createElement("td");
+        		td.setTextContent(row == 0 ? "Display" : "Mode");
+        		tr.appendChild(td);
+	        	for (var i = 0; i < displayFormats.length; i++) {
+	        		var mode = displayFormats[i];
+	        		td = document.createElement("td");
+	        		if (row == 1) {
+	        			td.innerHTML = mode;
+	        		} else {
+		        		var radio = document.createElement("input");
+		        		radio.setAttribute("type", "radio");
+		        		radio.setAttribute("value", mode);
+		        		radio.setAttribute("name", "display.mode");
+		        		if (i == 0) radio.setAttribute("checked", "checked");
+		        		radio.appendChild(document.createTextNode(mode.toUpperCase()));
+		        		td.appendChild(radio);
+		        		
+		        		radio.setAttribute('onchange', createModeSwitch(mode, displayFormats));
+	        		}
+	        		tr.appendChild(td);
+	        	}
+        		displayNode.appendChild(tr);
+        	}
+
+        	for (var i = 0; i < newDivs.length; i++) {
+        		targetNode.appendChild(newDivs[i]);
+        	}
+        },
+        error: function(error, ioargs) {
+        	console.log("error : " + error + " ioargs:" + ioargs);
+        	var errorDiv = renderErrorFromXMLAsHTML(error, ioargs);
+        	targetNode.appendChild(errorDiv);
+        }
+    };
+
+    //Call the asynchronous xhrGet
+    var deferred = dojo.xhrGet(xhrArgs);
+    return false;
+}
+
+function createModeSwitch(/* string */ visible, /* string[] */ all) {
+	var array = '[';
+	for (var i = 0; i < all.length; i++) {
+		if (all[i] != visible) {
+			array = array + (i == 0 ? '' : ', ') + '"display.mode.' + all[i] + '"';
+		}
+	}
+	return 'javascript:switchid("display.mode.' + visible+ '",' + array + '])';
+}
+
+/**
+ * The big switch for rendering all content types received as XML DOM.
+ * Finds out the supported display format for given content type and renders each display format
+ * in separate divs. The div corresponding to the given display format is made visible, and others
+ * are hidden. None of the divs are attached to the main document.
+ * 
+ * @param dom server response as a XML DOM document 
+ * @param contentType enumerated content type. One of 'instances', 'domain', 'properties' or 'error'
+ * 
+ * @returns an array of unattached divs only one of which is visible.
+ */
+function renderXMLResponse(/*XML DOM*/dom, /*enum*/contentType) {
+	var displayFormats = getSupportedDisplayFormat('xml', contentType);
+	var newDivs = new Array(displayFormats.length);
+	console.log("Display formats [" + displayFormats + " Content Type [" + contentType + "]");
+	for (var i = 0; i < displayFormats.length; i++) {
+		if (displayFormats[i] == 'xml') {
+			newDivs[i] = renderXMLasXML(dom);
+		} else if (contentType == 'instances') {
+			if (displayFormats[i] == 'html') {
+				newDivs[i] = renderInstancesFromXMLAsHTML(dom);
+			} else if (displayFormats[i] == 'dojo') {
+				newDivs[i] = renderInstancesFromXMLAsDojo(dom);
+			}
+		} else if (contentType == 'domain') {
+			if (displayFormats[i] == 'html') {
+				newDivs[i] = renderDomainFromXMLAsHTML(dom);
+			} else if (displayFormats[i] == 'dojo') {
+				newDivs[i] = renderDomainFromXMLAsDojo(dom);
+			}
+		} else if (contentType == 'properties') {
+			newDivs[i] = renderPropertiesFromXMLAsHTML(dom);
+		} 
+		newDivs[i].style.display = (i == 0 ? 'block' : 'none');
+		newDivs[i].setAttribute("id", "display.mode." + displayFormats[i]);
+	}
+	return newDivs;
+}
+
+/**
+ * Renders the given instance data in the format of a XML DOM document into a set of Dojo widgets
+ * inside a div element.  
+ * 
+ * @param data the root node of a XML document containing instances data
+ * 
+ * @returns an unattached div containing a set of dojo widgets
+ */
+function renderInstancesFromXMLAsDojo(/* XML DOM*/data) {
+	var target = document.createElement('div');
+    var panels = new Array();
+    dojo.query("instance", data).forEach(function(item, index) {
+    	  var panel = createInstanceDojoWidget(item);
+    	  panels[index] = panel;
+    });
+
+    // assign random location to each panel and add them to canvas
+    dojo.forEach(panels, function(item, index) {
+    	var domNode = item.domNode;
+    	domNode.style.width = "200px";
+    	domNode.style.position = "relative";
+    	domNode.style.left  = 10;//100 + (index % 5)*300 + "px";
+    	domNode.style.top   = 10;//100 + Math.floor(index / 5)*200 +"px";
+    	target.appendChild(domNode);
+    });
+    return target;
+}
+
+function renderDomainFromXMLAsDojo(/*XML DOM*/data) {
+	var target = document.createElement('div');
+    var panels = new Array();
+    dojo.query("entity, embeddable, mapped-superclass", data)
+        .forEach(function(item, index) {
+    	  var panel = createEntityTypeDojoWidget(item);
+    	  panels[index] = panel;
+    });
+
+    // assign random location to each panel and add them to canvas
+    dojo.forEach(panels, function(item, index) {
+    	var domNode = item.domNode;
+    	domNode.style.width = "200px";
+    	domNode.style.position = "absolute";
+    	domNode.style.left  = 100 + (index % 5)*300 + "px";
+    	domNode.style.top   = 100 + Math.floor(index / 5)*200 +"px";
+    	target.appendChild(domNode);
+    });
+    return target;
+}
+
+function renderInstancesFromXMLAsHTML(/* XML DOM */data) {
+	var empty = document.createElement('div');
+	empty.innerHTML = "<b>renderInstancesFromXMLAsHTML</b> not implemented";
+	return empty;
+}
+
+function renderDomainFromXMLAsHTML(/* XML DOM */data) {
+	var empty = document.createElement('div');
+	empty.innerHTML = "<b>renderDomainFromXMLAsHTML</b> not implemented";
+	return empty;
+}
+
+function renderPropertiesFromXMLAsHTML(/* XML DOM */data) {
+	var table = document.createElement("table");
+	var caption = document.createElement("caption");
+	caption.innerHTML = "Configuration Properties";
+	table.appendChild(caption);
+	dojo.query("property", data)
+	    .forEach(function(item) {
+		  var row = document.createElement("tr");
+		  var key = document.createElement("td");
+		  var val = document.createElement("td");
+		  key.innerHTML = item.getAttribute("name");
+		  val.innerHTML = item.getAttribute("value");
+		  row.appendChild(key);
+		  row.appendChild(val);
+		 table.appendChild(row);
+	    }
+	);
+	return table;
+}
+
+/**
+ * 
+ * @param data
+ * @returns
+ */
+function renderErrorFromXMLAsHTML(/*XML DOM*/data, ioargs) {
+	console.log("renderErrorFromXMLAsHTML " + data);
+	var div = document.createElement("div");
+//	var errorCode = document.createElement("p");
+//	var msg = document.createElement("p");
+//	var trace = document.createElement("pre");
+//	errorCode.setAttribute("class", "error-code");
+//	msg.setAttribute("class", "error-message");
+//	errorCode.innerHTML = getNodeValue(data.getElementsByTagName("error-code")[0]);
+//	msg.innerHTML       = getNodeValue(data.getElementsByTagName("error-message")[0]);
+//	trace.innerHTML     = getNodeValue(data.getElementsByTagName("stacktrace")[0]);
+//	div.appendChild(errorCode);
+//	div.appendChild(msg);
+//	div.appendChild(trace);
+	div.innerHTML = ioargs.xhr.status + ' ' + data;
+	return div;
+}
+
+/**
+ * Creates a dojo Title Pane from a DOM instance node. The pane has the instance
+ * id as its title. The content is a table with name and value of each attribute 
+ * in each row. Multi-cardinality values are in separate row without the attribute
+ * name repeated except the first row.
+ * 
+ * @param instanceNode an XML instance node
+ * 
+ * @returns dojo widget for a single instance
+ */
+function createInstanceDojoWidget(/*XML node*/instanceNode) {
+	var instanceTable = document.createElement("table");
+	dojo.query('id, basic, enum, version', instanceNode)
+	    .forEach(function(item) { 
+	    	console.log("createInstanceDojoWidget " + instanceNode.getAttribute("id") + "." + item.getAttribute("name"));
+			var attrRow     = document.createElement("tr");
+			var nameColumn  = document.createElement("td");
+			var valueColumn = document.createElement("td");
+			nameColumn.className  = item.nodeName.toLowerCase(); /* May be cross-browser trouble */
+			nameColumn.innerHTML  = item.getAttribute("name");
+			valueColumn.innerHTML = dojox.xml.parser.textContent(item);
+			attrRow.appendChild(nameColumn);
+			attrRow.appendChild(valueColumn);
+			instanceTable.appendChild(attrRow);
+		}
+	);
+	dojo.query('one-to-one, many-to-one', instanceNode)
+	    .forEach(function(item) { 
+		var attrRow     = document.createElement("tr");
+		var nameColumn  = document.createElement("td");
+		var valueColumn = document.createElement("td");
+		nameColumn.className = item.nodeName.toLowerCase(); /* May be cross-browser trouble */
+		nameColumn.innerHTML = item.getAttribute("name");
+		var ref = item.getElementsByTagName("ref");
+		if (ref.length > 0) {
+			valueColumn.innerHTML = ref[0].getAttribute("id");
+			valueColumn.className = ref[0].nodeName.toLowerCase();
+			attrRow.appendChild(nameColumn);
+			attrRow.appendChild(valueColumn);
+			instanceTable.appendChild(attrRow);
+		}
+    });
+	dojo.query('one-to-many, many-to-many', instanceNode).forEach(function(item) { 
+		var attrRow     = document.createElement("tr");
+		var nameColumn  = document.createElement("td");
+		var valueColumn = document.createElement("td");
+		nameColumn.className = item.nodeName.toLowerCase(); /* May be cross-browser trouble */
+		nameColumn.innerHTML = item.getAttribute("name");
+		var refs = item.getElementsByTagName("ref");
+		for (var i = 0; i < refs.length; i++) {
+			if (i == 0) {
+				valueColumn.innerHTML = refs[i].getAttribute("id");
+				valueColumn.className = refs[i].nodeName.toLowerCase();
+				attrRow.appendChild(nameColumn);
+				attrRow.appendChild(valueColumn);
+				instanceTable.appendChild(attrRow);
+			} else {
+				var attrRow     = document.createElement("tr");
+				var nameColumn  = document.createElement("td"); // empty column
+				var valueColumn = document.createElement("td");
+				valueColumn.className = refs[i].nodeName.toLowerCase();
+				valueColumn.innerHTML = refs[i].getAttribute("id");
+				attrRow.appendChild(nameColumn);
+				attrRow.appendChild(valueColumn);
+				instanceTable.appendChild(attrRow);
+			}
+		}
+      }
+    );
+	
+	var pane = new dijit.TitlePane({title:instanceNode.getAttribute("id"),content:instanceTable});
+	return pane;
+}
+
+
+/**
+ * Creates a dojo Title Pane from a DOM instance node. The pane has the instance
+ * id as its title. The content is name and value of each attribute in separate
+ * line.
+ * 
+ * @param node
+ *            an instance node
+ * @returns
+ */
+function createEntityTypeDojoWidget(node) {
+	var entityTable = document.createElement("table");
+	dojo.query('id, basic, enum, version, one-to-one, many-to-one, one-to-many, many-to-many', node)
+        .forEach(function(item) { 
+			var attr = document.createElement("tr");
+			var name = document.createElement("td");
+			name.className = item.nodeName.toLowerCase(); /* May be cross-browser trouble */
+			var type = item.getAttribute("type");
+			name.innerHTML = type;
+			if (name.className == 'one-to-many') {
+			     name.innerHTML = type + '&lt;' + item.getAttribute("member-type") + '&gt;';
+			}
+			var value = document.createElement("td");
+			value.innerHTML = dojox.xml.parser.textContent(item);
+			attr.appendChild(name);
+			attr.appendChild(value);
+			entityTable.appendChild(attr);
+		}
+	);
+    
+    var pane = new dijit.TitlePane({title:node.getAttribute("name"), content: entityTable});
+	return pane;
+}
+
+
+function renderJSONResponse(/*JSON*/json, /*enum*/contentType) {
+}
+
+/**
+ * Generic routine to render the given XML Document as a raw but indented text in to an unattached div section.
+ * 
+ * @param dom a XML DOM
+ * 
+ * @returns an unattached div section
+ */
+function renderXMLasXML(/*XML DOM*/dom) {
+	var newDiv = document.createElement('div');
+	var pre    = document.createElement('pre');
+	newDiv.appendChild(pre);
+	// replace all < character to &lt; so that they display properly
+	var replaced = dojox.xml.parser.innerXML(dom).replace(/</g, '&lt;');
+	pre.innerHTML = replaced;
+	return newDiv;
+}
+
+function renderXMLasXML2(/*XML DOM*/dom, /*int*/ indent) {
+	var div = document.createElement('div');
+    dojo.forEach(dom, function(item) {
+    	var tag = item.nodeName;
+    	var childDiv = document.createElement('div');
+    	div.appendChild(childDiv);
+    	childDiv.style.position = 'relative';
+    	childDiv.style.left = (indent + 1) + 'em';
+    	var span = document.createElement('span');
+    	span.className = tag.toLowerCase();
+    	span.setTextContent('&lt;' + tag);
+    	childDiv.appendChild(span);
+    	dojo.forEach(item.getAttributes(), function(attr) {
+    		var attrName = document.createElement('span');
+    		attrName.setTextContent(' ' + attr.nodeName + '="' + attr.nodeValue + '"');
+    		childDiv.appendChild(attrName);
+    	});
+    	if (item.has)
+    	dojo.forEach(item.childNodes) {
+    		
+    	}
+    });
+
+	dojo.forEach(dom)
+	var pre    = document.createElement('pre');
+	newDiv.appendChild(pre);
+	// replace all < character to &lt; so that they display properly
+	var replaced = dojox.xml.parser.innerXML(dom).replace(/</g, '&lt;');
+	pre.innerHTML = replaced;
+	return newDiv;
+}
+
+
+function renderJSON(target, data) {
+	target.innerHTML = data;
+}
+

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

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

Modified: openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties?rev=1041330&r1=1041329&r2=1041330&view=diff
==============================================================================
--- openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties (original)
+++ openjpa/sandboxes/jest/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties Thu Dec  2 11:24:53 2010
@@ -48,4 +48,13 @@ format-xml-null-closure: Set of visited 
 format-not-supported: format {0} in command {1} is not registered. Available formats are {2}.
 
 properties-caption: Configuration of {0} Persistence Unit 
-entity-not-found: Resource of type {0} with identifier {1} is not found.
\ No newline at end of file
+entity-not-found: Resource of type {0} with identifier {1} is not found.
+bad-uri: Can not reconstruct URI from original URL {0} 
+
+
+find-title: JEST find
+find-desc: JEST find command may return more than one result. Why? 
+query-title: JEST query
+query-desc: JEST query command may return more than the directly selected result. Why? 
+domain-command: JEST domain
+domain-desc: JEST domain command prints the persistent domain model



Mime
View raw message