fixed SLING-5541 for the JavaScript node types

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1732531 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..67db858
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,175 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..161117a
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,7 @@
+jsNodeTypes - The JavaScript Node Types library
+===========
+
+A public documentation of the library can be found at: http://www.jcrbrowser.org/sling/libs/jsnodetypes/content/documentation.html.
+The documentation of the library version you deployed is shipped with the bundle. It can be found at http://[yourserver]:[yourport]/libs/jsnodetypes/content/documentation.html
+
+Use 'mvn install -P autoInstallBundle' to install that bundle to your local Sling instance at port 8080. 
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5933c01
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.sling</groupId>
+		<artifactId>sling</artifactId>
+		<version>22</version>
+		<relativePath/>
+	</parent>
+
+	<artifactId>org.apache.sling.jcr.js.nodetypes</artifactId>
+	<packaging>bundle</packaging>
+	<version>0.1.0-SNAPSHOT</version>
+
+	<name>jsNodeTypes</name>
+	<description>
+	Uses Apache Sling to generate a JavaScript representation of JCR node types.
+    </description>
+
+	<licenses>
+		<license>
+			<name>The Apache Software License, Version 2.0</name>
+			<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+			<distribution>repo</distribution>
+		</license>
+	</licenses>
+
+	<scm>
+		<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/commons/jsnodetypes</connection>
+		<developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/commons/jsnodetypes</developerConnection>
+		<url>http://svn.apache.org/viewvc/sling/trunk/contrib/commons/jsnodetypes</url>
+	</scm>
+
+	<build>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>com.github.searls</groupId>
+					<artifactId>jasmine-maven-plugin</artifactId>
+					<version>1.3.1.0</version>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+		<plugins>
+			<plugin>
+				<groupId>com.github.searls</groupId>
+				<artifactId>jasmine-maven-plugin</artifactId>
+				<version>1.3.1.0</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>test</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<specRunnerTemplate>DEFAULT</specRunnerTemplate>
+					<jsSrcDir>${project.basedir}/src/main/resources/SLING-INF/libs/jsnodetypes/js</jsSrcDir>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Sling-Initial-Content>SLING-INF/libs/jsnodetypes;overwrite:=true;path:=/libs/jsnodetypes;uninstall:=true,SLING-INF/libs/jsnodetypes/documentation;overwrite:=true;path:=/libs/jsnodetypes/documentation;ignoreImportProviders:=json;uninstall:=true,SLING-INF/libs/jsnodetypes/js;overwrite:=true;path:=/libs/jsnodetypes/js;ignoreImportProviders:=json;uninstall:=true</Sling-Initial-Content>
+						<Export-Package>org.apache.sling.jcr.js.nodetypes.javascript</Export-Package>
+						<Provide-Capability>${project.artifactId}; version:Version=0.1.0</Provide-Capability>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-scr-plugin</artifactId>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.sling</groupId>
+				<artifactId>maven-sling-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>install-bundle</id>
+						<goals>
+							<goal>validate</goal>
+							<goal>install</goal>
+						</goals>
+						<configuration>
+							<mountByFS>false</mountByFS>
+							<slingUrl>http://localhost:8080/system/console</slingUrl>
+							<user>admin</user>
+							<password>admin</password>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<argLine>-Xmx448m</argLine>
+				</configuration>
+			</plugin>
+		</plugins>
+		<extensions>
+			<extension>
+				<groupId>org.apache.maven.wagon</groupId>
+				<artifactId>wagon-webdav-jackrabbit</artifactId>
+				<version>2.2</version>
+			</extension>
+		</extensions>
+	</build>
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.sling</groupId>
+			<artifactId>org.apache.sling.commons.json</artifactId>
+			<version>2.0.10</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.jackrabbit</groupId>
+			<artifactId>jackrabbit-jcr-commons</artifactId>
+			<version>2.7.5</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.jcr</groupId>
+			<artifactId>jcr</artifactId>
+			<version>2.0</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.sling</groupId>
+			<artifactId>org.apache.sling.api</artifactId>
+			<version>2.0.8</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.sling</groupId>
+			<artifactId>org.apache.sling.commons.osgi</artifactId>
+			<version>2.0.6</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.core</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.compendium</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.scr.annotations</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		<!-- Testing -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-all</artifactId>
+			<version>1.9.5</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONItemDefinition.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONItemDefinition.java
new file mode 100644
index 0000000..81088e5
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONItemDefinition.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Represents an ItemDefinition in JSON.
+ */
+public class JSONItemDefinition {
+
+	protected JSONObject jsonObj = new JSONObject();
+	
+	public JSONItemDefinition(ItemDefinition itemDefinition) throws JSONException {
+		
+		jsonObj.put("name", itemDefinition.getName());
+		
+		if (itemDefinition.isAutoCreated()){
+			jsonObj.put("autoCreated", true);
+		}
+		if (itemDefinition.isMandatory()){
+			jsonObj.put("mandatory", true);
+		}
+		if (itemDefinition.isProtected()){
+			jsonObj.put("protected", true);
+		}
+		boolean onParentVersionIsUnset = itemDefinition.getOnParentVersion() == 0;
+		int onParentVersion = onParentVersionIsUnset ? OnParentVersionAction.COPY : itemDefinition.getOnParentVersion();
+		String onParentVersionAction = OnParentVersionAction.nameFromValue(onParentVersion);
+		if (!"COPY".equals(onParentVersionAction)){
+			jsonObj.put("onParentVersion", onParentVersionAction);
+		}
+	}
+	
+	JSONObject getJSONObject(){
+		return jsonObj;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeDefinition.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeDefinition.java
new file mode 100644
index 0000000..97d1466
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeDefinition.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+
+/**
+ * Represents a NodeDefinition in JSON.
+ *
+ */
+public class JSONNodeDefinition extends JSONItemDefinition {
+
+	public JSONNodeDefinition(NodeDefinition childNodeDefinition) throws JSONException {
+		super(childNodeDefinition);
+
+		if (childNodeDefinition.allowsSameNameSiblings()){
+			jsonObj.put("allowsSameNameSiblings", true);
+		}
+		NodeType defaultPrimaryType = childNodeDefinition.getDefaultPrimaryType();
+		if (defaultPrimaryType!=null){
+			String defaultPrimaryTypeName = defaultPrimaryType.getName();
+			if (defaultPrimaryTypeName != null && !defaultPrimaryTypeName.equals("")){
+				jsonObj.put("defaultPrimaryType", defaultPrimaryTypeName);
+			}
+		}
+
+		NodeType[] primaryTypes = childNodeDefinition.getRequiredPrimaryTypes();
+		List<String> primaryTypeNames = new ArrayList<String>();
+		for (NodeType primaryType : primaryTypes) {
+			String primaryTypeName = primaryType.getName();
+			if (primaryTypeName != null) {
+				primaryTypeNames.add(primaryTypeName);
+			}
+		}
+		if (primaryTypeNames.size()>0 && !(primaryTypeNames.size()==1 && primaryTypeNames.get(0).equals("nt:base")) ){
+			jsonObj.put("requiredPrimaryTypes", new JSONArray(primaryTypeNames));
+		}
+	}
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeType.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeType.java
new file mode 100644
index 0000000..9212bca
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONNodeType.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Represents a NodeType in JSON.
+ *
+ */
+public class JSONNodeType {
+
+	private JSONObject jsonObj = new JSONObject();
+
+	public JSONNodeType(NodeType nodeType) throws ValueFormatException, RepositoryException, JSONException {
+		NodeDefinition[] declaredChildNodeDefinitions = nodeType.getDeclaredChildNodeDefinitions();
+		if (declaredChildNodeDefinitions != null) {
+			JSONArray jsonChildNodeDefArray = new JSONArray();
+			for (NodeDefinition childNodeDefinition : nodeType.getDeclaredChildNodeDefinitions()) {
+				String childNodeName = childNodeDefinition.getName();
+				if (childNodeName != null) {
+					JSONNodeDefinition jsonChildNodeDefinition = new JSONNodeDefinition(childNodeDefinition);
+					jsonChildNodeDefArray.put(jsonChildNodeDefinition.getJSONObject());
+				}
+			}
+			if (jsonChildNodeDefArray.length()>0){
+				jsonObj.put("declaredChildNodeDefinitions",jsonChildNodeDefArray);
+			}
+		}
+
+		PropertyDefinition[] declaredPropertyDefinitions = nodeType.getDeclaredPropertyDefinitions();
+		if (declaredPropertyDefinitions != null) {
+			JSONArray jsonPropDefArray = new JSONArray();
+			for (PropertyDefinition propertyDefinition : declaredPropertyDefinitions) {
+				JSONPropertyDefinition jsonPropertyDefinition = new JSONPropertyDefinition(propertyDefinition);
+				jsonPropDefArray.put(jsonPropertyDefinition.getJSONObject());
+			}
+			if (jsonPropDefArray.length()>0){
+				jsonObj.put("declaredPropertyDefinitions",jsonPropDefArray);
+			}
+		}
+
+		NodeType[] superTypes = nodeType.getDeclaredSupertypes();
+		List<String> superTypeNames = new ArrayList<String>();
+		for (NodeType superType : superTypes) {
+			superTypeNames.add(superType.getName());
+		}
+		if (superTypeNames.size()>0 && !("nt:base".equals(superTypeNames.get(0)) && superTypeNames.size()==1)){
+			jsonObj.put("declaredSupertypes", new JSONArray(superTypeNames));
+		}
+		if (nodeType.isMixin()){
+			jsonObj.put("mixin", true);
+		}
+		if (nodeType.hasOrderableChildNodes()){
+			jsonObj.put("orderableChildNodes", true);
+		}
+		String thePrimaryItemName = nodeType.getPrimaryItemName();
+		if (thePrimaryItemName != null && !thePrimaryItemName.equals("")){
+			jsonObj.put("primaryItemName", nodeType.getPrimaryItemName());
+		}
+	}
+	
+	JSONObject getJson(){
+		return jsonObj;
+	}
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONPropertyDefinition.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONPropertyDefinition.java
new file mode 100644
index 0000000..e1edb76
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONPropertyDefinition.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+
+/**
+ * Represents a PropertyDefinition in JSON.
+ *
+ */
+public class JSONPropertyDefinition extends JSONItemDefinition {
+
+	public JSONPropertyDefinition(PropertyDefinition propertyDefinition) throws ValueFormatException, RepositoryException, JSONException {
+		super(propertyDefinition);
+
+		Value[] defaultValues = propertyDefinition.getDefaultValues();
+		JSONArray defaultValueArray = new JSONArray();
+		if (defaultValues != null) {
+			if (defaultValues !=null){
+				for (int i=0; i<defaultValues.length; i++){
+					Value defaultValue = defaultValues[i];
+					JSONValue jsonValue = new JSONValue(defaultValue, i, propertyDefinition);
+					defaultValueArray.put(jsonValue.getJSONObject());
+				}
+			}
+		}
+
+		if (defaultValueArray.length()>0){
+			jsonObj.put("defaultValues", defaultValueArray);
+		}
+		String theRequiredType = PropertyType.nameFromValue(propertyDefinition.getRequiredType());
+		if (theRequiredType!=null && !theRequiredType.equals("") && !("String".equals(theRequiredType))){
+			jsonObj.put("requiredType", theRequiredType);
+		}
+		if (propertyDefinition.getValueConstraints()!=null){
+			List<String> theValueConstraints = Arrays.asList(propertyDefinition.getValueConstraints());
+			if (theValueConstraints != null && theValueConstraints.size()>0){
+				jsonObj.put("valueConstraints", theValueConstraints);
+			}
+		}
+		if (propertyDefinition.isMultiple()){
+			jsonObj.put("multiple", true);
+		}
+	}
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONValue.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONValue.java
new file mode 100644
index 0000000..0f9c534
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/JSONValue.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+import org.apache.jackrabbit.util.ISO8601;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+
+/**
+ * Represents a javax.jcr.Value in JSON.
+ *
+ */
+public class JSONValue {
+
+	transient JSONObject jsonObj = new JSONObject();
+	
+    public JSONValue(Value aValue, int index, PropertyDefinition propertyDef) throws ValueFormatException, RepositoryException, IllegalStateException, JSONException{
+    	switch (aValue.getType()) {
+		case PropertyType.STRING:
+			jsonObj.put("string", aValue.getString());
+			break;
+		case PropertyType.DATE:
+	    	String date = aValue.getDate() == null ? "" : ISO8601.format(aValue.getDate());
+			jsonObj.put("date", date);
+			break;
+		case PropertyType.BINARY:
+			String binary = getBinaryDownloadURLFromPropertyDef(index, propertyDef);
+			jsonObj.put("binary", binary);
+			break;
+		case PropertyType.DOUBLE:
+			jsonObj.put("double", aValue.getDouble());
+			break;
+		case PropertyType.LONG:
+			jsonObj.put("long", aValue.getLong());
+			break;
+		case PropertyType.BOOLEAN:
+			jsonObj.put("boolean", aValue.getBoolean());
+			break;
+		case PropertyType.NAME:
+			jsonObj.put("name",  aValue.getString());
+			break;
+		case PropertyType.PATH:
+			jsonObj.put("path",  aValue.getString());
+			break;
+		case PropertyType.REFERENCE:
+			jsonObj.put("reference",  aValue.getString());
+			break;
+		case PropertyType.UNDEFINED:
+			jsonObj.put("undefined",  aValue.getString());
+			break;
+/// The following property types are from JSR-283 / JCR 2.0
+		case PropertyType.WEAKREFERENCE:
+			jsonObj.put("weakReference",  aValue.getString());
+			break;
+		case PropertyType.URI:
+			jsonObj.put("uri",  aValue.getString());
+			break;
+		case PropertyType.DECIMAL:
+			String decimal = aValue.getDecimal() == null ? "" : aValue.getDecimal().toString();
+			jsonObj.put("decimal", decimal);
+			break;
+
+		default:
+			break;
+		}
+    	String type = PropertyType.nameFromValue(aValue.getType());
+		jsonObj.put("type", type);
+	}
+
+	private String getBinaryDownloadURLFromPropertyDef(int index, PropertyDefinition propertyDef) {
+		String nodeTypeName = propertyDef.getDeclaringNodeType().getName();
+		String propertyName = propertyDef.getName();
+		String propertyType = PropertyType.nameFromValue(propertyDef.getRequiredType());
+		boolean isAutoCreated = propertyDef.isAutoCreated();
+		boolean isMandatory = propertyDef.isMandatory();
+		boolean isProtected = propertyDef.isProtected();
+		boolean isMultiple = propertyDef.isMultiple();
+		String onParentVersionAction = OnParentVersionAction.nameFromValue(propertyDef.getOnParentVersion());
+		return String.format("/%s/%s/%s/%s/%s/%s/%s/%s/%s.default_binary_value.bin", nodeTypeName, propertyName,
+				propertyType, isAutoCreated, isMandatory, isProtected, isMultiple, onParentVersionAction, index);
+	}
+	
+    JSONObject getJSONObject(){
+    	return jsonObj;
+    }
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/NodeTypesJSONServlet.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/NodeTypesJSONServlet.java
new file mode 100644
index 0000000..f353d2c
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/NodeTypesJSONServlet.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Returns all completely registered node types of the repository in JSON format. Nodetypes without names will not end up in the JSON file.
+ * The binary default values of properties will not be part of the JSON file. They will have a String containing a URL. Use this URL to
+ * download the binary content.
+ *  
+ * The URL is <code>/libs/jsnodetypes/content/nodetypes.json</code>.
+ */
+@Component
+@Service(Servlet.class)
+@Properties({ @Property(name = "service.description", value = "Returns the node types as a JSON file"),
+		@Property(name = "service.vendor", value = "Sandro Boehme"),
+		@Property(name = "sling.servlet.extensions", value = "json"),
+		@Property(name = "sling.servlet.resourceTypes", value = "jsnodetypes")
+
+})
+public class NodeTypesJSONServlet extends SlingSafeMethodsServlet {
+	/*
+	 * In /src/main/resources/libs/jsnodetypes/content.json there is an automatically loaded node with a child node
+	 * that has the resource type 'jsnodetypes'. This servlet can render this resource type and thus provides the JSON
+	 * content at the URL as written in the JavaDoc.
+	 */
+
+	private static final long serialVersionUID = -1L;
+
+	/** default log */
+	private final Logger log = LoggerFactory.getLogger(NodeTypesJSONServlet.class);
+
+	@Override
+	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
+		response.setContentType("application/json; charset=UTF-8");
+		PrintWriter writer = response.getWriter();
+		Resource resource = request.getResource();
+		Node currentNode = resource.adaptTo(Node.class);
+		try {
+			NodeTypeIterator nodeTypeIterator = currentNode.getSession().getWorkspace().getNodeTypeManager().getAllNodeTypes();
+	        JSONObject nodeTypes = new JSONObject();
+			while (nodeTypeIterator.hasNext()) {
+				NodeType nodeType = nodeTypeIterator.nextNodeType();
+				if (nodeType.getName() != null) {
+					JSONNodeType jsonNodeType = new JSONNodeType(nodeType);
+					nodeTypes.put(nodeType.getName(), jsonNodeType.getJson());
+				}
+			}
+			writer.println(nodeTypes.toString(2));
+			writer.flush();
+			writer.close();
+		} catch (RepositoryException e) {
+			log.error("Could not generate the node types.", e);
+			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+		} catch (JSONException e) {
+			log.error("Could not generate the node types.", e);
+			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+		}
+
+	}
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AbstractPropertyMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AbstractPropertyMatcher.java
new file mode 100644
index 0000000..a5d285e
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AbstractPropertyMatcher.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+/**
+ * Makes it possible to specify the array and index but retrieving it on demand lazily. 
+ */
+public class AbstractPropertyMatcher {
+	
+	protected String[] idFields;
+	protected int index;
+
+	public String getArrayValue(String[] idFields, int index) {
+		if (index <= idFields.length-1){
+			return idFields[index];
+		}
+		return null;
+	}
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AutoCreatedMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AutoCreatedMatcher.java
new file mode 100644
index 0000000..8a3d6dd
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/AutoCreatedMatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public class AutoCreatedMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public AutoCreatedMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			boolean isAutoCreated = Boolean.parseBoolean(arrayValue);
+			return isAutoCreated == propertyDefinition.isAutoCreated();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueServlet.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueServlet.java
new file mode 100644
index 0000000..b7a10ff
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueServlet.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides a download for binary default values.
+ * 
+ * The fully qualified URL to specify a default value looks like this:
+ * <code>/ns:ntName/binPropDef/binary/true/true/true/true/version/1.default_binary_value.bin</code>
+ * The fully qualified format is: <code>/node type/property definition
+ * name/required property type name/is autoCreated/is mandatory/is
+ * protected/is multiple/on parent version action name/index of the
+ * default value.default_binary_value.bin</code>
+ * 
+ * In case you know which elements identify a property definition unambiguously
+ * you can shorten the URL. E.g. if you are sure the property definition
+ * 'binPropDef' does not exist twice within the node type 'ns:ntName' you can
+ * use the URL <code>/ns:ntName/binPropDef/1.default_binary_value.bin</code> to
+ * download the second binary default value from that property definition.
+ * 
+ * If you want to download the first binary default value you can shorten the
+ * URL even more by skipping the index in the URL like this:
+ * <code>/ns:ntName/binPropDef/default_binary_value.bin</code>
+ * 
+ * The type name, the boolean Strings and the parent version action name are
+ * case insensitive.
+ * 
+ * This long identification is needed as a property definition name with its
+ * type may not be unique within a node type. This is not only the case for
+ * residual property definitions. The JCR does not specify that there can be
+ * only one combination of property definition name / required property type
+ * name. Thats the reason why it is qualified like this.
+ * 
+ */
+
+@Component
+@Service(Servlet.class)
+@Properties({ @Property(name = "service.description", value = "Download Servlet for binary properties"),
+		@Property(name = "service.vendor", value = "Sandro Boehme"),
+		@Property(name = "sling.servlet.selectors", value = "default_binary_value"),
+		@Property(name = "sling.servlet.extensions", value = "bin"),
+		@Property(name = "sling.servlet.resourceTypes", value = "sling/servlet/default")
+
+})
+public class DownloadDefaultBinaryValueServlet extends SlingSafeMethodsServlet {
+
+	private static final long serialVersionUID = -1L;
+
+	/** default log */
+	private final Logger log = LoggerFactory.getLogger(DownloadDefaultBinaryValueServlet.class);
+
+	@SuppressWarnings("deprecation")
+	@Override
+	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
+		response.setContentType("application/octet-stream; charset=UTF-8");
+		String requestURI = request.getRequestURI();
+		String[] idFields = requestURI.substring(1).split("/");
+		try {
+			NodeTypeManager nodeTypeManager = request.getResourceResolver().getResource("/").adaptTo(Node.class).getSession()
+					.getWorkspace().getNodeTypeManager();
+			NodeType nodeType = nodeTypeManager.getNodeType(idFields[0]);
+			PropertyDefinition[] propertyDefinitions = nodeType.getPropertyDefinitions();
+			List<PropertyDefinition> propertyDefinitionList = Arrays.asList(propertyDefinitions);
+			if (propertyDefinitionList != null) {
+				
+				// Every matcher represents a path element in the URL and is initialized with its value.
+				// It will try to match the value of a path element with the corresponding property 
+				// element of all property definitions from the node type in findMatchingPropertyDef().
+				PropertyMatcher[] propertyMatcher = new PropertyMatcher[] { new PropertyNameMatcher(idFields, 1),
+						new RequiredPropertyTypeMatcher(idFields, 2), new AutoCreatedMatcher(idFields, 3),
+						new MandatoryMatcher(idFields, 4), new ProtectedMatcher(idFields, 5), new MultipleMatcher(idFields, 6),
+						new OnParentVersionMatcher(idFields, 7) };
+
+				PropertyDefinition propDef = findMatchingPropertyDef(propertyDefinitionList, new LinkedList<PropertyMatcher>(
+						Arrays.asList(propertyMatcher)));
+				if (propDef != null) {
+					Value[] defaultValues = propDef.getDefaultValues();
+					if (defaultValues != null && defaultValues.length > 0) {
+						int startIndex = requestURI.lastIndexOf('/') + 1;
+						int endIndex = requestURI.indexOf("default_binary_value.bin") - 1;
+						int defaultValueIndex = 0;
+						if (endIndex - startIndex == 1) {
+							String indexString = requestURI.substring(startIndex, endIndex);
+							defaultValueIndex = Integer.parseInt(indexString);
+						}
+						try {
+							if (defaultValueIndex < defaultValues.length) {
+								Value defaultValue = defaultValues[defaultValueIndex];
+								InputStream stream = defaultValue.getStream();
+								BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
+								PrintWriter writer = response.getWriter();
+								String line = null;
+								while ((line = bufferedReader.readLine()) != null) {
+									writer.write(line);
+								}
+								writer.flush();
+								writer.close();
+								response.setStatus(HttpServletResponse.SC_OK);
+							} else {
+								response.sendError(HttpServletResponse.SC_NOT_FOUND);
+							}
+						} catch (NumberFormatException nfe) {
+							response.sendError(HttpServletResponse.SC_NOT_FOUND);
+						}
+					} else {
+						response.sendError(HttpServletResponse.SC_NOT_FOUND);
+					}
+				} else {
+					response.sendError(HttpServletResponse.SC_NOT_FOUND);
+				}
+			}
+		} catch (RepositoryException e) {
+			log.error("Could not return the binary file.", e);
+			throw new ServletException(e);
+		}
+	}
+
+	/**
+	 * This method pulls the first matcher out of the list and iterates over the list of specified property definitions to find matches. 
+	 * Lets say this is a PropertyNameMatcher that has been initialized with the property name from the URL. Than it will match for every
+	 * property definition who's name is equal to the one specified in the URL. The matched property definitions and the rest of the matchers
+	 * will be provided for the next recursive call of the method to work through the other path elements until all matchers are processed or
+	 * until only one property definition matches. In the first case null is returned and in the second case the identified property definition
+	 * is returned. 
+	 * @param propertyDefinitions The list of property definitions.
+	 * @param propertyMatcherList The list of matcher in the order of appearance of their type in the URL. A matcher checks if the
+	 * content of a path element it was initialized with matches its corresponding value in the property definition.
+	 * @return Returns the property definition that is identified by the URL or null if no property definition matches the values specified in the URL.
+	 */
+	private PropertyDefinition findMatchingPropertyDef(List<PropertyDefinition> propertyDefinitions,
+			List<PropertyMatcher> propertyMatcherList) {
+		if (propertyMatcherList.size() > 0) {
+			// retrieve the matcher to be used for this iteration
+			PropertyMatcher propertyMatcher = propertyMatcherList.get(0);
+			// remove the matcher to make the next matcher available for the
+			// next iteration
+			propertyMatcherList.remove(0);
+			List<PropertyDefinition> matchedPropDefs = new LinkedList<PropertyDefinition>();
+			// try to match all property definitions with the top matcher
+			for (PropertyDefinition propertyDefinition : propertyDefinitions) {
+				if (propertyMatcher.match(propertyDefinition)) {
+					matchedPropDefs.add(propertyDefinition);
+				}
+			}
+			if (matchedPropDefs.size() == 1) {
+				return matchedPropDefs.get(0);
+			} else if (matchedPropDefs.size() > 1) {
+				return findMatchingPropertyDef(matchedPropDefs, propertyMatcherList);
+			}
+		}
+		return null;
+	}
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MandatoryMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MandatoryMatcher.java
new file mode 100644
index 0000000..8497507
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MandatoryMatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public class MandatoryMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public MandatoryMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			boolean isMandatory = Boolean.parseBoolean(arrayValue);
+			return isMandatory == propertyDefinition.isMandatory();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MultipleMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MultipleMatcher.java
new file mode 100644
index 0000000..4d74074
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/MultipleMatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public class MultipleMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public MultipleMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			boolean isMultiple = Boolean.parseBoolean(arrayValue);
+			return isMultiple == propertyDefinition.isMultiple();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/OnParentVersionMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/OnParentVersionMatcher.java
new file mode 100644
index 0000000..e40d044
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/OnParentVersionMatcher.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+/**
+ * The names are not case sensitive.
+ *
+ */
+public class OnParentVersionMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public OnParentVersionMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			int onParentVersion = OnParentVersionAction.valueFromName(arrayValue.toUpperCase());
+			return onParentVersion == propertyDefinition.getOnParentVersion();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyMatcher.java
new file mode 100644
index 0000000..5bc2367
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyMatcher.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public interface PropertyMatcher {
+
+	boolean match(PropertyDefinition propertyDefinition);
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyNameMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyNameMatcher.java
new file mode 100644
index 0000000..48d9acb
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/PropertyNameMatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public class PropertyNameMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public PropertyNameMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			String propName = propertyDefinition.getName();
+			return arrayValue.equals(propName);
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/ProtectedMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/ProtectedMatcher.java
new file mode 100644
index 0000000..9caf408
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/ProtectedMatcher.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.nodetype.PropertyDefinition;
+
+public class ProtectedMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public ProtectedMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			boolean isProtected = Boolean.parseBoolean(arrayValue);
+			return isProtected == propertyDefinition.isProtected();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/RequiredPropertyTypeMatcher.java b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/RequiredPropertyTypeMatcher.java
new file mode 100644
index 0000000..dbe6282
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/RequiredPropertyTypeMatcher.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import javax.jcr.PropertyType;
+import javax.jcr.nodetype.PropertyDefinition;
+
+/**
+ * The names are not case sensitive.
+ *
+ */
+public class RequiredPropertyTypeMatcher extends AbstractPropertyMatcher implements PropertyMatcher{
+
+	public RequiredPropertyTypeMatcher(String[] idFields, int index){
+		super.idFields = idFields;
+		super.index = index;
+	}
+	
+	@Override
+	public boolean match(PropertyDefinition propertyDefinition) {
+		String arrayValue = super.getArrayValue(idFields, index);
+		if (arrayValue!=null){
+			String propTypeName = (""+arrayValue.charAt(0)).toUpperCase()+arrayValue.substring(1).toLowerCase();
+			int requiredType = PropertyType.valueFromName(propTypeName);
+			return requiredType == propertyDefinition.getRequiredType();
+		}
+		return false;
+	}
+	
+}
diff --git a/src/main/resources/SLING-INF/libs/jsnodetypes/content.json b/src/main/resources/SLING-INF/libs/jsnodetypes/content.json
new file mode 100644
index 0000000..b8fa95c
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/jsnodetypes/content.json
@@ -0,0 +1,9 @@
+{
+	"primaryNodeType": "nt:unstructured",
+	"nodetypes" : {
+		"sling:resourceType" : "jsnodetypes"
+	},
+	"documentation" : {
+		"sling:resourceType" : "jsnodetypes/documentation"
+	}
+}
diff --git a/src/main/resources/SLING-INF/libs/jsnodetypes/documentation/html.jsp b/src/main/resources/SLING-INF/libs/jsnodetypes/documentation/html.jsp
new file mode 100644
index 0000000..a8c2729
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/jsnodetypes/documentation/html.jsp
@@ -0,0 +1,335 @@
+<%--
+ 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.
+--%>
+
+<!DOCTYPE html>
+<%@ page session="false"%>
+<%@ page isELIgnored="false"%>
+<%@ page import="javax.jcr.*,org.apache.sling.api.resource.Resource"%>
+<%@ taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
+<sling:defineObjects />
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+
+<script type="text/javascript" src="../js/jsnodetypes.js"></script>
+
+<style type="text/css">
+#main {
+    border: 1px dashed;
+    margin: 0 auto;
+    padding: 10px;
+    width: 1000px;
+}
+input {
+	margin: 10px 0;
+}
+.label {
+	margin: 5px;
+}
+#ntNames {
+	white-space: pre-wrap;
+}
+#ntJson {
+	display: inline;
+}
+.code.block-code {
+	display: block;
+}
+.code {
+	border: 1px solid black;
+	display: inline-block;
+	vertical-align: top;
+	margin-top: 10px;
+}
+.code pre {
+	margin: 5px;
+}
+.nodeTypeMethods {
+	display: inline-block;
+	margin: 0 10px 10px;
+	width: 350px;
+}
+.doc {
+	margin-bottom: 15px;
+}
+.parameter {
+	margin-left: 10px;
+}
+
+</style>
+
+<script type="text/javascript">
+
+var settings = {"contextPath": "${pageContext.request.contextPath}"};
+var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+
+function getNTNames(){
+	var ntNames = ntManager.getNodeTypeNames();
+	var ntNamesString = "[ ";
+	for (var ntNameIndex in ntNames) {
+		ntNamesString+= ntNames[ntNameIndex]
+		if (ntNameIndex != ntNames.length-1) {
+			ntNamesString += ", ";
+		}
+	}
+	ntNamesString+= " ]";
+	document.getElementById("ntNames").innerHTML=ntNamesString;
+};
+
+function getNTJson(){
+	var ntName = document.getElementById("ntName").value;
+	return ntManager.getNodeType(ntName);
+};
+
+function loadNTJson(){
+	document.getElementById("ntJson").innerHTML=JSON.stringify(getNTJson(), null, 4);
+};
+function loadChildNodeDefs(){
+	var ntJson = getNTJson();
+	if (ntJson != null){
+		var allChildNodeDefs = ntJson.getAllChildNodeDefinitions();
+		document.getElementById("ntMethodResult").innerHTML=JSON.stringify(allChildNodeDefs, null, 4);
+	}
+};
+function loadPropertyDefs(){
+	var ntJson = getNTJson();
+	if (ntJson != null){
+		var propertyDefs = ntJson.getAllPropertyDefinitions();
+		document.getElementById("ntMethodResult").innerHTML=JSON.stringify(propertyDefs, null, 4);
+	}
+};
+function loadApplicableChildNodeTypes(){
+	var ntJson = getNTJson();
+	if (ntJson != null){
+		var includeMixins = document.getElementById("includeMixins").checked;
+		var applicableChildNodeTypes = ntJson.getApplicableCnTypesPerCnDef(includeMixins);
+		document.getElementById("ntMethodResult").innerHTML=JSON.stringify(applicableChildNodeTypes, null, 4);
+	}
+};
+function canAddChildNode(){
+	var ntJson = getNTJson();
+	if (ntJson != null){
+		var nodeName = document.getElementById("nodeName").value;
+		var nodeTypeToAdd = document.getElementById("nodeTypeToAdd").value;
+		var canAddChildNode = ntJson.canAddChildNode(nodeName, ntManager.getNodeType(nodeTypeToAdd));
+		document.getElementById("ntMethodResult").innerHTML=canAddChildNode;
+	}
+}
+function canAddProperty(){
+	var ntJson = getNTJson();
+	if (ntJson != null){
+		var propertyName = document.getElementById("propertyName").value;
+		var propertyType = document.getElementById("propertyType").value;
+		var canAddProperty = ntJson.canAddProperty(propertyName, propertyType);
+		document.getElementById("ntMethodResult").innerHTML=canAddProperty;
+	}
+}
+</script>
+
+</head>
+<body>
+	<div id="main">
+		<h1><em>JSNodeTypes</em> - A JavaScript Node Types library for Apache Sling</h1>
+		<p>It uses Apache Sling to generate JavaScript object literals for JCR node types and calculates applicable child nodes and properties. Default binary values are converted to paths where they can be downloaded.</p>
+		<h2>Live Demo of the API</h2>
+		<p>Have a look at the simple source code of this page to see how it's done.</p>
+		<h3>Methods of the node type manager:</h3>
+		<div>
+			<input id="ntNamesButton" type="button" value="ntManager.getNodeTypeNames();" onclick="getNTNames();"/>
+		</div>
+		<div class="block-code code">
+			<pre id="ntNames">[]</pre>
+		</div>
+		
+		<div>
+			<input id="ntButton" type="button" value="ntManager.getNodeType" onclick="loadNTJson();"/>
+			(<input id="ntName" type="text" value="nt:version"/>);
+		</div>
+		<div>
+			<div class="code">
+				<pre id="ntJson">{}</pre>
+			</div>
+		</div>
+		<h3>Methods of the node type object selected above:</h3>
+		<ul class="nodeTypeMethods">
+	    	<li>
+	    		<input type="button" value="getAllChildNodeDefinitions();" onclick="loadChildNodeDefs();"/>
+				<span class="doc">That method returns the <strong>child node definitions</strong> of the node type and those <strong>of all inherited node types</strong>.<br/>Definitions with the same name are not overwritten but aggregated. If they are equal they are only listed once.</span>
+			</li>
+			<li>
+				<input type="button" value="getAllPropertyDefinitions();" onclick="loadPropertyDefs();"/>
+				<span class="doc">That method returns the <strong>property definitions</strong> of the node type and those <strong>of all inherited node types</strong>.<br/>Definitions with the same name are not overwritten but aggregated. If they are equal they are only listed once.<br/></span>
+			</li>
+			<li><input type="button" value="canAddChildNode" onclick="canAddChildNode();"/>
+					(<input type="text" value="nodeName" id="nodeName" class="parameter"/>,
+					<span style="display:inline-block" class="parameter">ntManager.getNodeType(<input type="select" value="nodeTypeToAdd" id="nodeTypeToAdd" class="parameter"/>)</span>);
+				<span class="doc"><br>That method returns `true` if a node with the specified node name and node type can be added as a child node of the current node type. The residual definitions and subtypes are considered.<br/>The <strong>first parameter is the string</strong> of the node name and the <strong>second parameter is a node type object</strong> (not a string).</span>
+			</li>
+			<li><input type="button" value="canAddProperty" onclick="canAddProperty();"/>
+					(<input type="text" value="propertyName" id="propertyName" class="parameter"/>, <input type="text" value="propertyType" id="propertyType" class="parameter"/>);
+				<span class="doc"><br>That method returns `true` if a property with the specified name and type can be to the current node type. The residual definitions and undefined types are considered.<br/>The <strong>first parameter is the string</strong> of the property name and the <strong>second parameter is the property type</strong> (case insensitive).</span>
+			</li>
+			<li>
+				<input type="button" value="getApplicableCnTypesPerCnDef()" onclick="loadApplicableChildNodeTypes();"/>
+					(<input type="checkbox" value="includeMixins" id="includeMixins" class="parameter"/> includeMixins);
+				<span class="doc"><br>Returns all node types that can be used for child nodes of this node type and its super types.<br/>If a child node definition specifies multiple required primary types, only node types that are subtypes of all of them are applicable.</br>The keys on the first level are the names of the child node definitions. Its values / the keys on the second level contain the node type names and its values in turn contain the node type definition itself. The <strong>parameter is a boolean</strong> and specifies if mixin types should be included in the result.</span>
+			</li>
+		</ul>
+		<div class="code">
+			<pre id="ntMethodResult">{}</pre>
+		</div>
+		<h2>Use</h2>
+		<ol>
+			<li>
+				<p>Include the JavaScript file to your page:</p>		
+				<div class="code">
+					<pre class="JavaScript">&lt;script type="text/javascript" src="/libs/jsnodetypes/js/jsnodetypes.js"&gt;&lt;/script&gt;</pre>
+				</div>
+			</li>
+			<li>
+				<p>Instantiate the NodeTypeManager:</p>
+				<div class="code">
+					<pre class="JavaScript">// this works if your WAR is deployed under the root context '/'
+var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager();
+					</pre>
+				</div>
+				<p>If your WAR is not deployed under the root context you have to specify it:</p>
+				<div class="code">
+					<pre class="JavaScript">var settings = {"contextPath": "/yourContextPath"};
+var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+					</pre>
+				</div>
+			</li>
+			<li>
+				<p>Use the NodeTypeManager instance like described above:</p>
+				<div class="code">
+					<pre class="JavaScript">var nodeTypesArray = ntManager.getNodeTypeNames();
+var firstNodeType = ntManager.getNodeType(nodeTypesArray[0]);
+var allChildNodeDefs = firstNodeType.getAllChildNodeDefinitions();
+var allPropertyDefs = firstNodeType.getAllPropertyDefinitions();
+var canAddChildNode = firstNodeType.canAddChildNode("myNodeName", nodeTypesArray[1]);
+					</pre>
+				</div>
+			</li>
+		</ol>
+		<h2>Version History</h2>
+		<ul>
+			<li><strong>0.1.0 (org.apache.sling.jcr.js.nodetypes)</strong>
+				<ul>
+					<li><strong>Non backwards compatible changes from SLING-5541:</strong>
+						<ul>
+							<li>New artifact name 'org.apache.sling.jcr.js.nodetypes'</li>
+							<li>Moved Java and JavaScript packages from org.apache.sling.commons and from de.sandroboehme to org.apache.sling.jcr.</li>
+						</ul>
+					</li>
+					<li>Other fixes for SLING-5541.
+						<ul>
+							<li>Moved out of contrib/commons.</li>
+							<li>Changed this documentation page to reflect begin hosted at Apache Sling.</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+			<li><strong>4.0.1</strong>
+				<ul>
+					<li><strong>Non backwards compatible change:</strong>Renamed getApplicableChildNodeTypes() to getApplicableCnTypesPerCnDef() to allow other similar methods and still have no overlapping meanings.</li>
+				</ul>
+			</li>
+			<li><strong>3.0.2</strong>
+				<ul>
+					<li>Fixed canAddChildNode() to check node name and node type combination and to return 'true' also for subtypes of a requiredPrimaryType.</li>
+					<li>Fixed canAddChildNode() to handle the protected property correctly</li>
+					<li>Added includeMixins parameter to getApplicableChildNodeTypes()</li>
+					<li>Added canAddProperty()</li>
+				</ul>
+			</li>
+			<li><strong>3.0.1</strong>
+				<ul>
+					<li>canAddChildNode(): checking if the provided node type is null</li>
+				</ul>
+			</li>
+			<li><strong>3.0</strong>
+				<ul>
+					<li>Rework of almost all of the runtime source code to remove the Google Gson dependency and use the sling.commons.json dependency instead as the latter it is already part of the Sling launchpad and Gson is not.</li>
+					<li>Added the new types of JCR 2.0: 'weakReference', 'uri', 'undefined' and 'decimal' as types for default values.</li>
+					<li><strong>Non backwards compatible changes:</strong> Changed the format of the default values:
+						<ul>
+							<li>The 'name' value can now be found with the 'name' key. Not with the 'string' key anymore.</li>
+							<li>The 'path' value can now be found with the 'path' key. Not with the 'string' key anymore.</li>
+							<li>The 'reference' value can now be found with the 'reference' key. Not with the 'string' key anymore.</li>
+							<li>The format of the 'date' value changed to provide more information from the Calendar object that is retrieved from the repository. Until this version the date value contained a JavaScript
+							object like this: '{"year": 2012, "month": 1, "dayOfMonth": 1, "hourOfDay": 0, "minute": 0, "second": 0}' and now it is a String containing an ISO8601 date. E.g. "2012-02-01T00:00:00.000+01:00". 
+							For the date ISO8601 conversion the dependency to 'jackrabbit-jcr-commons' has been added which is already part of the sling launchpad. 
+							</li>
+							<li>Empty 'declaredChildNodeDefinitions', 'declaredSupertypes' and 'declaredPropertyDefinitions' are not part of the JSON output anymore.</li>
+						</ul>
+					</li>
+				</ul>
+			</li>
+			<li><strong>2.0</strong>
+				<ul>
+					<li>getApplicableChildNodeTypes() added</li>
+					<li><strong>Non backwards compatible changes:</strong> getAllChildNodeDefinitions() and getAllPropertyDefinitions() changed to now return definitions with the same name as well. But only if they differ in any other way.</li>
+				</ul>
+			</li>
+			<li><strong>1.0</strong>
+				<ul>
+					<li>Initial version</li>
+				</ul>
+			</li>
+		</ul>
+		<h2>Architecture</h2>
+	 	<p>The JavaScript NodeTypeManager is developed in an object oriented way. It is instantiated in its own namespace and then loads <a href="${pageContext.request.contextPath}/libs/jsnodetypes/content/nodetypes.json">all available node types from the server in the JSON format</a>.</p> 
+	 	<p>This is handled by the <code>org.apache.sling.jcr.js.nodetypes.NodeTypesJSONServlet</code> at the server side. It</p> 
+	 	<ul>
+	 		<li>reads the node types from the repository</li>
+	 		<li>converts them to JSON</li>
+	 		<li>replaces the default binary values with URL's where they can later be downloaded from</li>
+	 		<li>removes the  <a href="${pageContext.request.contextPath}/libs/jsnodetypes/js/defaultNT/defaultNT.json">default values</a> to have smaller node type objects</li>
+	 		<li>and returns the result back to the JavaScript client.</li>
+	 	</ul>
+	 	<p>When <code>ntManager.getNodeType(nodeTypeName)</code> is called at the client side, the defaults are added again and 
+	 	the methods are added to the JSON object / JavaScript object literal and are finally returned.
+	 	</p>
+	 	<p>The internal 'processNodeTypeGraph()' method in jsnodetype.js is the basis for the other methods as it collects the needed data.</p>
+		<h2>Tests</h2>
+		<p>All JavaScript tests and Java tests are run in the Maven test phase as usual.
+		<h3>JavaScript</h3>
+		<p>The JavaScript tests are implemented in <code>src/test/javascript/NodeTypesSpec.js</code> using <a href="http://pivotal.github.com/jasmine/">Jasmine</a>. When you call <code>mvn jasmine:bdd</code> you can edit the tests and refresh the browser at <code>http://localhost:8234</code> to rerun the tests. 
+		<h3>Java</h3>
+		<p>The Java tests can be found in <code>src/test/java/org/apache/sling/jcr/js/nodetypes</code>. They query the <code>org.apache.sling.jcr.js.nodetypes.NodeTypesJSONServlet</code> while mocking the <code>javax.jcr.nodetype.NodeTypeManager</code> using <a href="http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html">Mockito</a>.
+		The result is then compared to the expected values in the <code>src/test/resources/expectedNTJSON/*.json</code> files using <code>org.apache.sling.jcr.js.nodetypes.testJSONAssert</code>. This class is actually copied from 
+		<code>org.apache.sling.commons.json.test.JSONAssert</code>. If somebody knows a better way to reuse this class please open an bug and let me know.
+		</p>
+		<h2>Build</h2>
+		<p>Please read the instructions in the README.txt file for instructions on how to build the project.</p>
+		<h2>License</h2>
+		<p>This library is licensed under the terms of the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache 2 license</a>.</p>
+		<h2>Compatibility</h2>
+		<p>This library has out of the box support for: IE 8.0 standards mode, Firefox 20.0, Chrome 26.0, Opera 12.1 and Safari 5.1</p>
+		<h3>Support for older browser versions</h3>
+		<p>If you would like to support older browser versions you can download the <a href="https://raw.github.com/douglascrockford/JSON-js/master/json2.js">json2.js script</a> and include it like that:</p>
+		<div class="code">
+			<pre class="JavaScript">&lt;script type="text/javascript" src="/path/to/json2.js"&gt;&lt;/script&gt;</pre>
+		</div>
+	</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/SLING-INF/libs/jsnodetypes/js/defaultNT/defaultNT.json b/src/main/resources/SLING-INF/libs/jsnodetypes/js/defaultNT/defaultNT.json
new file mode 100644
index 0000000..2e05a54
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/jsnodetypes/js/defaultNT/defaultNT.json
@@ -0,0 +1,32 @@
+{
+    "mixin": false,
+    "orderableChildNodes": false,
+    "declaredSupertypes": [
+      "nt:base"
+    ],
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": null,
+        "valueConstraints": null,
+        "requiredType": "String",
+        "multiple": false,
+        "autoCreated": false,
+        "mandatory": false,
+        "protected": false,
+        "onParentVersion": "COPY"
+      }
+    ],
+    "declaredChildNodeDefinitions": [
+      {
+        "allowsSameNameSiblings": false,
+        "defaultPrimaryType": null,
+        "requiredPrimaryTypes": [
+          "nt:base"
+        ],
+        "autoCreated": false,
+        "mandatory": false,
+        "protected": false,
+        "onParentVersion": "COPY"
+      }
+    ]
+}
diff --git a/src/main/resources/SLING-INF/libs/jsnodetypes/js/jsnodetypes.js b/src/main/resources/SLING-INF/libs/jsnodetypes/js/jsnodetypes.js
new file mode 100644
index 0000000..a4ffba9
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/jsnodetypes/js/jsnodetypes.js
@@ -0,0 +1,505 @@
+/*
+ * 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.
+ */
+
+// creating the namespace
+var org = org || {};
+org.apache = org.apache || {};
+org.apache.sling = org.apache.sling || {};
+org.apache.sling.jcr = org.apache.sling.jcr || {};
+org.apache.sling.jcr.js = org.apache.sling.jcr.js || {};
+org.apache.sling.jcr.js.nodetypes = org.apache.sling.jcr.js.nodetypes || {};
+
+/*
+ JSNodeTypes - The JavaScript Node Types library for Apache Sling
+
+ The documentation of the library can be found at:
+ http://www.jcrbrowser.org/sling/libs/jsnodetypes/content/documentation.html
+ 
+*/
+
+//defining the module
+org.apache.sling.jcr.js.nodetypes.NodeTypeManager = (function() {
+
+	function NodeTypeManager(settingsParameter){
+		// copies the setting parameters to the object scope and configures the defaults
+		
+		var noSettingsProvided = typeof settingsParameter === 'undefined' || settingsParameter == null;
+		var contextPath = (noSettingsProvided || typeof settingsParameter.contextPath === 'undefined') ? '' : settingsParameter.contextPath;
+		var defaultNTJsonURL = (noSettingsProvided || typeof settingsParameter.defaultNTJsonURL === 'undefined') ? contextPath+'/libs/jsnodetypes/js/defaultNT/defaultNT.json' : settingsParameter.defaultNTJsonURL;
+		this.defaultNTJson = getJson(defaultNTJsonURL);
+		this.nodeTypesJson = (noSettingsProvided || typeof settingsParameter.nodeTypesJson === 'undefined') ? getJson(contextPath+'/libs/jsnodetypes/content/nodetypes.json') : settingsParameter.nodeTypesJson;
+		initializeNodeTypes(this);
+	};
+	
+	function getJson(url){
+		var result;
+		var xhr = null;
+	    if (window.XMLHttpRequest) {
+	    	xhr = new XMLHttpRequest();
+	    } else if (window.ActiveXObject) { // Older IE.
+	    	xhr = new ActiveXObject("MSXML2.XMLHTTP.3.0");
+	    }
+		xhr.open("GET", url, false/*not async*/);
+		if (typeof xhr.overrideMimeType != "undefined"){
+			xhr.overrideMimeType("application/json");
+		}
+		xhr.onload = function (e) {
+		  if (xhr.readyState === 4) {
+		    if (xhr.status === 200) {
+		    	result = JSON.parse(xhr.responseText);
+		    } else {
+		    	console.error(xhr.statusText);
+		    }
+		  }
+		};
+		xhr.onerror = function (e) {
+		  console.error(xhr.statusText);
+		};
+		xhr.send(null);
+		return result;
+	}
+	
+	/* adding an indexOf function if it's not available */
+	if (!Array.prototype.indexOf) {
+	    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
+	        "use strict";
+	        if (this == null) {
+	            throw new TypeError();
+	        }
+	        var t = Object(this);
+	        var len = t.length >>> 0;
+	        if (len === 0) {
+	            return -1;
+	        }
+	        var n = 0;
+	        if (arguments.length > 1) {
+	            n = Number(arguments[1]);
+	            if (n != n) { // shortcut for verifying if it's NaN
+	                n = 0;
+	            } else if (n != 0 && n != Infinity && n != -Infinity) {
+	                n = (n > 0 || -1) * Math.floor(Math.abs(n));
+	            }
+	        }
+	        if (n >= len) {
+	            return -1;
+	        }
+	        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
+	        for (; k < len; k++) {
+	            if (k in t && t[k] === searchElement) {
+	                return k;
+	            }
+	        }
+	        return -1;
+	    }
+	}
+	
+	/*
+	 * Adds Object.keys if its not available.
+	 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
+	 */
+	if (!Object.keys) {
+		 Object.keys = (function() {
+			 'use strict';
+			 var hasOwnProperty = Object.prototype.hasOwnProperty,
+			    hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
+			    dontEnums = [
+			      'toString',
+			      'toLocaleString',
+			      'valueOf',
+			      'hasOwnProperty',
+			      'isPrototypeOf',
+			      'propertyIsEnumerable',
+			      'constructor'
+			    ],
+			    dontEnumsLength = dontEnums.length;
+
+			return function(obj) {
+			  if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
+			    throw new TypeError('Object.keys called on non-object');
+			  }
+
+			  var result = [], prop, i;
+
+			  for (prop in obj) {
+			    if (hasOwnProperty.call(obj, prop)) {
+			      result.push(prop);
+			    }
+			  }
+
+			  if (hasDontEnumBug) {
+			    for (i = 0; i < dontEnumsLength; i++) {
+			      if (hasOwnProperty.call(obj, dontEnums[i])) {
+			        result.push(dontEnums[i]);
+			      }
+			    }
+			  }
+			  return result;
+			};
+		}()); 
+	}
+
+	/*
+	 * This function walks recursively through all parent node types and calls the processing function with the current node type
+	 *  
+	 * currentNodeType - the node type to retrieve the property defs from in this call 
+	 * processingFunction - the function to call on every node type
+	 * processedNodeTypes - is used to avoid cycles by checking if a node type has been processed already
+	 * iterationProperty - the property of the nodeType that should be used for iteration e.g. 'declaredSupertypes'
+	 */
+	function processNodeTypeGraph (currentNodeType, iterationProperty, processingFunction, processedNodeTypes){
+		if (currentNodeType == null || iterationProperty == null || iterationProperty==="" || processingFunction == null ) return;
+		var initialCall = typeof processedNodeTypes === 'undefined';
+		if (initialCall){
+			processedNodeTypes = [];
+		}
+		
+		processingFunction(currentNodeType);
+
+		processedNodeTypes.push(currentNodeType.name);
+		
+		for (var supertypeIndex in currentNodeType[iterationProperty]) {
+			newNodeTypeName = currentNodeType[iterationProperty][supertypeIndex];
+			
+			newNodeType = this.getNodeType(newNodeTypeName);
+			
+			/* 
+			 * skip the processing of node types that have already been processed
+			 */
+			var notProcessedYet = processedNodeTypes.indexOf(newNodeTypeName) < 0;
+			if (notProcessedYet){
+				processNodeTypeGraph.call(this, newNodeType, iterationProperty, processingFunction, processedNodeTypes);
+			}
+		}
+	};
+	
+	/*
+	 * Sets the value of all properties of defaultNT.json to the corresponding undefined properties of the specified node type.
+	 * E.g. if nt.declaredChildNodeDefinitions[2].allowsSameNameSiblings is undefined it is set to testNodeType.declaredChildNodeDefinitions[0].allowsSameNameSiblings
+	 */
+	function setDefaults(nt){
+
+		if(typeof nt["declaredSupertypes"] === "undefined" && "nt:base" != nt.name){
+			nt["declaredSupertypes"] = this.defaultNTJson["declaredSupertypes"]; 
+		}
+		
+		// node type defaults
+		for(var propName in this.defaultNTJson){
+			if (propName != "declaredPropertyDefinitions" && propName != "declaredChildNodeDefinitions"){
+				setDefaultNTProps.call(this, propName);
+			}
+		}
+		
+		// property definition defaults
+		for(var propName in this.defaultNTJson.declaredPropertyDefinitions[0]){
+			/*
+			 * Sets the default values from all this.defaultNTJson.declaredPropertyDefinitions[0] properties
+			 * too all properties of all declaredPropertyDefinitions of 'nt'.
+			 */
+			for (var propDefIndex in nt.declaredPropertyDefinitions){
+				setDefaultPropDefProps.call(this, propDefIndex, propName);
+			}
+		}
+		// child node definition defaults	
+		for(var propName in this.defaultNTJson.declaredChildNodeDefinitions[0]){
+			/*
+			 * Sets the default values from all this.defaultNTJson.declaredChildNodeDefinitions[0] properties
+			 * too all properties of all declaredChildNodeDefinitions of 'nt'.
+			 */
+			for (var childNodeDefIndex in nt.declaredChildNodeDefinitions){
+				setDefaultChildNodeDefProps.call(this, childNodeDefIndex, propName);
+			}
+		}
+		
+		function setDefaultNTProps(propName){
+			if(typeof nt[propName] === "undefined") nt[propName] = this.defaultNTJson[propName]; 
+		}
+		
+		function setDefaultPropDefProps(index, propName){
+			if(typeof nt.declaredPropertyDefinitions[index][propName] === "undefined") nt.declaredPropertyDefinitions[index][propName] = this.defaultNTJson.declaredPropertyDefinitions[0][propName]; 
+		}
+		
+		function setDefaultChildNodeDefProps(index, propName){
+			if(typeof nt.declaredChildNodeDefinitions[index][propName] === "undefined") nt.declaredChildNodeDefinitions[index][propName] = this.defaultNTJson.declaredChildNodeDefinitions[0][propName]; 
+		}
+		
+	};
+	
+	NodeTypeManager.prototype.internalGetDefaultNodeType = function() {
+		return this.defaultNTJson;
+	};
+	
+	NodeTypeManager.prototype.getNodeTypeNames = function(name) {
+		var ntNames = [];
+		for (var ntJson in this.nodeTypesJson) {
+			ntNames.push(ntJson);
+		}
+		return ntNames;
+	}
+		
+	NodeTypeManager.prototype.getNodeType = function(name) {
+		return this.nodeTypesJson[name];
+	}
+	
+	function initializeNodeTypes(that){
+		try {
+			for (var ntIndex in Object.keys(that.nodeTypesJson)){
+				var nodeTypeName = Object.keys(that.nodeTypesJson)[ntIndex];
+				
+				if (typeof that.nodeTypesJson[nodeTypeName] != "undefined") {
+					that.nodeTypesJson[nodeTypeName].name = nodeTypeName;
+		
+					/*
+					 * Returns the child node definitions of the node type and those of all inherited node types.
+					 * Definitions with the same child node name are returned if they differ in any other attribute.
+					 */
+					that.nodeTypesJson[nodeTypeName].getAllChildNodeDefinitions = function(){
+						var allCollectedChildNodeDefs = [];
+						var allCollectedChildNodeDefHashes = [];
+						processNodeTypeGraph.call(that, this, 'declaredSupertypes', function(currentNodeType){
+							if (currentNodeType.declaredChildNodeDefinitions == null) return;
+							for (var childNodeDefIndex in currentNodeType.declaredChildNodeDefinitions) {
+								var childNodeDef = currentNodeType.declaredChildNodeDefinitions[childNodeDefIndex];
+								var childNodeDefName = childNodeDef.name;
+								var hashCode = childNodeDef.hashCode();
+								// in case the child has the same child node definition as its parent (supertype)
+								var processed = allCollectedChildNodeDefHashes.indexOf(hashCode) >= 0;
+								if (!processed){
+									allCollectedChildNodeDefHashes.push(hashCode);
+									allCollectedChildNodeDefs.push(childNodeDef);
+								}
+							}
+						}); 
+						return allCollectedChildNodeDefs;
+					};
+					/*
+					 * Returns the property definitions of the node type and those of all inherited node types.
+					 * Definitions with the same property name are returned if they differ in any other attribute. 
+					 */
+					that.nodeTypesJson[nodeTypeName].getAllPropertyDefinitions = function(){
+						var allCollectedPropertyDefs = [];
+						var allCollectedPropertyDefHashes = [];
+						processNodeTypeGraph.call(that, this, 'declaredSupertypes', function(currentNodeType){
+							if (currentNodeType.declaredPropertyDefinitions == null) return;
+							for (var propertyDefIndex in currentNodeType.declaredPropertyDefinitions) {
+								var propertyDef = currentNodeType.declaredPropertyDefinitions[propertyDefIndex];
+								var propertyDefName = propertyDef.name;
+								var hashCode = propertyDef.hashCode();
+								// in case the child has the same property definition as its parent (supertype)
+								var processed = allCollectedPropertyDefHashes.indexOf(hashCode) >= 0;
+								if (!processed){
+									allCollectedPropertyDefHashes.push(hashCode);
+									allCollectedPropertyDefs.push(propertyDef);
+								}
+							}
+						});
+						return allCollectedPropertyDefs;
+					};
+		
+					/*
+					 * Returns `true` if a node with the specified node name and node type can be added as a child node of the current node type. 
+					 * 
+					 * The first parameter is the string of the node name and 
+					 * the second parameter is a node type object (not a string).
+					 */
+					that.nodeTypesJson[nodeTypeName].canAddChildNode = function(nodeName, nodeTypeToAdd){
+						if (nodeName==null || nodeTypeToAdd==null) return false;
+						var allChildNodeDefNames = [];
+						processApplicableChildNodeTypes(that, this, function(cnDef, nodeTypeName){
+							if (cnDef.name === nodeName) {
+								allChildNodeDefNames.push(nodeName);
+							}
+						});
+						var canAddChildNode = false;
+						processApplicableChildNodeTypes(that, this, function(cnDef, nodeTypeName){
+							var noNonRisidualWithThatName = allChildNodeDefNames.indexOf(nodeName)<0;
+							var nodeNameMatches = (nodeName === cnDef.name) || ("*" === cnDef.name && noNonRisidualWithThatName); 
+							var canAddToCurrentCnDef = !cnDef.protected && nodeNameMatches && nodeTypeToAdd.name === nodeTypeName;
+							canAddChildNode = canAddChildNode || canAddToCurrentCnDef; 
+						});
+						return canAddChildNode;
+					}
+		
+					/*
+					 * Returns `true` if a property with the specified name and type can be to the current node type. 
+					 * 
+					 * The first parameter is the string of the property name and 
+					 * the second parameter is the property type (case insensitive).
+					 */
+					that.nodeTypesJson[nodeTypeName].canAddProperty = function(propertyName, propertyType){
+						if (propertyName == null || propertyType == null) return false;
+						var allPropertyDefNames = [];
+						processNodeTypeGraph.call(that, this, 'declaredSupertypes', function(currentNodeType){
+							if (currentNodeType.declaredPropertyDefinitions == null) return;
+						    for (var propDefIndex in currentNodeType.declaredPropertyDefinitions) {
+								var propDef = currentNodeType.declaredPropertyDefinitions[propDefIndex];
+								allPropertyDefNames.push(propDef.name);
+						    }
+						}); 
+						var canAddProperty = false;
+						processNodeTypeGraph.call(that, this, 'declaredSupertypes', function(currentNodeType){
+							if (currentNodeType.declaredPropertyDefinitions == null) return;
+						    for (var propDefIndex=0; canAddProperty === false && propDefIndex < currentNodeType.declaredPropertyDefinitions.length; propDefIndex++) {
+								var propDef = currentNodeType.declaredPropertyDefinitions[propDefIndex];
+								var noNonRisidualWithThatName = allPropertyDefNames.indexOf(propertyName)<0;
+								var namesMatch = propDef.name === propertyName || ("*" === propDef.name && noNonRisidualWithThatName);
+								var typesMatch = propDef.requiredType.toLowerCase() === propertyType.toLowerCase() || "undefined" === propDef.requiredType;
+								var isNotProtected = !propDef.protected;
+								canAddProperty = namesMatch && typesMatch && isNotProtected; 
+						    }
+						}); 
+						return canAddProperty;
+					};
+					
+					/*
+					 * Returns all node types that can be used for child nodes of this node type and its super types.
+					 * If a child node definition specifies multiple required primary types an applicable node type has
+					 * to be a subtype of all of them. 
+					 * The parameter is a boolean that specifies if mixins should be included or not. If no parameter is passed 'true' is assumed and mixins are
+					 * returned as well.
+					 */
+					that.nodeTypesJson[nodeTypeName].getApplicableCnTypesPerCnDef = function(includeMixins){
+						var allApplChildNodeTypes = {};
+						processApplicableChildNodeTypes(that, this, function(cnDef, nodeTypeName){
+							var nodeType = that.getNodeType(nodeTypeName);
+							if (typeof allApplChildNodeTypes[cnDef.name] === "undefined") {
+								allApplChildNodeTypes[cnDef.name] = {};
+							}
+							var includeAlsoMixins = typeof includeMixins === "undefined" || includeMixins;
+							if (nodeType.mixin === true && includeAlsoMixins || !nodeType.mixin){
+								allApplChildNodeTypes[cnDef.name][nodeTypeName] = that.getNodeType(nodeTypeName);
+							}
+						});
+						return allApplChildNodeTypes;
+					}
+				};
+				
+				setDefaults.call(that, that.nodeTypesJson[nodeTypeName]);
+				initializeChildNodeDefs.call(that);
+				initializePropertyDefs.call(that);
+			}
+		} catch (e){
+			console.log("Error, the node types JSON is not an object"); 
+		};
+		function itemHashCode(item){
+			var hash = "";
+			hash += item.name;
+			hash += item.autoCreated;
+			hash += item.mandatory;
+			hash += item.protected;
+			hash += item.onParentVersion;
+			return hash;
+		}
+
+		function initializeChildNodeDefs(){
+			for (var childNodeDefIndex in that.nodeTypesJson[nodeTypeName].declaredChildNodeDefinitions) {
+				var childNodeDef = that.nodeTypesJson[nodeTypeName].declaredChildNodeDefinitions[childNodeDefIndex];
+				
+				childNodeDef.hashCode = function (){
+					var hashCode = itemHashCode(this);
+					hashCode += this.allowsSameNameSiblings;
+					hashCode += this.defaultPrimaryType;
+					for (var reqPtIndex in this.requiredPrimaryTypes) {
+						hashCode += this.requiredPrimaryTypes[reqPtIndex];
+					}
+					return hashCode;
+				}
+			}
+		}
+
+		function initializePropertyDefs(){
+			for (var propertyIndex in that.nodeTypesJson[nodeTypeName].declaredPropertyDefinitions) {
+				var propertyDef = that.nodeTypesJson[nodeTypeName	].declaredPropertyDefinitions[propertyIndex];
+				
+				propertyDef.hashCode = function (){
+					var hashCode = itemHashCode(this);
+					for (var defaultValueIndex in this.defaultValues) {
+						hashCode += this.defaultValues[defaultValueIndex];
+					}
+					for (var valueConstraintIndex in this.valueConstraints) {
+						hashCode += this.valueConstraints[valueConstraintIndex];
+					}
+					hashCode += this.requiredType;
+					hashCode += this.multiple;
+					return hashCode;
+				}
+			}
+		}
+		
+		/*
+		 * Navigates to every node types' supertype and sets the subtype property there.
+		 */
+		function addSubtypeRelation(nodeTypesJson){
+			for (var nodeTypeName in nodeTypesJson) {
+				nodeTypeJson = nodeTypesJson[nodeTypeName];
+				for (var supertypeIndex in nodeTypeJson.declaredSupertypes) {
+					var supertypeName = nodeTypeJson.declaredSupertypes[supertypeIndex];
+					var supertype = this.getNodeType(supertypeName);
+					if (typeof supertype.subtypes === "undefined") {
+						supertype.subtypes = [];
+					}
+					supertype.subtypes.push(nodeTypeName);
+				}
+			}
+			return nodeTypesJson;
+		}
+		addSubtypeRelation.call(that, that.nodeTypesJson);
+	}
+
+	
+	function processApplicableChildNodeTypes(ntManager, nodeType, functionToCall){
+		var cnDefs = nodeType.getAllChildNodeDefinitions();
+		for (var cnDefIndex in cnDefs) {
+			var cnDef = cnDefs[cnDefIndex];
+			var nodeTypesPerChildNodeDef = {};
+			var reqChildNodeTypes = cnDef.requiredPrimaryTypes;
+			for (var reqChildNodeTypeIndex in reqChildNodeTypes) {
+				var childNodeTypeName = reqChildNodeTypes[reqChildNodeTypeIndex];
+				var childNodeType = ntManager.getNodeType(childNodeTypeName);
+				/* 
+				 * calls the function for every subtype of 'childNodeType' but skips
+				 * node types that have already been processed (e.g. because of cycles)
+				 */
+				processNodeTypeGraph.call(ntManager, childNodeType, 'subtypes', function(currentNodeType){
+					if (currentNodeType != null) {
+						// if 'true' the type has not yet been found in _one_of_the_ required primary type's subtype tree
+						// of the child node definition
+						var cnDefWithTypeNotYetProcessed = typeof nodeTypesPerChildNodeDef[currentNodeType.name] === "undefined";
+						// This increments the occurency count of a node type in the subtype hierarchy of a required primary type. 
+						nodeTypesPerChildNodeDef[currentNodeType.name] = cnDefWithTypeNotYetProcessed ? 1 : nodeTypesPerChildNodeDef[currentNodeType.name]+1; 
+					}
+				}); 
+				
+			}
+			for (var keyIndex in Object.keys(nodeTypesPerChildNodeDef)){
+				var nodeTypeName = Object.keys(nodeTypesPerChildNodeDef)[keyIndex];
+				/* 
+				 * If the type has been found in all iterations of the required primary types it means it is a subtype
+				 * of all of them and can be used for the child node definition.
+				 */
+				var nodeTypeCountInThisChildNodeDef = nodeTypesPerChildNodeDef[nodeTypeName];
+				var subtypeOfAllReqPrimaryTypes = nodeTypeCountInThisChildNodeDef === cnDef.requiredPrimaryTypes.length;
+				if (subtypeOfAllReqPrimaryTypes){
+					functionToCall(cnDef, nodeTypeName);
+				}
+			}
+		}
+	}
+	
+	return NodeTypeManager;
+}());
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/ChildNodeDefGenerationTest.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/ChildNodeDefGenerationTest.java
new file mode 100644
index 0000000..ab0d20b
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/ChildNodeDefGenerationTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.servlet.ServletException;
+
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.jcr.js.nodetypes.mock.MockNodeTypeGenerator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests if the servlet generates the combinations child node definitions in the correct JSON format. 
+ */
+public class ChildNodeDefGenerationTest extends MockNodeTypeGenerator{
+
+	@Before
+	public void setUp() throws RepositoryException, IOException{
+		super.setUp();
+	}
+	
+	@Test
+	public void testOneSimpleChildNodeDefinition() throws ServletException, IOException, JSONException{
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithChildNodeDefs");
+
+		NodeDefinition[] childNodeDefs = {getSimpleChildNodeDef("childNodeDef1")};
+		when(ntWithChildNodeDefs.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testOneSimpleChildNodeDefinition");
+	}
+	
+	@Test
+	public void testSimpleChildNodeDefinitions() throws ServletException, IOException, JSONException{
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithChildNodeDefs");
+
+		NodeDefinition childNodeDef1 = getSimpleChildNodeDef("childNodeDef1");
+		NodeDefinition childNodeDef2 = getSimpleChildNodeDef("childNodeDef2");
+		
+		NodeDefinition[] childNodeDefs = {childNodeDef1, childNodeDef2};
+		when(ntWithChildNodeDefs.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testSimpleChildNodeDefinitions");
+	}
+	
+	@Test
+	public void testCompleteChildNodeDefinitions() throws ServletException, IOException, JSONException{
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithChildNodeDefs");
+
+		NodeDefinition childNodeDef1 = getCompleteChildNodeDef("childNodeDef1");
+		NodeDefinition childNodeDef2 = getCompleteChildNodeDef("childNodeDef2");
+		
+		NodeDefinition[] childNodeDefs = {childNodeDef1, childNodeDef2};
+		when(ntWithChildNodeDefs.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testCompleteChildNodeDefinitions");
+	}
+	
+	@Test
+	public void testResidualChildNodeDefinitions() throws JSONException, ServletException, IOException{
+		NodeType ntWithChildNOdeDefs = getSimpleNodeTypeWithName("ntWithChildNodeDefs");
+
+		NodeDefinition childNodeDef1 = getSimpleChildNodeDef("*");
+		NodeDefinition childNodeDef2 = getSimpleChildNodeDef("*");
+		NodeDefinition childNodeDef3 = getSimpleChildNodeDef("childNodeDef");
+		
+		NodeDefinition[] childNodeDefs = {childNodeDef1, childNodeDef2, childNodeDef3};
+		when(ntWithChildNOdeDefs.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNOdeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testResidualChildNodeDefinitions");
+	}
+
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/DefaultNodeTypeTest.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/DefaultNodeTypeTest.java
new file mode 100644
index 0000000..1c7fbb1
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/DefaultNodeTypeTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.servlet.ServletException;
+
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.jcr.js.nodetypes.mock.MockNodeTypeGenerator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests if the JSON is generated with the default values omitted.
+ */
+public class DefaultNodeTypeTest extends MockNodeTypeGenerator{
+	
+	@Before
+	public void setUp() throws RepositoryException, IOException{
+		super.setUp();
+	}
+
+	private String getDefaultNTJSON() throws IOException {
+		URL fileUri = MockNodeTypeGenerator.class.getResource("/SLING-INF/libs/jsnodetypes/js/defaultNT/defaultNT.json");
+		BufferedReader in = new BufferedReader(new FileReader(fileUri.getFile()));
+		String currentLine = null;
+		StringBuilder fileContent = new StringBuilder();
+		while ((currentLine = in.readLine()) != null) {
+			fileContent.append(currentLine);
+		}
+		return fileContent.toString();
+	}
+
+	/**
+	 * Simulates a node type in the repository that has only default values and checks if they are omitted in the generated
+	 * JSON file. 
+	 */
+	@Test
+	public void testIfDefaultsAreOmittedWithServlet() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType");
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+
+		NodeType ntBase = mock(NodeType.class);
+		when(ntBase.getName()).thenReturn("nt:base");
+
+		NodeDefinition childNodeDef1 = mock(NodeDefinition.class);
+		NodeType[] reqPrimaryTypes = { ntBase };
+		when(childNodeDef1.getRequiredPrimaryTypes()).thenReturn(reqPrimaryTypes);
+		when(childNodeDef1.getName()).thenReturn("childNodeDef");
+		
+		NodeDefinition[] childNodeDefs = {childNodeDef1};
+		when(nt1.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		String propertyName = "stringPropertyDef";
+		PropertyDefinition propertyDef = mock(PropertyDefinition.class);
+		when(propertyDef.getRequiredType()).thenReturn(PropertyType.STRING);
+		when(propertyDef.getName()).thenReturn(propertyName);
+		
+		when(nt1.getDeclaredPropertyDefinitions()).thenReturn(new PropertyDefinition[]{propertyDef});
+
+		assertEqualsWithServletResult("testIfDefaultsAreOmittedWithServlet");
+	}
+	
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/GenerationConstants.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/GenerationConstants.java
new file mode 100644
index 0000000..1f8e7d9
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/GenerationConstants.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+/**
+ * Used by generators to generate the right content and by the test cases to compare if the right content has been returned.
+ *
+ */
+public class GenerationConstants {
+	
+	public static final String CONSTRAINT_STRING = ".*";
+	private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");		
+	private static Calendar maxDate = Calendar.getInstance();
+	static {
+		maxDate.clear();
+		maxDate.set(2012, 03, 01);
+	}
+	public static final String CONSTRAINT_DATE = df.format(maxDate.getTime());
+	public static final String CONSTRAINT_DOUBLE = "[,5]";
+	public static final String CONSTRAINT_LONG = "[,55]";
+	public static final String CONSTRAINT_BINARY = "[,1024]";
+	public static final String CONSTRAINT_BOOLEAN = "true";
+	public static final String CONSTRAINT_NAME = "myapp:myName";
+	public static final String CONSTRAINT_PATH = "/myapp:myName/myapp:myChildNode/*";
+	public static final String CONSTRAINT_REFERENCE = "nt:unstructured";
+	
+	
+	public static final Calendar DEFAULT_VALUE_CALENDAR = Calendar.getInstance();
+	static {
+		DEFAULT_VALUE_CALENDAR.clear();
+		DEFAULT_VALUE_CALENDAR.set(2012, 01, 01);	
+	}
+	public static final String DEFAULT_VALUE_BINARY = "/ntName/stringPropertyDef/Binary/true/true/true/true/VERSION/0.default_binary_value.bin";
+	public static final String DEFAULT_VALUE_STRING = "Default-String";
+	public static final String DEFAULT_VALUE_BINARY_0 = "A content";
+	public static final String DEFAULT_VALUE_BINARY_1 = "An other content";
+	public static final Double DEFAULT_VALUE_DOUBLE = new Double(2.2);
+	public static final Long DEFAULT_VALUE_LONG = new Long(2);
+	public static final Boolean DEFAULT_VALUE_BOOLEAN = Boolean.TRUE;
+	public static final String DEFAULT_VALUE_NAME = "myapp:myName";
+	public static final String DEFAULT_VALUE_PATH = "/myapp:myName/myapp:myChildNode/aSubChildNode";
+	public static final String DEFAULT_VALUE_REFERENCE = "nt:unstructured";
+
+	public static final String NODETYPE_REQ_PRIMARY_TYPE_NAME1 = "requiredPrimaryType1";
+	public static final String NODETYPE_REQ_PRIMARY_TYPE_NAME2 = "requiredPrimaryType2";
+
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/NodeTypeGenerationTest.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/NodeTypeGenerationTest.java
new file mode 100644
index 0000000..a7b14bb
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/NodeTypeGenerationTest.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+import javax.servlet.ServletException;
+
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.jcr.js.nodetypes.mock.MockNodeTypeGenerator;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests if the servlet generates the combinations node type definitions in the correct JSON format.
+ */
+public class NodeTypeGenerationTest extends MockNodeTypeGenerator{
+	
+	@Before
+	public void setUp() throws RepositoryException, IOException{
+		super.setUp();
+	}
+
+	@Test
+	public void testSupertypeList() throws JSONException, ServletException, IOException{
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType");
+		NodeType[] superTypes = {getSimpleNodeTypeWithName("superType1"), getSimpleNodeTypeWithName("superType2"), getSimpleNodeTypeWithName("superType3")};
+		when(nt1.getDeclaredSupertypes()).thenReturn(superTypes);
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testSupertypeList");
+	}
+
+	@Test
+	public void testOneSimpleNodeType() throws ServletException, IOException, JSONException {
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType");
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testOneSimpleNodeType");
+	}
+
+	@Test
+	public void testSimpleNodeTypes() throws ServletException, IOException, JSONException {
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType1");
+		NodeType nt2 = getSimpleNodeTypeWithName("testNodeType2");
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1, nt2);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testSimpleNodeTypes");
+	}
+
+	@Test
+	public void testNodeTypeWithEmptyName() throws ServletException, IOException, JSONException {
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType1");
+		NodeType nt2 = getSimpleNodeTypeWithName(null);
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1, nt2);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testNodeTypeWithEmptyName");
+	}
+
+	@Test
+	public void testCompleteNodeTypes() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		NodeType nt1 = getSimpleNodeTypeWithName("testNodeType");
+		NodeType[] superTypes = {getSimpleNodeTypeWithName("superType1"), getSimpleNodeTypeWithName("superType2"), getSimpleNodeTypeWithName("superType3")};
+		NodeType nt2 = getSimpleNodeTypeWithName(null);
+		when(nt1.getDeclaredSupertypes()).thenReturn(superTypes);
+		when(nodeTypeIterator.nextNodeType()).thenReturn(nt1, nt2);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE);
+
+
+		NodeDefinition childNodeDef1 = getCompleteChildNodeDef("childNodeDef1");
+		NodeDefinition childNodeDef2 = getCompleteChildNodeDef("childNodeDef2");
+		
+		NodeDefinition[] childNodeDefs = {childNodeDef1, childNodeDef2};
+		when(nt1.getDeclaredChildNodeDefinitions()).thenReturn(childNodeDefs);
+
+		String propertyName = "stringPropertyDef";
+		PropertyDefinition propertyDef = mock(PropertyDefinition.class);
+		when(propertyDef.getOnParentVersion()).thenReturn(OnParentVersionAction.VERSION);
+		when(propertyDef.getName()).thenReturn(propertyName);
+		when(propertyDef.getRequiredType()).thenReturn(PropertyType.STRING);
+		when(propertyDef.getValueConstraints()).thenReturn( new String[]{GenerationConstants.CONSTRAINT_STRING});
+		when(propertyDef.isMultiple()).thenReturn(Boolean.TRUE);
+		when(propertyDef.isProtected()).thenReturn(Boolean.TRUE);
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getType()).thenReturn(PropertyType.STRING);
+		when(defaultValue.getString()).thenReturn(GenerationConstants.DEFAULT_VALUE_STRING);
+		when(propertyDef.getDefaultValues()).thenReturn(new Value[]{defaultValue});
+		when(propertyDef.isAutoCreated()).thenReturn(Boolean.TRUE);
+		when(propertyDef.isMandatory()).thenReturn(Boolean.TRUE);
+		
+		when(nt1.getDeclaredPropertyDefinitions()).thenReturn(new PropertyDefinition[]{propertyDef});
+
+		assertEqualsWithServletResult("testCompleteNodeTypes");
+	}
+
+	public void testCompletePropertyDefinition(PropertyDefinition[] propertyDef) throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithPropertyDefs");
+
+		when(ntWithChildNodeDefs.getDeclaredPropertyDefinitions()).thenReturn(propertyDef);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testCompletePropertyDefinition");
+	}
+	
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/PropertyDefGenerationTest.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/PropertyDefGenerationTest.java
new file mode 100644
index 0000000..9bfa80f
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/PropertyDefGenerationTest.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes;
+
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_STRING;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_STRING;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.servlet.ServletException;
+
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.jcr.js.nodetypes.mock.MockNodeTypeGenerator;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Tests if the servlet generates the combinations property definitions in the correct JSON format.
+ */
+public class PropertyDefGenerationTest extends MockNodeTypeGenerator{
+
+	@Before
+	public void setUp() throws RepositoryException, IOException{
+		super.setUp();
+	}
+
+	@Test
+	public void testCompleteBinaryPropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "stringPropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteBinaryPropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteBinaryPropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteStringPropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "stringPropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteStringPropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteStringPropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteDatePropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "datePropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteDatePropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteDatePropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteDoublePropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "doublePropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteDoublePropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteDoublePropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteLongPropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "longPropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteLongPropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteLongPropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteBooleanPropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "booleanPropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteBooleanPropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteBooleanPropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteNamePropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "namePropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteNamePropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteNamePropertyDefinition");
+	}
+
+	@Test
+	public void testCompletePathPropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "pathPropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompletePathPropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompletePathPropertyDefinition");
+	}
+
+	@Test
+	public void testCompleteReferencePropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "referencePropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getCompleteReferencePropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testCompleteReferencePropertyDefinition");
+	}
+
+	public void testCompletePropertyDefinition(PropertyDefinition[] propertyDef, String filename) throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithPropertyDefs");
+
+		when(ntWithChildNodeDefs.getDeclaredPropertyDefinitions()).thenReturn(propertyDef);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult(filename);
+	}
+
+
+	@Test
+	public void testOneSimplePropertyDefinition() throws JSONException, ServletException, IOException, ValueFormatException, IllegalStateException, RepositoryException{
+		String propertyName = "simplePropertyDef";
+		PropertyDefinition[] propertyDef = {getPropertyGenerator().getSimplePropertyDef(propertyName)};
+		testCompletePropertyDefinition(propertyDef, "testOneSimplePropertyDefinition");
+	}
+
+	@Test
+	public void testTwoResidualPropertyDefinitions() throws ValueFormatException, IllegalStateException, RepositoryException, JSONException, ServletException, IOException{
+		//Is only be possible for multi valued property defs
+		PropertyDefinition[] residualPropertyDefs = {getPropertyGenerator().getCompleteStringPropertyDef("*"), getPropertyGenerator().getCompleteDatePropertyDef("*")};
+
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithPropertyDefs");
+
+		when(ntWithChildNodeDefs.getDeclaredPropertyDefinitions()).thenReturn(residualPropertyDefs);
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testTwoResidualPropertyDefinitions");
+	}
+
+	@Test
+	public void testMultipleDefaultValues() throws ValueFormatException, IllegalStateException, RepositoryException, JSONException, ServletException, IOException{
+		Value defaultValue1 = mock(Value.class);
+		when(defaultValue1.getString()).thenReturn(DEFAULT_VALUE_STRING);
+		Value defaultValue2 = mock(Value.class);
+		when(defaultValue2.getString()).thenReturn(DEFAULT_VALUE_STRING+"2");
+		PropertyDefinition propertyDef = getPropertyGenerator().getPropertyDef("stringProp", PropertyType.STRING, new String[]{CONSTRAINT_STRING}, new Value[] {defaultValue1, defaultValue2});
+
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithPropertyDefs");
+
+		when(ntWithChildNodeDefs.getDeclaredPropertyDefinitions()).thenReturn(new PropertyDefinition[]{propertyDef});
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult("testMultipleDefaultValues");
+	}
+
+	@Test
+	public void testMultipleConstraints() throws ValueFormatException, IllegalStateException, RepositoryException, JSONException, ServletException, IOException{
+		PropertyDefinition propertyDef = getPropertyGenerator().getPropertyDef("stringProp", PropertyType.STRING, new String[]{"banana", "apple"}, null);
+
+		NodeType ntWithChildNodeDefs = getSimpleNodeTypeWithName("ntWithPropertyDefs");
+
+		when(ntWithChildNodeDefs.getDeclaredPropertyDefinitions()).thenReturn(new PropertyDefinition[]{propertyDef});
+
+		when(nodeTypeIterator.nextNodeType()).thenReturn(ntWithChildNodeDefs);
+		when(nodeTypeIterator.hasNext()).thenReturn(Boolean.TRUE, Boolean.FALSE);
+		
+		assertEqualsWithServletResult( "testMultipleConstraints");
+	}
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueTest.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueTest.java
new file mode 100644
index 0000000..81d8943
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/downloaddefaultbinary/DownloadDefaultBinaryValueTest.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.ValueFormatException;
+import javax.jcr.Workspace;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.servlets.HttpConstants;
+import org.apache.sling.jcr.js.nodetypes.GenerationConstants;
+import org.apache.sling.jcr.js.nodetypes.downloaddefaultbinary.DownloadDefaultBinaryValueServlet;
+import org.apache.sling.jcr.js.nodetypes.mock.MockPropertyDefGenerator;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests the DownloadDefaultBinaryValueServlet
+ *
+ */
+public class DownloadDefaultBinaryValueTest {
+
+	// mock classes
+	private SlingHttpServletRequest request = null;
+	private SlingHttpServletResponse response = null;
+	private Resource resource = null;
+	private Node rootNode = null;
+	private Session session = null;
+	private Workspace workspace = null;
+	private NodeTypeManager ntManager = null;
+	private ByteArrayOutputStream outStream = null;
+	private ResourceResolver resourceResolver = null;
+	private MockPropertyDefGenerator propDefGenerator = null;
+
+	@Before
+	public void setUp() throws RepositoryException, IOException{
+		// create mocks
+		request = mock(SlingHttpServletRequest.class);
+		response = mock(SlingHttpServletResponse.class);
+		resourceResolver = mock(ResourceResolver.class);
+		resource = mock(Resource.class);
+		rootNode = mock(Node.class);
+		session = mock(Session.class);
+		workspace = mock(Workspace.class);
+		ntManager = mock(NodeTypeManager.class);
+		outStream = new ByteArrayOutputStream();
+		
+		// stubbing
+		when(request.getMethod()).thenReturn(HttpConstants.METHOD_GET);
+		when(request.getResourceResolver()).thenReturn(resourceResolver);
+		when(resourceResolver.getResource("/")).thenReturn(resource);
+		when(resource.adaptTo(Node.class)).thenReturn(rootNode);
+		when(rootNode.getSession()).thenReturn(session);
+		when(session.getWorkspace()).thenReturn(workspace);
+		when(workspace.getNodeTypeManager()).thenReturn(ntManager);
+		when(response.getWriter()).thenReturn(new PrintWriter(outStream, true));
+		propDefGenerator = new MockPropertyDefGenerator();
+	}
+
+	private void invokeServletWithDifferentPropertyDefs() throws NoSuchNodeTypeException, RepositoryException,
+			ValueFormatException, ServletException, IOException {
+		NodeType nodeType = mock(NodeType.class);
+		when(ntManager.getNodeType("ns:ntName")).thenReturn(nodeType);
+		PropertyDefinition[] propDefs = propDefGenerator.getDifferentPropertyDefinitions();
+		when(nodeType.getPropertyDefinitions()).thenReturn(propDefs);
+		DownloadDefaultBinaryValueServlet downloadServlet = new DownloadDefaultBinaryValueServlet();
+		downloadServlet.service(request, response);
+	}
+
+	private void invokeServletWithEqualPropertyDefs() throws NoSuchNodeTypeException, RepositoryException,
+			ValueFormatException, ServletException, IOException {
+		NodeType nodeType = mock(NodeType.class);
+		when(ntManager.getNodeType("ns:ntName")).thenReturn(nodeType);
+		PropertyDefinition[] propDefs = propDefGenerator.getEqualPropertyDefinitions();
+		when(nodeType.getPropertyDefinitions()).thenReturn(propDefs);
+		DownloadDefaultBinaryValueServlet downloadServlet = new DownloadDefaultBinaryValueServlet();
+		downloadServlet.service(request, response);
+	}
+	
+	@Test
+	public void testSuccessfulSingleMatchWithIndex() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/true/version/1.default_binary_value.bin");
+		invokeServletWithDifferentPropertyDefs();
+		verify(response, never()).sendError(anyInt());
+		Assert.assertEquals(GenerationConstants.DEFAULT_VALUE_BINARY_1, new String(outStream.toByteArray()));
+	}
+	
+	@Test
+	public void testSuccessfulSingleMatchWithoutIndex() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/true/version/default_binary_value.bin");
+		invokeServletWithDifferentPropertyDefs();
+		verify(response, never()).sendError(anyInt());
+		Assert.assertEquals(GenerationConstants.DEFAULT_VALUE_BINARY_0, new String(outStream.toByteArray()));
+	}
+	
+	@Test
+	public void testSuccessfulShortenedSingleMatchWithoutIndex() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/false/default_binary_value.bin");
+		testDifferentPropertyDefsWithExpectedBinary0();
+
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/false/default_binary_value.bin");
+		testDifferentPropertyDefsWithExpectedBinary0();
+
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/false/default_binary_value.bin");
+		testDifferentPropertyDefsWithExpectedBinary0();
+		
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/boolean/default_binary_value.bin");
+		testDifferentPropertyDefsWithExpectedBinary0();
+
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef2/default_binary_value.bin");
+		testDifferentPropertyDefsWithExpectedBinary0();
+	}
+
+	private void testDifferentPropertyDefsWithExpectedBinary0() throws NoSuchNodeTypeException, RepositoryException,
+			ValueFormatException, ServletException, IOException {
+		invokeServletWithDifferentPropertyDefs();
+		verify(response, never()).sendError(anyInt());
+		Assert.assertEquals(GenerationConstants.DEFAULT_VALUE_BINARY_0, new String(outStream.toByteArray()));
+	}
+	
+	@Test
+	public void testSuccessfulSingleMatchWithInvalidIndex() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/true/version/5.default_binary_value.bin");
+		invokeServletWithDifferentPropertyDefs();
+		verify(response).sendError(HttpServletResponse.SC_NOT_FOUND);
+	}
+	
+	@Test
+	public void testUnsuccessfulMultipleMatches() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/true/version/5.default_binary_value.bin");
+		invokeServletWithEqualPropertyDefs();
+		verify(response).sendError(HttpServletResponse.SC_NOT_FOUND);
+	}
+	
+	@Test
+	public void testUnsuccessfulNoMatches() throws ServletException, IOException, NoSuchNodeTypeException, RepositoryException {
+		when(request.getRequestURI()).thenReturn("/ns:ntName/binPropDef/binary/true/true/true/true/ignore/default_binary_value.bin");
+		invokeServletWithDifferentPropertyDefs();
+		verify(response).sendError(HttpServletResponse.SC_NOT_FOUND);
+	}
+	
+
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockNodeTypeGenerator.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockNodeTypeGenerator.java
new file mode 100644
index 0000000..bcb26c2
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockNodeTypeGenerator.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.mock;
+
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.NODETYPE_REQ_PRIMARY_TYPE_NAME1;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.NODETYPE_REQ_PRIMARY_TYPE_NAME2;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.version.OnParentVersionAction;
+import javax.servlet.ServletException;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.servlets.HttpConstants;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.json.JSONTokener;
+import org.apache.sling.jcr.js.nodetypes.NodeTypesJSONServlet;
+import org.apache.sling.jcr.js.nodetypes.test.JSONAssert;
+
+/**
+ * Generates NodeType mocks that will be returned when the servlet calles
+ * NodeTypeManager.getAllNodeTypes(). It also mocks request, response, output
+ * stream and so on to simulate the environment the servlet needs at runtime.
+ * 
+ */
+public class MockNodeTypeGenerator {
+
+	// mock classes
+	protected SlingHttpServletRequest request = null;
+	protected SlingHttpServletResponse response = null;
+	protected Resource resource = null;
+	protected Node currentNode = null;
+	protected Session session = null;
+	protected Workspace workspace = null;
+	protected NodeTypeManager ntManager = null;
+	protected NodeTypeIterator nodeTypeIterator = null;
+	protected ByteArrayOutputStream outStream = null;
+	private MockPropertyDefGenerator propertyGenerator = new MockPropertyDefGenerator();
+
+	public void setUp() throws RepositoryException, IOException {
+		// create mocks
+		request = mock(SlingHttpServletRequest.class);
+		response = mock(SlingHttpServletResponse.class);
+		resource = mock(Resource.class);
+		currentNode = mock(Node.class);
+		session = mock(Session.class);
+		workspace = mock(Workspace.class);
+		ntManager = mock(NodeTypeManager.class);
+		nodeTypeIterator = mock(NodeTypeIterator.class);
+		outStream = new ByteArrayOutputStream();
+
+		// stubbing
+		when(request.getResource()).thenReturn(resource);
+		when(request.getMethod()).thenReturn(HttpConstants.METHOD_GET);
+		when(response.getWriter()).thenReturn(new PrintWriter(outStream, true));
+		when(resource.adaptTo(Node.class)).thenReturn(currentNode);
+		when(currentNode.getSession()).thenReturn(session);
+		when(session.getWorkspace()).thenReturn(workspace);
+		when(workspace.getNodeTypeManager()).thenReturn(ntManager);
+		when(ntManager.getAllNodeTypes()).thenReturn(nodeTypeIterator);
+
+	}
+
+	public MockPropertyDefGenerator getPropertyGenerator() {
+		return this.propertyGenerator;
+	}
+
+	public NodeDefinition getSimpleChildNodeDef(String name) {
+		NodeDefinition childNodeDef1 = mock(NodeDefinition.class);
+		NodeType[] reqPrimaryTypes = { getSimpleNodeTypeWithName(NODETYPE_REQ_PRIMARY_TYPE_NAME1),
+				getSimpleNodeTypeWithName(NODETYPE_REQ_PRIMARY_TYPE_NAME2) };
+		when(childNodeDef1.getRequiredPrimaryTypes()).thenReturn(reqPrimaryTypes);
+		when(childNodeDef1.getName()).thenReturn(name);
+		when(childNodeDef1.getOnParentVersion()).thenReturn(OnParentVersionAction.COPY);
+		return childNodeDef1;
+	}
+
+	public NodeDefinition getCompleteChildNodeDef(String name) {
+		NodeDefinition childNodeDef1 = mock(NodeDefinition.class);
+		NodeType requiredPrimaryType1 = getSimpleNodeTypeWithName(NODETYPE_REQ_PRIMARY_TYPE_NAME1);
+		NodeType requiredPrimaryType2 = getSimpleNodeTypeWithName(NODETYPE_REQ_PRIMARY_TYPE_NAME2);
+		NodeType[] reqPrimaryTypes = { requiredPrimaryType1, requiredPrimaryType2 };
+		when(childNodeDef1.getRequiredPrimaryTypes()).thenReturn(reqPrimaryTypes);
+		when(childNodeDef1.getName()).thenReturn(name);
+		when(childNodeDef1.getOnParentVersion()).thenReturn(OnParentVersionAction.VERSION);
+		when(childNodeDef1.getDefaultPrimaryType()).thenReturn(requiredPrimaryType1);
+		when(childNodeDef1.allowsSameNameSiblings()).thenReturn(Boolean.TRUE);
+		when(childNodeDef1.isAutoCreated()).thenReturn(Boolean.TRUE);
+		when(childNodeDef1.isMandatory()).thenReturn(Boolean.TRUE);
+		when(childNodeDef1.isProtected()).thenReturn(Boolean.TRUE);
+		return childNodeDef1;
+	}
+
+	public void assertEqualsWithServletResult(String filename) throws JSONException, ServletException,
+			IOException {
+		NodeTypesJSONServlet generationServlet = new NodeTypesJSONServlet();
+		generationServlet.service(request, response);
+		verify(response, never()).sendError(anyInt());
+		String resultingJSON = new String(outStream.toByteArray(), "utf-8");
+
+
+		String expectedNTJSON = getExpectedNTJSON(filename);
+		
+		JSONObject actualJsonObjectFromServlet = new JSONObject(new JSONTokener(resultingJSON));
+
+		JSONAssert.assertEquals("Actual JSON: " + resultingJSON + "\nExpected JSON: " + expectedNTJSON, new JSONObject(
+				new JSONTokener(expectedNTJSON)), actualJsonObjectFromServlet);
+	}
+
+	protected String getExpectedNTJSON(String filename) throws IOException {
+		URL fileUri = MockNodeTypeGenerator.class.getResource("/expectedNTJSON/"+filename+".json");
+		BufferedReader in = new BufferedReader(new FileReader(fileUri.getFile()));
+		String currentLine = null;
+		StringBuilder fileContent = new StringBuilder();
+		while ((currentLine = in.readLine()) != null) {
+			fileContent.append(currentLine);
+		}
+		return fileContent.toString();
+	}
+
+	public NodeType getSimpleNodeTypeWithName(String nodeTypeName) {
+		NodeType nt1 = mock(NodeType.class);
+		NodeType supertype = mock(NodeType.class);
+		when(supertype.getName()).thenReturn("nt:base");
+		NodeType[] supertypes = { supertype };
+		when(nt1.getDeclaredSupertypes()).thenReturn(supertypes);
+		when(nt1.getName()).thenReturn(nodeTypeName);
+		return nt1;
+	}
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockPropertyDefGenerator.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockPropertyDefGenerator.java
new file mode 100644
index 0000000..6285caf
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/mock/MockPropertyDefGenerator.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.mock;
+
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_BINARY;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_BOOLEAN;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_DATE;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_DOUBLE;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_LONG;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_NAME;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_PATH;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_REFERENCE;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.CONSTRAINT_STRING;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_BOOLEAN;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_CALENDAR;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_DOUBLE;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_LONG;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_NAME;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_PATH;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_REFERENCE;
+import static org.apache.sling.jcr.js.nodetypes.GenerationConstants.DEFAULT_VALUE_STRING;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.jcr.js.nodetypes.GenerationConstants;
+
+/**
+ * Generates the PropertyDefinition mocks to simulate the property definitions that the servlet gets
+ * from the node type manager.
+ *
+ */
+public class MockPropertyDefGenerator {
+
+	// mock classes
+	protected SlingHttpServletRequest request = null;
+	protected SlingHttpServletResponse response = null;
+	protected Resource resource = null;
+	protected Node currentNode = null;
+	protected Session session = null;
+	protected Workspace workspace = null;
+	protected NodeTypeManager ntManager = null;
+	protected NodeTypeIterator nodeTypeIterator = null;
+	protected ByteArrayOutputStream outStream = null;
+	
+	public PropertyDefinition getSimplePropertyDef(String name) {
+		PropertyDefinition propertyDef = mock(PropertyDefinition.class);
+		when(propertyDef.getOnParentVersion()).thenReturn(OnParentVersionAction.COPY);
+		when(propertyDef.getName()).thenReturn(name);
+		return propertyDef;
+	}	
+
+	private PropertyDefinition getCompletePropertyDev(String name, Integer type, String[] valueConstraints, String defaultValueString) throws ValueFormatException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getString()).thenReturn(defaultValueString);
+		PropertyDefinition propertyDef = getPropertyDef(name, type, valueConstraints, new Value[] {defaultValue});
+		return propertyDef;
+	}
+
+	/**
+	 * @param name
+	 * @param type
+	 * @param valueConstraints
+	 * @param defaultValue - the getType() method will be mocked within this method. You only need to mock the getString(), getDouble() methods.
+	 * @return
+	 * @throws ValueFormatException
+	 * @throws RepositoryException
+	 */
+	public PropertyDefinition getPropertyDef(String name, Integer type, String[] valueConstraints, Value[] defaultValues)
+			throws ValueFormatException, RepositoryException {
+		return getPropertyDef(name, type, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, OnParentVersionAction.VERSION, valueConstraints, defaultValues);
+	}
+
+	public PropertyDefinition getPropertyDef(String propertyName, Integer type, Boolean isAutoCreated, Boolean isMandatory, Boolean isProtected, Boolean isMultiple, Integer onParentVersionAction, String[] valueConstraints, Value[] defaultValues)
+			throws ValueFormatException, RepositoryException {
+		PropertyDefinition propertyDef = mock(PropertyDefinition.class);
+		when(propertyDef.getOnParentVersion()).thenReturn(onParentVersionAction);
+		when(propertyDef.getName()).thenReturn(propertyName);
+		when(propertyDef.getRequiredType()).thenReturn(type);
+		when(propertyDef.getValueConstraints()).thenReturn(valueConstraints);
+		when(propertyDef.isMultiple()).thenReturn(isMultiple);
+		when(propertyDef.isProtected()).thenReturn(isProtected);
+		NodeType declaringNodeType = mock(NodeType.class);
+		when(declaringNodeType.getName()).thenReturn("ntName");
+		when(propertyDef.getDeclaringNodeType()).thenReturn(declaringNodeType);
+		if (defaultValues!=null){
+			for (Value defaultValue : defaultValues) {
+				when(defaultValue.getType()).thenReturn(type);
+			}
+		}
+		when(propertyDef.getDefaultValues()).thenReturn(defaultValues);
+		when(propertyDef.isAutoCreated()).thenReturn(isAutoCreated);
+		when(propertyDef.isMandatory()).thenReturn(isMandatory);
+		return propertyDef;
+	}
+	
+	@SuppressWarnings("deprecation")
+	public PropertyDefinition[] getDifferentPropertyDefinitions() throws ValueFormatException, RepositoryException{
+		Value defaultValue1 = mock(Value.class);
+		when(defaultValue1.getType()).thenReturn(PropertyType.BINARY);
+		when(defaultValue1.getStream()).thenReturn(new ByteArrayInputStream(GenerationConstants.DEFAULT_VALUE_BINARY_0.getBytes()));
+		Value defaultValue2 = mock(Value.class);
+		when(defaultValue2.getType()).thenReturn(PropertyType.BINARY);
+		when(defaultValue2.getStream()).thenReturn(new ByteArrayInputStream(GenerationConstants.DEFAULT_VALUE_BINARY_1.getBytes()));
+
+		PropertyDefinition binPropDef1 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, true, true, OnParentVersionAction.VERSION, new String[]{"[,1024]", "[,2048]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef2 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, true, true, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef3 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, true, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef4 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, false, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef5 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, false, false, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef6 = this.getPropertyDef("binPropDef", PropertyType.BINARY, false, false, false, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef7 = this.getPropertyDef("binPropDef", PropertyType.BOOLEAN, false, false, false, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef8 = this.getPropertyDef("binPropDef2", PropertyType.BOOLEAN, false, false, false, false, OnParentVersionAction.COPY, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		return new PropertyDefinition[]{binPropDef8, binPropDef7, binPropDef6, binPropDef5, binPropDef4, binPropDef3, binPropDef2, binPropDef1};
+	}
+	
+	@SuppressWarnings("deprecation")
+	public PropertyDefinition[] getEqualPropertyDefinitions() throws ValueFormatException, RepositoryException{
+		Value defaultValue1 = mock(Value.class);
+		when(defaultValue1.getType()).thenReturn(PropertyType.BINARY);
+		when(defaultValue1.getStream()).thenReturn(new ByteArrayInputStream("A content".getBytes()));
+		Value defaultValue2 = mock(Value.class);
+		when(defaultValue2.getType()).thenReturn(PropertyType.BINARY);
+		when(defaultValue2.getStream()).thenReturn(new ByteArrayInputStream("An other content".getBytes()));
+
+		PropertyDefinition binPropDef1 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, true, true, OnParentVersionAction.VERSION, new String[]{"[,1024]", "[,2048]"}, new Value[] {defaultValue1, defaultValue2});
+		PropertyDefinition binPropDef2 = this.getPropertyDef("binPropDef", PropertyType.BINARY, true, true, true, true, OnParentVersionAction.VERSION, new String[]{"[,1024]", "[,512]"}, new Value[] {defaultValue1, defaultValue2});
+		return new PropertyDefinition[]{binPropDef2, binPropDef1};
+	}
+	
+	public PropertyDefinition getCompleteStringPropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		return getCompletePropertyDev(name, PropertyType.STRING, new String[]{CONSTRAINT_STRING}, DEFAULT_VALUE_STRING);
+	}
+	
+	@SuppressWarnings("deprecation")
+	public PropertyDefinition getCompleteBinaryPropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getType()).thenReturn(PropertyType.BINARY);
+		when(defaultValue.getStream()).thenReturn(new ByteArrayInputStream("A content".getBytes()));
+		return getPropertyDef(name, PropertyType.BINARY, new String[]{CONSTRAINT_BINARY}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompleteDatePropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getDate()).thenReturn(DEFAULT_VALUE_CALENDAR);
+		return getPropertyDef(name, PropertyType.DATE, new String[]{CONSTRAINT_DATE}, new Value[] {defaultValue});
+	}
+
+	public PropertyDefinition getCompleteDoublePropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getDouble()).thenReturn(DEFAULT_VALUE_DOUBLE);
+		return getPropertyDef(name, PropertyType.DOUBLE, new String[]{CONSTRAINT_DOUBLE}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompleteLongPropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getLong()).thenReturn(DEFAULT_VALUE_LONG);
+		return getPropertyDef(name, PropertyType.LONG, new String[]{CONSTRAINT_LONG}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompleteBooleanPropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getBoolean()).thenReturn(DEFAULT_VALUE_BOOLEAN);
+		return getPropertyDef(name, PropertyType.BOOLEAN, new String[]{CONSTRAINT_BOOLEAN}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompleteNamePropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getString()).thenReturn(DEFAULT_VALUE_NAME);
+		return getPropertyDef(name, PropertyType.NAME, new String[]{CONSTRAINT_NAME}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompletePathPropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getString()).thenReturn(DEFAULT_VALUE_PATH);
+		return getPropertyDef(name, PropertyType.PATH, new String[]{CONSTRAINT_PATH}, new Value[] {defaultValue});
+	}
+	
+	public PropertyDefinition getCompleteReferencePropertyDef(String name) throws ValueFormatException, IllegalStateException, RepositoryException {
+		Value defaultValue = mock(Value.class);
+		when(defaultValue.getString()).thenReturn(DEFAULT_VALUE_REFERENCE);
+		return getPropertyDef(name, PropertyType.REFERENCE, new String[]{CONSTRAINT_REFERENCE}, new Value[] {defaultValue});
+	}
+	
+}
diff --git a/src/test/java/org/apache/sling/jcr/js/nodetypes/test/JSONAssert.java b/src/test/java/org/apache/sling/jcr/js/nodetypes/test/JSONAssert.java
new file mode 100644
index 0000000..4a8713d
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/js/nodetypes/test/JSONAssert.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.js.nodetypes.test;
+
+import java.util.Iterator;
+
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.junit.Assert;
+
+/**
+ * Provides assertions on equality for JSON Arrays and Objects.
+ *
+ * This class is copied from org.apache.sling.commons.json.test.JSONAssert.
+ * This code in turn was based on code written by Andres Almiray <aalmiray@users.sourceforge.net> as
+ * part of the json-lib project - http://json-lib.sourceforge.net/
+ * 
+ * TODO: It should be made reusable in some way or the other. 
+ */
+public class JSONAssert extends Assert {
+	/**
+	 * Asserts that two JSONArrays are equal.
+	 */
+	public static void assertEquals(JSONArray expected, JSONArray actual)
+			throws JSONException {
+		assertEquals(null, expected, actual);
+	}
+
+	/**
+	 * Asserts that two JSONObjects are equal.
+	 */
+	public static void assertEquals(JSONObject expected, JSONObject actual)
+			throws JSONException {
+		assertEquals(null, expected, actual);
+	}
+
+	/**
+	 * Asserts that two JSONArrays are equal.
+	 */
+	public static void assertEquals(String message, JSONArray expected,
+			JSONArray actual) throws JSONException {
+		String header = message == null ? "" : message + ": ";
+		if (expected == null) {
+			fail(header + "expected array was null");
+		}
+		if (actual == null) {
+			fail(header + "actual array was null");
+		}
+		if (expected == actual || expected.equals(actual)) {
+			return;
+		}
+		if (actual.length() != expected.length()) {
+			fail(header + "arrays sizes differed, expected.length()="
+					+ expected.length() + " actual.length()=" + actual.length());
+		}
+
+		int max = expected.length();
+		for (int i = 0; i < max; i++) {
+			Object o1 = expected.get(i);
+			Object o2 = actual.get(i);
+
+			// handle nulls
+			if (JSONObject.NULL.equals(o1)) {
+				if (JSONObject.NULL.equals(o2)) {
+					continue;
+                }
+				fail(header + "arrays first differed at element [" + i
+						+ "];");
+			} else {
+				if (JSONObject.NULL.equals(o2)) {
+					fail(header + "arrays first differed at element [" + i
+							+ "];");
+				}
+			}
+
+			if (o1 instanceof JSONArray && o2 instanceof JSONArray) {
+				JSONArray e = (JSONArray) o1;
+				JSONArray a = (JSONArray) o2;
+				assertEquals(header + "arrays first differed at element " + i
+						+ ";", e, a);
+			} else if (o1 instanceof JSONObject && o2 instanceof JSONObject) {
+				assertEquals(header + "arrays first differed at element [" + i
+						+ "];", (JSONObject) o1, (JSONObject) o2);
+			} else if (o1 instanceof String) {
+				assertEquals(header + "arrays first differed at element [" + i
+						+ "];", (String) o1, String.valueOf(o2));
+			} else if (o2 instanceof String) {
+				assertEquals(header + "arrays first differed at element [" + i
+						+ "];", String.valueOf(o1), (String) o2);
+			} else {
+				assertEquals(header + "arrays first differed at element [" + i
+						+ "];", o1, o2);
+			}
+		}
+	}
+
+	/**
+	 * Asserts that two JSONObjects are equal.
+	 */
+	public static void assertEquals(String message, JSONObject expected,
+			JSONObject actual) throws JSONException {
+		String header = message == null ? "" : message + ": ";
+		if (expected == null) {
+			fail(header + "expected object was null");
+		}
+		if (actual == null) {
+			fail(header + "actual object was null");
+		}
+		if (expected == actual /* || expected.equals( actual ) */) {
+			return;
+		}
+
+		JSONArray expectedNames = expected.names();
+		JSONArray actualNames = actual.names();
+
+		if (expectedNames == null && actualNames == null) {
+			return;
+		}
+
+		if (expectedNames == null) {
+		    expectedNames = new JSONArray();
+		}
+
+		if (actualNames == null) {
+		    actualNames = new JSONArray();
+		}
+
+		assertEquals(header
+				+ "names sizes differed, expected.names().length()="
+				+ expectedNames.length() + " actual.names().length()="
+				+ actualNames.length(), expectedNames.length(), actualNames
+				.length());
+		for (Iterator<String> keys = expected.keys(); keys.hasNext();) {
+			String key = keys.next();
+			Object o1 = expected.opt(key);
+			Object o2 = actual.opt(key);
+
+			if (JSONObject.NULL.equals(o1)) {
+				if (JSONObject.NULL.equals(o2)) {
+					continue;
+                }
+				fail(header + "objects differed at key [" + key + "];");
+			} else {
+				if (JSONObject.NULL.equals(o2)) {
+					fail(header + "objects differed at key [" + key + "];");
+				}
+			}
+
+			if (o1 instanceof JSONObject && o2 instanceof JSONObject) {
+				assertEquals(header + "objects differed at key [" + key + "];",
+						(JSONObject) o1, (JSONObject) o2);
+			} else if (o1 instanceof JSONArray && o2 instanceof JSONArray) {
+				assertEquals(header + "objects differed at key [" + key + "];",
+						(JSONArray) o1, (JSONArray) o2);
+			} else if (o1 instanceof String) {
+				assertEquals(header + "objects differed at key [" + key + "];",
+						(String) o1, String.valueOf(o2));
+			} else if (o2 instanceof String) {
+				assertEquals(header + "objects differed at key [" + key + "];",
+						String.valueOf(o1), (String) o2);
+			} else {
+				assertEquals(header + "objects differed at key [" + key + "];",
+						o1, o2);
+			}
+		}
+	}
+
+}
diff --git a/src/test/javascript/NodeTypesSpec.js b/src/test/javascript/NodeTypesSpec.js
new file mode 100644
index 0000000..db2196e
--- /dev/null
+++ b/src/test/javascript/NodeTypesSpec.js
@@ -0,0 +1,1129 @@
+/*
+ * 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.
+ */
+
+describe('The Node Type Manager', function() {
+
+	// The documentation about the spec format can be found here:
+	// http://pivotal.github.com/jasmine/
+	var defaultNTJsonURL = "src/defaultNT/defaultNT.json";
+	
+	function compareItemDefitions(actualItemDefinitions, expectedItemDefinitions){
+		expect(actualItemDefinitions.autoCreated).toEqual(expectedItemDefinitions.autoCreated);
+		expect(actualItemDefinitions.mandatory).toEqual(expectedItemDefinitions.mandatory);
+		expect(actualItemDefinitions.protected).toEqual(expectedItemDefinitions.protected);
+		expect(actualItemDefinitions.onParentVersion).toEqual(expectedItemDefinitions.onParentVersion);
+	}
+	
+	function compareNodeTypeProperties(actualNodeType, expectedNodeType){
+		expect(actualNodeType.mixin).toBe(expectedNodeType.mixin);
+		expect(actualNodeType.orderableChildNodes).toBe(expectedNodeType.orderableChildNodes);
+		expect(actualNodeType.declaredSupertypes).toEqual(expectedNodeType.declaredSupertypes);
+	}
+	
+	function comparePropertyDefProperties(actualPropertyDefs, expectedPropertyDefs){
+		expect(actualPropertyDefs.defaultValues).toEqual(expectedPropertyDefs.defaultValues);
+		expect(actualPropertyDefs.valueConstraints).toEqual(expectedPropertyDefs.valueConstraints);
+		expect(actualPropertyDefs.requiredType).toEqual(expectedPropertyDefs.requiredType);
+		expect(actualPropertyDefs.multiple).toEqual(expectedPropertyDefs.multiple);
+	}
+
+	function compareChildNodeDefProperties(actualChildNodeDefs, expectedChildNodeDefs){
+		expect(actualChildNodeDefs.allowsSameNameSiblings).toEqual(expectedChildNodeDefs.allowsSameNameSiblings);
+		expect(actualChildNodeDefs.defaultPrimaryType).toEqual(expectedChildNodeDefs.defaultPrimaryType);
+		expect(actualChildNodeDefs.requiredPrimaryTypes).toEqual(expectedChildNodeDefs.requiredPrimaryTypes);
+	}
+
+	it('returns the node type names.', function() {
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"nt:base" : {
+					},
+					"n1" : {
+					},"n2" : {
+					},"n3" : {
+					},"n4" : {
+				}} 
+		};
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+		expect(ntManager.getNodeTypeNames()).toEqual(["nt:base","n1","n2","n3","n4"]);
+	});
+
+	it('returns the specified node type.', function() {
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"nt:base" : {
+					},
+					"aNodeType" : {
+				}} 
+		};
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+		expect(ntManager.getNodeType("aNodeType")).toEqual(settings.nodeTypesJson["aNodeType"]);
+	});
+	
+	describe('collects', function () {
+		var ntManager;
+
+		describe('all child node definitions from the super types ', function () {
+			
+			function arrayContainsCnDefWithName(array, cnDefName){
+				var found = false;
+				for (var i=0; i<array.length && found===false; i++){
+					found = array[i].name === cnDefName;
+				}
+				return found;
+			}
+			
+			it('with <getAllChildNodeDefinitions()>.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType", "aMixinParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								},{
+									"name" : "childNodeDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef3"
+								},{
+									"name" : "childNodeDef4"} 
+								]
+						},"aMixinParentNodeType" : {
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef5"
+								},{
+									"name" : "childNodeDef6"} 
+								]
+						},"aGrandParentNodeType" : {
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef7"
+								},{
+									"name" : "childNodeDef8"} 
+								]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}} 
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingChildNodeDefs = ntManager.getNodeType("aNodeType").getAllChildNodeDefinitions();
+				expect(resultingChildNodeDefs.length).toBe(8);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef1")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef2")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef3")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef4")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef5")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef6")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef7")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef8")).toBe(true);
+			});
+			
+			it('with <getAllChildNodeDefinitions()> but does not contain duplicate entries from the parents.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								},{
+									"name" : "childNodeDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								},{
+									"name" : "childNodeDef2"} 
+								]
+						},"nt:base" : {
+						}
+					} 
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingChildNodeDefs = ntManager.getNodeType("aNodeType").getAllChildNodeDefinitions();
+				expect(resultingChildNodeDefs.length).toBe(2);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef1")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef2")).toBe(true);
+			});
+			
+			it('with <getAllChildNodeDefinitions()> and lists child node definitions with the same name but different content.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1",
+							        "requiredPrimaryTypes": [
+							            "aNodeType"
+		                            ],
+								},{
+									"name" : "childNodeDef2"
+								} 
+							]
+						},"aParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								},{
+									"name" : "childNodeDef2"
+								} 
+							]
+						},"aGrandParentNodeType" : {
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								}
+							]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}} 
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingChildNodeDefs = ntManager.getNodeType("aNodeType").getAllChildNodeDefinitions();
+				
+				expect(resultingChildNodeDefs.length).toBe(3);
+				
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef1")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef2")).toBe(true);
+			});
+			
+			it('with <getAllChildNodeDefinitions()> but does not follow circular dependencies.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType", "aMixinParentNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef1"
+								},{
+									"name" : "childNodeDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef3"
+								},{
+									"name" : "childNodeDef4"} 
+								]
+						},"aMixinParentNodeType" : {
+							//this creates a circular dependency
+							"declaredSupertypes" : [ "aNodeType" ],
+							"declaredChildNodeDefinitions" : [{
+									"name" : "childNodeDef5"
+								},{
+									"name" : "childNodeDef6"} 
+								]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}} 
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+	
+				var resultingChildNodeDefs = ntManager.getNodeType("aNodeType").getAllChildNodeDefinitions();
+				expect(resultingChildNodeDefs.length).toBe(6);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef1")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef2")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef3")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef4")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef5")).toBe(true);
+				expect(arrayContainsCnDefWithName(resultingChildNodeDefs, "childNodeDef6")).toBe(true);
+			});
+		});
+	
+		describe('all property definitions from the super types', function () {
+			
+			function arrayContainsPropDefWithName(array, propDefName){
+				var found = false;
+				for (var i=0; i<array.length && found===false; i++){
+					found = array[i].name === propDefName;
+				}
+				return found;
+			}
+			
+			it('with <getAllPropertyDefinitions()>', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType", "aMixinParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef1"
+								},{
+									"name" : "propertyDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef3"
+								},{
+									"name" : "propertyDef4"} 
+								]
+						},"aMixinParentNodeType" : {
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef5"
+								},{
+									"name" : "propertyDef6"} 
+								]
+						},"aGrandParentNodeType" : {
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef7"
+								},{
+									"name" : "propertyDef8"} 
+								]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}}
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingPropertyDefs = ntManager.getNodeType("aNodeType").getAllPropertyDefinitions();
+				expect(resultingPropertyDefs.length).toBe(8);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef1")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef2")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef3")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef4")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef5")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef6")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef7")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef8")).toBe(true);
+			});
+			
+			it('with <getAllPropertyDefinitions()> but does not contain duplicate entries from the parents.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef1"
+								},{
+									"name" : "propertyDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1"
+							},{
+								"name" : "propertyDef2"} 
+								]
+						},"aGrandParentNodeType" : {
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1"
+							},{
+								"name" : "propertyDef2"} 
+								]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}}
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingPropertyDefs = ntManager.getNodeType("aNodeType").getAllPropertyDefinitions();
+				expect(resultingPropertyDefs.length).toBe(2);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef1")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef2")).toBe(true);
+			});
+			
+			it('with <getAllPropertyDefinitions()>  and lists property definitions with the same name but different content.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1",
+								"multiple": true
+								},{
+								"name" : "propertyDef2",
+								"multiple": true
+								} 
+							]
+						},"aParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1"
+								},{
+								"name" : "propertyDef2",
+								"multiple": true
+								} 
+							]
+						},"aGrandParentNodeType" : {
+							"declaredSupertypes" : [ "aGrandGrandParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1",
+						        "valueConstraints": [
+						          "nt:versionHistory"
+						        ],
+								},{
+								"name" : "propertyDef2",
+								"multiple": true
+								} 
+							]
+						},"aGrandGrandParentNodeType" : {
+							"declaredPropertyDefinitions" : [{
+								"name" : "propertyDef1",
+								"defaultValues": [{
+									"name": "nt:base",
+									"type": "Name"
+                                }],
+								},{
+								"name" : "propertyDef2",
+								"multiple": true
+								} 
+							]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}}
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingPropertyDefs = ntManager.getNodeType("aNodeType").getAllPropertyDefinitions();
+				expect(resultingPropertyDefs.length).toBe(5);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef1")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef2")).toBe(true);
+			});
+			
+			it('with <getAllPropertyDefinitions()> but does not follow circular dependencies.', function() {
+				var settings = {
+						"defaultNTJsonURL": defaultNTJsonURL,
+						"nodeTypesJson" : {"aNodeType" : {
+							"declaredSupertypes" : [ "aParentNodeType", "aMixinParentNodeType" ],
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef1"
+								},{
+									"name" : "propertyDef2"} 
+								]
+						},"aParentNodeType" : {
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef3"
+								},{
+									"name" : "propertyDef4"} 
+								]
+						},"aMixinParentNodeType" : {
+							// this supertype should not create a circular dependency
+							"declaredSupertypes" : [ "aNodeType" ],
+							"declaredPropertyDefinitions" : [{
+									"name" : "propertyDef5"
+								},{
+									"name" : "propertyDef6"} 
+								]
+						},"nt:base" : {
+							"declaredSupertypes" : []
+						}}
+				};
+				ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+				var resultingPropertyDefs = ntManager.getNodeType("aNodeType").getAllPropertyDefinitions();
+				expect(resultingPropertyDefs.length).toBe(6);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef1")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef2")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef3")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef4")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef5")).toBe(true);
+				expect(arrayContainsPropDefWithName(resultingPropertyDefs, "propertyDef6")).toBe(true);
+			});
+
+		});
+	});
+	
+	describe('recognizes the default settings', function () {
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"nt": {
+					    "declaredPropertyDefinitions": [{"name": "propertyDef1"}, {"name": "propertyDef2"}],
+					    "declaredChildNodeDefinitions": [{"name": "childNodeDef1"}, {"name": "childNodeDef2"}],
+					},
+					"nt:base" : {
+					}
+				} 
+		};
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+		
+		it('for the properties at the node type level', function() {
+			compareNodeTypeProperties(ntManager.getNodeType("nt"), ntManager.internalGetDefaultNodeType())
+		});
+		
+		describe('for the properties at the property definition level', function() {
+			it('that do inherit from item definition', function() {
+				comparePropertyDefProperties(ntManager.getNodeType("nt").getAllPropertyDefinitions(), ntManager.internalGetDefaultNodeType().declaredPropertyDefinitions);
+			});
+			it('that don\'t inherit from item definition', function() {
+				compareItemDefitions(ntManager.getNodeType("nt").getAllPropertyDefinitions(), ntManager.internalGetDefaultNodeType().declaredPropertyDefinitions);
+			});
+		});
+		
+		describe('for the properties at the child node definition level', function() {
+			ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+			it('that do inherit from item definition', function() {
+				compareChildNodeDefProperties(ntManager.getNodeType("nt").getAllChildNodeDefinitions(), ntManager.internalGetDefaultNodeType().declaredChildNodeDefinitions);
+			});
+	        
+			it('that don\'t inherit from item definition', function() {
+				compareItemDefitions(ntManager.getNodeType("nt").getAllChildNodeDefinitions(), ntManager.internalGetDefaultNodeType().declaredChildNodeDefinitions);
+			});
+		});		
+	});
+	
+	describe('overwrites the default settings', function () {
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"nt": {
+					    "mixin": true,
+					    "orderableChildNodes": true,
+					    "declaredSupertypes": [
+					      "otherNodeType"
+					    ],
+					    "declaredPropertyDefinitions": [
+					      {
+					        "defaultValues":  [{
+								"string": "a default value",
+								"type": "String"
+                            }],
+					        "valueConstraints": ["banana","apple"],
+					        "requiredType": "String",
+					        "multiple": true,
+					        
+					        "autoCreated": true,
+					        "mandatory": true,
+					        "protected": true,
+					        "onParentVersion": "VERSION"
+					      }
+					    ],
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "allowsSameNameSiblings": true,
+					        "defaultPrimaryType": "otherNodeType",
+					        "requiredPrimaryTypes": [
+					          "otherNodeType"
+					        ],
+					        
+					        "autoCreated": true,
+					        "mandatory": true,
+					        "protected": true,
+					        "onParentVersion": "VERSION"
+					      }
+					    ]
+					  },
+					"nt:base" : {
+					},
+					"otherNodeType" : {
+						
+					}
+			} 
+		};
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+
+		it('for the properties at the node type level', function() {
+			compareNodeTypeProperties(ntManager.getNodeType("nt"), settings.nodeTypesJson.nt)
+		});
+		
+		describe('for the properties at the property definition level', function() {
+			it('that do inherit from item definition', function() {
+				comparePropertyDefProperties(ntManager.getNodeType("nt").getAllPropertyDefinitions(), settings.nodeTypesJson.nt.declaredPropertyDefinitions);
+			});
+			it('that don\'t inherit from item definition', function() {
+				compareItemDefitions(ntManager.getNodeType("nt").getAllPropertyDefinitions(), settings.nodeTypesJson.nt.declaredPropertyDefinitions);
+			});
+		});
+		
+		describe('for the properties at the child node definition level', function() {
+			it('that do inherit from item definition', function() {
+				compareChildNodeDefProperties(ntManager.getNodeType("nt").getAllChildNodeDefinitions(), settings.nodeTypesJson.nt.declaredChildNodeDefinitions);
+			});
+	        
+			it('that don\'t inherit from item definition', function() {
+				compareItemDefitions(ntManager.getNodeType("nt").getAllChildNodeDefinitions(), settings.nodeTypesJson.nt.declaredChildNodeDefinitions);
+			});
+		});			
+	});
+
+	describe('returns in getApplicableCnTypesPerCnDef()', function () {
+		/* adding a keySize function to Object */
+		if (typeof Object.keySize === "undefined") {
+			Object.keySize = function(obj) {
+			    var keySize = 0, key;
+			    for (key in obj) {
+			        if (obj.hasOwnProperty(key)) keySize++;
+			    }
+			    return keySize;
+			};
+		}
+		describe('all valid child node types', function () {
+			var settings = {
+					"defaultNTJsonURL": defaultNTJsonURL,
+					"nodeTypesJson" : {
+						"nt:base" : {
+						},
+						"aSuperType" : {
+						    "declaredChildNodeDefinitions": [
+						     {
+						    	 "requiredPrimaryTypes": [
+						    	     "supCnDef1"
+						    	 ],
+						      	 "name" : "supCnDef1Name"
+						      },
+						      {
+							     "requiredPrimaryTypes": [
+		  					  		"supCnDef3",
+							  		"supCnDef2"
+							     ],
+							     "name" : "*"
+							  }
+						    ]
+						},
+						"mix:supSupCnDef1" : {
+						    "mixin": true
+						},
+						"mix:supSupCnDef2" : {
+						    "mixin": true
+						},
+						"supCnDef1" : {
+						    "declaredSupertypes": [
+						  		"mix:supSupCnDef1",
+						  		"mix:supSupCnDef2"
+						  	]
+						},
+						"supCnDef1Sub1" : {
+						    "declaredSupertypes": [
+						  		"supCnDef1"
+						  	]
+						},
+						"supCnDef1Sub11" : {
+						    "declaredSupertypes": [
+						  		"supCnDef1Sub1"
+						  	]
+						},
+						"supCnDef2": {
+						},
+						"supCnDef2Sub1" : {
+						    "declaredSupertypes": [
+						  		"supCnDef2"
+						  	]
+						},
+						"supCnDef2Sub11" : {
+						    "declaredSupertypes": [
+						  		"supCnDef2Sub1"
+						  	]
+						},
+						"supCnDef2Mixin" : {
+						    "declaredSupertypes": [
+						  		"supCnDef2Sub11"
+						  	],
+						  	"mixin": true
+						},
+						"supCnDef3": {
+						},
+						"supCnDef3Def2" : {
+						    "declaredSupertypes": [
+						  		"supCnDef3",
+						  		"supCnDef2"
+						  	]
+						},
+						"aNodeType" : {
+						    "declaredSupertypes": [
+						        "aSuperType"
+	 					    ],
+	 					    "declaredChildNodeDefinitions": [
+						     {
+						    	 "requiredPrimaryTypes": [
+						    	     "cnDef1"
+						    	 ],
+						      	 "name" : "cnDef1Name"
+						      },
+						      {
+							     "requiredPrimaryTypes": [
+							          "cnDef2"
+							     ],
+							     "name" : "cnDef2Name"
+						      },
+						      {
+							     "requiredPrimaryTypes": [
+							          "cnDef3"
+							     ],
+							     "name" : "*"
+								  
+						      },
+						      {
+							     "requiredPrimaryTypes": [
+							          "cnDef4",
+							          "cnDef5"
+							     ],
+							     "name" : "*"
+						      }
+						    ]
+						},
+						"cnDef1" : {
+						},
+						"cnDef2" : {
+						},
+						"cnDef2Sub1" : {
+						    "declaredSupertypes": [
+						        "cnDef2"
+						  	]
+						},
+						"cnDef2Sub11" : {
+						    "declaredSupertypes": [
+						        "cnDef2Sub1"
+						  	]
+						},
+						"cnDef2Sub2" : {
+						    "declaredSupertypes": [
+						        "cnDef2"
+						  	]
+						},
+						"cnDef3" : {
+						},
+						"cnDef4" : {
+						},
+						"cnDef5" : {
+						    "declaredSupertypes": [
+						  		"cnDef2Sub2"
+						  	]
+						},
+						"cnDef4Sub1" : {
+						    "declaredSupertypes": [
+						  		"cnDef4"
+						  	]
+						},
+						"cnDef4Sub11" : {
+						    "declaredSupertypes": [
+						  		"cnDef4Sub1"
+						  	]
+						},
+						"cnDef4Sub2" : {
+						    "declaredSupertypes": [
+						  		"cnDef4"
+						  	]
+						},
+						"cnDef5Sub1" : {
+						    "declaredSupertypes": [
+						  		"cnDef5"
+						  	]
+						},
+						"cnDef5Sub2" : {
+						    "declaredSupertypes": [
+						  		"cnDef5",
+						  		"cnDef2Sub2"
+						  	]
+						},
+						"CnDef2Mixin" : {
+						    "declaredSupertypes": [
+						  		"cnDef5Sub2"
+						  	],
+						  	"mixin": true
+						},
+						"cnDef45" : {
+						    "declaredSupertypes": [
+						  		"cnDef4Sub11",
+						  		"cnDef5Sub2"
+						  	]
+						},
+						"cnDef45Sub1" : {
+						    "declaredSupertypes": [
+						  		"cnDef45"
+						  	]
+						}
+					}
+			};
+	
+			// see "/src/test/resources/applicableChildNodeTypesDatastructure.jpg" for a
+			// visualization of the test datastructure
+			
+			var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+			var applicableCnTypes = ntManager.getNodeType("aNodeType").getApplicableCnTypesPerCnDef();
+	
+			it('generally', function() {
+				expect(applicableCnTypes!=null).toBe(true);
+				expect(applicableCnTypes).toBeDefined();
+				
+				expect(applicableCnTypes["cnDef1Name"]).toBeDefined();
+				expect(Object.keySize(applicableCnTypes["cnDef1Name"])).toBe(1);
+				expect(applicableCnTypes["cnDef1Name"]["cnDef1"]).toBeDefined();
+	
+				expect(applicableCnTypes["cnDef2Name"]).toBeDefined();
+				expect(Object.keySize(applicableCnTypes["cnDef2Name"])).toBe(10);
+				expect(applicableCnTypes["cnDef2Name"]["cnDef2"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef2Sub1"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef2Sub11"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef2Sub2"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef5"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef5Sub1"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef5Sub2"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef45"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["cnDef45Sub1"]).toBeDefined();
+				expect(applicableCnTypes["cnDef2Name"]["CnDef2Mixin"]).toBeDefined();
+				
+				expect(applicableCnTypes["*"]).toBeDefined();
+				expect(Object.keySize(applicableCnTypes["*"])).toBe(4);
+				expect(applicableCnTypes["*"]["supCnDef3Def2"]).toBeDefined();
+				
+				expect(applicableCnTypes["*"]["cnDef3"]).toBeDefined();
+	
+				expect(applicableCnTypes["*"]["cnDef45"]).toBeDefined();
+				expect(applicableCnTypes["*"]["cnDef45Sub1"]).toBeDefined();
+	
+				expect(applicableCnTypes["supCnDef1Name"]).toBeDefined();
+				expect(Object.keySize(applicableCnTypes["supCnDef1Name"])).toBe(3);
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1"]).toBeDefined();
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1Sub1"]).toBeDefined();
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1Sub11"]).toBeDefined();
+			});
+			
+			it('with multiple requiredPrimaryTypes', function() {
+				expect(applicableCnTypes["*"]).toBeDefined();
+				expect(applicableCnTypes["*"]["supCnDef3Def2"]).toBeDefined();
+				expect(applicableCnTypes["*"]["cnDef3"]).toBeDefined();			
+				expect(applicableCnTypes["*"]["cnDef45"]).toBeDefined();
+				expect(applicableCnTypes["*"]["cnDef45Sub1"]).toBeDefined();
+			});
+			
+			it('including all valid super types\' child node types and its subtypes with multiple requiredPrimaryTypes', function() {
+				expect(applicableCnTypes["supCnDef1Name"]).toBeDefined();
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1Sub1"]).toBeDefined();
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1Sub1"]).toBeDefined();
+				expect(applicableCnTypes["supCnDef1Name"]["supCnDef1Sub11"]).toBeDefined();
+				
+				expect(applicableCnTypes["*"]["supCnDef3Def2"]).toBeDefined();
+			});
+
+		});
+		describe('all node types', function () {
+			var settings = {
+					"defaultNTJsonURL": defaultNTJsonURL,
+					"nodeTypesJson" : {
+						"nt:base" : {
+						},
+						"aNodeType" : {
+	 					    "declaredChildNodeDefinitions": [
+						     {
+//						    	 no required primary types declared:
+						      	 "name" : "cnDef1Name"
+						      }
+						    ]
+						},
+						"nt1" : {
+						},
+						"nt2" : {
+						}
+					}
+			};
+	
+			var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+			var applicableCnTypes = ntManager.getNodeType("aNodeType").getApplicableCnTypesPerCnDef();
+
+			it('if required primary types is \'nt:base\'', function() {
+				expect(applicableCnTypes!=null).toBe(true);
+				expect(applicableCnTypes["cnDef1Name"]).toBeDefined(true);
+				expect(applicableCnTypes["cnDef1Name"]["nt:base"]).toBeDefined(true);
+				expect(applicableCnTypes["cnDef1Name"]["aNodeType"]).toBeDefined(true);
+				expect(applicableCnTypes["cnDef1Name"]["nt1"]).toBeDefined(true);
+				expect(applicableCnTypes["cnDef1Name"]["nt2"]).toBeDefined(true);
+				expect(Object.keySize(applicableCnTypes["cnDef1Name"])).toBe(4);
+			});
+		});
+		it('the residual definition', function () {
+			var settings = {
+					"defaultNTJsonURL": defaultNTJsonURL,
+					"nodeTypesJson" : {
+						"nt:base" : {
+						},
+						"aNodeType" : {
+	 					    "declaredChildNodeDefinitions": [{
+   						    	 "requiredPrimaryTypes": [
+   						    	     "cnType1"
+   						    	 ],
+   						      	 "name" : "cnDef1Name"
+	   						 },{
+							     "requiredPrimaryTypes": [
+							    	  "cnType2"
+							     ],
+							     "name" : "*"
+							 }
+						    ]
+						},
+						"cnType1" : {
+						},
+						"cnType2" : {
+						}
+					}
+			};
+	
+			var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+			var applicableCnTypes = ntManager.getNodeType("aNodeType").getApplicableCnTypesPerCnDef();
+
+			expect(applicableCnTypes!=null).toBe(true);
+			expect(applicableCnTypes["cnDef1Name"]).toBeDefined(true);
+			expect(applicableCnTypes["cnDef1Name"]["cnType1"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypes["cnDef1Name"])).toBe(1);
+			
+			expect(applicableCnTypes["*"]["cnType2"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypes["*"])).toBe(1);
+		});
+
+		it('the applicable mixin node types if \'true\' has been passed to the mixin parameter', function () {
+			var settings = {
+					"defaultNTJsonURL": defaultNTJsonURL,
+					"nodeTypesJson" : {
+						"nt:base" : {
+						},
+						"aNodeType" : {
+	 					    "declaredChildNodeDefinitions": [{
+  						    	 "requiredPrimaryTypes": [
+	   						    	     "cnType1"
+	   						    	 ],
+	   						      	 "name" : "cnDef1Name"
+		   						  },{
+	   						    	 "requiredPrimaryTypes": [
+	   						    	     "cnType2"
+	   						    	 ],
+	   						      	 "name" : "cnDef2Name"
+		   						 },{
+							     "requiredPrimaryTypes": [
+							    	  "cnType3"
+							     ],
+							     "name" : "*"
+							 }
+						    ]
+						},
+						"cnType1" : {
+						},
+						"cnType2" : {
+						    "mixin": true
+						},
+						"cnType3" : {
+							"mixin": true
+						}
+					}
+			};
+	
+			var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+			var applicableCnTypesWithMixin = ntManager.getNodeType("aNodeType").getApplicableCnTypesPerCnDef(true);
+
+			expect(applicableCnTypesWithMixin!=null).toBe(true);
+			expect(applicableCnTypesWithMixin["cnDef1Name"]).toBeDefined(true);
+			expect(applicableCnTypesWithMixin["cnDef1Name"]["cnType1"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithMixin["cnDef1Name"])).toBe(1);
+			
+			expect(applicableCnTypesWithMixin["cnDef2Name"]).toBeDefined(true);
+			expect(applicableCnTypesWithMixin["cnDef2Name"]["cnType2"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithMixin["cnDef1Name"])).toBe(1);
+			
+			expect(applicableCnTypesWithMixin["*"]["cnType3"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithMixin["*"])).toBe(1);
+			
+
+			var applicableCnTypesWithoutMixin = ntManager.getNodeType("aNodeType").getApplicableCnTypesPerCnDef(false);
+
+			expect(applicableCnTypesWithoutMixin!=null).toBe(true);
+			expect(applicableCnTypesWithoutMixin["cnDef1Name"]).toBeDefined(true);
+			expect(applicableCnTypesWithoutMixin["cnDef1Name"]["cnType1"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithoutMixin["cnDef1Name"])).toBe(1);
+			
+			expect(applicableCnTypesWithoutMixin["cnDef2Name"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithoutMixin["cnDef2Name"])).toBe(0);
+
+			expect(applicableCnTypesWithoutMixin["*"]).toBeDefined(true);
+			expect(Object.keySize(applicableCnTypesWithoutMixin["*"])).toBe(0);
+		});
+	});
+
+	describe('checks in canAddChildNode()', function () {
+
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"ntResidualChild": {
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "requiredPrimaryTypes": [
+					          "nt:base"
+					        ],
+					    	"name" : "*"
+					      }
+					    ]
+					  },
+					"ntNonResidualChild": {
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "requiredPrimaryTypes": [
+					          "nt:base"
+					        ],
+					    	"name" : "aChildNodeDef1"
+					      }
+					    ]
+					  },
+					"ntNonResidualProtectedChild": {
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "requiredPrimaryTypes": [
+					          "nt:base"
+					        ],
+					    	"name" : "aChildNodeDef2",
+					        "protected": true
+					      }
+					    ]
+					  },
+					"ntWithOtherChildNode": {
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "requiredPrimaryTypes": [
+					          "otherNodeType"
+					        ],
+					    	"name" : "*"
+					      }
+					    ]
+					  },
+					"nt:base" : {
+					},
+					"otherNodeType" : {
+					},
+					"inheritedNodeType" : {
+					    "declaredSupertypes": [
+ 					      "otherNodeType"
+ 					    ]
+					},
+					"aNodeType" : {
+					    "declaredChildNodeDefinitions": [
+					      {
+					        "requiredPrimaryTypes": [
+					          "aChildNodeType"
+					        ],
+					    	"name" : "*"
+					      }
+					    ]
+					},
+					"aChildNodeType" : {
+					},
+					"aChildNodesSubtype" : {
+					    "declaredSupertypes": [
+ 					      "aChildNodeType"
+ 					    ]
+					}
+			}
+		};
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+		var ntBase = ntManager.getNodeType("nt:base");
+		var ntResidualChild = ntManager.getNodeType("ntResidualChild");
+		
+		describe('if the name is valid', function() {
+			it('for residual node names', function() {
+				expect(ntManager.getNodeType("ntResidualChild").canAddChildNode("childNodeDefName", ntBase)).toBe(true);
+			});
+			it('for non residual node names', function() {
+				expect(ntManager.getNodeType("ntNonResidualChild").canAddChildNode("aChildNodeDef1", ntBase)).toBe(true);
+				expect(ntManager.getNodeType("ntNonResidualChild").canAddChildNode("aChildNodeDefA", ntBase)).toBe(false);
+			});
+		});
+		it('if the destination is not protected', function() {
+			expect(ntManager.getNodeType("ntNonResidualProtectedChild").canAddChildNode("aChildNodeDef2", ntResidualChild)).toBe(false);
+		});
+		describe('if the type is valid', function() {
+			it('for direct types', function() {
+				var otherNodeType = ntManager.getNodeType("otherNodeType");
+				expect(ntManager.getNodeType("ntWithOtherChildNode").canAddChildNode("otherNodeType", otherNodeType)).toBe(true);
+				expect(ntManager.getNodeType("ntWithOtherChildNode").canAddChildNode("otherNodeType", ntBase)).toBe(false);
+			});
+			it('for an inherited type', function() {
+				var inheritedNodeType = ntManager.getNodeType("inheritedNodeType");
+				expect(ntManager.getNodeType("ntWithOtherChildNode").canAddChildNode("inheritedNodeType", inheritedNodeType)).toBe(true);
+				expect(ntManager.getNodeType("ntWithOtherChildNode").canAddChildNode("inheritedNodeType", ntBase)).toBe(false);
+			});
+			it('for subtype', function() {
+				var aChildNodeType = ntManager.getNodeType("aChildNodeType");
+				var aChildNodesSubtype = ntManager.getNodeType("aChildNodesSubtype");
+				expect(ntManager.getNodeType("aNodeType").canAddChildNode("aNodeName", aChildNodeType)).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddChildNode("aNodeName", aChildNodesSubtype)).toBe(true);
+			});
+		});
+	});
+
+	describe('checks in canAddProperty()', function () {
+
+		var settings = {
+				"defaultNTJsonURL": defaultNTJsonURL,
+				"nodeTypesJson" : {
+					"nt:base" : {
+					},
+					"aParentNodeType" : {
+						"declaredPropertyDefinitions" : [{
+							"name" : "propertyDef6",
+						    "requiredType": "Date"
+						},{
+							"name" : "propertyDef4",
+						    "requiredType": "Date",
+						    "protected": true
+						},{
+							"name" : "propertyDef5",
+						    "requiredType": "String"
+						},{
+							"name" : "*",
+						    "requiredType": "String"
+						},{
+							"name" : "propertyDef2",
+					        "requiredType": "undefined"
+						}]
+					},		
+					"aNodeType" : {
+						"declaredSupertypes" : [ "aParentNodeType" ],
+						"declaredPropertyDefinitions" : [{
+							"name" : "propertyDef1",
+				        	"requiredType": "String"
+						}]
+					}
+				}
+		};
+		
+		var ntManager = new org.apache.sling.jcr.js.nodetypes.NodeTypeManager(settings);
+		
+		describe('if the name and type is applicable', function() {
+			it('for residual property names', function() {
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("aPropertyDef", "String")).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("aPropertyDef", "Binary")).toBe(false);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("aPropertyDef", "Date")).toBe(false);
+			});
+			it('for undefined property types', function() {
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef2", "Binary")).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef2", "Date")).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef2", "String")).toBe(true);
+			});
+			it('for non residual property names', function() {
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef1", "String")).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef1", "Binary")).toBe(false);
+			});
+			it('for properties of super types', function() {
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef5", "String")).toBe(true);
+				expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef5", "Binary")).toBe(false);
+			});
+		});
+		it('if the type is case insensitive', function() {
+			expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef1", "stRING")).toBe(true);
+		});
+		it('if the name and type is not applicable for protected properties', function() {
+			expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef4", "Date")).toBe(false);
+		});
+		it('that residual property definitions are not applicable for non residual property types', function() {
+			expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef6", "Date")).toBe(true);
+			expect(ntManager.getNodeType("aNodeType").canAddProperty("propertyDef6", "String")).toBe(false);
+		});
+	});
+	
+	function sameArrayContent(array1, array2){
+		expect(array1.length).toBe(array2.length); 
+		for (var i=0; i<array2.length; i++){
+			if (typeof array2[i] !== "undefined") {
+				expect(array1).toContain(array2[i]);
+			}
+		}
+	}
+
+});
diff --git a/src/test/resources/applicableChildNodeTypesDatastructure.jpg b/src/test/resources/applicableChildNodeTypesDatastructure.jpg
new file mode 100644
index 0000000..b5b29ef
--- /dev/null
+++ b/src/test/resources/applicableChildNodeTypesDatastructure.jpg
Binary files differ
diff --git a/src/test/resources/expectedNTJSON/testCompleteBinaryPropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteBinaryPropertyDefinition.json
new file mode 100644
index 0000000..c8fc00c
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteBinaryPropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "binary": "/ntName/stringPropertyDef/Binary/true/true/true/true/VERSION/0.default_binary_value.bin",
+            "type": "Binary"
+          }
+        ],
+        "requiredType": "Binary",
+        "valueConstraints": [
+          "[,1024]"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "stringPropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteBooleanPropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteBooleanPropertyDefinition.json
new file mode 100644
index 0000000..5fbeb74
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteBooleanPropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "boolean": true,
+            "type": "Boolean"
+          }
+        ],
+        "requiredType": "Boolean",
+        "valueConstraints": [
+          "true"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "booleanPropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteChildNodeDefinitions.json b/src/test/resources/expectedNTJSON/testCompleteChildNodeDefinitions.json
new file mode 100644
index 0000000..b736d9a
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteChildNodeDefinitions.json
@@ -0,0 +1,32 @@
+{
+  "ntWithChildNodeDefs": {
+    "declaredChildNodeDefinitions": [
+      {
+        "allowsSameNameSiblings": true,
+        "defaultPrimaryType": "requiredPrimaryType1",
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "childNodeDef1"
+      },
+      {
+        "allowsSameNameSiblings": true,
+        "defaultPrimaryType": "requiredPrimaryType1",
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "childNodeDef2"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteDatePropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteDatePropertyDefinition.json
new file mode 100644
index 0000000..05dbf98
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteDatePropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "date": "2012-02-01T00:00:00.000+01:00",
+            "type": "Date"
+          }
+        ],
+        "requiredType": "Date",
+        "valueConstraints": [
+          "2012-04-01T00:00:00Z"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "datePropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteDoublePropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteDoublePropertyDefinition.json
new file mode 100644
index 0000000..e660208
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteDoublePropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "double": 2.2,
+            "type": "Double"
+          }
+        ],
+        "requiredType": "Double",
+        "valueConstraints": [
+          "[,5]"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "doublePropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteLongPropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteLongPropertyDefinition.json
new file mode 100644
index 0000000..f9cd723
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteLongPropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "long": 2,
+            "type": "Long"
+          }
+        ],
+        "requiredType": "Long",
+        "valueConstraints": [
+          "[,55]"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "longPropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteNamePropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteNamePropertyDefinition.json
new file mode 100644
index 0000000..c3b8c9f
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteNamePropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "name": "myapp:myName",
+            "type": "Name"
+          }
+        ],
+        "requiredType": "Name",
+        "valueConstraints": [
+          "myapp:myName"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "namePropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteNodeTypes.json b/src/test/resources/expectedNTJSON/testCompleteNodeTypes.json
new file mode 100644
index 0000000..de2730a
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteNodeTypes.json
@@ -0,0 +1,56 @@
+{
+  "testNodeType": {
+    "declaredSupertypes": [
+      "superType1",
+      "superType2",
+      "superType3"
+    ],
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "string": "Default-String",
+            "type": "String"
+          }
+        ],
+        "valueConstraints": [
+          ".*"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "stringPropertyDef"
+      }
+    ],
+    "declaredChildNodeDefinitions": [
+      {
+        "allowsSameNameSiblings": true,
+        "defaultPrimaryType": "requiredPrimaryType1",
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "childNodeDef1"
+      },
+      {
+        "allowsSameNameSiblings": true,
+        "defaultPrimaryType": "requiredPrimaryType1",
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "childNodeDef2"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompletePathPropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompletePathPropertyDefinition.json
new file mode 100644
index 0000000..8ea913b
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompletePathPropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "path": "/myapp:myName/myapp:myChildNode/aSubChildNode",
+            "type": "Path"
+          }
+        ],
+        "requiredType": "Path",
+        "valueConstraints": [
+          "/myapp:myName/myapp:myChildNode/*"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "pathPropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteReferencePropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteReferencePropertyDefinition.json
new file mode 100644
index 0000000..6f9743d
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteReferencePropertyDefinition.json
@@ -0,0 +1,24 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "reference": "nt:unstructured",
+            "type": "Reference"
+          }
+        ],
+        "requiredType": "Reference",
+        "valueConstraints": [
+          "nt:unstructured"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "referencePropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testCompleteStringPropertyDefinition.json b/src/test/resources/expectedNTJSON/testCompleteStringPropertyDefinition.json
new file mode 100644
index 0000000..79a1ab2
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testCompleteStringPropertyDefinition.json
@@ -0,0 +1,23 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "string": "Default-String",
+            "type": "String"
+          }
+        ],
+        "valueConstraints": [
+          ".*"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "stringPropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithServlet.json b/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithServlet.json
new file mode 100644
index 0000000..49ba8b7
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithServlet.json
@@ -0,0 +1,12 @@
+{
+  "testNodeType": {
+    "declaredPropertyDefinitions": [{
+        "name": "stringPropertyDef"
+      }
+    ],
+    "declaredChildNodeDefinitions": [{
+        "name": "childNodeDef"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithoutServlet.json b/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithoutServlet.json
new file mode 100644
index 0000000..559d056
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testIfDefaultsAreOmittedWithoutServlet.json
@@ -0,0 +1,8 @@
+{
+  "declaredPropertyDefinitions": [
+    {}
+  ],
+  "declaredChildNodeDefinitions": [
+    {}
+  ]
+}
\ No newline at end of file
diff --git a/src/test/resources/expectedNTJSON/testMultipleConstraints.json b/src/test/resources/expectedNTJSON/testMultipleConstraints.json
new file mode 100644
index 0000000..cb4e1fe
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testMultipleConstraints.json
@@ -0,0 +1,18 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "valueConstraints": [
+          "banana",
+          "apple"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "stringProp"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testMultipleDefaultValues.json b/src/test/resources/expectedNTJSON/testMultipleDefaultValues.json
new file mode 100644
index 0000000..f7fc45d
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testMultipleDefaultValues.json
@@ -0,0 +1,27 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "string": "Default-String",
+            "type": "String"
+          },
+          {
+            "string": "Default-String2",
+            "type": "String"
+          }
+        ],
+        "valueConstraints": [
+          ".*"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "stringProp"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testNodeTypeWithEmptyName.json b/src/test/resources/expectedNTJSON/testNodeTypeWithEmptyName.json
new file mode 100644
index 0000000..870a4bf
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testNodeTypeWithEmptyName.json
@@ -0,0 +1,4 @@
+{
+  "testNodeType1": {
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testOneSimpleChildNodeDefinition.json b/src/test/resources/expectedNTJSON/testOneSimpleChildNodeDefinition.json
new file mode 100644
index 0000000..7da8627
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testOneSimpleChildNodeDefinition.json
@@ -0,0 +1,13 @@
+{
+  "ntWithChildNodeDefs": {
+    "declaredChildNodeDefinitions": [
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "childNodeDef1"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testOneSimpleNodeType.json b/src/test/resources/expectedNTJSON/testOneSimpleNodeType.json
new file mode 100644
index 0000000..719905d
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testOneSimpleNodeType.json
@@ -0,0 +1,4 @@
+{
+  "testNodeType": {
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testOneSimplePropertyDefinition.json b/src/test/resources/expectedNTJSON/testOneSimplePropertyDefinition.json
new file mode 100644
index 0000000..15c2eb4
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testOneSimplePropertyDefinition.json
@@ -0,0 +1,10 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "requiredType": "undefined",
+        "name": "simplePropertyDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testResidualChildNodeDefinitions.json b/src/test/resources/expectedNTJSON/testResidualChildNodeDefinitions.json
new file mode 100644
index 0000000..a37b214
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testResidualChildNodeDefinitions.json
@@ -0,0 +1,27 @@
+{
+  "ntWithChildNodeDefs": {
+    "declaredChildNodeDefinitions": [
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "*"
+      },
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "*"
+      },
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "childNodeDef"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testSimpleChildNodeDefinitions.json b/src/test/resources/expectedNTJSON/testSimpleChildNodeDefinitions.json
new file mode 100644
index 0000000..dc7ca9e
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testSimpleChildNodeDefinitions.json
@@ -0,0 +1,20 @@
+{
+  "ntWithChildNodeDefs": {
+    "declaredChildNodeDefinitions": [
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "childNodeDef1"
+      },
+      {
+        "requiredPrimaryTypes": [
+          "requiredPrimaryType1",
+          "requiredPrimaryType2"
+        ],
+        "name": "childNodeDef2"
+      }
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testSimpleNodeTypes.json b/src/test/resources/expectedNTJSON/testSimpleNodeTypes.json
new file mode 100644
index 0000000..0911ac5
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testSimpleNodeTypes.json
@@ -0,0 +1,6 @@
+{
+  "testNodeType2": {
+  },
+  "testNodeType1": {
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testSupertypeList.json b/src/test/resources/expectedNTJSON/testSupertypeList.json
new file mode 100644
index 0000000..beea378
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testSupertypeList.json
@@ -0,0 +1,9 @@
+{
+  "testNodeType": {
+    "declaredSupertypes": [
+      "superType1",
+      "superType2",
+      "superType3"
+    ]
+  }
+}
diff --git a/src/test/resources/expectedNTJSON/testTwoResidualPropertyDefinitions.json b/src/test/resources/expectedNTJSON/testTwoResidualPropertyDefinitions.json
new file mode 100644
index 0000000..4854e55
--- /dev/null
+++ b/src/test/resources/expectedNTJSON/testTwoResidualPropertyDefinitions.json
@@ -0,0 +1,41 @@
+{
+  "ntWithPropertyDefs": {
+    "declaredPropertyDefinitions": [
+      {
+        "defaultValues": [
+          {
+            "string": "Default-String",
+            "type": "String"
+          }
+        ],
+        "valueConstraints": [
+          ".*"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "*"
+      },
+      {
+        "defaultValues": [
+          {
+            "date": "2012-02-01T00:00:00.000+01:00",
+            "type": "Date"
+          }
+        ],
+        "requiredType": "Date",
+        "valueConstraints": [
+          "2012-04-01T00:00:00Z"
+        ],
+        "multiple": true,
+        "autoCreated": true,
+        "mandatory": true,
+        "protected": true,
+        "onParentVersion": "VERSION",
+        "name": "*"
+      }
+    ]
+  }
+}