This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.resource.inventory-0.5.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resource-inventory.git
commit 12839adf75423569a2c339e0f22dad556c27afd2 Author: Carsten Ziegeler <[email protected]> AuthorDate: Wed Aug 14 15:12:50 2013 +0000 SLING-3018 : Add an inventory printer which dumps a resource tree into json git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/resource-inventory@1513925 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 99 ++++++++++ .../resource/inventory/impl/JsonObjectCreator.java | 211 +++++++++++++++++++++ .../impl/ResourceInventoryPrinterFactory.java | 90 +++++++++ .../resource/inventory/impl/ResourceTraversor.java | 120 ++++++++++++ 4 files changed, 520 insertions(+) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..22cc664 --- /dev/null +++ b/pom.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>17</version> + </parent> + + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.resource.inventory</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>Apache Sling Inventory Printer Based on Resources</name> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/resourceinventory</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/resourceinventory</developerConnection> + <url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/resourceinventory</url> + </scm> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Private-Package> + org.apache.sling.resource.inventory.impl + </Private-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.api</artifactId> + <version>2.4.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>org.apache.felix</groupId> + <artifactId>org.apache.felix.inventory</artifactId> + <version>1.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + </dependencies> +</project> diff --git a/src/main/java/org/apache/sling/resource/inventory/impl/JsonObjectCreator.java b/src/main/java/org/apache/sling/resource/inventory/impl/JsonObjectCreator.java new file mode 100644 index 0000000..25984e7 --- /dev/null +++ b/src/main/java/org/apache/sling/resource/inventory/impl/JsonObjectCreator.java @@ -0,0 +1,211 @@ +/* + * 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.resource.inventory.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.commons.json.JSONArray; +import org.apache.sling.commons.json.JSONException; +import org.apache.sling.commons.json.JSONObject; + +/** + * Creates a JSONObject from a resource + * + */ +public abstract class JsonObjectCreator { + + /** Dump given resource in JSON, optionally recursing into its objects */ + public static JSONObject create(final Resource resource) + throws JSONException { + final ValueMap valueMap = resource.adaptTo(ValueMap.class); + + @SuppressWarnings("unchecked") + final Map propertyMap = (valueMap != null) + ? valueMap + : resource.adaptTo(Map.class); + + final JSONObject obj = new JSONObject(); + + if (propertyMap == null) { + + // no map available, try string + final String value = resource.adaptTo(String.class); + if (value != null) { + + // single value property or just plain String resource or... + obj.put(resource.getName(), value); + + } else { + + // Try multi-value "property" + final String[] values = resource.adaptTo(String[].class); + if (values != null) { + obj.put(resource.getName(), new JSONArray(Arrays.asList(values))); + } + + } + if ( resource.getResourceType() != null ) { + obj.put("sling:resourceType", resource.getResourceType()); + } + if ( resource.getResourceSuperType() != null ) { + obj.put("sling:resourceSuperType", resource.getResourceSuperType()); + } + + } else { + + @SuppressWarnings("unchecked") + final Iterator<Map.Entry> props = propertyMap.entrySet().iterator(); + + // the node's actual properties + while (props.hasNext()) { + @SuppressWarnings("unchecked") + final Map.Entry prop = props.next(); + + if ( prop.getValue() != null ) { + createProperty(obj, valueMap, prop.getKey().toString(), + prop.getValue()); + } + } + } + + // the child nodes + final Iterator<Resource> children = resource.listChildren(); + while (children.hasNext()) { + final Resource n = children.next(); + createSingleResource(n, obj); + } + + return obj; + } + + /** Used to format date values */ + private static final String ECMA_DATE_FORMAT = "EEE MMM dd yyyy HH:mm:ss 'GMT'Z"; + + /** Used to format date values */ + private static final Locale DATE_FORMAT_LOCALE = Locale.US; + + private static final DateFormat CALENDAR_FORMAT = new SimpleDateFormat(ECMA_DATE_FORMAT, DATE_FORMAT_LOCALE); + + private static synchronized String format(final Calendar date) { + return CALENDAR_FORMAT.format(date.getTime()); + } + + /** Dump only a value in the correct format */ + private static Object getValue(final Object value) { + if ( value instanceof InputStream ) { + // input stream is already handled + return 0; + } else if ( value instanceof Calendar ) { + return format((Calendar)value); + } else if ( value instanceof Boolean ) { + return value; + } else if ( value instanceof Long ) { + return value; + } else if ( value instanceof Integer ) { + return value; + } else if ( value instanceof Double ) { + return value; + } else { + return value.toString(); + } + } + + /** Dump a single node */ + private static void createSingleResource(final Resource n, final JSONObject parent) + throws JSONException { + parent.put(n.getName(), create(n)); + } + + /** + * Write a single property + */ + private static void createProperty(final JSONObject obj, + final ValueMap valueMap, + final String key, + final Object value) + throws JSONException { + Object[] values = null; + if (value.getClass().isArray()) { + values = (Object[])value; + // write out empty array + if ( values.length == 0 ) { + obj.put(key, new JSONArray()); + return; + } + } + + // special handling for binaries: we dump the length and not the data! + if (value instanceof InputStream + || (values != null && values[0] instanceof InputStream)) { + // TODO for now we mark binary properties with an initial colon in + // their name + // (colon is not allowed as a JCR property name) + // in the name, and the value should be the size of the binary data + if (values == null) { + obj.put(":" + key, getLength(valueMap, -1, key, (InputStream)value)); + } else { + final JSONArray result = new JSONArray(); + for (int i = 0; i < values.length; i++) { + result.put(getLength(valueMap, i, key, (InputStream)values[i])); + } + obj.put(":" + key, result); + } + return; + } + + if (!value.getClass().isArray()) { + obj.put(key, getValue(value)); + } else { + final JSONArray result = new JSONArray(); + for (Object v : values) { + result.put(getValue(v)); + } + obj.put(key, result); + } + } + + private static long getLength(final ValueMap valueMap, + final int index, + final String key, + final InputStream stream) { + try { + stream.close(); + } catch (IOException ignore) {} + long length = -1; + if ( valueMap != null ) { + if ( index == -1 ) { + length = valueMap.get(key, length); + } else { + Long[] lengths = valueMap.get(key, Long[].class); + if ( lengths != null && lengths.length > index ) { + length = lengths[index]; + } + } + } + return length; + } +} diff --git a/src/main/java/org/apache/sling/resource/inventory/impl/ResourceInventoryPrinterFactory.java b/src/main/java/org/apache/sling/resource/inventory/impl/ResourceInventoryPrinterFactory.java new file mode 100644 index 0000000..4591274 --- /dev/null +++ b/src/main/java/org/apache/sling/resource/inventory/impl/ResourceInventoryPrinterFactory.java @@ -0,0 +1,90 @@ +/* + * 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.resource.inventory.impl; + +import java.io.PrintWriter; +import java.util.Map; + +import org.apache.felix.inventory.Format; +import org.apache.felix.inventory.InventoryPrinter; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.ConfigurationPolicy; +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.Service; +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceResolverFactory; +import org.apache.sling.commons.json.JSONException; + +@Component(configurationFactory=true, policy=ConfigurationPolicy.REQUIRE, metatype=true) +@Service(value=InventoryPrinter.class) +@Properties({ + @Property(name=InventoryPrinter.FORMAT, value="JSON", propertyPrivate=true), + @Property(name=InventoryPrinter.NAME), + @Property(name=InventoryPrinter.TITLE), + @Property(name=InventoryPrinter.WEBCONSOLE, boolValue=false, propertyPrivate=true) +}) +public class ResourceInventoryPrinterFactory implements InventoryPrinter { + + @Property(value = "") + private static final String PROP_PATH = "path"; + + private String path; + + @Activate + protected void activate(final Map<String, Object> props) { + this.path = (String)props.get(PROP_PATH); + } + + @Reference + private ResourceResolverFactory factory; + + /** + * @see org.apache.felix.inventory.InventoryPrinter#print(java.io.PrintWriter, org.apache.felix.inventory.Format, boolean) + */ + public void print(PrintWriter printWriter, Format format, boolean isZip) { + if ( this.path == null || !format.equals(Format.JSON) ) { + return; + } + ResourceResolver resolver = null; + try { + resolver = factory.getAdministrativeResourceResolver(null); + final Resource rootResource = resolver.getResource(this.path); + if ( rootResource != null ) { + final ResourceTraversor rt = new ResourceTraversor(rootResource); + rt.collectResources(); + printWriter.write(rt.getJSONObject().toString(2)); + + } + } catch (final LoginException e) { + // ignore + } catch (JSONException e) { + // ignore + } finally { + if ( resolver != null ) { + resolver.close(); + } + } + } + +} diff --git a/src/main/java/org/apache/sling/resource/inventory/impl/ResourceTraversor.java b/src/main/java/org/apache/sling/resource/inventory/impl/ResourceTraversor.java new file mode 100644 index 0000000..b984cd6 --- /dev/null +++ b/src/main/java/org/apache/sling/resource/inventory/impl/ResourceTraversor.java @@ -0,0 +1,120 @@ +/* + * 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.resource.inventory.impl; + +import java.util.Iterator; +import java.util.LinkedList; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.commons.json.JSONException; +import org.apache.sling.commons.json.JSONObject; + +public class ResourceTraversor { + + public static final class Entry { + public final Resource resource; + public final JSONObject json; + + public Entry(final Resource r, final JSONObject o) { + this.resource = r; + this.json = o; + } + } + + private final JSONObject startObject; + + private LinkedList<Entry> currentQueue; + + private LinkedList<Entry> nextQueue; + + private final Resource startResource; + + public ResourceTraversor(final Resource resource) + throws JSONException { + this.startResource = resource; + this.currentQueue = new LinkedList<Entry>(); + this.nextQueue = new LinkedList<Entry>(); + this.startObject = this.adapt(resource); + } + + /** + * Recursive descent from startResource, collecting JSONObjects into + * startObject. + * @throws JSONException + */ + public void collectResources() throws JSONException { + collectChildren(startResource, this.startObject, 0); + } + + /** + * @param resource + * @param currentLevel + * @throws JSONException + */ + private void collectChildren(final Resource resource, + final JSONObject jsonObj, + int currentLevel) + throws JSONException { + + final Iterator<Resource> children = resource.listChildren(); + while (children.hasNext()) { + final Resource res = children.next(); + final JSONObject json = collectResource(res, jsonObj); + nextQueue.addLast(new Entry(res, json)); + } + + while (!currentQueue.isEmpty() || !nextQueue.isEmpty()) { + if (currentQueue.isEmpty()) { + currentLevel++; + currentQueue = nextQueue; + nextQueue = new LinkedList<Entry>(); + } + final Entry nextResource = currentQueue.removeFirst(); + collectChildren(nextResource.resource, nextResource.json, currentLevel); + } + } + + /** + * Adds a resource in the JSON tree. + * + * @param resource The resource to add + * @param level The level where this resource is located. + * @throws JSONException + */ + private JSONObject collectResource(Resource resource, final JSONObject parent) + throws JSONException { + final JSONObject o = adapt(resource); + parent.put(resource.getName(), o); + return o; + } + + /** + * Adapt a Resource to a JSON Object. + * + * @param resource The resource to adapt. + * @return The JSON representation of the Resource + * @throws JSONException + */ + private JSONObject adapt(final Resource resource) throws JSONException { + return JsonObjectCreator.create(resource); + } + + public JSONObject getJSONObject() { + return startObject; + } +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
