You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by to...@apache.org on 2015/10/22 13:15:17 UTC

svn commit: r1709989 - in /sling/trunk/contrib/extensions/distribution/extensions: ./ src/ src/main/ src/main/avro/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/distribution/...

Author: tommaso
Date: Thu Oct 22 11:15:16 2015
New Revision: 1709989

URL: http://svn.apache.org/viewvc?rev=1709989&view=rev
Log:
SLING-5181 - Apache Avro based package builder

Added:
    sling/trunk/contrib/extensions/distribution/extensions/src/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/shallowresource.avsc
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java   (with props)
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java   (with props)
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java   (with props)
    sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java   (with props)
    sling/trunk/contrib/extensions/distribution/extensions/src/test/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java   (with props)
    sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/avro/
    sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/avro/dp.avro   (with props)
Modified:
    sling/trunk/contrib/extensions/distribution/extensions/pom.xml

Modified: sling/trunk/contrib/extensions/distribution/extensions/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/pom.xml?rev=1709989&r1=1709988&r2=1709989&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/pom.xml (original)
+++ sling/trunk/contrib/extensions/distribution/extensions/pom.xml Thu Oct 22 11:15:16 2015
@@ -54,7 +54,9 @@
             <resource>
                 <directory>src/main/resources</directory>
             </resource>
-
+            <resource>
+                <directory>src/main/avro</directory>
+            </resource>
         </resources>
         <plugins>
             <plugin>
@@ -76,6 +78,10 @@
                         <goals>
                             <goal>schema</goal>
                         </goals>
+                        <configuration>
+                            <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
+                            <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
@@ -94,6 +100,37 @@
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>org.apache.sling.distribution.extensions</Bundle-SymbolicName>
+                        <Embed-Dependency>kryo,reflectasm,minlog,asm,objenesis,avro,avro-ipc,
+                            jackson-core-asl,
+                            jackson-mapper-asl,
+                            paranamer,
+                            commons-compress,
+                            org.apache.sling.jcr.resource;inline="org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.*|
+                            org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.*|
+                            org/apache/sling/jcr/resource/internal/helper/LazyInputStream.*|
+                            org/apache/sling/jcr/resource/internal/HelperData*|
+                            org/apache/sling/jcr/resource/internal/JcrModifiableValueMap*|"
+                            org/apache/sling/jcr/resource/internal/JcrValueMap*|"
+                            org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper*|"
+                            org/apache/sling/jcr/resource/internal/helper/JcrPropertyMapCacheEntry*"
+                        </Embed-Dependency>
+                        <Import-Package>
+                            !sun.*,
+                            !org.joda.time.*,
+                            !org.tukaani.xz,
+                            !org.xerial.snappy,
+                            !sun.misc,
+                            !javax.inject,
+                            !org.apache.velocity.*,
+                            !org.jboss.netty.*,
+                            !org.mortbay.jetty.*,
+                            !org.mortbay.resource.*,
+                            !org.apache.sling.api.resource,
+                            *
+                        </Import-Package>
+                        <DynamicImport-Package>
+                            org.apache.sling.api.resource
+                        </DynamicImport-Package>
                     </instructions>
                 </configuration>
             </plugin>
@@ -243,6 +280,43 @@
             <version>2.0.0</version>
             <scope>provided</scope>
         </dependency>
+
+        <!-- avro -->
+        <dependency>
+            <groupId>org.apache.avro</groupId>
+            <artifactId>avro</artifactId>
+            <version>1.7.7</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.avro</groupId>
+            <artifactId>avro-ipc</artifactId>
+            <version>1.7.7</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <version>1.9.13</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <version>1.9.13</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.paranamer</groupId>
+            <artifactId>paranamer</artifactId>
+            <version>2.3</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+            <version>1.4.1</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
     <reporting>
         <plugins>

