Index: src/main/java/org/modeshape/web/jcr/rest/client/domain/NodeType.java =================================================================== --- src/main/java/org/modeshape/web/jcr/rest/client/domain/NodeType.java (revision 2258) +++ src/main/java/org/modeshape/web/jcr/rest/client/domain/NodeType.java (working copy) @@ -62,6 +62,8 @@ private List propertyDefinitons = null; private List childNodeDefinitons = null; + + private List superTypes = null; // =========================================================================================================================== // Constructors @@ -82,7 +84,7 @@ assert workspace != null; this.name = name; this.workspace = workspace; - this.properties = (properties == null ? new Properties() : properties); + this.properties = properties; } @@ -124,7 +126,7 @@ * @return the node type attributes as a property set. */ public Properties getProperties() { - return this.properties; + return (this.properties != null ? properties : new Properties()); } public void setProperties(Properties properties ){ @@ -132,7 +134,7 @@ } public String getProperty(String key) { - return this.properties.getProperty(key); + return (this.properties != null ? this.properties.getProperty(key) : null); } @SuppressWarnings("unchecked") @@ -161,6 +163,11 @@ childNodeDefinitionNodeType.setParentNodeType(this); } + public void addSuperNodeType(NodeType superNodeType) { + if (this.superTypes == null) this.superTypes = new ArrayList(); + superTypes.add(superNodeType); + } + @SuppressWarnings("unchecked") public List getPropertyDefinitions() { return (List) (this.propertyDefinitons != null ? this.propertyDefinitons : Collections.emptyList()); @@ -171,6 +178,11 @@ return (List) (this.childNodeDefinitons != null ? this.childNodeDefinitons : Collections.emptyList()); } + @SuppressWarnings("unchecked") + public List getSuperNodeTypes() { + return (List) (this.superTypes != null ? this.superTypes : Collections.emptyList()); + } + public NodeType getParentNodeType() { return this.parentNodeType; } @@ -179,7 +191,6 @@ this.parentNodeType = parent; } - /** * {@inheritDoc} * Index: src/main/java/org/modeshape/web/jcr/rest/client/json/NodeTypeNode.java =================================================================== --- src/main/java/org/modeshape/web/jcr/rest/client/json/NodeTypeNode.java (revision 2258) +++ src/main/java/org/modeshape/web/jcr/rest/client/json/NodeTypeNode.java (working copy) @@ -24,13 +24,18 @@ package org.modeshape.web.jcr.rest.client.json; import java.net.URL; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; + import net.jcip.annotations.Immutable; + import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONObject; import org.modeshape.common.util.CheckArg; @@ -38,18 +43,26 @@ import org.modeshape.web.jcr.rest.client.domain.Workspace; /** - * The NodeTypeNode class is responsible for knowing how to obtain a NodeType based on the Workspace.
- * An example URL to obtain all the node types would look like:
- * {context root}/{repository name}/{workspace name}/items/jcr:system/jcr:nodeTypes"
- * And an example url to obtain a specific node type would look like:
- * {context root}/{repository name}/{workspace name}/items/jcr:system/jcr:nodeTypes/{node type name} + * The NodeTypeNode class is responsible for knowing how to obtain a NodeType based + * on the Workspace. + *
+ * + * An example URL to obtain all the node types would look like: + *
+ * {context root}/{repository name}/{workspace name}/items/jcr:system/jcr:nodeTypes" + *
+ * And an example url to obtain a specific node type would look like: + *
+ * {context root}/{repository name}/{workspace name}/items/jcr:system/jcr:nodeTypes/{node type name} + * + *
+ * A Node Type will not be created if: + *
  • jcr:isMixin is true
  • + *
  • jcr:multiple is true
  • */ @Immutable public final class NodeTypeNode extends JsonNode { - - /* the path used to get to the node types */ - // private static final String GET_NODE_TYPES_URL = "/jcr:system/jcr:nodeTypes"; - + // =========================================================================================================================== // Fields // =========================================================================================================================== @@ -54,6 +67,11 @@ // Fields // =========================================================================================================================== + /** + * EXCLUDE_TYEPS are those node types that are to be excluded from the inclusion + * in the node types returned. + */ + private static Set EXCLUDE_TYPES = new HashSet() ; /** * The workspace from where the node type is being obtained. */ @@ -58,11 +76,16 @@ * The workspace from where the node type is being obtained. */ private final Workspace workspace; - + private final String depth; - - private Map nodeTypeMap = new HashMap(); - + + private MapnodeTypeMap = new HashMap(); + + { + EXCLUDE_TYPES.add("mode:defined"); + EXCLUDE_TYPES.add("*"); + } + // =========================================================================================================================== // Constructors // =========================================================================================================================== @@ -69,7 +92,6 @@ /** * Use this constructor if wanting all node types for a workspace - * * @param workspace the workspace being used (never null) * @param relative_path is the relative location after the workspace * @param nodeDepth , nullable, can specify the depth of the node types to be returned @@ -75,34 +97,15 @@ * @param nodeDepth , nullable, can specify the depth of the node types to be returned * @throws Exception if there is a problem creating the folder node */ - public NodeTypeNode( Workspace workspace, - String relative_path, - String nodeDepth ) throws Exception { + public NodeTypeNode( Workspace workspace, String relative_path, String nodeDepth) throws Exception { super(relative_path); - assert workspace != null; - + assert workspace != null; + this.workspace = workspace; this.depth = nodeDepth; - } - - // /** - // * Use this constructor if wanting a specific node type - // * @param workspace the workspace being used (never null) - // * @param relative_path is the relative location after the workspace - // * @param nodeTypeName is the node type to be returned - // * @throws Exception if there is a problem creating the folder node - // */ - // public NodeTypeNode( Workspace workspace, String relative_path) throws Exception { - // super(relative_path); - // - // CheckArg.isNotNull(workspace, "workspace"); - // CheckArg.isNotNull(relative_path, "relative_path"); - // - // this.workspace = workspace; - // this.depth = 2; - // } - + } + // =========================================================================================================================== // Methods // =========================================================================================================================== @@ -125,7 +128,7 @@ public URL getUrl() throws Exception { WorkspaceNode workspaceNode = new WorkspaceNode(this.workspace); StringBuilder url = new StringBuilder(workspaceNode.getUrl().toString()); - + // make sure path starts with a '/' String path = getPath(); @@ -139,18 +142,10 @@ } // path needs to be encoded - url.append(JsonUtils.encode(path)); - - // if wanting a specific node type, need to append the node type name and the depth in order to get its properties - // if (this.nodeTypeName != null) { - // // url.append("/").append(JsonUtils.encode(this.nodeTypeName)).append(JsonUtils.encode("?depth=" + this.depth)); - // url.append("/").append((this.nodeTypeName)); - // } else if (depth >= 0) { - // url.append(("?depth=" + this.depth)); - // } - + url.append(JsonUtils.encode(path)); + if (this.depth != null) { - url.append(this.depth); + url.append(this.depth); } return new URL(url.toString()); @@ -155,7 +150,7 @@ return new URL(url.toString()); } - + /** * @param jsonResponse the HTTP connection JSON response (never null) containing the NodeTypes * @return the node types for this workspace (never null) @@ -163,127 +158,131 @@ */ public Collection getNodeTypes( String jsonResponse ) throws Exception { CheckArg.isNotNull(jsonResponse, "jsonResponse"); - Collection nodetypes = new ArrayList(); - JSONObject body = new JSONObject(jsonResponse); - processBody(body, nodetypes, null); - return nodetypes; - } - @SuppressWarnings( "unchecked" ) - protected void processBody( JSONObject body, - Collection nodetypes, - NodeType parentNodeType ) throws Exception { - NodeType parent = parentNodeType; - - parent = createNodeType(null, body, null); - nodetypes.add(parent); - this.nodeTypeMap.put(parent.getName(), parent); - - if (body.has("children")) { - Object obj = body.get("children"); - - if (obj instanceof JSONObject) { - - JSONObject children = (JSONObject)obj; - for (Iterator itr = children.keys(); itr.hasNext();) { - String key = JsonUtils.decode(itr.next()); - - Object child = children.get(key); - if (child != null) { - - if (child instanceof JSONObject) { - JSONObject jsonchild = (JSONObject)child; - NodeType nodeType = createNodeType(key, jsonchild, parent); - nodetypes.add(nodeType); - processNodeType(nodeType, jsonchild, parent); - - } else if (child instanceof JSONArray) { - JSONArray childarray = (JSONArray)child; - for (int idx = 0; idx < childarray.length(); idx++) { - String cname = childarray.getString(idx); - NodeType childnodeType = createNodeType(cname, null, parent); - nodetypes.add(childnodeType); - } - } else { - throw new Exception("Program Error: didnt handle object type: " + child.getClass().getName()); - } - - } + JSONObject body = new JSONObject(jsonResponse); + NodeType parent = createNodeType(null, body, null); - } - } else if (obj instanceof JSONArray) { - JSONArray childarray = (JSONArray)obj; - for (int i = 0; i < childarray.length(); i++) { - String cname = childarray.getString(i); - createNodeType(cname, null, parent); - } - } else { - throw new Exception("Program Error: didnt handle object type: " + obj.getClass().getName()); - } - } + processBody(body, parent); + return nodeTypeMap.values(); } - - @SuppressWarnings( "unchecked" ) - private void processNodeType( NodeType nodeType, - JSONObject child, - NodeType parentNodeType ) throws Exception { - - if (child.has("children")) { - Object obj = child.get("children"); - - if (obj instanceof JSONObject) { - JSONObject children = (JSONObject)obj; - for (Iterator itr = children.keys(); itr.hasNext();) { - String childkey = JsonUtils.decode(itr.next()); - Object childObj = children.get(childkey); - - if (childObj instanceof JSONObject) { - JSONObject childJson = (JSONObject)childObj; - NodeType childnodeType = createNodeType(childkey, childJson, nodeType); - processNodeType(childnodeType, (JSONObject)childObj, nodeType); - - } else { - throw new Exception("Program Error: class type not handled " + childObj.getClass().getName()); - } - } - - } else if (obj instanceof JSONArray) { - JSONArray childarray = (JSONArray)obj; - for (int i = 0; i < childarray.length(); i++) { - String cname = childarray.getString(i); - createNodeType(cname, null, nodeType); - } + + @SuppressWarnings("unchecked") + protected void processBody(JSONObject body, NodeType parentNodeType) throws Exception { + NodeType parent = parentNodeType; + + if (body.has("children")) { + Object obj = body.get("children"); + + if (obj instanceof JSONObject) { + + JSONObject children = (JSONObject) obj; + for (Iterator itr = children.keys(); itr.hasNext();) { + String key = JsonUtils.decode(itr.next()); + Object child = children.get(key); + if (child != null) { + + if (child instanceof JSONObject) { + JSONObject jsonchild = (JSONObject) child; + createNodeType(key, jsonchild, parent); - } else { - throw new Exception("Program Error: didnt handle object type: " + obj.getClass().getName()); - } + } else if (child instanceof JSONArray) { + JSONArray childarray = (JSONArray) child; + for (int idx=0; idx superTypes = new HashSet(3); + + Properties properties = new Properties(); for (Iterator itr = jsonProperties.keys(); itr.hasNext();) { String key = JsonUtils.decode(itr.next()); Object obj = jsonProperties.get(key); @@ -288,49 +287,50 @@ String key = JsonUtils.decode(itr.next()); Object obj = jsonProperties.get(key); if (obj != null) { - if (obj instanceof JSONObject) { - // JSONObject child = (JSONObject) obj; + if (obj instanceof JSONObject) { + throw new Exception("Program Error: didnt handle object type: " + obj.getClass().getName()); + } + + if (key.equalsIgnoreCase("jcr:supertypes")) { - throw new Exception("Program Error: didnt handle object type: " + obj.getClass().getName()); - // processBody(child, nodetypes, nodeType); - } - properties.put(key, obj.toString()); - } - } + JSONArray superArray = jsonProperties.getJSONArray(key); + + for (int i=0; i it=superTypes.iterator(); it.hasNext();) { + childnodeType.addSuperNodeType(it.next()); } + + this.nodeTypeMap.put(childnodeType.getName(), childnodeType); + + if (childNode != null) { + processBody(childNode, childnodeType); + } - CheckArg.isNotNull(nodeName, "nodeName ends up in null state for childkey: " + childkey); return childnodeType; } - + /** * @param jsonResponse the HTTP connection JSON response (never null) containing the NodeTypes * @return the node types for this workspace (never null) @@ -337,29 +337,48 @@ * @throws Exception if there is a problem obtaining the node types */ - @SuppressWarnings( "unchecked" ) - public NodeType getNodeType( String jsonResponse ) throws Exception { + @SuppressWarnings("unchecked") + public NodeType getNodeType( String jsonResponse ) throws Exception { CheckArg.isNotNull(jsonResponse, "jsonResponse"); - JSONObject jsonChild = new JSONObject(jsonResponse); + JSONObject jsonChild = new JSONObject(jsonResponse); + + NodeType nodetype = createNodeType(null, jsonChild, null); - Properties properties = new Properties(); - - NodeType nodetype = null; - - // keys are the repository names - for (Iterator itr = jsonChild.keys(); itr.hasNext();) { - String name = JsonUtils.decode(itr.next()); - Object obj = jsonChild.get(name); - if (obj != null && obj instanceof JSONObject) { - JSONObject child = (JSONObject)obj; - nodetype = new NodeType(name, this.workspace, properties); - this.processNodeType(nodetype, child, null); - - return nodetype; - } + return nodetype; + } + + /** + * The Super Type weak reference is used because there's no guaranteed order for loading + * all the node types, therefore, a referenced super type might not have been loaded + * at the time of loading its child. Therefore, the findSuperTypeMap + * is used to find the super type after the fact. + * + */ + class WeakSuperTypeReference extends NodeType { + private MapfindSuperTypeMap = null; + + public WeakSuperTypeReference( String name, + Workspace workspace, + Properties properties, + MapnodeTypeMap) { + super(name, workspace, properties); + findSuperTypeMap = nodeTypeMap; + } + + @SuppressWarnings("unchecked") + @Override + public List getPropertyDefinitions() { + NodeType superType = findSuperTypeMap.get(getName()); + return (List) (superType != null ? superType.getPropertyDefinitions() : Collections.emptyList()); } - - return null; + + @SuppressWarnings("unchecked") + @Override + public List getChildNodeDefinitions() { + NodeType superType = findSuperTypeMap.get(getName()); + return (List) (superType != null ? superType.getChildNodeDefinitions() : Collections.emptyList()); + } + } } Index: src/test/java/org/modeshape/web/jcr/rest/client/json/JsonRestClientTest.java =================================================================== --- src/test/java/org/modeshape/web/jcr/rest/client/json/JsonRestClientTest.java (revision 2258) +++ src/test/java/org/modeshape/web/jcr/rest/client/json/JsonRestClientTest.java (working copy) @@ -60,6 +60,7 @@ // Constants // =========================================================================================================================== + // user and password configured in pom private static final String PSWD = "password"; private static final String USER = "dnauser"; @@ -102,11 +103,8 @@ assertThat(repositories.size(), equalTo(1)); assertThat(repositories.iterator().next(), is(REPOSITORY1)); } - - // Test is not currently working as a unit test, cause it throws an exception when using the default cargo setup - // but does work when pointed at a local jbossas server - // TODO: determine how to add/setup the local cargo server with cnd files - @Ignore + + @Test public void shouldGetNodeTypes() throws Exception { Workspace ws = new Workspace(WORKSPACE_NAME, REPOSITORY1); @@ -111,26 +109,11 @@ public void shouldGetNodeTypes() throws Exception { Workspace ws = new Workspace(WORKSPACE_NAME, REPOSITORY1); Collection results = this.restClient.getNodeTypes(ws, "jcr:system", "?depth=5"); - // this is currently the number returned from the default jbossas installation - // assertThat(results.size(), is(2)); - - for (Iterator it=results.iterator(); it.hasNext();) { - NodeType nt = it.next(); - System.out.println("NODETYPE: " + nt.getName()); - List children = nt.getChildren(); - if (children != null) { - for (Iterator itc=children.iterator(); itc.hasNext();){ - NodeType ntc = (NodeType) itc.next(); - System.out.println("NODETYPECHILD: " + ntc.getName()); - } - } - - } + + assertThat(results.size(), is(92)); } - // Test is not currently working as a unit test, cause it throws an exception when using the default cargo setup - // but does work when pointed at a local jbossas server - // TODO: determine how to add/setup the local cargo server with cnd files + // Test is not currently working as a unit test @Ignore @Test public void shouldGetNodeType() throws Exception { @@ -135,7 +118,9 @@ @Test public void shouldGetNodeType() throws Exception { Workspace ws = new Workspace(WORKSPACE_NAME , REPOSITORY1); - NodeType nt = this.restClient.getNodeType(ws, "mode:system/nodeTypes/nt:base", "?depth=2"); + NodeType nt = this.restClient.getNodeType(ws, "jcr:system/jcr:nodeTypes/vdb:virtualDatabase", "?depth=5"); + + //jcr:versionStorage assertThat(nt, is(notNullValue())); } Index: src/test/java/org/modeshape/web/jcr/rest/client/domain/WorkspaceTest.java =================================================================== --- src/test/java/org/modeshape/web/jcr/rest/client/domain/WorkspaceTest.java (revision 2258) +++ src/test/java/org/modeshape/web/jcr/rest/client/domain/WorkspaceTest.java (working copy) @@ -47,12 +47,8 @@ private static final Server SERVER1 = new Server("file:/tmp/temp.txt/resources", "user", "pswd"); - // private static final Server SERVER2 = new Server("http:www.redhat.com/resources", "user", "pswd"); - private static final Repository REPOSITORY1 = new Repository(NAME1, SERVER1); - // private static final Repository REPOSITORY2 = new Repository(NAME2, SERVER2); - private static final Workspace WORKSPACE1 = new Workspace(NAME1, REPOSITORY1); private static final Workspace WORKSPACE2 = new Workspace(NAME2, REPOSITORY1); Index: src/test/java/org/modeshape/web/jcr/rest/client/domain/NodeTypeTest.java =================================================================== --- src/test/java/org/modeshape/web/jcr/rest/client/domain/NodeTypeTest.java (revision 2258) +++ src/test/java/org/modeshape/web/jcr/rest/client/domain/NodeTypeTest.java (working copy) @@ -28,6 +28,7 @@ import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertThat; import java.util.HashSet; +import java.util.Properties; import java.util.Set; import org.junit.Test; @@ -46,13 +47,15 @@ private static final Server SERVER1 = new Server("file:/tmp/temp.txt/resources", "user", "pswd"); - private static final Server SERVER2 = new Server("http:www.redhat.com/resources", "user", "pswd"); - private static final Repository REPOSITORY1 = new Repository(NAME1, SERVER1); - private static final Repository REPOSITORY2 = new Repository(NAME2, SERVER2); - private static final Workspace WORKSPACE1 = new Workspace(NAME1, REPOSITORY1); + + private static final Workspace WORKSPACE2 = new Workspace(NAME2, REPOSITORY1); + + private static final NodeType NODETYPE1 = new NodeType(NAME1, WORKSPACE1, new Properties()); + + // =========================================================================================================================== // Tests @@ -60,7 +63,7 @@ @Test public void shouldBeEqualIfHavingSameProperies() { - assertThat(WORKSPACE1, equalTo(new Workspace(WORKSPACE1.getName(), WORKSPACE1.getRepository()))); + assertThat(NODETYPE1, equalTo(new NodeType(NODETYPE1.getName(), WORKSPACE1, new Properties()))); } @Test @@ -65,9 +68,9 @@ @Test public void shouldHashToSameValueIfEquals() { - Set set = new HashSet(); - set.add(WORKSPACE1); - set.add(new Workspace(WORKSPACE1.getName(), WORKSPACE1.getRepository())); + Set set = new HashSet(); + set.add(NODETYPE1); + set.add(new NodeType(NODETYPE1.getName(), WORKSPACE1, null)); assertThat(set.size(), equalTo(1)); } @@ -73,22 +76,22 @@ @Test( expected = java.lang.AssertionError.class ) public void shouldNotAllowNullName() { - new Workspace(null, REPOSITORY1); + new NodeType(null, WORKSPACE1, null); } @Test( expected = java.lang.AssertionError.class ) - public void shouldNotAllowNullRepository() { - new Workspace(NAME1, null); + public void shouldNotAllowNullWorkspace() { + new NodeType(NAME1, null, null); } @Test - public void shouldNotBeEqualIfSameNameButDifferentRepository() { - assertThat(WORKSPACE1, is(not(equalTo(new Workspace(WORKSPACE1.getName(), REPOSITORY2))))); + public void shouldNotBeEqualIfSameNameButDifferentWorkspace() { + assertThat(NODETYPE1, is(not(equalTo(new NodeType(NODETYPE1.getName(), WORKSPACE2, null))))); } @Test - public void shouldNotBeEqualIfSameRepositoryButDifferentName() { - assertThat(WORKSPACE1, is(not(equalTo(new Workspace(NAME2, WORKSPACE1.getRepository()))))); + public void shouldNotBeEqualIfSameWorkspaceButDifferentName() { + assertThat(NODETYPE1, is(not(equalTo(new NodeType(NAME2, WORKSPACE1, null))))); } }