SLING-1707 - adding a nodetype configuration printer

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@990832 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 2a9c8a0..90116c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,7 +92,7 @@
         <dependency>
         	<groupId>org.apache.felix</groupId>
         	<artifactId>org.apache.felix.webconsole</artifactId>
-        	<version>1.2.0</version>
+        	<version>3.0.0</version>
         </dependency>
         <dependency>
         	<groupId>javax.servlet</groupId>
@@ -100,6 +100,12 @@
         	<version>2.4</version>
         	<scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/src/main/java/org/apache/sling/jcr/webconsole/internal/NamespaceConfigurationPrinter.java b/src/main/java/org/apache/sling/jcr/webconsole/internal/NamespaceConfigurationPrinter.java
index f69a634..d2b957f 100644
--- a/src/main/java/org/apache/sling/jcr/webconsole/internal/NamespaceConfigurationPrinter.java
+++ b/src/main/java/org/apache/sling/jcr/webconsole/internal/NamespaceConfigurationPrinter.java
@@ -26,32 +26,34 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+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.Reference;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
 import org.apache.felix.webconsole.ConfigurationPrinter;
 import org.apache.sling.jcr.api.SlingRepository;
 
 /**
  * A Felix WebConsole ConfigurationPrinter which outputs the current JCR
  * namespace mappings.
- *
- * @scr.component immediate="true" label="%namespace.printer.name"
- *                description="%namespace.printer.description"
- *                metatype="no"
- * @scr.property name="service.description"
- *               value="JCR Namespace Configuration Printer"
- * @scr.property name="service.vendor" value="The Apache Software Foundation"
- * @scr.service interface="org.apache.felix.webconsole.ConfigurationPrinter"
- *
  */