Added: sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/shallowresource.avsc
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/shallowresource.avsc?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/shallowresource.avsc (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/main/avro/shallowresource.avsc Thu Oct 22 11:15:16 2015
@@ -0,0 +1,11 @@
+{"namespace": "org.apache.sling.distribution.serialization.impl.avro",
+  "type": "record",
+  "name": "AvroShallowResource",
+  "fields": [
+    {"name": "name", "type": "string"},
+    {"name": "valueMap",  "type": {"type": "map", "values": ["int","long","float","double","string","boolean","bytes",{"type":"array","items":["int","long","float","double","string","boolean","bytes"]}]}},
+    {"name": "path", "type": ["string", "null"]},
+    {"name": "children", "type": [{"type": "array", "items": "AvroShallowResource"},"null"]},
+    {"name": "resourceType", "type": ["string", "null"]}
+  ]
+}
\ No newline at end of file

Added: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java Thu Oct 22 11:15:16 2015
@@ -0,0 +1,74 @@
+/*
+ * 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.distribution.serialization.impl;
+
+import javax.annotation.Nonnull;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sling.distribution.serialization.DistributionPackage;
+import org.apache.sling.distribution.serialization.DistributionPackageInfo;
+
+/**
+ * A {@link DistributionPackage} based on a {@link File}.
+ */
+public class FileDistributionPackage implements DistributionPackage {
+
+    private final File file;
+    private final String type;
+    private final DistributionPackageInfo info;
+
+    public FileDistributionPackage(@Nonnull File file, @Nonnull String type) {
+        this.info = new DistributionPackageInfo(type);
+        this.file = file;
+        this.type = type;
+    }
+
+    @Nonnull
+    public String getId() {
+        return file.getAbsolutePath();
+    }
+
+    @Nonnull
+    public String getType() {
+        return type;
+    }
+
+    @Nonnull
+    public InputStream createInputStream() throws IOException {
+        return new FileInputStream(file);
+    }
+
+    public void close() {
+        // do nothing
+    }
+
+    public void delete() {
+        assert file.delete();
+    }
+
+    @Nonnull
+    @Override
+    public DistributionPackageInfo getInfo() {
+        return info;
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/FileDistributionPackage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java Thu Oct 22 11:15:16 2015
@@ -0,0 +1,283 @@
+/*
+ * 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.distribution.serialization.impl.avro;
+
+import javax.annotation.Nonnull;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.avro.Schema;
+import org.apache.avro.file.DataFileReader;
+import org.apache.avro.file.DataFileWriter;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.io.DatumReader;
+import org.apache.avro.io.DatumWriter;
+import org.apache.avro.specific.SpecificDatumReader;
+import org.apache.avro.specific.SpecificDatumWriter;
+import org.apache.avro.util.Utf8;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.distribution.DistributionException;
+import org.apache.sling.distribution.DistributionRequest;
+import org.apache.sling.distribution.serialization.DistributionPackage;
+import org.apache.sling.distribution.serialization.DistributionPackageBuilder;
+import org.apache.sling.distribution.serialization.impl.FileDistributionPackage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Avro based {@link DistributionPackageBuilder}
+ */
+public class AvroDistributionPackageBuilder implements DistributionPackageBuilder {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private DataFileWriter<AvroShallowResource> dataFileWriter;
+    private Schema schema;
+
+    private final Set<String> ignoredProperties;
+    private final Set<String> ignoredNodeNames;
+    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.sss+hh:mm");
+
+    public AvroDistributionPackageBuilder() {
+        DatumWriter<AvroShallowResource> datumWriter = new SpecificDatumWriter<AvroShallowResource>(AvroShallowResource.class);
+        this.dataFileWriter = new DataFileWriter<AvroShallowResource>(datumWriter);
+        try {
+            schema = new Schema.Parser().parse(getClass().getResourceAsStream("/shallowresource.avsc"));
+        } catch (IOException e) {
+            // do nothing
+        }
+        Set<String> iProps = new HashSet<String>();
+        iProps.add(JcrConstants.JCR_FROZENMIXINTYPES);
+        iProps.add(JcrConstants.JCR_FROZENPRIMARYTYPE);
+        iProps.add(JcrConstants.JCR_FROZENUUID);
+        iProps.add(JcrConstants.JCR_VERSIONHISTORY);
+        iProps.add(JcrConstants.JCR_BASEVERSION);
+        iProps.add(JcrConstants.JCR_PREDECESSORS);
+        iProps.add(JcrConstants.JCR_SUCCESSORS);
+        iProps.add(JcrConstants.JCR_ISCHECKEDOUT);
+        iProps.add(JcrConstants.JCR_UUID);
+        ignoredProperties = Collections.unmodifiableSet(iProps);
+
+        Set<String> iNames = new HashSet<String>();
+        iNames.add("rep:policy");
+        ignoredNodeNames = Collections.unmodifiableSet(iNames);
+    }
+
+    @Override
+    public String getType() {
+        return AvroDistributionPackageBuilderFactory.RESOURCEAVRO;
+    }
+
+    @Override
+    public DistributionPackage createPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull DistributionRequest request) throws DistributionException {
+        DistributionPackage distributionPackage;
+        try {
+            File file = File.createTempFile("dp-" + System.nanoTime(), ".avro");
+            dataFileWriter.create(schema, file);
+
+            for (String path : request.getPaths()) {
+                Resource resource = resourceResolver.getResource(path);
+
+                AvroShallowResource avroShallowResource = getAvroShallowResource(request.isDeep(path), path, resource);
+
+                dataFileWriter.append(avroShallowResource);
+            }
+
+            distributionPackage = new FileDistributionPackage(file, getType());
+        } catch (Exception e) {
+            throw new DistributionException(e);
+        } finally {
+            try {
+                dataFileWriter.close();
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+        return distributionPackage;
+    }
+
+    private AvroShallowResource getAvroShallowResource(boolean deep, String path, Resource resource) throws IOException {
+        AvroShallowResource avroShallowResource = new AvroShallowResource();
+        avroShallowResource.setName("avro_" + System.nanoTime());
+        avroShallowResource.setPath(path);
+        avroShallowResource.setResourceType(resource.getResourceType());
+        ValueMap valueMap = resource.getValueMap();
+        Map<CharSequence, Object> map = new HashMap<CharSequence, Object>();
+        for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
+            if (!ignoredProperties.contains(entry.getKey())) {
+                Object value = entry.getValue();
+                if (value instanceof GregorianCalendar) {
+                    value = dateFormat.format(((GregorianCalendar) value).getTime());
+                } else if (value instanceof Object[]) {
+                    Object[] ar = (Object[]) value;
+                    value = Arrays.asList(ar);
+                } else if (value instanceof InputStream) {
+                    value = ByteBuffer.wrap(IOUtils.toByteArray(((InputStream) value)));
+                }
+                map.put(entry.getKey(), value);
+            }
+        }
+        avroShallowResource.setValueMap(map);
+        List<AvroShallowResource> children = new LinkedList<AvroShallowResource>();
+        if (deep) {
+            for (Resource child : resource.getChildren()) {
+                String childPath = child.getPath();
+                if (!ignoredNodeNames.contains(child.getName())) {
+                    children.add(getAvroShallowResource(true, childPath, child));
+                }
+            }
+        }
+        avroShallowResource.setChildren(children);
+        return avroShallowResource;
+    }
+
+    @Override
+    public DistributionPackage readPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull InputStream stream) throws DistributionException {
+        try {
+            File file = File.createTempFile("dp_" + System.nanoTime(), ".avro");
+            OutputStream output = new FileOutputStream(file);
+            int copied = IOUtils.copy(stream, output);
+
+            log.debug("copied {} bytes", copied);
+
+            return new FileDistributionPackage(file, getType());
+        } catch (Exception e) {
+            throw new DistributionException(e);
+        }
+    }
+
+    private Collection<AvroShallowResource> readAvroResources(File file) throws IOException {
+        DatumReader<AvroShallowResource> datumReader = new SpecificDatumReader<AvroShallowResource>(AvroShallowResource.class);
+        DataFileReader<AvroShallowResource> dataFileReader = new DataFileReader<AvroShallowResource>(file, datumReader);
+        AvroShallowResource avroResource = null;
+        Collection<AvroShallowResource> avroResources = new LinkedList<AvroShallowResource>();
+        while (dataFileReader.hasNext()) {
+// Reuse avroResource object by passing it to next(). This saves us from
+// allocating and garbage collecting many objects for files with
+// many items.
+            avroResource = dataFileReader.next(avroResource);
+            avroResources.add(avroResource);
+        }
+        return avroResources;
+    }
+
+    @Override
+    public DistributionPackage getPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull String id) {
+        File file = new File(id);
+        if (file.exists()) {
+            return new FileDistributionPackage(file, getType());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean installPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull DistributionPackage distributionPackage) throws DistributionException {
+        if (distributionPackage instanceof FileDistributionPackage) {
+            try {
+                String filePath = distributionPackage.getId();
+                File f = new File(filePath);
+                Collection<AvroShallowResource> avroShallowResources = readAvroResources(f);
+                for (AvroShallowResource r : avroShallowResources) {
+                    persistResource(resourceResolver, r);
+                }
+                resourceResolver.commit();
+            } catch (Exception e) {
+                throw new DistributionException(e);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void persistResource(@Nonnull ResourceResolver resourceResolver, AvroShallowResource r) throws PersistenceException {
+        String path = r.getPath().toString().trim();
+        String name = path.substring(path.lastIndexOf('/') + 1);
+        String substring = path.substring(0, path.lastIndexOf('/'));
+        String parentPath = substring.length() == 0 ? "/" : substring;
+        Map<String, Object> map = new HashMap<String, Object>();
+        Map<CharSequence, Object> valueMap = r.getValueMap();
+        for (Map.Entry<CharSequence, Object> entry : valueMap.entrySet()) {
+            Object value = entry.getValue();
+            if (value instanceof GenericData.Array) {
+                GenericData.Array array = (GenericData.Array) value;
+                String[] s = new String[array.size()];
+                for (int i = 0; i < s.length; i++) {
+                    Object gd = array.get(i);
+                    s[i] = gd.toString();
+                }
+                value = s;
+            } else if (value instanceof Utf8) {
+                value = value.toString();
+            } else if (value instanceof ByteBuffer) {
+                byte[] bytes = ((ByteBuffer) value).array();
+                value = new BufferedInputStream(new ByteArrayInputStream(bytes));
+            }
+            map.put(entry.getKey().toString(), value);
+        }
+        Resource existingResource = resourceResolver.getResource(path);
+        if (existingResource != null) {
+            resourceResolver.delete(existingResource);
+        }
+        Resource parent = resourceResolver.getResource(parentPath);
+        if (parent == null) {
+            parent = createParent(resourceResolver, parentPath);
+        }
+        Resource createdResource = resourceResolver.create(parent, name, map);
+        log.info("created resource {}", createdResource);
+        for (AvroShallowResource child : r.getChildren()) {
+            persistResource(createdResource.getResourceResolver(), child);
+        }
+    }
+
+    private Resource createParent(ResourceResolver resourceResolver, String path) throws PersistenceException {
+        String parentPath = path.substring(0, path.lastIndexOf('/'));
+        String name = path.substring(path.lastIndexOf('/') + 1);
+        Resource parentResource = resourceResolver.getResource(parentPath);
+        if (parentResource == null) {
+            parentResource = createParent(resourceResolver, parentPath);
+        }
+        Map<String, Object> properties = new HashMap<String, Object>();
+        return resourceResolver.create(parentResource, name, properties);
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java Thu Oct 22 11:15:16 2015
@@ -0,0 +1,119 @@
+/*
+ * 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.distribution.serialization.impl.avro;
+
+import javax.annotation.Nonnull;
+import java.io.InputStream;
+import java.util.Map;
+
+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.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.distribution.DistributionException;
+import org.apache.sling.distribution.DistributionRequest;
+import org.apache.sling.distribution.serialization.DistributionPackage;
+import org.apache.sling.distribution.serialization.DistributionPackageBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory for {@link DistributionPackageBuilder}s based on Apache Avro.
+ */
+@Component(metatype = true,
+        label = "Apache Sling Distribution Packaging - Avro Package Builder Factory",
+        description = "OSGi configuration for Avro package builders",
+        configurationFactory = true,
+        specVersion = "1.1",
+        policy = ConfigurationPolicy.REQUIRE
+)
+@Service(DistributionPackageBuilder.class)
+public class AvroDistributionPackageBuilderFactory implements DistributionPackageBuilder {
+
+    /**
+     * name of this package builder.
+     */
+    @Property(label = "Name", description = "The name of the package builder.")
+    public static final String NAME = "name";
+
+    public static final String JCRAVRO = "jcravro";
+
+    public static final String RESOURCEAVRO = "resourceavro";
+
+    /**
+     * type of this package builder.
+     */
+    @Property(options = {
+            @PropertyOption(name = JCRAVRO,
+                    value = "Avro JCR packages"
+            ),
+            @PropertyOption(name = RESOURCEAVRO,
+                    value = "Avro Resource packages"
+            )},
+            value = RESOURCEAVRO, label = "type", description = "The type of this package builder")
+    public static final String TYPE = "type";
+
+    /**
+     * Temp file folder
+     */
+    @Property(label = "Temp Filesystem Folder", description = "The filesystem folder where the temporary files should be saved.")
+    public static final String TEMP_FS_FOLDER = "tempFsFolder";
+
+    private DistributionPackageBuilder packageBuilder;
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Activate
+    public void activate(Map<String, Object> config) {
+
+        String type = PropertiesUtil.toString(config.get(TYPE), null);
+        log.info("starting avro package builder of type {}", type);
+
+        if (RESOURCEAVRO.equals(type)) {
+            packageBuilder = new AvroDistributionPackageBuilder();
+            log.info("started avro resource package builder");
+        } else {
+            throw new RuntimeException(type + " package builder not supported with Avro");
+        }
+    }
+
+    public String getType() {
+        return packageBuilder.getType();
+    }
+
+    public DistributionPackage createPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull DistributionRequest request) throws DistributionException {
+        return packageBuilder.createPackage(resourceResolver, request);
+    }
+
+    public DistributionPackage readPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull InputStream stream) throws DistributionException {
+        return packageBuilder.readPackage(resourceResolver, stream);
+    }
+
+    public DistributionPackage getPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull String id) throws DistributionException {
+        return packageBuilder.getPackage(resourceResolver, id);
+    }
+
+    public boolean installPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull DistributionPackage distributionPackage) throws DistributionException {
+        return packageBuilder.installPackage(resourceResolver, distributionPackage);
+    }
+}

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java Thu Oct 22 11:15:16 2015
@@ -0,0 +1,376 @@
+/*
+ * 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.distribution.serialization.impl.avro;  
+@SuppressWarnings("all")
+@org.apache.avro.specific.AvroGenerated
+public class AvroShallowResource extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
+  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"AvroShallowResource\",\"namespace\":\"org.apache.sling.distribution.serialization.impl.avro\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"valueMap\",\"type\":{\"type\":\"map\",\"values\":[\"int\",\"long\",\"float\",\"double\",\"string\",\"boolean\",\"bytes\",{\"type\":\"array\",\"items\":[\"int\",\"long\",\"float\",\"double\",\"string\",\"boolean\",\"bytes\"]}]}},{\"name\":\"path\",\"type\":[\"string\",\"null\"]},{\"name\":\"children\",\"type\":[{\"type\":\"array\",\"items\":\"AvroShallowResource\"},\"null\"]},{\"name\":\"resourceType\",\"type\":[\"string\",\"null\"]}]}");
+  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
+  @Deprecated
+  public java.lang.CharSequence name;
+  @Deprecated
+  public java.util.Map<java.lang.CharSequence,java.lang.Object> valueMap;
+  @Deprecated
+  public java.lang.CharSequence path;
+  @Deprecated
+  public java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> children;
+  @Deprecated
+  public java.lang.CharSequence resourceType;
+
+  /**
+   * Default constructor.  Note that this does not initialize fields
+   * to their default values from the schema.  If that is desired then
+   * one should use <code>newBuilder()</code>.
+   */
+  public AvroShallowResource() {}
+
+  /**
+   * All-args constructor.
+   */
+  public AvroShallowResource(java.lang.CharSequence name, java.util.Map<java.lang.CharSequence,java.lang.Object> valueMap, java.lang.CharSequence path, java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> children, java.lang.CharSequence resourceType) {
+    this.name = name;
+    this.valueMap = valueMap;
+    this.path = path;
+    this.children = children;
+    this.resourceType = resourceType;
+  }
+
+  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
+  // Used by DatumWriter.  Applications should not call.
+  public java.lang.Object get(int field$) {
+    switch (field$) {
+    case 0: return name;
+    case 1: return valueMap;
+    case 2: return path;
+    case 3: return children;
+    case 4: return resourceType;
+    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
+    }
+  }
+  // Used by DatumReader.  Applications should not call.
+  @SuppressWarnings(value="unchecked")
+  public void put(int field$, java.lang.Object value$) {
+    switch (field$) {
+    case 0: name = (java.lang.CharSequence)value$; break;
+    case 1: valueMap = (java.util.Map<java.lang.CharSequence,java.lang.Object>)value$; break;
+    case 2: path = (java.lang.CharSequence)value$; break;
+    case 3: children = (java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource>)value$; break;
+    case 4: resourceType = (java.lang.CharSequence)value$; break;
+    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
+    }
+  }
+
+  /**
+   * Gets the value of the 'name' field.
+   */
+  public java.lang.CharSequence getName() {
+    return name;
+  }
+
+  /**
+   * Sets the value of the 'name' field.
+   * @param value the value to set.
+   */
+  public void setName(java.lang.CharSequence value) {
+    this.name = value;
+  }
+
+  /**
+   * Gets the value of the 'valueMap' field.
+   */
+  public java.util.Map<java.lang.CharSequence,java.lang.Object> getValueMap() {
+    return valueMap;
+  }
+
+  /**
+   * Sets the value of the 'valueMap' field.
+   * @param value the value to set.
+   */
+  public void setValueMap(java.util.Map<java.lang.CharSequence,java.lang.Object> value) {
+    this.valueMap = value;
+  }
+
+  /**
+   * Gets the value of the 'path' field.
+   */
+  public java.lang.CharSequence getPath() {
+    return path;
+  }
+
+  /**
+   * Sets the value of the 'path' field.
+   * @param value the value to set.
+   */
+  public void setPath(java.lang.CharSequence value) {
+    this.path = value;
+  }
+
+  /**
+   * Gets the value of the 'children' field.
+   */
+  public java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> getChildren() {
+    return children;
+  }
+
+  /**
+   * Sets the value of the 'children' field.
+   * @param value the value to set.
+   */
+  public void setChildren(java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> value) {
+    this.children = value;
+  }
+
+  /**
+   * Gets the value of the 'resourceType' field.
+   */
+  public java.lang.CharSequence getResourceType() {
+    return resourceType;
+  }
+
+  /**
+   * Sets the value of the 'resourceType' field.
+   * @param value the value to set.
+   */
+  public void setResourceType(java.lang.CharSequence value) {
+    this.resourceType = value;
+  }
+
+  /** Creates a new AvroShallowResource RecordBuilder */
+  public static org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder newBuilder() {
+    return new org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder();
+  }
+
+  /** Creates a new AvroShallowResource RecordBuilder by copying an existing Builder */
+  public static org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder newBuilder(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder other) {
+    return new org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder(other);
+  }
+
+  /** Creates a new AvroShallowResource RecordBuilder by copying an existing AvroShallowResource instance */
+  public static org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder newBuilder(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource other) {
+    return new org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder(other);
+  }
+
+  /**
+   * RecordBuilder for AvroShallowResource instances.
+   */
+  public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<AvroShallowResource>
+    implements org.apache.avro.data.RecordBuilder<AvroShallowResource> {
+
+    private java.lang.CharSequence name;
+    private java.util.Map<java.lang.CharSequence,java.lang.Object> valueMap;
+    private java.lang.CharSequence path;
+    private java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> children;
+    private java.lang.CharSequence resourceType;
+
+    /** Creates a new Builder */
+    private Builder() {
+      super(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.SCHEMA$);
+    }
+
+    /** Creates a Builder by copying an existing Builder */
+    private Builder(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder other) {
+      super(other);
+      if (isValidValue(fields()[0], other.name)) {
+        this.name = data().deepCopy(fields()[0].schema(), other.name);
+        fieldSetFlags()[0] = true;
+      }
+      if (isValidValue(fields()[1], other.valueMap)) {
+        this.valueMap = data().deepCopy(fields()[1].schema(), other.valueMap);
+        fieldSetFlags()[1] = true;
+      }
+      if (isValidValue(fields()[2], other.path)) {
+        this.path = data().deepCopy(fields()[2].schema(), other.path);
+        fieldSetFlags()[2] = true;
+      }
+      if (isValidValue(fields()[3], other.children)) {
+        this.children = data().deepCopy(fields()[3].schema(), other.children);
+        fieldSetFlags()[3] = true;
+      }
+      if (isValidValue(fields()[4], other.resourceType)) {
+        this.resourceType = data().deepCopy(fields()[4].schema(), other.resourceType);
+        fieldSetFlags()[4] = true;
+      }
+    }
+
+    /** Creates a Builder by copying an existing AvroShallowResource instance */
+    private Builder(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource other) {
+            super(org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.SCHEMA$);
+      if (isValidValue(fields()[0], other.name)) {
+        this.name = data().deepCopy(fields()[0].schema(), other.name);
+        fieldSetFlags()[0] = true;
+      }
+      if (isValidValue(fields()[1], other.valueMap)) {
+        this.valueMap = data().deepCopy(fields()[1].schema(), other.valueMap);
+        fieldSetFlags()[1] = true;
+      }
+      if (isValidValue(fields()[2], other.path)) {
+        this.path = data().deepCopy(fields()[2].schema(), other.path);
+        fieldSetFlags()[2] = true;
+      }
+      if (isValidValue(fields()[3], other.children)) {
+        this.children = data().deepCopy(fields()[3].schema(), other.children);
+        fieldSetFlags()[3] = true;
+      }
+      if (isValidValue(fields()[4], other.resourceType)) {
+        this.resourceType = data().deepCopy(fields()[4].schema(), other.resourceType);
+        fieldSetFlags()[4] = true;
+      }
+    }
+
+    /** Gets the value of the 'name' field */
+    public java.lang.CharSequence getName() {
+      return name;
+    }
+
+    /** Sets the value of the 'name' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder setName(java.lang.CharSequence value) {
+      validate(fields()[0], value);
+      this.name = value;
+      fieldSetFlags()[0] = true;
+      return this;
+    }
+
+    /** Checks whether the 'name' field has been set */
+    public boolean hasName() {
+      return fieldSetFlags()[0];
+    }
+
+    /** Clears the value of the 'name' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder clearName() {
+      name = null;
+      fieldSetFlags()[0] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'valueMap' field */
+    public java.util.Map<java.lang.CharSequence,java.lang.Object> getValueMap() {
+      return valueMap;
+    }
+
+    /** Sets the value of the 'valueMap' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder setValueMap(java.util.Map<java.lang.CharSequence,java.lang.Object> value) {
+      validate(fields()[1], value);
+      this.valueMap = value;
+      fieldSetFlags()[1] = true;
+      return this;
+    }
+
+    /** Checks whether the 'valueMap' field has been set */
+    public boolean hasValueMap() {
+      return fieldSetFlags()[1];
+    }
+
+    /** Clears the value of the 'valueMap' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder clearValueMap() {
+      valueMap = null;
+      fieldSetFlags()[1] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'path' field */
+    public java.lang.CharSequence getPath() {
+      return path;
+    }
+
+    /** Sets the value of the 'path' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder setPath(java.lang.CharSequence value) {
+      validate(fields()[2], value);
+      this.path = value;
+      fieldSetFlags()[2] = true;
+      return this;
+    }
+
+    /** Checks whether the 'path' field has been set */
+    public boolean hasPath() {
+      return fieldSetFlags()[2];
+    }
+
+    /** Clears the value of the 'path' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder clearPath() {
+      path = null;
+      fieldSetFlags()[2] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'children' field */
+    public java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> getChildren() {
+      return children;
+    }
+
+    /** Sets the value of the 'children' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder setChildren(java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource> value) {
+      validate(fields()[3], value);
+      this.children = value;
+      fieldSetFlags()[3] = true;
+      return this;
+    }
+
+    /** Checks whether the 'children' field has been set */
+    public boolean hasChildren() {
+      return fieldSetFlags()[3];
+    }
+
+    /** Clears the value of the 'children' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder clearChildren() {
+      children = null;
+      fieldSetFlags()[3] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'resourceType' field */
+    public java.lang.CharSequence getResourceType() {
+      return resourceType;
+    }
+
+    /** Sets the value of the 'resourceType' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder setResourceType(java.lang.CharSequence value) {
+      validate(fields()[4], value);
+      this.resourceType = value;
+      fieldSetFlags()[4] = true;
+      return this;
+    }
+
+    /** Checks whether the 'resourceType' field has been set */
+    public boolean hasResourceType() {
+      return fieldSetFlags()[4];
+    }
+
+    /** Clears the value of the 'resourceType' field */
+    public org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource.Builder clearResourceType() {
+      resourceType = null;
+      fieldSetFlags()[4] = false;
+      return this;
+    }
+
+    @Override
+    public AvroShallowResource build() {
+      try {
+        AvroShallowResource record = new AvroShallowResource();
+        record.name = fieldSetFlags()[0] ? this.name : (java.lang.CharSequence) defaultValue(fields()[0]);
+        record.valueMap = fieldSetFlags()[1] ? this.valueMap : (java.util.Map<java.lang.CharSequence,java.lang.Object>) defaultValue(fields()[1]);
+        record.path = fieldSetFlags()[2] ? this.path : (java.lang.CharSequence) defaultValue(fields()[2]);
+        record.children = fieldSetFlags()[3] ? this.children : (java.util.List<org.apache.sling.distribution.serialization.impl.avro.AvroShallowResource>) defaultValue(fields()[3]);
+        record.resourceType = fieldSetFlags()[4] ? this.resourceType : (java.lang.CharSequence) defaultValue(fields()[4]);
+        return record;
+      } catch (Exception e) {
+        throw new org.apache.avro.AvroRuntimeException(e);
+      }
+    }
+  }
+}

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/main/java/org/apache/sling/distribution/serialization/impl/avro/AvroShallowResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java?rev=1709989&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java (added)
+++ sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java Thu Oct 22 11:15:16 2015
@@ -0,0 +1,110 @@
+/*
+ * 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.distribution.serialization.impl.avro;
+
+import javax.annotation.Nonnull;
+import java.io.File;
+import java.io.InputStream;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.DistributionRequest;
+import org.apache.sling.distribution.DistributionRequestType;
+import org.apache.sling.distribution.SimpleDistributionRequest;
+import org.apache.sling.distribution.serialization.DistributionPackage;
+import org.apache.sling.distribution.serialization.impl.FileDistributionPackage;
+import org.apache.sling.testing.resourceresolver.MockHelper;
+import org.apache.sling.testing.resourceresolver.MockResourceResolverFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link AvroDistributionPackageBuilder}
+ */
+public class AvroDistributionPackageBuilderTest {
+
+    private MockHelper helper;
+    private ResourceResolver resourceResolver;
+
+    @Before
+    public void setUp() throws Exception {
+        resourceResolver = new MockResourceResolverFactory().getResourceResolver(null);
+        helper = MockHelper.create(resourceResolver).resource("/libs").p("prop", "value")
+                .resource("sub").p("sub", "hello")
+                .resource(".sameLevel")
+                .resource("/apps").p("foo", "baa");
+        helper.commit();
+    }
+
+    @Test
+    public void testCreatePackage() throws Exception {
+        AvroDistributionPackageBuilder avroDistributionPackageBuilder = new AvroDistributionPackageBuilder();
+        DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, "/libs");
+        DistributionPackage avroPackage = avroDistributionPackageBuilder.createPackage(resourceResolver, request);
+        assertNotNull(avroPackage);
+    }
+
+    @Test
+    public void testReadPackage() throws Exception {
+        AvroDistributionPackageBuilder avroDistributionPackageBuilder = new AvroDistributionPackageBuilder();
+        InputStream stream = getClass().getResourceAsStream("/avro/dp.avro");
+        DistributionPackage distributionPackage = avroDistributionPackageBuilder.readPackage(resourceResolver, stream);
+        assertNotNull(distributionPackage);
+    }
+
+    @Test
+    public void testGetPackage() throws Exception {
+        AvroDistributionPackageBuilder avroDistributionPackageBuilder = new AvroDistributionPackageBuilder();
+        DistributionPackage aPackage = avroDistributionPackageBuilder.getPackage(resourceResolver, getClass().getResource("/avro/dp.avro").getFile());
+        assertNotNull(aPackage);
+    }
+
+    @Test
+    public void testInstallPackage() throws Exception {
+        AvroDistributionPackageBuilder avroDistributionPackageBuilder = new AvroDistributionPackageBuilder();
+        File f = new File(getClass().getResource("/avro/dp.avro").getFile());
+        DistributionPackage distributionPackage = new FileDistributionPackage(f, "avro");
+        boolean success = avroDistributionPackageBuilder.installPackage(resourceResolver, distributionPackage);
+        assertTrue(success);
+    }
+
+    @Test
+    public void testPackageLifecycle() throws Exception {
+        AvroDistributionPackageBuilder avroDistributionPackageBuilder = new AvroDistributionPackageBuilder();
+        DistributionPackage distributionPackage = avroDistributionPackageBuilder.createPackage(resourceResolver, new DistributionRequest() {
+            @Nonnull
+            public DistributionRequestType getRequestType() {
+                return DistributionRequestType.ADD;
+            }
+
+            public String[] getPaths() {
+                return new String[]{"/libs"};
+            }
+
+            public boolean isDeep(String path) {
+                return false;
+            }
+        });
+        assertNotNull(distributionPackage);
+        DistributionPackage readPackage = avroDistributionPackageBuilder.readPackage(resourceResolver, distributionPackage.createInputStream());
+        assertTrue(avroDistributionPackageBuilder.installPackage(resourceResolver, readPackage));
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/test/java/org/apache/sling/distribution/serialization/impl/avro/AvroDistributionPackageBuilderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/avro/dp.avro
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/avro/dp.avro?rev=1709989&view=auto
==============================================================================
Binary file - no diff available.

Propchange: sling/trunk/contrib/extensions/distribution/extensions/src/test/resources/avro/dp.avro
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream