SLING-4513 - import donated HApi tools

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1697419 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..518c151
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+target/
+.project
+.classpath
+.settings/
+/sling/
+derby.log
+*.iml
+*.ipr
+*.iws
+coverage.em
+coverage.ec
+coverage/
+.DS_Store
+.idea/
+bundles/extensions/models/integration-tests/sling
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..59d7fb5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~ 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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>20</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.hapi</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>HApi - Sling Hypermedia API tools</name>
+    <description>Sling tools for adding support for defining, maintaining and consuming a Hypermedia API in sling components</description>
+
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>maven-sling-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Category>sling</Bundle-Category>
+                        <Sling-Initial-Content>SLING-INF;overwrite=true</Sling-Initial-Content>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.3.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.api</artifactId>
+            <version>2.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>1.9.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.scripting.sightly</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/src/main/java/org/apache/sling/hapi/HApiException.java b/src/main/java/org/apache/sling/hapi/HApiException.java
new file mode 100644
index 0000000..b9922e0
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/HApiException.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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.hapi;
+
+/**
+ * A Hypermedia API exception
+ */
+public class HApiException extends RuntimeException {
+    public HApiException() {
+    }
+
+    /**
+     *
+     * @param message
+     */
+    public HApiException(String message) {
+        super(message);
+    }
+
+    /**
+     *
+     * @param message
+     * @param cause
+     */
+    public HApiException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     *
+     * @param cause
+     */
+    public HApiException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/src/main/java/org/apache/sling/hapi/HApiProperty.java b/src/main/java/org/apache/sling/hapi/HApiProperty.java
new file mode 100644
index 0000000..7cbe6a2
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/HApiProperty.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.hapi;
+
+/**
+ * A Hypermedia API property for a {@link HApiType}
+ */
+public interface HApiProperty {
+
+    /**
+     * Get the name of this property
+     * @return
+     */
+    String getName();
+
+    /**
+     * Set the name of this property
+     * @param name
+     */
+    void setName(String name);
+
+    /**
+     * Get the description of this property
+     * @return
+     */
+    String getDescription();
+
+    /**
+     * Set the description of this property
+     * @return
+     */
+    void setDescription(String description);
+
+    /**
+     * Get the type of this property
+     * @return
+     */
+    HApiType getType();
+
+    /**
+     * Set the type of this property
+     * @return
+     */
+    void setType(HApiType type);
+
+    /**
+     * Whether this property is a multiple value
+     * @return
+     */
+    Boolean getMultiple();
+
+    /**
+     * Set the boolean value for multiple
+     * @param multiple
+     */
+    void setMultiple(Boolean multiple);
+}
diff --git a/src/main/java/org/apache/sling/hapi/HApiType.java b/src/main/java/org/apache/sling/hapi/HApiType.java
new file mode 100644
index 0000000..e562187
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/HApiType.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.hapi;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A Hypermedia API type.
+ */
+public interface HApiType {
+
+    /**
+     * The name of this type
+     * @return
+     */
+    String getName();
+
+
+    /**
+     * The description of this type
+     * @return
+     */
+    String getDescription();
+
+    /**
+     * The JCR path of the node representing this type
+     * @return
+     */
+    String getPath();
+
+    /**
+     * The URL of the node representing this type
+     * @return
+     */
+    String getUrl();
+
+    /**
+     * The fully qualified domain name of this type
+     * @return
+     */
+    String getFqdn();
+
+    /**
+     * A list of {@link String} representing java-like generic types that can be used as types for the properties belonging to this type
+     * @return
+     */
+    List<String> getParameters();
+
+    /**
+     * A map with the names of the properties as keys and the HApiProperty object as values defined for this type
+     * <p>This list does not include properties inherited from the parent type</p>
+     * @return
+     */
+    Map<String, HApiProperty> getProperties();
+
+    /**
+     * A map with the names of the properties as keys and the HApiProperty object as values defined for this type,
+     * including the properties inherited from the parent type
+     * @return
+     */
+    Map<String, HApiProperty> getAllProperties();
+
+    /**
+     * Returns the parent type object
+     * @return
+     */
+    HApiType getParent();
+
+    /**
+     * Whether this type is abstract or not.
+     * An abstract type is an identifier that does not map to a jcr node as a path or as a FQDN
+     * @return
+     */
+    boolean isAbstract();
+}
diff --git a/src/main/java/org/apache/sling/hapi/HApiUse.java b/src/main/java/org/apache/sling/hapi/HApiUse.java
new file mode 100644
index 0000000..1dfe348
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/HApiUse.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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.hapi;
+
+import org.apache.sling.scripting.sightly.pojo.Use;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.Bindings;
+import java.util.Map;
+
+/**
+ * Sightly use class helper to provide the hypermedia API microdata attributes for the type configured throught the 'type' binding.
+ * <p>The type can be a JCR path or a fully qualified domain name like in
+ * {@link HApiUtil#getTypeNode(org.apache.sling.api.resource.ResourceResolver, String)}</p>
+ * <p>The convenience get methods are meant to be used in the 'data-sly-attribute' in the sightly script.</p>
+ */
+public class HApiUse implements Use {
+    private static final Logger LOG = LoggerFactory.getLogger(HApiUse.class);
+
+    private HApiUtil hapi;
+    private MicrodataAttributeHelper helper;
+    private SlingHttpServletRequest request;
+    private SlingScriptHelper sling;
+    private Resource resource;
+    private ResourceResolver resourceResolver;
+    private String typeId;
+    private Map<String, String> itemTypeAttr;
+    private Map<String, Map<String, String>> itemPropAttrs;
+    private Map<String, String> itemPropTypes;
+
+    /**
+     * {@inheritDoc}
+     * @param bindings
+     */
+    public void init(Bindings bindings) {
+        request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+        sling = (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+        resource = (Resource)bindings.get(SlingBindings.RESOURCE);
+        resourceResolver = request.getResourceResolver();
+        typeId = (String) bindings.get("type");
+        LOG.debug("init type: {}", typeId);
+
+        try {
+            activate();
+        } catch (Exception e) {
+            LOG.error("Failed to activate Use class", e);
+        }
+    }
+
+    /**
+     * Initializes the helper and the attribute maps for the given type though the bindings
+     * @throws Exception
+     */
+    public void activate() throws Exception {
+        hapi = sling.getService(HApiUtil.class);
+        helper = hapi.getHelper(resourceResolver, typeId);
+        itemTypeAttr = helper.itemtypeMap();
+        itemPropAttrs = helper.allItemPropMap();
+        itemPropTypes = helper.allPropTypesMap();
+    }
+
+    /**
+     * Get the itemtype html attributes map for the type
+     * @return
+     */
+    public Map<String, String> getItemtype() {
+        LOG.debug("itemtype attrs: {}", itemTypeAttr);
+        return itemTypeAttr;
+    }
+
+    /**
+     * Get the itemprop attributes map for the type, for each property.
+     * The key is the property name and the value is a map of html attributes for the property
+     * @return
+     */
+    public Map<String, Map<String, String>> getItemprop() {
+        LOG.debug("itemprop attrs: {}", itemPropAttrs);
+        return itemPropAttrs;
+    }
+
+    /**
+     * Get a map of the type for each property name of the type
+     * The key is the property name and the value is the type path in JCR
+     * @return
+     */
+    public Map<String, String> getProptype() {
+        LOG.debug("property type attrs: {}", itemPropTypes);
+        return itemPropTypes;
+    }
+}
diff --git a/src/main/java/org/apache/sling/hapi/HApiUtil.java b/src/main/java/org/apache/sling/hapi/HApiUtil.java
new file mode 100644
index 0000000..c262b74
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/HApiUtil.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.hapi;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+public interface HApiUtil {
+    public static final Logger LOG = LoggerFactory.getLogger(HApiUtil.class);
+
+    public static final String DEFAULT_RESOURCE_TYPE = "sling/hapi/components/type";
+
+    /**
+     * <p>Get a HApi type object from a type identifier.</p>
+     * <p>The JCR node must be [nt:unstructured], a descendant of any of the HAPi search path defined by the
+     * {@see HAPI_PATHS} config and the sling:resourceType should be set to the value defined by the {@see HAPI_RESOURCE_TYPE} config</p>
+     * <p>The first result is returned</p>
+     * @param resolver The sling resource resolver object
+     * @param type The type identifier, which is either in the form of a jcr path,
+     *             same as the path for {@link: ResourceResolver#getResource(String)}. If the path cannot be resolved, type is treated like
+     *             a fully qualified domain name, which has to match the "fqdn" property on the JCR node which represents the type.
+     * @return The first node that matches that type or null if none is found.
+     * @throws RepositoryException
+     */
+    public Node getTypeNode(ResourceResolver resolver, String type) throws RepositoryException;
+
+
+    /**
+     * <p>Get a HApi type object from a type identifier.</p>
+     * <p>The type identifier is resolved to a {@link javax.jcr.Node} and then
+     * {@link #fromNode(org.apache.sling.api.resource.ResourceResolver, javax.jcr.Node)} is called.</p>
+     * <p>For restrictions on the {@link javax.jcr.Node}
+     * see {@link HApiUtil#getTypeNode(org.apache.sling.api.resource.ResourceResolver, String)}</p>
+     * @param resolver The sling resource resolver object
+     * @param type The type identifier, which is either in the form of a jcr path,
+     *             same as the path for{@link: ResourceResolver#getResource(String)}. If the path cannot be resolved, type is treated like
+     *             a fully qualified domain name, which has to match the "fqdn" property on the JCR node which represents the type.
+     * @return The HApiType resolved from the type identifier
+     * @throws javax.jcr.RepositoryException
+     */
+    public HApiType fromPath(ResourceResolver resolver, String type) throws RepositoryException;
+
+    /**
+     * <p>Get a HApi type object from the {@link javax.jcr.Node}.</p>
+     * The Node has the following properties:
+     * <ul>
+     *     <li>name: A 'Name' of the type (mandatory)</li>
+     *     <li>description: A 'String' with the description text for this type (mandatory)</li>
+     *     <li>fqdn: A 'String' with the fully qualified domain name; A namespace like a java package (mandatory)</li>
+     *     <li>extends: A type identifier (either a path or a fqdn); (optional). This defines the parent type of this type</li>
+     *     <li>parameter: A multivalue property to define a list of java-like generic types
+     *     that can be used as types for properties; (optional)</li>
+     * </ul>
+     *
+     * <p>The properties of this type are defined as children nodes.</p>
+     * <p>The name of property node defines the name of the property for this type. </p>
+     * The children property nodes have the following properties:
+     * <ul>
+     *     <li>type: The type identifier (mandatory). Can be of type 'Name' or 'Path'
+     *      See {@link HApiUtil#getTypeNode(org.apache.sling.api.resource.ResourceResolver, String)}
+     *      for the format of this value</li>
+     *     <li>description: A 'String' with the description for this property (mandatory)</li>
+     *     <li>multiple: A 'Boolean' that defines whether this property can exist multiple times on an object of this type (optional)</li>
+     * </ul>
+     *
+     * @param resolver The resource resolver
+     * @param typeNode The jcr node of the HApi type
+     * @return The HApiType
+     * @throws RepositoryException
+     */
+    public HApiType fromNode(ResourceResolver resolver, Node typeNode) throws RepositoryException;
+
+    /**
+     * Get a new instance of AttributeHelper for the type identified by 'type'
+     * @param resolver
+     * @param type See {@link #getTypeNode(org.apache.sling.api.resource.ResourceResolver, String)}
+     *             for the format of the type identifier
+     * @return
+     * @throws RepositoryException
+     */
+    public MicrodataAttributeHelper getHelper(ResourceResolver resolver, String type) throws RepositoryException;
+}
diff --git a/src/main/java/org/apache/sling/hapi/MicrodataAttributeHelper.java b/src/main/java/org/apache/sling/hapi/MicrodataAttributeHelper.java
new file mode 100644
index 0000000..c52f068
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/MicrodataAttributeHelper.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.hapi;
+
+import org.apache.sling.api.resource.ResourceResolver;
+
+import java.util.Map;
+
+public interface MicrodataAttributeHelper {
+
+    /**
+     * Calls {@link #itemtypeMap()} and normalizes the map into a String of the form 'attr1="val1" attr2="val2"'
+     * @return
+     */
+    String itemtype();
+
+    /**
+     * Get a map with the HTMl attributes for a new item of the type defined through
+     * a new {@link MicrodataAttributeHelper} object
+     * <p>The key is the HTMl attribute name and the value is the HTML attribute value</p>
+     * @return
+     */
+    Map<String, String> itemtypeMap();
+
+    /**
+     * Calls {@link #itemprop(String, boolean)} with 'withType' true
+     * @param propName
+     * @return
+     */
+    String itemprop(String propName);
+
+    /**
+     * Calls {@link #itempropMap(String, boolean)} and normalizes the map into a String of the form 'attr1="val1" attr2="val2"'
+     * @param propName
+     * @param withType
+     * @return
+     */
+    String itemprop(String propName, boolean withType);
+
+    /**
+     * Get a map with the HTMl attributes for the given property of the type defined through
+     * a new {@link MicrodataAttributeHelper}
+     * <p>The key is the HTMl attribute name and the value is the HTML attribute value</p>
+     * <p> Will through a {@link HApiException}
+     * runtime exception if the property propName does not exist for the type</p>
+     * @param propName the name of the property
+     * @param withType whether to include the 'itemtype' attribute
+     * @return
+     */
+    Map<String, String> itempropMap(String propName, boolean withType);
+
+    /**
+     *  Get a map of maps with the HTMl attributes for each property of the type defined through
+     *  a new {@link MicrodataAttributeHelper}
+     *  <p>The key is the property name and the value is a map of attributes like the one returned
+     *  by {@link #itempropMap(String, boolean)}</p>
+     * @return
+     */
+    Map<String, Map<String, String>> allItemPropMap();
+
+    /**
+     * Get a map of types for each type property.
+     * <p> The key is the property name and the value is the type path identifier of that property</p>
+     * @return
+     */
+    Map<String, String> allPropTypesMap();
+}
diff --git a/src/main/java/org/apache/sling/hapi/TypeView.java b/src/main/java/org/apache/sling/hapi/TypeView.java
new file mode 100644
index 0000000..3fb0d33
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/TypeView.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * 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.hapi;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.scripting.sightly.pojo.Use;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.Bindings;
+import java.util.*;
+
+public class TypeView implements Use {
+    private static final Logger LOG = LoggerFactory.getLogger(TypeView.class);
+
+    private HApiUtil hapi;
+    private HApiType me;
+    private HApiType parent;
+
+    private String description;
+    private SlingHttpServletRequest request;
+    private SlingScriptHelper sling;
+    private Resource resource;
+    private ResourceResolver resourceResolver;
+
+    public void init(Bindings bindings) {
+        request = (SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
+        sling =   (SlingScriptHelper) bindings.get(SlingBindings.SLING);
+        resource = (Resource)bindings.get(SlingBindings.RESOURCE);
+        resourceResolver = request.getResourceResolver();
+
+        try {
+            activate();
+        } catch (Exception e) {
+            LOG.error("Failed to activate Use class", e);
+        }
+    }
+
+    public void activate() throws Exception {
+        hapi = sling.getService(HApiUtil.class);
+        me = hapi.fromPath(resourceResolver, resource.getPath());
+        LOG.debug("me: {}  resource: {}", me, resource.getPath());
+        description = me.getDescription();
+        parent = me.getParent();
+    }
+
+    public String getTitle() {
+        return me.getFqdn();
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getParentUrl() {
+        if (null != parent) {
+            return parent.getUrl();
+        } else {
+            return null;
+        }
+    }
+
+    public String getParentFqdn() {
+        if (null != parent) {
+            return parent.getFqdn();
+        } else {
+            return null;
+        }
+    }
+
+    public List<String> getParameters() {
+        return me.getParameters();
+    }
+
+    public List<HApiProperty> getProps() {
+        List<HApiProperty> props = new ArrayList<HApiProperty>(me.getAllProperties().values());
+        LOG.debug("props: ", props);
+        return props;
+    }
+
+    public boolean getHasProps() {
+        return getProps().size() > 0;
+    }
+}
diff --git a/src/main/java/org/apache/sling/hapi/impl/AbstractHapiTypeImpl.java b/src/main/java/org/apache/sling/hapi/impl/AbstractHapiTypeImpl.java
new file mode 100644
index 0000000..6469522
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/AbstractHapiTypeImpl.java
@@ -0,0 +1,86 @@
+/*************************************************************************
+ *
+ * ADOBE CONFIDENTIAL
+ * __________________
+ *
+ *  Copyright 2014 Adobe Systems Incorporated
+ *  All Rights Reserved.
+ *
+ * NOTICE:  All information contained herein is, and remains
+ * the property of Adobe Systems Incorporated and its suppliers,
+ * if any.  The intellectual and technical concepts contained
+ * herein are proprietary to Adobe Systems Incorporated and its
+ * suppliers and may be covered by U.S. and Foreign Patents,
+ * patents in process, and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * from Adobe Systems Incorporated.
+ **************************************************************************/
+package org.apache.sling.hapi.impl;
+
+import org.apache.sling.hapi.HApiProperty;
+import org.apache.sling.hapi.HApiType;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AbstractHapiTypeImpl implements HApiType {
+
+    public static final String ABSTRACT = "Abstract";
+    private final String name;
+
+    public AbstractHapiTypeImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return ABSTRACT;
+    }
+
+    @Override
+    public String getPath() {
+        return null;
+    }
+
+    @Override
+    public String getUrl() {
+        return null;
+    }
+
+    @Override
+    public String getFqdn() {
+        return null;
+    }
+
+    @Override
+    public List<String> getParameters() {
+        return null;
+    }
+
+    @Override
+    public Map<String, HApiProperty> getProperties() {
+        return new HashMap<String, HApiProperty>();
+    }
+
+    @Override
+    public Map<String, HApiProperty> getAllProperties() {
+        return getProperties();
+    }
+
+    @Override
+    public HApiType getParent() {
+        return null;
+    }
+
+    @Override
+    public boolean isAbstract() {
+        return true;
+    }
+}
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiPropertyImpl.java b/src/main/java/org/apache/sling/hapi/impl/HApiPropertyImpl.java
new file mode 100644
index 0000000..cb3a280
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiPropertyImpl.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * 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.hapi.impl;
+
+import org.apache.sling.hapi.HApiType;
+import org.apache.sling.hapi.HApiProperty;
+
+/**
+ * {@inheritDoc}
+ */
+public class HApiPropertyImpl implements HApiProperty {
+    private String name;
+    private String description;
+    private HApiType type;
+    private Boolean multiple;
+
+    /**
+     *
+     * @param name
+     * @param description
+     * @param type
+     * @param multiple
+     */
+    public HApiPropertyImpl(String name, String description, HApiType type, Boolean multiple) {
+        this.name = name;
+        this.description = description;
+        this.type = type;
+        this.multiple = multiple;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HApiType getType() {
+        return type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setType(HApiType type) {
+        this.type = type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Boolean getMultiple() {
+        return multiple;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMultiple(Boolean multiple) {
+        this.multiple = multiple;
+    }
+
+    @Override
+    public String toString() {
+        return "HApiProperty{" +
+                "name='" + name + '\'' +
+                ", description='" + description + '\'' +
+                ", type=" + type +
+                ", multiple=" + multiple +
+                '}';
+    }
+}
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java b/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java
new file mode 100644
index 0000000..faa6e1e
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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.hapi.impl;
+
+import org.apache.sling.hapi.HApiProperty;
+import org.apache.sling.hapi.HApiType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.*;
+
+/**
+ * {@inheritDoc}
+ */
+public class HApiTypeImpl implements HApiType {
+
+    public static final Logger LOG = LoggerFactory.getLogger(HApiTypeImpl.class);
+
+    private final HApiType parent;
+
+    private String name;
+
+    private String description;
+    private String path;
+    private String fqdn;
+    private List<String> parameters;
+    private Map<String, HApiProperty> properties;
+    private boolean isAbstract;
+
+    /**
+     * A new HApiType
+     * @param name
+     * @param description
+     * @param path
+     * @param fqdn
+     * @param parameters
+     * @param properties
+     * @param parent
+     */
+    public HApiTypeImpl(String name, String description, String path, String fqdn, List<String> parameters, Map<String,
+            HApiProperty> properties, HApiType parent, boolean isAbstract) {
+        this.name = name;
+        this.description = description;
+        this.path = path;
+        this.fqdn = fqdn;
+        this.parameters = parameters;
+        this.properties = properties;
+        this.parent = parent;
+        this.isAbstract = isAbstract;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getUrl() {
+        return getPath() + ".html";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getFqdn() {
+        return fqdn;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getParameters() {
+        return parameters;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, HApiProperty> getProperties() {
+        return properties;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, HApiProperty> getAllProperties() {
+        Map<String, HApiProperty> allProps = new HashMap<String, HApiProperty>();
+        LOG.debug("parent: {}", parent);
+        if (null != parent) {
+            Map<String, HApiProperty> parentProps = parent.getAllProperties();
+            LOG.debug("parent props: {}", parentProps);
+            allProps.putAll(parentProps);
+        }
+        allProps.putAll(getProperties());
+        return allProps;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HApiType getParent() {
+        return parent;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAbstract() {
+        return isAbstract;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java b/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java
new file mode 100644
index 0000000..a8f3d51
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * 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.hapi.impl;
+
+import org.apache.sling.hapi.HApiProperty;
+import org.apache.sling.hapi.HApiType;
+import org.apache.sling.hapi.MicrodataAttributeHelper;
+import org.apache.sling.hapi.HApiUtil;
+import org.apache.felix.scr.annotations.*;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.*;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import java.util.*;
+
+
+@Component(label = "Apache Sling Hypermedia API tools", metatype = true)
+@Service()
+
+public class HApiUtilImpl implements HApiUtil {
+
+    @Property(label = "HApi Resource Type", cardinality = 0, value = DEFAULT_RESOURCE_TYPE)
+    public static final String HAPI_RESOURCE_TYPE = "org.apache.sling.hapi.tools.resourcetype";
+
+
+    @Property(label = "HApi Types Search Paths", cardinality=50, value = {"/libs/sling/hapi/types"})
+    public static final String HAPI_PATHS = "org.apache.sling.hapi.tools.searchpaths";
+
+    public static String resourceType;
+    public static String[] hApiPaths;
+
+
+    @Activate
+    private void activate(ComponentContext context, Map<String, Object> configuration) {
+        resourceType = PropertiesUtil.toString(configuration.get(HAPI_RESOURCE_TYPE), DEFAULT_RESOURCE_TYPE);
+        hApiPaths = PropertiesUtil.toStringArray(configuration.get(HAPI_PATHS));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Node getTypeNode(ResourceResolver resolver, String type) throws RepositoryException {
+        Session session = resolver.adaptTo(Session.class);
+
+        // Try to resolve the resource as a path
+        Resource res = resolver.getResource(type);
+        if (null != res) {
+            LOG.debug("res = " + res.getName() + " " + res.getPath());
+            return res.adaptTo(Node.class);
+        } else {
+            for (String path : new HashSet<String>(Arrays.asList(hApiPaths))) {
+                // Remove trailing slash from path
+                path = (path.endsWith("/")) ? path.substring(0,path.length() - 1) : path;
+
+                // Get the query manager for the session
+                QueryManager queryManager = session.getWorkspace().getQueryManager();
+
+                // Build query for the search paths
+                StringBuilder queryString = new StringBuilder("SELECT * FROM [nt:unstructured] WHERE ");
+                queryString.append(String.format("ISDESCENDANTNODE([%s]) ", path));
+                queryString.append(String.format("AND [sling:resourceType]='%s' AND fqdn = '%s'", resourceType, type));
+
+                // Execute query
+                Query query = queryManager.createQuery(queryString.toString(), Query.JCR_SQL2);
+                LOG.debug("Querying HAPi: {}", queryString.toString());
+                QueryResult result = query.execute();
+
+                NodeIterator nodeIter = result.getNodes();
+                if (nodeIter.hasNext()) {
+                    return nodeIter.nextNode();
+                } else {
+                    // continue
+                }
+            }
+
+            // Type has to be abstract
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public HApiType fromPath(ResourceResolver resolver, String type) throws RepositoryException {
+        Node typeNode = this.getTypeNode(resolver, type);
+        LOG.debug("typeNode=" + typeNode);
+        if (null == typeNode) {
+            return new AbstractHapiTypeImpl(type);
+        } else {
+            return fromNode(resolver, typeNode);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public HApiType fromNode(ResourceResolver resolver, Node typeNode) throws RepositoryException {
+        if (null == typeNode) return null;
+        String name = typeNode.getProperty("name").getValue().getString();
+        String description = typeNode.getProperty("description").getValue().getString();
+        String path = typeNode.getPath();
+        String fqdn = typeNode.getProperty("fqdn").getValue().getString();
+
+        // get parent if it exists
+        HApiType parent = null;
+        String parentPath = typeNode.hasProperty("extends") ? typeNode.getProperty("extends").getString() : null;
+        if (null != parentPath) {
+            parent = this.fromPath(resolver, parentPath);
+        }
+
+        // get parameters
+        Value[] parameterValues = typeNode.hasProperty("parameters") ? typeNode.getProperty("parameters").getValues() : new Value[]{};
+        List<String> parameters = new ArrayList<String>(parameterValues.length);
+
+        for (Value p : Arrays.asList(parameterValues)) {
+            parameters.add(p.getString());
+        }
+
+        // Get properties
+        Map<String, HApiProperty> properties = new HashMap<String, HApiProperty>();
+
+        // Add the properties from this node
+        Iterator<Node> it = typeNode.getNodes();
+        while (it.hasNext()) {
+            Node propNode = it.next();
+            String propName  = propNode.getName();
+            String propDescription = propNode.hasProperty("description") ? propNode.getProperty("description").getString() : "";
+
+            // TODO: maybe create adapter and use adaptTo()
+            // TODO: this could be slow, the types can be instantiated externally in a service activate()
+            String type = propNode.getProperty("type").getValue().getString();
+            HApiType propType = this.fromPath(resolver, type);
+            Boolean propMultiple = propNode.hasProperty("multiple") ? propNode.getProperty("multiple").getBoolean() : false;
+
+            HApiProperty prop = new HApiPropertyImpl(propName, propDescription, propType, propMultiple);
+            properties.put(prop.getName(), prop);
+        }
+        return new HApiTypeImpl(name, description, path, fqdn, parameters, properties, parent, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MicrodataAttributeHelper getHelper(ResourceResolver resolver, String type) throws RepositoryException {
+        return new MicrodataAttributeHelperImpl(resolver, TypesCache.getInstance(this).getType(resolver, type));
+    }
+}
+
+/**
+ * <p>Cache for types</p>
+ *
+ */
+class TypesCache {
+    private static final Logger LOG = LoggerFactory.getLogger(TypesCache.class);
+    Map<String, HApiType> types;
+    private static TypesCache singleton = null;
+    private HApiUtil hApiUtil;
+
+    public static TypesCache getInstance(HApiUtil hApiUtil) {
+        if (null == singleton) {
+            singleton = new TypesCache(hApiUtil);
+        }
+        LOG.debug("singleton: {}", singleton);
+        return singleton;
+    }
+
+    private TypesCache(HApiUtil hApiUtil) {
+        this.types = new HashMap<String, HApiType>();
+        this.hApiUtil = hApiUtil;
+    }
+
+    public HApiType getType(ResourceResolver resolver, String typePath) throws RepositoryException {
+        if (types.containsKey(typePath)) {
+            return this.types.get(typePath);
+        } else {
+
+            HApiType type = hApiUtil.fromPath(resolver, typePath);
+            types.put(type.getPath(), type);
+            return type;
+        }
+    }
+
+    public void addType(HApiType type) {
+        this.types.put(type.getPath(), type);
+    }
+}
+
diff --git a/src/main/java/org/apache/sling/hapi/impl/MicrodataAttributeHelperImpl.java b/src/main/java/org/apache/sling/hapi/impl/MicrodataAttributeHelperImpl.java
new file mode 100644
index 0000000..8b06163
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/MicrodataAttributeHelperImpl.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * 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.hapi.impl;
+
+import org.apache.sling.hapi.HApiProperty;
+import org.apache.sling.hapi.HApiType;
+import org.apache.sling.hapi.MicrodataAttributeHelper;
+import org.apache.sling.hapi.HApiException;
+import org.apache.sling.api.resource.ResourceResolver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Helper class for HTML microdata attributes
+ */
+public class MicrodataAttributeHelperImpl implements MicrodataAttributeHelper {
+    private final ResourceResolver resolver;
+    HApiType type;
+
+    /**
+     * Get a new microdata html attributes helper for the given HApiType object.
+     * <p>Provides convenience methods to get the html attributes needed for instrumenting the markup with a Hypermedia API</p>
+     * @param resolver
+     * @param type
+     */
+    public MicrodataAttributeHelperImpl(ResourceResolver resolver, HApiType type) {
+        this.resolver = resolver;
+        this.type = type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String itemtype() {
+        return itemtypeMap().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> itemtypeMap() {
+        Map<String, String> attrMap = new AttrMap(2);
+        attrMap.put("itemtype", type.getPath() + ".html");
+        attrMap.put("itemscope", !type.getAllProperties().isEmpty());
+        
+        return attrMap;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String itemprop(String propName) {
+        return itemprop(propName, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String itemprop(String propName, boolean withType) {
+        return itempropMap(propName, withType).toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> itempropMap(String propName, boolean withType) {
+        HApiProperty prop = this.type.getAllProperties().get(propName);
+        if (null == prop) throw new HApiException("Property " + propName + " does not exist for type " + type.getPath());
+
+        Map<String, String> attrMap = new AttrMap(3);
+        attrMap.put("itemprop", propName);
+        if (withType) {
+            attrMap.putAll(new MicrodataAttributeHelperImpl(resolver, prop.getType()).itemtypeMap());
+        }
+        return attrMap;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Map<String, String>> allItemPropMap() {
+        Map<String, Map<String, String>> m = new PropMap(type);
+        for (String prop: type.getAllProperties().keySet()) {
+            m.put(prop, itempropMap(prop, true));
+        }
+        return m;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> allPropTypesMap() {
+        Map<String, HApiProperty> props = type.getAllProperties();
+        Map<String, String> types = new HashMap<String, String>(props.size());
+        for (String propName : props.keySet()) {
+            types.put(propName, props.get(propName).getType().getPath());
+        }
+        return types;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private class PropMap extends HashMap<String, Map<String, String>> {
+
+        private final HApiType type;
+
+        public PropMap(HApiType type) {
+            super();
+            this.type = type;
+        }
+
+        @Override
+        public Map<String, String> get(Object key) {
+            Map<String, String> val = super.get(key);
+            if (null == val) {
+                throw new HApiException("Property " + key + " does not exist for type " + type.getPath());
+            }
+            return val;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    private class AttrMap extends HashMap<String, String> {
+
+        public AttrMap(int i) {
+            super(i);
+        }
+
+        public AttrMap() {
+            super();
+        }
+
+        public AttrMap(int initialCapacity, float loadFactor) {
+            super(initialCapacity, loadFactor);
+        }
+
+        @Override
+        public String toString() {
+            String norm = "";
+            for (Map.Entry<String, String> entry : this.entrySet()) {
+                norm += entry.getKey() + "=\"" + entry.getValue() + "\"" + " ";
+            }
+            return norm;
+        }
+    }
+}
+
diff --git a/src/main/java/org/apache/sling/hapi/package-info.java b/src/main/java/org/apache/sling/hapi/package-info.java
new file mode 100644
index 0000000..fcded2d
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/package-info.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+
+@Version("1.0.0")
+package org.apache.sling.hapi;
+
+import aQute.bnd.annotation.Version;
diff --git a/src/main/resources/SLING-INF/libs/sling/hapi/components/type/type.html b/src/main/resources/SLING-INF/libs/sling/hapi/components/type/type.html
new file mode 100644
index 0000000..b24977c
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/sling/hapi/components/type/type.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ 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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+<html data-sly-use.type="org.apache.sling.hapi.TypeView" lang="${type.lang}">
+
+    <head>
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+
+        <!-- Bootstrap -->
+        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
+
+        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
+        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+        <!--[if lt IE 9]>
+          <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+          <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+        <![endif]-->
+
+        <title>${type.title}</title>
+
+    </head>
+    <body>
+        <div class="container">
+
+            <h1>${type.title}</h1>
+            <div>
+                <p>${type.description}</p>
+            </div>
+            <h2 data-sly-test.parentUrl="${type.parentUrl}"> extends
+                <a href="${parentUrl}" >${type.parentFqdn}</a>
+            </h2>
+            <h3 data-sly-test="${type.parameters}">Parameters: </h3>
+                <ul data-sly-list.param="${type.parameters}" title="Parameters" class="list-inline">
+                <li>${param}</li>
+            </ul>
+            <h3>Properties: </h3>
+            <table class="table" data-sly-test.props="${type.props}">
+                <thead>
+                    <tr>
+                        <th>Property</th>
+                        <th>Expected Type</th>
+                        <th>Multiple</th>
+                        <th>Description</th>
+                    </tr>
+                </thead>
+                <tbody data-sly-list.prop="${type.props}">
+                    <tr>
+                        <th>${prop.name}</th>
+                        <td>
+                            <a href="${prop.type.url}">${prop.type.name}</a>
+                        </td>
+                        <td>${prop.multiple}</td>
+                        <td>${prop.description}</td>
+                    </tr>
+                </tbody>
+            </table>
+            <div data-sly-test="${!props}">None</div>
+        </div>
+    </body>
+</html>
diff --git a/src/main/resources/SLING-INF/libs/sling/hapi/types.json b/src/main/resources/SLING-INF/libs/sling/hapi/types.json
new file mode 100644
index 0000000..7984006
--- /dev/null
+++ b/src/main/resources/SLING-INF/libs/sling/hapi/types.json
@@ -0,0 +1,110 @@
+{
+  "jcr:primaryType": "sling:Folder",
+  "image": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "An image src",
+    "fqdn": "org.apache.sling.hapi.common.Image",
+    "name": "Image",
+    "sling:resourceType": "sling/hapi/components/type"
+  },
+  "date": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "a date value; format has to be described in each property of this type",
+    "fqdn": "org.apache.sling.hapi.common.Date",
+    "name": "Date",
+    "sling:resourceType": "sling/hapi/components/type"
+  },
+  "text": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "A text value",
+    "fqdn": "org.apache.sling.hapi.common.Text",
+    "name": "Text",
+    "sling:resourceType": "sling/hapi/components/type"
+  },
+  "collection": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "Generic collection type. Can be parameterized with a generic type.",
+    "fqdn": "org.apache.sling.hapi.common.collection",
+    "name": "collection",
+    "parameters": [
+      "T"
+    ],
+    "sling:resourceType": "sling/hapi/components/type",
+    "item": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "",
+      "type": "T",
+      "multiple": true
+    }
+  },
+  "boolean": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "true or false",
+    "fqdn": "org.apache.sling.hapi.common.Boolean",
+    "name": "Boolean",
+    "sling:resourceType": "sling/hapi/components/type"
+  },
+  "pair": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "The key-value pair. Usually used to indicate a Map entry.",
+    "fqdn": "org.apache.sling.hapi.common.pair",
+    "name": "pair",
+    "parameters": [
+      "K",
+      "V"
+    ],
+    "sling:resourceType": "sling/hapi/components/type",
+    "key": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "The key of the pair",
+      "type": "K",
+      "multiple": false
+    },
+    "value": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "The value of the pair",
+      "type": "V",
+      "multiple": false
+    }
+  },
+  "number": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "A number value",
+    "fqdn": "org.apache.sling.hapi.common.Number",
+    "name": "Number",
+    "sling:resourceType": "sling/hapi/components/type"
+  },
+  "demo_type": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "A demo HApi type to show a more advanced structure",
+    "demo_description": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "The description of the demo object",
+      "type": "org.apache.sling.hapi.common.Text",
+      "multiple": false
+    },
+    "fqdn": "org.apache.sling.hapi.common.collection",
+    "name": "collection",
+    "parameters": [],
+    "sling:resourceType": "sling/hapi/components/type",
+    "title": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "The title of the demo object",
+      "type": "org.apache.sling.hapi.common.Text",
+      "multiple": false
+    },
+    "entries": {
+      "jcr:primaryType": "nt:unstructured",
+      "description": "An entry of type pair in the demo object",
+      "type": "org.apache.sling.hapi.common.pair",
+      "multiple": true
+    }
+  },
+  "url": {
+    "jcr:primaryType": "nt:unstructured",
+    "description": "A URL value type",
+    "fqdn": "org.apache.sling.hapi.common.URL",
+    "name": "URL",
+    "sling:resourceType": "sling/hapi/components/type"
+  }
+}