| /* |
| * 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.jcr.classloader.internal; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| import javax.jcr.Item; |
| import javax.jcr.ItemNotFoundException; |
| import javax.jcr.Node; |
| import javax.jcr.Property; |
| import javax.jcr.PropertyType; |
| import javax.jcr.RepositoryException; |
| import javax.jcr.ValueFormatException; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * The <code>Util</code> provides helper methods for the repository |
| * classloader and its class path entry and resource classes. |
| * <p> |
| * This class may not be extended or instantiated, it just contains static |
| * utility methods. |
| */ |
| public class Util { |
| |
| /** default logging */ |
| private static final Logger log = LoggerFactory.getLogger(Util.class); |
| |
| /** Private constructor to not instantiate */ |
| private Util() { |
| } |
| |
| /** |
| * Resolves the given <code>item</code> to a <code>Property</code> from |
| * which contents can be read. |
| * <p> |
| * The following mechanism is used to derive the contents: |
| * <ol> |
| * <li>If the <code>item</code> is a property, this property is used</li> |
| * <li>If the <code>item</code> is a node, three steps are tested: |
| * <ol> |
| * <li>If the node has a <code>jcr:content</code> child node, use that |
| * child node in the next steps. Otherwise continue with the node.</li> |
| * <li>Check for a <code>jcr:data</code> property and use that property |
| * if existing.</li> |
| * <li>Otherwise call <code>getPrimaryItem</code> method repeatedly until |
| * a property is returned or until no more primary item is available.</li> |
| * </ol> |
| * </ol> |
| * If no property can be resolved using the above algorithm or if the |
| * resulting property is a multivalue property, <code>null</code> is |
| * returned. Otherwise if the resulting property is a <code>REFERENCE</code> |
| * property, the node referred to is retrieved and this method is called |
| * recursively with the node. Otherwise, the resulting property is returned. |
| * |
| * @param item The <code>Item</code> to resolve to a <code>Property</code>. |
| * @return The resolved <code>Property</code> or <code>null</code> if |
| * the resolved property is a multi-valued property or the |
| * <code>item</code> is a node which cannot be resolved to a data |
| * property. |
| * @throws ValueFormatException If the <code>item</code> resolves to a |
| * single-valued <code>REFERENCE</code> type property which |
| * cannot be resolved to the node referred to. |
| * @throws RepositoryException if another error occurrs accessing the |
| * repository. |
| */ |
| public static Property getProperty(Item item) throws ValueFormatException, |
| RepositoryException { |
| |
| Property prop; |
| if (item.isNode()) { |
| |
| // check whether the node has a jcr:content node (e.g. nt:file) |
| Node node = (Node) item; |
| if (node.hasNode("jcr:content")) { |
| node = node.getNode("jcr:content"); |
| } |
| |
| // if the node has a jcr:data property, use that property |
| if (node.hasProperty("jcr:data")) { |
| |
| prop = node.getProperty("jcr:data"); |
| |
| } else { |
| |
| // otherwise try to follow default item trail |
| try { |
| item = node.getPrimaryItem(); |
| while (item.isNode()) { |
| item = ((Node) item).getPrimaryItem(); |
| } |
| prop = (Property) item; |
| } catch (ItemNotFoundException infe) { |
| // we don't actually care, but log for completeness |
| log.debug("getProperty: No primary items for " |
| + node.getPath(), infe); |
| return null; |
| } |
| } |
| |
| } else { |
| |
| prop = (Property) item; |
| |
| } |
| |
| // we get here with a property - otherwise an exception has already |
| // been thrown |
| if (prop.getDefinition().isMultiple()) { |
| log.error("{} is a multivalue property", prop.getPath()); |
| return null; |
| } else if (prop.getType() == PropertyType.REFERENCE) { |
| Node node = prop.getNode(); |
| log.info("Property {} refers to node {}; finding primary item", |
| prop.getPath(), node.getPath()); |
| return getProperty(node); |
| } |
| |
| return prop; |
| } |
| |
| /** |
| * Returns the resource as an array of bytes |
| */ |
| public static byte[] getBytes(final Node node) throws IOException, RepositoryException { |
| InputStream in = null; |
| |
| try { |
| in = getProperty(node).getStream(); |
| final ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| final byte[] buffer = new byte[2048]; |
| int l = 0; |
| while ( (l = in.read(buffer)) > -1 ) { |
| baos.write(buffer, 0, l); |
| } |
| return baos.toByteArray(); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (final IOException ignore) { |
| // ignore |
| } |
| } |
| } |
| } |
| } |