+@Component(label = "%namespace.printer.name", description = "%namespace.printer.description", metatype = false)
+@Service(ConfigurationPrinter.class)
+@Properties({
+    @Property(name = "service.description", value = "JCR Namespace Configuration Printer"),
+    @Property(name = "service.vendor", value = "The Apache Software Foundation")
+})
 public class NamespaceConfigurationPrinter implements ConfigurationPrinter {
 
-    /**
-     * @scr.reference policy="dynamic"
-     */
+
+    @Reference(policy=ReferencePolicy.DYNAMIC)
     private SlingRepository slingRepository;
 
     /**
      * Get the title of the configuration status page.
-     *
+     * 
      * @return the title
      */
     public String getTitle() {
@@ -60,7 +62,7 @@
 
     /**
      * Output a list of namespace prefixes and URIs from the NamespaceRegistry.
-     *
+     * 
      * @param pw a PrintWriter
      */
     public void printConfiguration(PrintWriter pw) {
diff --git a/src/main/java/org/apache/sling/jcr/webconsole/internal/NodeTypeConfigurationPrinter.java b/src/main/java/org/apache/sling/jcr/webconsole/internal/NodeTypeConfigurationPrinter.java
new file mode 100644
index 0000000..7172f49
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/webconsole/internal/NodeTypeConfigurationPrinter.java
@@ -0,0 +1,231 @@
+package org.apache.sling.jcr.webconsole.internal;
+
+import java.io.PrintWriter;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeDefinition;
+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.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.ModeAwareConfigurationPrinter;
+import org.apache.sling.jcr.api.SlingRepository;
+
+/**
+ * @author justin
+ *
+ */
+/**
+ * A Felix WebConsole ConfigurationPrinter which outputs the current JCR
+ * nodetypes.
+ */
+@Component(label = "%nodetype.printer.name", description = "%nodetype.printer.description", metatype = false)
+@Service(ConfigurationPrinter.class)
+@Properties({ @Property(name = "service.description", value = "JCR Nodetype Configuration Printer"),
+        @Property(name = "service.vendor", value = "The Apache Software Foundation") })
+public class NodeTypeConfigurationPrinter implements ModeAwareConfigurationPrinter {
+
+    @Reference(policy = ReferencePolicy.DYNAMIC)
+    private SlingRepository slingRepository;
+
+    /**
+     * Get the title of the configuration status page.
+     * 
+     * @return the title
+     */
+    public String getTitle() {
+        return "JCR NodeTypes";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void printConfiguration(PrintWriter pw, String mode) {
+        if (slingRepository != null) {
+            try {
+                Session session = slingRepository.loginAdministrative(null);
+                NodeTypeManager ntm = session.getWorkspace().getNodeTypeManager();
+                NodeTypeIterator it = ntm.getAllNodeTypes();
+                while (it.hasNext()) {
+                    NodeType nt = it.nextNodeType();
+
+                    pw.printf("[%s]", nt.getName());
+
+                    printSuperTypes(pw, nt);
+
+                    if (nt.hasOrderableChildNodes()) {
+                        pw.print(" orderable");
+                    }
+                    if (nt.isMixin()) {
+                        pw.print(" mixin");
+                    }
+                    pw.println();
+
+                    for (PropertyDefinition prop : nt.getPropertyDefinitions()) {
+                        if (prop.getDeclaringNodeType() == nt) {
+                            startBold(pw, mode);
+                        }
+
+                        pw.printf("- %s", prop.getName());
+                        printDefaultValues(pw, prop);
+                        if (prop.getName().equals(nt.getPrimaryItemName())) {
+                            pw.print(" primary");
+                        }
+                        if (prop.isMandatory()) {
+                            pw.print(" mandatory");
+                        }
+                        if (prop.isAutoCreated()) {
+                            pw.print(" autocreated");
+                        }
+                        if (prop.isProtected()) {
+                            pw.print(" protected");
+                        }
+                        if (prop.isMultiple()) {
+                            pw.print(" multiple");
+                        }
+                        pw.printf(" %s", OnParentVersionAction.nameFromValue(prop.getOnParentVersion()));
+                        printConstraints(pw, prop);
+
+                        if (prop.getDeclaringNodeType() == nt) {
+                            stopBold(pw, mode);
+                        }
+
+                        pw.println();
+                    }
+                    for (NodeDefinition child : nt.getChildNodeDefinitions()) {
+                        if (child.getDeclaringNodeType() == nt) {
+                            startBold(pw, mode);
+                        }
+
+                        pw.printf("+ %s", child.getName());
+
+                        printRequiredChildTypes(pw, child);
+
+                        if (child.getDefaultPrimaryType() != null) {
+                            pw.printf(" = %s", child.getDefaultPrimaryType().getName());
+                        }
+
+                        if (child.isMandatory()) {
+                            pw.print(" mandatory");
+                        }
+                        if (child.isAutoCreated()) {
+                            pw.print(" autocreated");
+                        }
+                        if (child.isProtected()) {
+                            pw.print(" protected");
+                        }
+                        if (child.allowsSameNameSiblings()) {
+                            pw.print(" multiple");
+                        }
+                        pw.printf(" %s", OnParentVersionAction.nameFromValue(child.getOnParentVersion()));
+
+                        if (child.getDeclaringNodeType() == nt) {
+                            stopBold(pw, mode);
+                        }
+
+                        pw.println();
+                    }
+
+                    pw.println();
+
+                }
+            } catch (RepositoryException e) {
+                pw.println("Unable to output namespace mappings.");
+                e.printStackTrace(pw);
+            }
+        } else {
+            pw.println("SlingRepsoitory is not available.");
+        }
+    }
+
+    /**
+     * Output a list of node types from the NamespaceRegistry.
+     * 
+     * @param pw a PrintWriter
+     */
+    public void printConfiguration(PrintWriter pw) {
+        printConfiguration(pw, ConfigurationPrinter.MODE_TXT);
+
+    }
+
+    private void stopBold(PrintWriter pw, String mode) {
+        if (ConfigurationPrinter.MODE_WEB.equals(mode)) {
+            pw.print("</b>");
+        }
+    }
+
+    private void startBold(PrintWriter pw, String mode) {
+        if (ConfigurationPrinter.MODE_WEB.equals(mode)) {
+            pw.print("<b>");
+        }
+    }
+
+    private void printRequiredChildTypes(PrintWriter pw, NodeDefinition child) {
+        if (child.getRequiredPrimaryTypes() != null && child.getRequiredPrimaryTypes().length > 0) {
+            pw.print(" (");
+
+            boolean first = true;
+            for (NodeType required : child.getRequiredPrimaryTypes()) {
+                if (!first) {
+                    pw.print(", ");
+                }
+                pw.print(required.getName());
+                first = false;
+            }
+            pw.print(")");
+        }
+
+    }
+
+    private void printDefaultValues(PrintWriter pw, PropertyDefinition prop) throws RepositoryException {
+        if (prop.getDefaultValues() != null && prop.getDefaultValues().length > 0) {
+            pw.print(" = ");
+
+            boolean first = true;
+            for (Value v : prop.getDefaultValues()) {
+                if (!first) {
+                    pw.print(", ");
+                }
+                pw.print(v.getString());
+                first = false;
+            }
+        }
+    }
+
+    private void printConstraints(PrintWriter pw, PropertyDefinition prop) throws RepositoryException {
+        if (prop.getValueConstraints() != null && prop.getValueConstraints().length > 0) {
+            pw.print(" < ");
+            boolean first = true;
+            for (String s : prop.getValueConstraints()) {
+                if (!first) {
+                    pw.print(", ");
+                }
+                pw.print(s);
+                first = false;
+            }
+        }
+    }
+
+    private void printSuperTypes(PrintWriter pw, NodeType nt) {
+        pw.print(" > ");
+        boolean first = true;
+        for (NodeType st : nt.getSupertypes()) {
+            if (!first) {
+                pw.print(", ");
+            }
+            pw.print(st.getName());
+            first = false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
index 12be97a..ea277ab 100644
--- a/src/main/resources/OSGI-INF/metatype/metatype.properties
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -26,3 +26,6 @@
 namespace.printer.name = Namespace Mapping Configuration Printer
 namespace.printer.description = Namespace Mapping Configuration Printer
 
+nodetype.printer.name = NodeType Configuration Printer
+nodetype.printer.description = NodeType Configuration Printer
+