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/09 22:50:49 UTC

svn commit: r1044138 [3/3] - in /openjpa/trunk/openjpa-jest: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/openjpa/ src/main/java/org/apache/openjpa/persistence/ src/main/java/org/apache/openjpa/...

Propchange: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/images/query2.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/images/underconstruction.jpg
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/images/underconstruction.jpg?rev=1044138&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/images/underconstruction.jpg
------------------------------------------------------------------------------
    svn:mime-type = image/jpeg

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd?rev=1044138&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd (added)
+++ openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd Thu Dec  9 21:50:47 2010
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- 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. -->
+<!-- ========================================================================= -->
+<!-- Schema for serialized persistence instance.                               -->
+<!-- ========================================================================= -->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	attributeFormDefault="unqualified" elementFormDefault="qualified"
+	version="1.0">
+
+	<xsd:annotation>
+		<xsd:documentation><![CDATA[
+         Describes closure of managed persistence instance.
+         Each instance is described by all its loaded persistent attribute.
+         The related instances are resolved within the document root.
+         Document root represents zero or more instances. 
+          
+         The file must be named "jest-instance.xsd".
+         ]]>
+		</xsd:documentation>
+	</xsd:annotation>
+
+    <!-- The root element of the document contains zero or more instances -->
+	<xsd:element name="instances">
+		<xsd:complexType>
+			<xsd:sequence>
+			    <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>
+	</xsd:element>
+
+	<!-- The root element for a single instance. Children of this element are persistent attribute -->
+	<!-- Persistent Attributes occur in order. The order is determined by the attribute category.  -->
+	<!-- Attribute category is determined by the enumerated PersistentAttributeType defined in     -->
+	<!-- javax.persistence.metamodel and then further refined by id, version, lob and enum.        -->
+	<!-- See org.apache.openjpa.persistence.jest.MetamodelHelper for further details.              -->
+	<xsd:complexType name="instance-type">
+		<xsd:sequence>
+			<xsd:element name="id"           type="basic-attr-type"      minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="version"      type="basic-attr-type"      minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="basic"        type="basic-attr-type"      minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="enum"         type="basic-attr-type"      minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="embedded"     type="instance-type"        minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="lob"          type="lob-attr-type"        minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="one-to-one"   type="singular-attr-type"   minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="many-to-one"  type="singular-attr-type"	 minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="element-collection" type="collection-attr-type" minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="one-to-many"  type="collection-attr-type" minOccurs="0" maxOccurs="unbounded"/>
+			<xsd:element name="many-to-many" type="map-attr-type"        minOccurs="0" maxOccurs="unbounded"/>
+		</xsd:sequence>
+		<xsd:attribute name="id" type="xsd:ID" use="required" />
+	</xsd:complexType>
+
+	<!-- A reference to another instance within the same(?) document -->
+	<xsd:complexType name="ref-type">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute name="id" type="xsd:IDREF" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+	
+	<!-- A null reference                                            -->
+	<xsd:complexType name="ref-null">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!-- Basic Attribute has a name and its runtime type   -->
+	<!-- non-null value appears as text content.           -->
+	<!-- null value appears as attribute with empty text . -->
+	<xsd:complexType name="basic-attr-type">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute name="name" type="xsd:string" use="required" />
+				<xsd:attribute name="type" type="xsd:string" use="required" />
+				<xsd:attribute name="null" type="xsd:boolean" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+	
+	<!-- Large Binary Objects (LOB) represented as hex array -->
+	<xsd:complexType name="lob-attr-type">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:hexBinary">
+				<xsd:attribute name="name" type="xsd:string" use="required" />
+				<xsd:attribute name="type" type="xsd:string" use="required" />
+				<xsd:attribute name="null" type="xsd:boolean" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!-- Singular attribute is a reference to another instance or a null reference. -->
+	<xsd:complexType name="singular-attr-type">
+		<xsd:choice>
+			<xsd:element name="null" type="ref-null" />
+			<xsd:element name="ref" type="ref-type" />
+		</xsd:choice>
+		<xsd:attribute name="name" type="xsd:string" use="required" />
+		<xsd:attribute name="type" type="xsd:string" use="required" />
+	</xsd:complexType>
+
+	<!-- Collection attributes list their members with their runtime type -->
+	<!-- Members can be basic or other managed instance                   -->
+	<xsd:complexType name="collection-attr-type">
+		<xsd:sequence>
+			<xsd:element name="member" type="member-type" minOccurs="0"
+				maxOccurs="unbounded" />
+		</xsd:sequence>
+		<xsd:attribute name="name" type="xsd:string" use="required" />
+		<xsd:attribute name="type" type="xsd:string" use="required" />
+		<xsd:attribute name="member-type" type="xsd:string" use="required" />
+	</xsd:complexType>
+
+	<!-- Map attributes list their entries with runtime type of key and value    -->
+	<!-- Both key and value can be independently basic or other managed instance -->
+	<xsd:complexType name="map-attr-type">
+		<xsd:sequence>
+			<xsd:element name="entry" type="entry-type" />
+		</xsd:sequence>
+		<xsd:attribute name="name" type="xsd:string" use="required" />
+		<xsd:attribute name="type" type="xsd:string" use="required" />
+		<xsd:attribute name="key-type" type="xsd:string" use="required" />
+		<xsd:attribute name="value-type" type="xsd:string" use="required" />
+	</xsd:complexType>
+
+	<!-- Value of a member of basic type. -->
+	<xsd:complexType name="basic-value-type">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute name="null" type="xsd:boolean" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+
+	<!-- Value of a member of a collection/map -->
+	<xsd:complexType name="member-type">
+		<xsd:choice>
+			<xsd:element name="basic" type="basic-value-type" />
+			<xsd:element name="null" type="ref-null" />
+			<xsd:element name="ref" type="ref-type" />
+		</xsd:choice>
+	</xsd:complexType>
+
+	<!-- Denotes entry of a map element -->
+	<xsd:complexType name="entry-type">
+		<xsd:sequence>
+			<xsd:element name="key"   type="member-type" minOccurs="1" maxOccurs="1" />
+			<xsd:element name="value" type="member-type" minOccurs="1" maxOccurs="1"  />
+		</xsd:sequence>
+	</xsd:complexType>
+	
+</xsd:schema>

