FELIX-4890 Add a MetaType service InventoryPrinter
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1679974 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/metatype/pom.xml b/webconsole-plugins/metatype/pom.xml
new file mode 100644
index 0000000..6d871cc
--- /dev/null
+++ b/webconsole-plugins/metatype/pom.xml
@@ -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.
+-->
+<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.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>2.1</version>
+ <relativePath>../../../pom/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.felix.webconsole.plugins.metatype</artifactId>
+ <packaging>bundle</packaging>
+ <version>0.0.1-SNAPSHOT</version>
+
+ <name>Apache Felix Web Console Metatype Service Inventory Printer</name>
+ <description>
+ This is an Apache Felix InventoryPrinter for printing Metatype Service information
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/felix/trunk/webconsole-plugins/metatype</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/trunk/webconsole-plugins/metatype</developerConnection>
+ <url>http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/metatype</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.4</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>
+ ${project.artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-Activator>
+ org.apache.felix.webconsole.plugins.metatype.internal.Activator
+ </Bundle-Activator>
+ <DynamicImport-Package>
+ org.osgi.service.metatype; version="[1.1,2)"
+ </DynamicImport-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.inventory</artifactId>
+ <version>1.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20070829</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/Activator.java b/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/Activator.java
new file mode 100644
index 0000000..a2632df
--- /dev/null
+++ b/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/Activator.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.felix.webconsole.plugins.metatype.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * Activator is the main starting class.
+ */
+public class Activator implements BundleActivator, ServiceTrackerCustomizer
+{
+
+ private static final String META_TYPE_NAME = "org.osgi.service.metatype.MetaTypeService"; //$NON-NLS-1$
+
+ private ServiceTracker tracker;
+ private BundleContext context;
+
+ /**
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public final void start(BundleContext context) throws Exception
+ {
+ this.context = context;
+ this.tracker = new ServiceTracker(context, META_TYPE_NAME, this);
+ this.tracker.open();
+ }
+
+ /**
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public final void stop(BundleContext context) throws Exception
+ {
+ if (tracker != null)
+ {
+ tracker.close();
+ tracker = null;
+ }
+ }
+
+ public final void modifiedService(ServiceReference reference, Object service)
+ {/* unused */
+ }
+
+ public final Object addingService(ServiceReference reference)
+ {
+ final MetaTypeService service = (MetaTypeService) context.getService(reference);
+ return new MetatypeInventoryPrinter(context, service);
+ }
+
+ public final void removedService(ServiceReference reference, Object service)
+ {
+ ((MetatypeInventoryPrinter) service).unregister();
+ }
+}
diff --git a/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/MetatypeInventoryPrinter.java b/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/MetatypeInventoryPrinter.java
new file mode 100644
index 0000000..72b83fa
--- /dev/null
+++ b/webconsole-plugins/metatype/src/main/java/org/apache/felix/webconsole/plugins/metatype/internal/MetatypeInventoryPrinter.java
@@ -0,0 +1,330 @@
+/*
+ * 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.felix.webconsole.plugins.metatype.internal;
+
+import java.io.PrintWriter;
+import java.util.Hashtable;
+
+import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.InventoryPrinter;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.MetaTypeInformation;
+import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * the {@code MetaTypeInve}
+ */
+class MetatypeInventoryPrinter implements InventoryPrinter
+{
+
+ private final BundleContext bundleContext;
+ private final MetaTypeService metatype;
+
+ private ServiceRegistration registration;
+
+ @SuppressWarnings("serial")
+ MetatypeInventoryPrinter(final BundleContext bundleContext, final MetaTypeService metatype)
+ {
+ this.bundleContext = bundleContext;
+ this.metatype = metatype;
+
+ this.registration = bundleContext.registerService(InventoryPrinter.SERVICE, this,
+ new Hashtable<String, Object>()
+ {
+ {
+ put(InventoryPrinter.NAME, "metatype");
+ put(InventoryPrinter.TITLE, "Metatype Service");
+ put(InventoryPrinter.FORMAT, new String[]
+ { Format.TEXT.toString(), Format.JSON.toString() });
+ }
+ });
+ }
+
+ void unregister()
+ {
+ ServiceRegistration registration = this.registration;
+ this.registration = null;
+ if (registration != null)
+ {
+ registration.unregister();
+ }
+ }
+
+ public String getTitle()
+ {
+ return "Metatype Service";
+ }
+
+ public void print(PrintWriter printWriter, Format format, boolean isZip)
+ {
+ final Bundle[] bundles = this.bundleContext.getBundles();
+ final Printer printer = (format == Format.JSON) ? new JsonPrinter(printWriter) : new TextPrinter(printWriter);
+
+ printer.start();
+ for (Bundle bundle : bundles)
+ {
+ printComponents(printer, bundle, metatype.getMetaTypeInformation(bundle));
+ }
+ printer.end();
+ }
+
+ private static final void printComponents(final Printer pw, final Bundle bundle, final MetaTypeInformation info)
+ {
+ if (info == null) {
+ return;
+ }
+
+ final String[] pids = info.getPids();
+ final String[] factoryPids = info.getFactoryPids();
+ if ((pids == null || pids.length == 0) && (factoryPids == null || factoryPids.length == 0))
+ {
+ return;
+ }
+
+ pw.group(bundle.getSymbolicName() + " (" + bundle.getBundleId() + ")");
+
+ // PIDs
+ if (pids != null && pids.length > 0)
+ {
+ for (String pid : pids)
+ {
+ ocd(pw, info.getObjectClassDefinition(pid, null));
+ }
+ }
+
+ // Factory PIDs
+ if (factoryPids != null && factoryPids.length > 0)
+ {
+ for (String factoryPid : factoryPids)
+ {
+ ocd(pw, info.getObjectClassDefinition(factoryPid, null));
+ }
+ }
+
+ pw.endGroup();
+ }
+
+ private static final void ocd(final Printer pw, final ObjectClassDefinition ocd)
+ {
+ pw.group(ocd.getID());
+ pw.keyValue("name", ocd.getName());
+ pw.keyValue("description", ocd.getDescription());
+
+ AttributeDefinition[] ads = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL);
+ if (ads != null)
+ {
+ for (AttributeDefinition ad : ads)
+ {
+ ad(pw, ad);
+ }
+ }
+
+ pw.endGroup();
+ }
+
+ private static final void ad(final Printer pw, final AttributeDefinition ad)
+ {
+ pw.group(ad.getID());
+ pw.keyValue("name", ad.getName());
+ pw.keyValue("description", ad.getDescription());
+ pw.keyValue("type", type(ad.getType()));
+ pw.keyValue("cardinality", cardinality(ad.getCardinality()));
+ pw.endGroup();
+
+ // Omitted:
+ // ad.getDefaultValue()
+ // ad.getOptionLabels()
+ // ad.getOptionValues()
+ }
+
+ @SuppressWarnings("deprecation")
+ private static final String type(final int type)
+ {
+ switch (type)
+ {
+ case AttributeDefinition.BIGDECIMAL:
+ return "BigDecimal";
+ case AttributeDefinition.BIGINTEGER:
+ return "BigInteger";
+ case AttributeDefinition.BOOLEAN:
+ return "Boolean";
+ case AttributeDefinition.BYTE:
+ return "Byte";
+ case AttributeDefinition.CHARACTER:
+ return "Character";
+ case AttributeDefinition.DOUBLE:
+ return "Double";
+ case AttributeDefinition.FLOAT:
+ return "Float";
+ case AttributeDefinition.INTEGER:
+ return "Integer";
+ case AttributeDefinition.LONG:
+ return "Long";
+ case AttributeDefinition.SHORT:
+ return "Short";
+ case AttributeDefinition.STRING:
+ return "String";
+ case 12 /* PASSWORD */:
+ return "Password";
+ default:
+ return String.valueOf(type);
+ }
+ }
+
+ private static final String cardinality(final int cardinality)
+ {
+ if (cardinality == 0)
+ {
+ return "required";
+ }
+ else if (cardinality == Integer.MAX_VALUE || cardinality == Integer.MIN_VALUE)
+ {
+ return "unlimited";
+ }
+ else
+ {
+ return String.valueOf(Math.abs(cardinality));
+ }
+ }
+
+ private static interface Printer
+ {
+ void start();
+
+ void group(String name);
+
+ void keyValue(String key, Object value);
+
+ void endGroup();
+
+ void end();
+ }
+
+ private static class TextPrinter implements Printer
+ {
+
+ private final PrintWriter pw;
+
+ private String indent = "";
+
+ TextPrinter(final PrintWriter pw)
+ {
+ this.pw = pw;
+ }
+
+ public void start()
+ {
+ }
+
+ public void group(String name)
+ {
+ this.pw.printf("%s%s:%n", indent, name);
+ this.indent += " ";
+ }
+
+ public void keyValue(String key, Object value)
+ {
+ this.pw.printf("%s%s: %s%n", indent, key, value);
+ }
+
+ public void endGroup()
+ {
+ if (this.indent.length() > 2)
+ {
+ this.indent = this.indent.substring(0, this.indent.length() - 2);
+ }
+ }
+
+ public void end()
+ {
+ }
+ }
+
+ private static class JsonPrinter implements Printer
+ {
+
+ private final JSONWriter pw;
+
+ JsonPrinter(final PrintWriter pw)
+ {
+ this.pw = new JSONWriter(pw);
+ }
+
+ public void start()
+ {
+ try
+ {
+ this.pw.object();
+ }
+ catch (JSONException ignore)
+ {
+ }
+ }
+
+ public void group(String name)
+ {
+ try
+ {
+ this.pw.key(name).object();
+ }
+ catch (JSONException ignore)
+ {
+ }
+ }
+
+ public void keyValue(String key, Object value)
+ {
+ try
+ {
+ this.pw.key(key).value(value);
+ }
+ catch (JSONException ignore)
+ {
+ }
+ }
+
+ public void endGroup()
+ {
+ try
+ {
+ this.pw.endObject();
+ }
+ catch (JSONException ignore)
+ {
+ }
+ }
+
+ public void end()
+ {
+ try
+ {
+ this.pw.endObject();
+ }
+ catch (JSONException ignore)
+ {
+ }
+ }
+ }
+}