/* * 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.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), pid); } } // Factory PIDs if (factoryPids != null && factoryPids.length > 0) { for (String factoryPid : factoryPids) { ocd(pw, info.getObjectClassDefinition(factoryPid, null), factoryPid); } } pw.endGroup(); } private static final void ocd(final Printer pw, final ObjectClassDefinition ocd, String id) { pw.group(id); pw.keyValue("name", ocd.getName()); pw.keyValue("description", ocd.getDescription()); AttributeDefinition[] ads = ocd.getAttributeDefinitions(ObjectClassDefinition.ALL); if (ads != null) { pw.group("attributes"); for (AttributeDefinition ad : ads) { ad(pw, ad); } pw.endGroup(); } 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())); defaultValue(pw, ad.getDefaultValue()); options(pw, ad.getOptionLabels(), ad.getOptionValues()); pw.endGroup(); } private static final void defaultValue(final Printer pw, final String[] defaultValue) { if (defaultValue != null) { switch (defaultValue.length) { case 0: // ignore break; case 1: pw.keyValue("default", defaultValue[0]); break; default: pw.list("default", defaultValue); break; } } } private static final void options(final Printer pw, final String[] optionLabels, final String[] optionValues) { if (optionLabels != null && optionLabels.length > 0) { pw.group("options"); for (int i = 0; i < optionLabels.length; i++) { pw.keyValue(optionLabels[i], optionValues[i]); } pw.endGroup(); } } @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 end(); void group(String name); void endGroup(); void list(String name, String[] values); void keyValue(String key, String value); } private static class TextPrinter implements Printer { private final PrintWriter pw; private String indent; TextPrinter(final PrintWriter pw) { this.pw = pw; this.indent = ""; } public void start() { } public void end() { } public void group(String name) { this.pw.printf("%s%s:%n", indent, name); this.indent += " "; } public void endGroup() { if (this.indent.length() > 2) { this.indent = this.indent.substring(0, this.indent.length() - 2); } } public void list(String name, String[] values) { this.pw.printf("%s%s: [", indent, name); boolean first = true; for (String val : values) { if (first) { first = false; } else { this.pw.print(", "); } this.pw.print(val); } this.pw.println("]"); } public void keyValue(String key, String value) { this.pw.printf("%s%s: %s%n", indent, key, value); } } private static class JsonPrinter implements Printer { private boolean needsComma; private final PrintWriter pw; JsonPrinter(final PrintWriter pw) { this.pw = pw; } public void start() { this.pw.print('{'); } public void end() { this.pw.print('}'); } private void key(String name) { if (needsComma) { this.pw.print(','); } this.pw.print('"'); this.pw.print(name); this.pw.print("\" : "); } public void group(String name) { this.key(name); this.pw.print('{'); this.needsComma = false; } public void endGroup() { this.pw.print('}'); this.needsComma = true; } public void list(String name, String[] values) { this.key(name); this.pw.print('['); boolean first = true; for (String val : values) { if (first) { first = false; } else { this.pw.print(','); } value(val); } this.pw.print(']'); this.needsComma = true; } private void value(String value) { if (value == null) { this.pw.print("null"); } else { this.pw.print('"'); // escape the value final int len = value.length(); for(int i=0;i<len;i++){ final char c = value.charAt(i); switch(c){ case '"': this.pw.print("\\\""); break; case '\\': this.pw.print("\\\\"); break; case '\b': this.pw.print("\\b"); break; case '\f': this.pw.print("\\f"); break; case '\n': this.pw.print("\\n"); break; case '\r': this.pw.print("\\r"); break; case '\t': this.pw.print("\\t"); break; case '/': this.pw.print("\\/"); break; default: if ((c>='\u0000' && c<='\u001F') || (c>='\u007F' && c<='\u009F') || (c>='\u2000' && c<='\u20FF')) { final String hex=Integer.toHexString(c); this.pw.print("\\u"); for(int k=0;k<4-hex.length();k++){ this.pw.print('0'); } this.pw.print(hex.toUpperCase()); } else{ this.pw.print(c); } } } this.pw.print('"'); } } public void keyValue(String key, String value) { key(key); value(value); this.needsComma = true; } } }