Propchange: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest-instance.xsd
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.css
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.css?rev=1044138&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.css (added)
+++ openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.css Thu Dec  9 21:50:47 2010
@@ -0,0 +1,248 @@
+/*
+ * 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.    
+ */
+
+/** -----------------------------------------------------------------------
+ *  Basic layout consists of a left menu section (class='menu')and two  
+ *  vertical sections for command specification (class='highlight') and 
+ *  JEST response (class='canvas') respectively.
+ * --------------------------------------------------------------------- */
+ 
+/** -----------------------------------------------------------------------
+ *  div section containing the command menu.
+ *  Lodged on the top-left corner
+ *  -------------------------------------------------------------------- */
+.menu {
+	position:absolute;
+	left:0em;
+	top:80px;
+	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 {
+	position:relative;
+	left:10em;
+	top:0em;
+//	background-color:#F9F9F9;
+	width:60em;
+
+//	border:1px solid black;
+//	padding:0em 1em 1em 1em; // top, right, bottom, left
+
+}
+
+.logo {
+	font-size:2em;
+	font-weight:bold;
+	font-family: "Palatino Linotype, Times Roman"
+}
+
+/** -----------------------------------------------------------------------
+ * 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;
+	width:60em;
+	padding:0em 1em 0em 1em; // top, right, bottom, left
+}
+
+.help {
+	float:right;
+	text-align:right;
+	margin-right:0.1em;
+	margin-top: -0.1em;
+}
+/** -----------------------------------------------------------------------
+ * Visible/Invisible divisions
+ * --------------------------------------------------------------------- */
+.open {
+	display:block;
+}
+.close {
+	display:none;
+}
+
+/** -----------------------------------------------------------------------
+ * 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 
+ * --------------------------------------------------------------------- */
+pre, code { 
+	background-color: white;
+}
+.tag {
+	color:green;
+	font-family:"Courier New";
+	font-weight:bold;
+	border:0px;
+}
+/** -----------------------------------------------------------------------
+ * Data Table used for Tabular HTML
+ * --------------------------------------------------------------------- */
+table.data td th {
+	width : 70%;
+	border-collapse:collapse;
+	border:2px solid black;
+	margin: 10px 10px 10px 10px;
+}
+tr {
+	vertical-align:top;
+}
+th {
+   background-color:#444444;
+   color:white;
+   text-align:left;
+}
+caption {
+	background-color:#000000;
+    color:white;
+	font-size:1.2em;
+	font-weight:bold;
+	padding:5px 5px 5px 5px;
+}
+/** -----------------------------------------------------------------------
+ * Alternate Table Row
+ * --------------------------------------------------------------------- */
+tr.even td {
+   background-color: #FFFFFF; color: black;
+   padding:2px 20px;
+   border:2px solid black;
+	vertical-align:top;
+}
+tr.odd td {
+   background-color: #EEEEEE; color: black;
+   padding:2px 20px;
+   border:2px solid black;
+	vertical-align:top;
+}
+td.mandatory {
+	font-weight:bold;
+	color:red;
+}
+
+td input {
+	width : 99%;
+}
+td select {
+	width : 99%;
+}
+
+/** -----------------------------------------------------------------------
+ * Paragraph with smaller line breaks 
+ * --------------------------------------------------------------------- */
+p.small {
+	line-height:60%;
+}
+
+/** -----------------------------------------------------------------------
+ * Error Page 
+ * --------------------------------------------------------------------- */
+.error-header {
+	color:red;
+	font-size:2em;
+	font-weight:bold;
+}
+.error-message {
+	color:red;
+	font-size:1.2em;
+}
+
+/*
+ *  JPA styles
+*/
+.id {
+	color:red;
+	font-weight:bold;
+}
+.enum {
+	color:magenta;
+	font-weight:bold;
+}
+.basic {
+	color:green;
+	font-weight:bold;
+}
+.one-to-one {
+	color:lightblue;
+	font-weight:bold;
+}
+.one-to-many {
+	color:darkblue;
+	font-weight:bold;
+}
+
+.ref {
+	color : blue;
+}
+.null {
+	color : red;
+}
+
+.delimiter {
+  color:lightgray;
+  font-weight:bold;
+}
+.attr-name {
+	color:gray;
+}
+.attr-value {
+	color:green;
+}
+.node-value {
+	font-weight:bold;
+}
+.entity {
+	font-weight:bold;
+}
+.metamodel {
+	font-weight:bold;
+}
+
+.instances {
+	font-weight:bold;
+}
+.instance {
+	font-weight:bold;
+}
+
+
+	
\ No newline at end of file

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

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.html
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.html?rev=1044138&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.html (added)
+++ openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.html Thu Dec  9 21:50:47 2010
@@ -0,0 +1,329 @@
+<!--
+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.
+-->
+
+<!--
+   The single web page for JEST is a templated HTML. This page consists of three major divisions
+   a) a section holds the menu items for available commands 
+   b) a section for the command window where user enters command specifications
+   c) a section displays the server response of the command execution
+     
+   This templated file contains replaceable tokens in ${token} form.  JEST servlet replaces the tokens with 
+   actual deployment values on initialization.
+     
+   The menu navigation and command window are managed by jest.js script.
+   The rendition of server response is managed by dojo script.
+   
+   All hyperlinks in this page are relative to the base URI of this page to prevent
+   any cross-domain scripting.
+     
+ -->
+<html>
+<head>
+<!-- ==================================================================================== -->
+<!-- Base URI is replaced with actual deployment data on initialization                   -->
+<!-- ==================================================================================== -->
+<base href="${jest.uri}">
+<!-- base href="http://localhost:8080/demo/jest/" -->
+<title>JEST: REST on OpenJPA</title>
+
+<link   type="text/css" rel="stylesheet" href="${dojo.base}/dijit/themes/${dojo.theme}/${dojo.theme}.css">
+<!-- link   type="text/css" rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css" -->
+<link   type="text/css" rel="stylesheet" href="jest.css">
+<script type="text/javascript" language="javascript" djConfig="parseOnLoad: true, isDebug: true"  
+        src="${dojo.base}/dojo/dojo.xd.js">
+</script>
+<!-- script type="text/javascript" djConfig="parseOnLoad:true;isDebug=true" src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"></script -->
+<script type="text/javascript" language="javascript" src="jest.js">
+</script>
+
+<meta content="REST,OpenJPA,JPA,JEST">
+</head>
+
+
+<body class=" ${dojo.theme} ">
+<!-- body class=" claro " -->
+<a name="top"></a>
+<img src="images/jest.jpg" width="63px" height="69px" alt="JEST logo" align="middle">
+<span class="logo">JEST: REST on OpenJPA</span>
+<hr>
+<!-- ==================================================================================== -->
+<!--                     Section for menu based commands.                                 -->
+<!--                                                                                      -->
+<!-- Each menu opens a command window by making a menu section visible                    -->
+<!-- ==================================================================================== -->
+<div id="menu" class="menu">
+<table cellspacing="1em">
+ <tr><td><img alt="Home" src="images/home.jpg" width="100" height="100"></td></tr>
+ <tr><td style="text-align:center"><a href="javascript:openMenu('home');">Info</a></td></tr>
+ <tr><td><img alt="Domain" src="images/domain.jpg" width="100" height="100"></td></tr>
+ <tr><td style="text-align:center"><a href="javascript:openMenu('domain');">browse domain</a></td></tr>
+ <tr><td><img alt="Find"   src="images/find.jpg" width="100" height="100"></td></tr>
+ <tr><td style="text-align:center"><a href="javascript:openMenu('find');">find instances</a></td></tr>
+ <tr><td><img alt="Query"  src="images/query2.png" width="100" height="100"></td></tr>
+ <tr><td style="text-align:center"><a href="javascript:openMenu('query');">query objects</a></td></tr>
+ <tr><td><img alt="View" src="images/properties.jpg"  width="100" height="100"></td></tr>
+ <tr><td style="text-align: center"><a href="javascript:openMenu('properties');">view properties</a></td></tr>
+ <tr><td><img alt="Deploy" src="images/monitor.jpg" width="100" height="100"></td></tr>
+ <tr><td style="text-align:center"><a href="javascript:openMenu('deploy');">deploy</a></td></tr>
+</table>
+</div>
+
+<!-- ==================================================================================== -->
+<!--                        Section for each command specification                        -->
+<!--                                                                                      -->
+<!-- Contains a set of div sub-sections each for a single command. A command window       -->
+<!-- consists of a brief description of the command and set of input elements where user  -->
+<!-- can enter command qualifiers and arguments.                                          -->
+<!-- The URI for the command is updated as user entry changes. If the user clicks on the  -->
+<!-- URI hyperlink, then a request with the URI is sent to the server.                    -->
+<!-- ==================================================================================== -->
+<!--                   Introduces basic information about JEST                            -->
+<!-- ==================================================================================== -->
+<div id="home" class="highlight" dojoType="dijit.TitlePane" 
+title="<a href='http://openjpa.apache.org/jest-usage.html' target='_blank'>JEST</a>  
+      <b>facilitates RESTful interaction with OpenJPA</b>">
+
+
+<UL>
+<LI>Deployed as a HTTP servlet in <b>any</b> web or enterprise application module using 
+OpenJPA as its JPA persistence provider. 
+</LI>
+
+<LI>Completely <b>metadata-driven</b> and hence <b>generic</b> as opposed to specific to any 
+application domain.
+</LI> 
+
+<LI>Introduces a <b>URI syntax</b>. Interprets the HTTP request as a JPA resource based on 
+that syntax. The response is in <tt>XML</tt> or <tt>JSON</tt> format. </LI>
+
+<LI>Representational state for persistent instances is <b>coherent</b>. 
+The response always contains the <em>closure</em> of the persistent instances. 
+</LI>
+      
+<LI>Connects to the <b>persistent unit</b> of an application in the same module. Or
+    instantiates its own persistence unit.
+</LI>
+</UL>
+</div>
+
+<!-- ==================================================================================== -->
+<!--        Describes deployment details                                                  -->
+<!-- ==================================================================================== -->
+<div id="deploy" class="highlight" style="display:none;" dojoType="dijit.TitlePane" 
+	title='<a href="http://openjpa.apache.org/jest-usage.html" target="_blank">Deploy JEST</a> 
+	<b>as a servlet in a web application.</b>'>
+	
+	
+	Following <code>WEB-INF/web.xml</code> descriptor will enable JEST to
+	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>${persistence.unit}</code> as its persistence unit.  
+	<br>
+<pre>
+<code class="tag">&lt;servlet&gt;</code>
+  <code class="tag">&lt;servlet-name&gt;</code>${servlet.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">${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>
+  <code class="tag">&lt;servlet-name&gt;</code>${servlet.name}<code class="tag">&lt;/servlet-name&gt;</code>
+  <code class="tag">&lt;url-pattern&gt;</code><span style="color:red">/${servlet.name}/*</span><code class="tag">&lt;/url-pattern&gt;</code>
+<code class="tag">&lt;/servlet-mapping&gt;</code>
+
+</pre>
+	When an web application module named <code>${webapp.name}</code> containing the above JEST servlet 
+	in a servlet container runs on <code>${server.name}</code> at port ${server.port}, then the JEST servlet
+	can be accessed at <br>
+	<code class="url">http://${server.name}:${server.port}/${webapp.name}/${servlet.name}/</code> 
+	<br>
+	(<span style="color:red">do not miss the the trailing forward-slash / character</span>) 
+	<p>
+</div>
+		 
+<!-- ==================================================================================== -->
+<!--        Command window for find                                                       -->
+<!--                                                                                      -->
+<!-- The div element contains a table and some of the table columns hold the input        -->
+<!-- elements. The div, table and input elements are all identified with following        -->
+<!-- naming convention:                                                                   -->
+<!-- the main div section identifier is the moniker of the command itself i.e. 'find'     -->
+<!-- the table identifier is 'find.command'                                               -->
+<!-- the input element identifiers are 'find.{qualifier or argument name}' e.g.           -->
+<!-- 'find.type' or 'find.format'. The qualifier or argument name must be the same as     -->
+<!--  specified in jest.js JavaScript.                                                    -->
+<!--                                                                                      -->
+<!-- The naming convention is crucial because the JavaScript jest.js identifies these     -->
+<!-- elements by this implicit naming conventions.                                        -->
+<!--                                                                                      -->
+<!-- The user entries result in a relative URI displayed in this section itself.          -->
+<!-- The event handlers on the input elements update the URI on change.                   -->
+<!-- The user can click the hyperlink to send the request to the server.                  -->
+<!-- ==================================================================================== -->
+<div id="find"  class="highlight" style="display:none;" dojoType="dijit.TitlePane" 
+  title='<a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">Find</a>  
+	<b>persistent objects by primary identifier.</b>'>
+	
+	<!-- a form for user to fill in the find specifications. Script uses these entries to -->
+	<!-- build up a request URI for JEST server                                           -->
+	<table id="find.command">
+<tr>
+  <th width="30%" class="mandatory" title="Name of a persistent entity to find.">Entity Name
+    <span class="help">
+  	  <img src="images/help.jpg"  width="8px" height="8px" onclick="showHelp('Entity', 'help/entity-name.html');">
+    </span>
+  </th>
+  <th width="30%" class="mandatory" title="Primary Key of the entity.">Identifier</th>
+  <th width="30%" title="Fetch Plan(s) to use. Separate each plan with comma.">Fetch Plan
+    <span class="help">
+      <img src="images/help.jpg"   width="8px" height="8px" 
+          onclick="showHelp('Fetch Plan', 'help/fetch-plan.html');">
+    </span>
+  </th>
+  <th width="10%" title="Format of the response.">Format
+    <span class="help">
+      <img src="images/help.jpg"   width="8px" height="8px" 
+         onclick="showHelp('Response Format', 'help/response-format.html');"></img>
+    </span>
+  </th>
+</tr>
+	<tr>
+	  <td><input id="find.type"  onblur="javascript:toURI('find');"></td>
+	  <td><input id="find.pk"    onblur="javascript:toURI('find');"></td>
+	  <td><input id="find.plan"  onblur="javascript:toURI('find');" ></td>
+	  <td>
+	    <select id="find.format" onchange="javascript:toURI('find');" >
+	    <option value=""></option>
+	    <option value="xml">XML</option>
+	    <option value="json">JSON</option>
+	    </select>
+	  </td>
+	</tr>
+	</table>
+	<p>
+	<!-- Script will fill in the URI in this element based on user entries from the above -->
+	<!-- The element is made to look like a hyperlink but actually a span to omit the     -->
+	<!-- associated complexity of preventing the browser's default handling of hyperlink  -->
+	<!-- click events.                                                                    -->
+	<b>URI: </b><span id="find.uri" class="url-invalid">filling the form will update 
+	this hyperlink.</span>
+	<button id="find.execute" style="display:none;">
+	<img src="images/arrow_right.jpg" width="12px" height="12px"></button>
+</div>
+		 
+<!-- ==================================================================================== -->
+<!--                      Command window for Query                                        -->
+<!--                                                                                      -->
+<!-- Similar to window for 'find' command. The added complexity is variable number of     -->
+<!-- query binding parameters that the user may enter for a query.                        -->
+<!-- Each query binding parameter is accepted via two inputs on a dynamically created row -->
+<!-- The dynamic row is identified as 'query.vararg.{n}' and the pair of input elements   -->
+<!-- 'query.vararg.{n}.key' and 'query.vararg.{n}.value' respectively. {n} is a monotonic -->
+<!-- integer. If a dynamically created row is removed by the user, the index {n} does not -->
+<!-- decrement.                                                                           -->
+<!-- ==================================================================================== -->
+<div id="query"  class="highlight" style="display:none;" dojoType="dijit.TitlePane" 
+	title='<a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">Query</a> 
+	<b>with JPQL or named query and binding parameters.</b>'>
+	
+	<!-- a form for user to fill in the find specifications. Script uses these entries to -->
+	<!-- build up a request URI for JEST server. This form is more complicated than that  -->
+	<!-- of find, because a query can accept variable number of binding parameters        -->
+	<table id="query.command">
+	<tr>
+	  <th width="20%" class="mandatory" title="JPQL query or a named query">Query
+	  <span class="help"><img src="images/help.jpg"   width="8px" height="8px" 
+	  onclick="showHelp('Query', 'help/query.html');"></img></span></th>
+      <th width="10%"style="display: hidden"></th>
+      <th width="10%"style="display: hidden"></th>
+      <th width="10%"style="display: hidden"></th>
+	  <th width="5%" title="Is it a named query?">Single</th>
+	  <th width="5%" title="Returns single result?">Named</th>
+	  <th width="30%" title="Fetch Plan(s) to use. Separate each plan with comma.">Fetch Plan
+	  <span class="help"><img src="images/help.jpg"   width="8px" height="8px" 
+	  onclick="showHelp('Fetch Plan', 'help/fetch-plan.html');"></img></span></th>
+	  <th width="10%" title="Format of the response.">Format
+	</tr>
+	<tr>
+	  <td colspan="4"><input id="query.q"                         onblur="javascript:toURI('query');"></td>
+	  <td><input id="query.single" type="checkbox" value="true"   onchange="javascript:toURI('query');"></td>
+	  <td><input id="query.named"  type="checkbox" value="true"   onchange="javascript:toURI('query');"></td>
+	  <td><input id="query.plan"                                  onblur="javascript:toURI('query');" ></td>
+	  <td>
+	    <select id="query.format"                                 onchange="javascript:toURI('query');" >
+	    <option value=""></option>
+	    <option value="xml">XML</option>
+	    <option value="json">JSON</option>
+	    </select>
+	  </td>
+	</tr>
+	<tr id="query.vararg.0">
+	  <td>
+	    <button onclick="javascript:addVarArgRow('query.vararg',0,'Bind Query Parameter');">Bind Parameter</button>
+	  </td>
+	</tr>
+	</table>
+	<p>
+	<!-- Script will fill in the URI in this element based on user entries from the above -->
+	<!-- The element is made to look like a hyperlink but actually a span to omit the     -->
+	<!-- associated complexity of preventing the browser's default handling of hyperlink  -->
+	<!-- click events.                                                                    -->
+	<b>URI: </b><span id="query.uri" class="url-invalid">filling the form will update 
+	this hyperlink.</span> <button id="query.execute" style="display:none;">
+	<img src="images/arrow_right.jpg" width="12px" height="12px"></button>
+	 
+</div>
+		 
+<!-- ==================================================================================== -->
+<!--    Command window for browsing persistent domain model                               -->
+<!-- ==================================================================================== -->
+<div id="domain"  class="highlight" style="display:none;" dojoType="dijit.TitlePane" 
+  title='<a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">Browse</a> 
+  <b>persistent domain model.</b>'>
+  
+	This command accepts no qualifier or arguments.	 <br>
+	
+	<b>JEST URI: </b><span id="domain.uri" class="url"
+	onclick="javascript:render('domain','canvas', 'domain', 'xml');">domain</span>
+</div>
+		 
+<!-- ==================================================================================== -->
+<!--    Command window for viewing configuration of the persistence unit.                 -->
+<!-- ==================================================================================== -->
+<div id="properties"  class="highlight" style="display:none;" dojoType="dijit.TitlePane" 
+ title='<a href="http://openjpa.apache.org/jest-syntax.html" target="_blank">View</a> 
+ <b>configuration properties of the persistence unit.</b>'>
+ 
+	This command accepts no qualifier or arguments	 <br>
+		 
+	<b>URI: </b><span id="properties.uri" class="url" 
+	onclick="javascript:render('properties','canvas', 'properties', 'xml');">properties</span>
+</div>
+
+<!-- ==================================================================================== -->
+<!-- This empty section will be filled in by server response                              -->
+<!-- ==================================================================================== -->
+<div id="canvas" class="canvas">
+</div>
+
+
+</body>
+</html>
\ No newline at end of file

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

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.js
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.js?rev=1044138&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.js (added)
+++ openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/jest.js Thu Dec  9 21:50:47 2010
@@ -0,0 +1,1146 @@
+/*
+ * 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");
+dojo.require("dijit.Dialog");
+
+
+/** -----------------------------------------------------------------------------------------
+ *                        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.
+ * --------------------------------------------------------------------------------------- */ 
+
+var menuIds = new Array('home', 'deploy', 'find', 'query', 'domain', 'properties');
+
+/**
+ * Opening a menu implies clearing the canvas, hiding the current menu item and making
+ * the given menu identifier visible.
+ * 
+ * @param id menu section identifier 
+ */
+function openMenu(/*HTML element id*/id) {
+	clearElement('canvas');
+	switchId(id, menuIds);
+    document.location = "#top";
+}
+/**
+ * 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';
+        div.focus();
+    }
+}
+
+/** -----------------------------------------------------------------------------------------
+ *    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);
+	clearElement(rowId);
+	
+	// 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('onblur', '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('onblur', 'javascript:toURI("' + rowIdPrefix.split('.')[0] + '");');
+	argValueColumn.appendChild(argValueInput);
+	
+	// New column for remove button. Will remove this row.
+	var removeColumn   = document.createElement('td');
+	var removeColumnButton  = document.createElement('button');
+	removeColumnButton.innerHTML = 'Remove';
+	removeColumnButton.setAttribute('onclick', 'javascript:removeVarArgRow("' + rowId + '");');
+	removeColumn.appendChild(removeColumnButton);
+	
+	// Empty column as the first column
+	var emptyColumn = document.createElement('td');
+	emptyColumn.appendChild(document.createTextNode("Key-Value pair"));
+	
+	// Add the empty column, two 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 addColumnButton = document.createElement('button');
+	addColumnButton.innerHTML = message;
+	addColumnButton.setAttribute('onclick', 'javascript:addVarArgRow("' + rowIdPrefix + '",' + newIndex + ',"'
+			+ message + '");');
+	newColumn.appendChild(addColumnButton);
+	
+	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() {
+	var uri = this.name; // command name is same as URI name -- need not be
+	var iformat = 'xml';  // default response format
+	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);
+			if (this.qualifiers[i].key == 'format') {
+				iformat = getNodeValue(inode);
+			}
+		}
+	}
+	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");
+	var uriCtrl  = document.getElementById(this.name + ".execute");
+	if (invalid == null) {
+		uriNode.setAttribute('class', 'url');
+		uriNode.innerHTML = uri;
+		var contentType = getContentTypeForCommand(this.name);
+		uriCtrl.setAttribute('onclick', 
+				'javascript:render("' 
+				   + uri 
+				   + '", "canvas"' + ',"' 
+				   + contentType   + '","' 
+				   + iformat + '");');
+		uriCtrl.style.display = 'inline';
+	} else {
+		uriNode.setAttribute('class', 'url-invalid');
+		uriNode.innerHTML = uri + ' (' + invalid + ')';
+		uriCtrl.style.display = 'none';
+		uriCtrl.removeAttribute('onclick');
+	}
+	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 id */ id) {
+	var element = dojo.byId(id);
+	if (element == null) return;
+	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 following formats :
+ *      1a) XML 
+ *      1b) JSON 
+ *  The response can be rendered in following display modes :
+ *      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 mode
+ *  combinations are not supported. The following matrix describes the supported 
+ *  display modes 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          [y] HTML          [y] HTML          [y] HTML 
+ *               [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               [y] HTML
+ *               [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', 'dojo', 'html'), // instances
+		          new Array('xml', 'dojo', 'html'), // domain
+		          new Array('xml','html'),          // properties
+		          new Array('html')),               // error
+/*JSON*/new Array(new Array('json'),                // instances
+		          new Array('xml', 'dojo', 'html'), // 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 getSupportedDisplayModes(/*enum*/iformat,/*enum*/contentType) {
+	var displayModes = renderingCombo[getOrdinalResponseFormat(iformat)][getOrdinalContentType(contentType)];
+	if (displayModes == null) {
+		warn("No display format for response format [" + iformat + "] and content type [" + contentType + "]");
+	}
+	return displayModes;
+} 
+
+/**
+ * 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(targetId);
+
+    //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: contentType == 'instances',
+        timeout : 1000,
+        load: function(data, ioargs) {
+        	if (ioargs.xhr.status == 200) { // HTTP OK
+	    		var newDivs = null;
+	        	if (iformat == 'json') {
+	        		newDivs = renderJSONResponse(data, contentType);
+	        	} else {
+	        		newDivs = renderXMLResponse(data, contentType);
+	        	} 
+	    		var displayModes = getSupportedDisplayModes(iformat, contentType);
+	        	targetNode.appendChild(createDisplayModeControl(displayModes));
+	        	for (var i = 0; i < newDivs.length; i++) {
+	        		targetNode.appendChild(newDivs[i]);
+	        	}
+        	} else {
+            	var errorDiv = renderErrorFromXMLAsHTML(data, ioargs);
+            	targetNode.appendChild(errorDiv);
+        	}
+        },
+        error: function(error, ioargs) {
+        	var errorDiv = renderErrorFromXMLAsHTML(ioargs.xhr.responseXML, ioargs);
+        	targetNode.appendChild(errorDiv);
+        }
+    };
+
+    //Call the asynchronous xhrGet
+    var deferred = dojo.xhrGet(xhrArgs);
+    return false;
+}
+
+/**
+ * Creates a table with radio buttons for supported display modes.
+ * 
+ * @param displayModes name of supported display modes.
+ * 
+ * @returns an unattached HTML table
+ */
+function createDisplayModeControl(displayModes) {
+	var displayMode = document.createElement("table");
+	displayMode.style.width = "100%";
+	
+	var tr = document.createElement("tr");
+	displayMode.appendChild(tr);
+	// append columns. 0-th an dfirst columns are descriptive texts. 
+	var caption = document.createElement("th");
+	caption.style.width = (100 - displayModes.length*12) + '%';
+	caption.appendChild(document.createTextNode("JEST Response"));
+	tr.appendChild(caption);
+
+    for (var i = 0; i < displayModes.length; i++) {
+    	var mode = displayModes[i];
+    	var modeColumn = document.createElement("th");
+    	modeColumn.style.width = "12%";
+    	tr.appendChild(modeColumn);
+        
+    	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.setAttribute('onchange', createModeSwitchFunction(mode, displayModes));
+       	
+       	modeColumn.appendChild(radio);
+       	modeColumn.appendChild(document.createTextNode(mode.toUpperCase()));
+    }
+	
+	return displayMode;
+}
+
+/**
+ * Creates a string for javascript function call to switch between display modes
+ * @param visible the visible display mode
+ * @param all available display modes
+ * @returns {String} a event handler function string 
+ */
+function createModeSwitchFunction(/* string */ visible, /* string[] */ all) {
+	var array = '';
+	for (var i = 0; i < all.length; i++) {
+		if (all[i] != visible) {
+			array = array + (array.length == 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 displayModes = getSupportedDisplayModes('xml', contentType);
+	var newDivs = new Array(displayModes.length);
+	for (var i = 0; i < displayModes.length; i++) {
+		var displayMode = displayModes[i];
+		if (displayMode == 'xml') {
+			newDivs[i] = renderXMLasXML(dom);
+		} else if (contentType == 'instances') {
+			if (displayMode == 'html') {
+				newDivs[i] = renderInstancesFromXMLAsHTML(dom);
+			} else if (displayMode == 'dojo') {
+				newDivs[i] = renderInstancesFromXMLAsDojo(dom);
+			}
+		} else if (contentType == 'domain') {
+			if (displayMode == 'html') {
+				newDivs[i] = renderDomainFromXMLAsHTML(dom);
+			} else if (displayMode == '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." + displayMode);
+	}
+	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 = "absolute";
+    	domNode.style.left  = 100 + (index % 5)*300 + "px";
+    	domNode.style.top   = 100 + Math.floor(index / 5)*200 +"px";
+    	target.appendChild(domNode);
+    });
+    return target;
+}
+
+/**
+ * Renders given DOM for metamodel as dojo widgets.
+ * 
+ * @param data XML DOM for domain model.
+ * @returns a HTML div 
+ */
+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;
+}
+
+/**
+ * Renders given XML DOM for instances to HTML tables.
+ * *** NOT IMPLEMENTED
+ * 
+ * @param data XML DOM for list of instances. All instanes may not belong to same entity.
+ * @returns a div with zero or more tables.
+ */
+function renderInstancesFromXMLAsHTML(/* XML DOM */data) {
+	return unimplemented("Rendering Instances as HTML is not implemented");
+}
+
+/**
+ * Renders given XML DOM for domain model to HTML tables.
+ * *** NOT IMPLEMENTED
+ * 
+ * @param data XML DOM for list of domain model. 
+ * @returns a div with zero or more tables.
+ */
+function renderDomainFromXMLAsHTML(/* XML DOM */data) {
+	return unimplemented("Rendering Domain as HTML is not implemented");
+}
+
+function unimplemented(/*string*/message) {
+	var empty = document.createElement('img');
+	empty.setAttribute("src", "images/underconstruction.jpg");
+	empty.setAttribute("alt", message);
+	return empty;
+}
+
+/**
+ * Renders configration (name-value pairs) in a HTML table.
+ * 
+ * @param data XML DOM for name-value pair properties.
+ * @returns a HTML table
+ */
+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, index) {
+		  var row = document.createElement("tr");
+		  row.className = index%2 == 0 ? 'even' : 'odd'; 
+		  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;
+}
+
+/**
+ * Renders error message in HTML
+ * 
+ * @param data XML DOM containing error description
+ * 
+ * @returns a div element with error details
+ */
+function renderErrorFromXMLAsHTML(/*response as XML DOM*/responseXML, ioargs) {
+	var div    = document.createElement("div");
+	var ecode  = document.createElement("h3");
+	var header = document.createElement("p");
+	var msg    = document.createElement("p");
+	var trace  = document.createElement("pre");
+	ecode.setAttribute("class", "error-header");
+	header.setAttribute("class", "error-message");
+	msg.setAttribute("class", "error-message");
+	
+	var serverError = responseXML.documentElement;
+	ecode.innerHTML  = "HTTP Error " + ioargs.xhr.status;
+	header.innerHTML = dojox.xml.parser.textContent(serverError.getElementsByTagName("error-header").item(0));
+	msg.innerHTML    = dojox.xml.parser.textContent(serverError.getElementsByTagName("error-message").item(0));
+	trace.innerHTML  = dojox.xml.parser.textContent(serverError.getElementsByTagName("stacktrace").item(0));
+	div.appendChild(ecode);
+	div.appendChild(header);
+	div.appendChild(msg);
+	div.appendChild(trace);
+
+	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) { 
+			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");
+		dojo.query('ref, null', instanceNode)
+		    .forEach(function(ref) {
+				valueColumn.innerHTML = ref.nodeName == 'null' ? 'null' : ref.getAttribute("id");
+				valueColumn.className = ref.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;
+}
+
+/**
+ * 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');
+	print(dom.documentElement, newDiv, 0);
+	return newDiv;
+}
+
+/**
+ * Renders a XML DOM node as a new child of the given HTML node.
+ * 
+ * CSS styles used: 
+ * node-value : The value of a text node
+ * attr-name  : The name of an attribute
+ * attr-value : The value of an attribute
+ * delimiter  : symbols such = " < \ > used in visual XML
+ * the XML element name : e.g. A <metamodel> tag will be decorated with .metamodel CSS style    
+ *  
+ */
+function print(/* XML node */xnode, /* HTML node*/ hnode, /*int*/counter) {
+	if (xnode.nodeName == '#text') {
+		addTextNode(hnode, xnode.nodeValue, "node-value");
+		return;
+	}
+	var root = document.createElement('div');
+	root.style.position = 'relative';
+	root.style.left = '2em';
+	addRoot(xnode, hnode, root, ++counter);
+	
+	var attrs = xnode.attributes;
+	if (attrs) {
+	 	for (var i = 0; i < attrs.length; i++) {
+			var attr = attrs[i];
+			addTextNode(root, ' ' + attr.nodeName, "attr-name");
+			addDelimiter(root, '=');
+			addTextNode(root, '"' + attr.nodeValue + '"', "attr-value");
+		}
+	 	addDelimiter(root, '>');
+	}
+	var children = xnode.childNodes;
+	if (children) {
+		for (var i = 0; i < children.length; i++) {
+			print(children[i], root, ++counter);
+		}
+	}
+	addDelimiter(root, '</');
+	addTextNode(root, xnode.nodeName, xnode.nodeName);
+	addDelimiter(root, '>');
+    return;	
+}
+
+/**
+ * Adds the given delimiter text with CSS style 'delimiter' to the given parent node
+ * @param parentNode
+ * @param text
+ */
+function addDelimiter(/* HTML node*/ parentNode, /* Delimiter String*/ delim) {
+	addTextNode(parentNode, delim, 'delimiter');
+}
+/**
+ * Adds a <span> node of given className to the given parentNode with the given text.
+ * 
+ * @param parentNode the parent node to which new text is added as a <span> element.
+ * @param text text to be added to the new <span> element
+ * @param className class of the new <span> element
+ * @returns the new <span> node
+ */
+function addTextNode(/* HTML node*/parentNode, /* String */text, /* String*/className) {
+	if (isEmpty(text)) return null;
+	newNode = document.createElement('span');
+	if (className) {  
+		newNode.className  = className;
+	}
+	if (text) { 
+		newNode.appendChild(document.createTextNode(text)); 
+	}
+	if (parentNode) { 
+		parentNode.appendChild(newNode); 
+	}
+	return newNode;		
+}
+function isTextNode(/* XML node */ xnode) {
+	return xnode == null || xnode.nodeName == '#text';
+}
+
+function isTogglable(/* XML node */ xnode) {
+	if (xnode == null) return false;
+	if (isTextNode(xnode)) return false;
+	var children = xnode.childNodes;
+	if (children == null || children.length == 0) return false;
+	if (children.length == 1 && isTextNode(children[0])) return false;
+	return true;
+}
+
+function addRoot(xnode, hnode, root, counter) {
+   if (isTogglable(xnode)) {
+	   hnode.appendChild(document.createElement('br'));
+		var ctrl = addTextNode(hnode, '-');
+		root.setAttribute("id", counter);
+		var moniker = '&lt;' + xnode.nodeName + '&gt;...';
+		ctrl.setAttribute("onclick", 'javascript:toggle(this, "' + moniker + '", "' + counter + '");');
+   } 
+   addDelimiter(root, '<');
+   addTextNode(root, xnode.nodeName, xnode.nodeName);
+   hnode.appendChild(root);
+   
+}
+
+function toggle(/* HTML node */ctrl, /* id */ moniker, /* id */ targetId) {
+	var visible = ctrl.innerHTML == '-';
+	ctrl.innerHTML = visible ? '+' + moniker : '-';
+	var target = document.getElementById(targetId);
+	if (visible) {
+		target.style.display = "none";
+	} else {
+		target.style.display = "inline";
+	}
+}
+
+
+/**
+ * Renders server response of JSON objects.
+ * Server sends always an array of JSON objects.
+ * @param json an array of hopefully non-empty array of JSON objects
+ * @param contentType type of content. Currently only instances are JSONized.
+ * @returns an array of div with a single member
+ */
+function renderJSONResponse(/*JSON[]*/json, /*enum*/contentType) {
+	var text = dojo.toJson(json, true);
+	var div = document.createElement("div");
+	var pre = document.createElement("pre");
+	pre.innerHTML = text;
+	div.appendChild(pre);
+	return [div]; // an array of a single div
+}
+
+/**
+ * Help related utilities.
+ */
+
+var helpDialog;
+
+function createDialog() {
+	if (helpDialog == null) {
+		helpDialog = new dijit.Dialog({style: "width: 400px; height:300px;overflow:auto"});
+	}
+	return helpDialog;
+}
+
+function showHelp(title, href) {
+	var dialog = createDialog();
+	dialog.set("title", title);
+	dialog.set("href", href);
+	dialog.show();
+}
+
+

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

Added: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties?rev=1044138&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties (added)
+++ openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties Thu Dec  9 21:50:47 2010
@@ -0,0 +1,60 @@
+# 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.
+
+no-persistence-unit-param: Missing <b>persistence.unit</b> parameter. JEST Servlet must be \
+	configured with a parameter named <b>persistence.unit<b> in &lt;init-param&gt; clause \
+	of &lt;servlet&gt; declaration in <code>WEB-INF/web.xml</code> descriptor.
+servlet-init: JEST Servlet is initialized for "{0}" persistence unit.
+servlet-not-init: JEST Servlet can not find "{0}" persistence unit during servlet initialization. \
+    JEST Servlet will try to locate the unit when a request is to be served.
+    
+no-persistence-unit: JEST can not locate the component using persistence unit <b>{0}</b>. This can happen \
+    for several reasons: \
+    <OL>the component is not initialized. </OL>\
+    <OL>the component and JEST servlet do not belong to the same deployment module</OL>\
+    <OL>the component did not configure the persistence unit for pooling. To enable pooling, \
+    create the persistence unit with configuration property <code>openjpa.EntityManagerFactoryPool=true</code>.<br> \
+    The property must be passed to <code>Persistence.createEntityManagerFactory(String unit, Map props)</code> \
+    with the second <code>Map</code> argument and <em>not</em> via <code>META-INF/persistence.xml</code></OL>.
+      
+
+resource-not-found: Can not locate resource {0}. <br>This can happen for wrong URI syntax. See \
+<A href="http://openjpa.apache.org/jest-syntax.html" target="_blank">JEST URI Help page</A> for correct syntax.
+
+query-execution-error: Error executing query "{0}". See stacktrace for details.
+parse-invalid-qualifier: {0} command does not recognize "{1}" as a qualifier. Valid qualifiers are {2}.
+parse-missing-mandatory-argument: {0} command must have "{1}" argument. Available arguments are {2}.
+parse-less-argument: {0} command must have at least {2} argument. Available arguments are {1}.
+# ----------------------------------------------------------------------
+# Format related error
+# ----------------------------------------------------------------------
+format-xml-null-parent: A null XML parent element encountered during serialization 
+format-xml-null-doc: Given parent element is not part of XML document
+format-xml-null-closure: Set of visited instances can not be null for serialization
+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.
+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

Propchange: openjpa/trunk/openjpa-jest/src/main/resources/org/apache/openjpa/persistence/jest/localizer.properties
------------------------------------------------------------------------------
    svn:eol-style = native