You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/18 23:24:00 UTC

[sling-org-apache-sling-distribution-kryo-serializer] 01/05: SLING-6325 - split Avro and Kryo serializers into own bundles

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-distribution-kryo-serializer.git

commit e0131c5b95ab87c68de119d84b31419554caf91d
Author: Tommaso Teofili <to...@apache.org>
AuthorDate: Thu Feb 23 15:28:47 2017 +0000

    SLING-6325 - split Avro and Kryo serializers into own bundles
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1784154 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 360 +++++++++++++++++++++
 .../impl/kryo/KryoContentSerializer.java           | 242 ++++++++++++++
 .../KryoDistributionContentSerializerFactory.java  |  91 ++++++
 .../impl/kryo/KryoContentSerializerTest.java       | 160 +++++++++
 src/test/resources/kryo/dp.kryo                    | Bin 0 -> 717 bytes
 5 files changed, 853 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e6e1147
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,360 @@
+<?xml version="1.0"?>
+<!--
+    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>
+    <!-- ======================================================================= -->
+    <!-- P A R E N T   P R O J E C T                                             -->
+    <!-- ======================================================================= -->
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>26</version>
+    </parent>
+
+    <!-- ======================================================================= -->
+    <!-- P R O J E C T                                                           -->
+    <!-- ======================================================================= -->
+    <artifactId>org.apache.sling.distribution.kryo-serializer</artifactId>
+    <version>0.0.9-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Distribution Kryo Serializer</name>
+    <description>
+        The Apache Sling Distribution Kryo Serializer extension bundle provides a Kryo based serializer implementations for Sling Content Distribution
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/distribution/kryo-serializer</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/distribution/kryo-serializer</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/kryo-serializer</url>
+    </scm>
+
+    <!-- ======================================================================= -->
+    <!-- B U I L D                                                               -->
+    <!-- ======================================================================= -->
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>**/*.kryo</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>maven-sling-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>org.apache.sling.distribution.extensions</Bundle-SymbolicName>
+                        <Embed-Dependency>kryo,reflectasm,minlog,asm,objenesis
+                            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,
+                            !org.apache.sling.distribution.component.*,
+                            !org.apache.sling.distribution.packaging.*,
+                            !org.apache.sling.distribution.serialization.impl.vlt.*,
+                            *
+                        </Import-Package>
+                        <DynamicImport-Package>
+                            org.apache.sling.api.resource
+                        </DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+    <!-- ======================================================================= -->
+    <!-- D E P E N D E N C I E S                                                 -->
+    <!-- ======================================================================= -->
+    <dependencies>
+        <!-- TESTING -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-spi-commons</artifactId>
+            <version>2.6.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
+            <version>1.1.12</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- SLING -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.7.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.distribution.api</artifactId>
+            <version>0.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.distribution.core</artifactId>
+            <version>0.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.scheduler</artifactId>
+            <version>2.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.api</artifactId>
+            <version>2.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.event</artifactId>
+            <version>3.3.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.hc.core</artifactId>
+            <version>1.0.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.settings</artifactId>
+            <version>1.3.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.8</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.event.dea</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <!-- LOGGING -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.6.2</version>
+            <scope>runtime</scope>
+        </dependency>
+        <!-- SPECs -->
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <!-- JACKRABBIT -->
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>2.6.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-api</artifactId>
+            <version>2.6.2</version>
+        </dependency>
+        <!-- COMMONS -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <version>2.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <!-- kryo -->
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>kryo</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>reflectasm</artifactId>
+            <version>1.11.0</version>
+            <classifier>shaded</classifier>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>minlog</artifactId>
+            <version>1.3.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+            <version>5.0.3</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.objenesis</groupId>
+            <artifactId>objenesis</artifactId>
+            <version>2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.resource</artifactId>
+            <version>2.5.6</version>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.scripting.api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.jcr.api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.adapter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.commons.osgi</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.auth.core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.commons.classloader</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-collections</groupId>
+                    <artifactId>commons-collections</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-lang</groupId>
+                    <artifactId>commons-lang</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>adapter-annotations</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>org.apache.sling.serviceusermapper</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>2.5.3</version>
+            </plugin>
+        </plugins>
+    </reporting>
+</project>
diff --git a/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializer.java b/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializer.java
new file mode 100644
index 0000000..541b4ec
--- /dev/null
+++ b/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializer.java
@@ -0,0 +1,242 @@
+/*
+ * 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.kryo;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import org.apache.commons.io.IOUtils;
+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.SyntheticResource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.distribution.common.DistributionException;
+import org.apache.sling.distribution.serialization.DistributionContentSerializer;
+import org.apache.sling.distribution.serialization.DistributionExportFilter;
+import org.apache.sling.distribution.serialization.DistributionExportOptions;
+import org.objenesis.strategy.StdInstantiatorStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Kryo based {@link DistributionContentSerializer}
+ */
+public class KryoContentSerializer implements DistributionContentSerializer {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final String name;
+
+    public KryoContentSerializer(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void exportToStream(ResourceResolver resourceResolver, DistributionExportOptions options, OutputStream outputStream) throws DistributionException {
+
+        DistributionExportFilter filter = options.getFilter();
+
+        Kryo kryo = new Kryo();
+        kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
+        kryo.addDefaultSerializer(Resource.class, new ResourceSerializer(filter.getPropertyFilter()));
+        kryo.addDefaultSerializer(InputStream.class, new InputStreamSerializer());
+
+        Output output = new Output(outputStream);
+        LinkedList<Resource> resources = new LinkedList<Resource>();
+        for (DistributionExportFilter.TreeFilter nodeFilter : filter.getNodeFilters()) {
+            Resource resource = resourceResolver.getResource(nodeFilter.getPath());
+            if (resource != null) {
+                addResource(nodeFilter, resources, resource);
+            }
+        }
+        kryo.writeObject(output, resources);
+        output.flush();
+
+    }
+
+    @Override
+    public void importFromStream(ResourceResolver resourceResolver, InputStream stream) throws DistributionException {
+        Kryo kryo = new Kryo();
+        kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
+        kryo.addDefaultSerializer(Resource.class, new ResourceSerializer(null));
+        kryo.addDefaultSerializer(InputStream.class, new InputStreamSerializer());
+        try {
+            Input input = new Input(stream);
+            LinkedList<Resource> resources = (LinkedList<Resource>) kryo.readObject(input, LinkedList.class);
+            input.close();
+            for (Resource resource : resources) {
+                persistResource(resourceResolver, resource);
+            }
+            resourceResolver.commit();
+        } catch (Exception e) {
+            throw new DistributionException(e);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean isRequestFiltering() {
+        return false;
+    }
+
+    private void persistResource(@Nonnull ResourceResolver resourceResolver, Resource resource) throws PersistenceException {
+        String path = resource.getPath().trim();
+        String name = path.substring(path.lastIndexOf('/') + 1);
+        String substring = path.substring(0, path.lastIndexOf('/'));
+        String parentPath = substring.length() == 0 ? "/" : substring;
+        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, resource.getValueMap());
+        log.debug("created resource {}", createdResource);
+    }
+
+    private Resource createParent(ResourceResolver resourceResolver, String path) throws PersistenceException {
+        String parentPath = path.substring(0, path.lastIndexOf('/'));
+        if (parentPath.length() == 0) {
+            parentPath = "/";
+        }
+        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);
+    }
+
+    private class ResourceSerializer extends Serializer<Resource> {
+
+        private final DistributionExportFilter.TreeFilter propertyFilter;
+
+        private ResourceSerializer(@Nullable DistributionExportFilter.TreeFilter propertyFilter) {
+            this.propertyFilter = propertyFilter;
+        }
+
+        @Override
+        public void write(Kryo kryo, Output output, Resource resource) {
+            ValueMap valueMap = resource.getValueMap();
+
+            output.writeString(resource.getPath());
+            output.writeString(resource.getResourceType());
+
+            HashMap map = new HashMap<String, Object>();
+            for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
+                if (propertyFilter == null || propertyFilter.matches(entry.getKey())) {
+                    map.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            kryo.writeObjectOrNull(output, map, HashMap.class);
+        }
+
+        @Override
+        public Resource read(Kryo kryo, Input input, Class<Resource> type) {
+
+            String path = input.readString();
+            String resourceType = input.readString();
+
+            final HashMap<String, Object> map = kryo.readObjectOrNull(input, HashMap.class);
+
+            return new SyntheticResource(null, path, resourceType) {
+                @Override
+                public ValueMap getValueMap() {
+                    return new ValueMapDecorator(map);
+                }
+            };
+        }
+
+    }
+
+    private class ValueMapSerializer extends Serializer<ValueMap> {
+        @Override
+        public void write(Kryo kryo, Output output, ValueMap valueMap) {
+            for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
+                output.writeString(entry.getKey());
+                output.writeString(entry.getValue().toString());
+            }
+        }
+
+        @Override
+        public ValueMap read(Kryo kryo, Input input, Class<ValueMap> type) {
+            final Map<String, Object> map = new HashMap<String, Object>();
+
+            String key;
+            while ((key = input.readString()) != null) {
+                String value = input.readString();
+                map.put(key, value);
+            }
+            return new ValueMapDecorator(map);
+        }
+    }
+
+    private class InputStreamSerializer extends Serializer<InputStream> {
+        @Override
+        public void write(Kryo kryo, Output output, InputStream stream) {
+            try {
+                byte[] bytes = IOUtils.toByteArray(stream);
+                output.writeInt(bytes.length);
+                output.write(bytes);
+            } catch (IOException e) {
+                log.warn("could not serialize input stream", e);
+            }
+        }
+
+        @Override
+        public InputStream read(Kryo kryo, Input input, Class<InputStream> type) {
+            int size = input.readInt();
+            byte[] bytes = new byte[size];
+            input.readBytes(bytes);
+            return new ByteArrayInputStream(bytes);
+        }
+    }
+
+    private void addResource(DistributionExportFilter.TreeFilter nodeFilter, LinkedList<Resource> resources, Resource resource) {
+        resources.add(resource);
+        for (Resource child : resource.getChildren()) {
+            if (nodeFilter.matches(child.getPath())) {
+                addResource(nodeFilter, resources, child);
+            }
+        }
+    }
+
+
+}
diff --git a/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoDistributionContentSerializerFactory.java b/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoDistributionContentSerializerFactory.java
new file mode 100644
index 0000000..a18bb9d
--- /dev/null
+++ b/src/main/java/org/apache/sling/distribution/serialization/impl/kryo/KryoDistributionContentSerializerFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.kryo;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+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.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.distribution.common.DistributionException;
+import org.apache.sling.distribution.serialization.DistributionContentSerializer;
+import org.apache.sling.distribution.serialization.DistributionExportOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory for {@link DistributionContentSerializer}s based on Kryo.
+ */
+@Component(metatype = true,
+        label = "Apache Sling Distribution Packaging - Kryo Serialization Format Factory",
+        description = "OSGi configuration for Kryo serializers",
+        configurationFactory = true,
+        specVersion = "1.1",
+        policy = ConfigurationPolicy.REQUIRE
+)
+@Service(DistributionContentSerializer.class)
+@Property(name = "webconsole.configurationFactory.nameHint", value = "Content serializer name: {name}")
+public class KryoDistributionContentSerializerFactory implements DistributionContentSerializer {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * name of this package builder.
+     */
+    @Property(label = "Name", description = "The name of the package builder.")
+    public static final String NAME = "name";
+
+    private KryoContentSerializer format;
+
+    @Activate
+    public void activate(Map<String, Object> config) {
+
+        String name = PropertiesUtil.toString(config.get(NAME), null);
+
+        format = new KryoContentSerializer(name);
+        log.info("started Kryo content serializer {}", name);
+    }
+
+
+    @Override
+    public void exportToStream(ResourceResolver resourceResolver, DistributionExportOptions options, OutputStream outputStream) throws DistributionException {
+        format.exportToStream(resourceResolver, options, outputStream);
+    }
+
+    @Override
+    public void importFromStream(ResourceResolver resourceResolver, InputStream stream) throws DistributionException {
+        format.importFromStream(resourceResolver, stream);
+    }
+
+    @Override
+    public String getName() {
+        return format.getName();
+    }
+
+    @Override
+    public boolean isRequestFiltering() {
+        return format.isRequestFiltering();
+    }
+}
diff --git a/src/test/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializerTest.java b/src/test/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializerTest.java
new file mode 100644
index 0000000..df3aa04
--- /dev/null
+++ b/src/test/java/org/apache/sling/distribution/serialization/impl/kryo/KryoContentSerializerTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.kryo;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+
+import org.apache.sling.api.resource.Resource;
+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.packaging.DistributionPackage;
+import org.apache.sling.distribution.packaging.DistributionPackageBuilder;
+import org.apache.sling.distribution.packaging.impl.FileDistributionPackageBuilder;
+import org.apache.sling.distribution.serialization.DistributionContentSerializer;
+import org.apache.sling.distribution.serialization.DistributionExportFilter;
+import org.apache.sling.distribution.serialization.DistributionExportOptions;
+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 KryoContentSerializer}
+ */
+public class KryoContentSerializerTest {
+
+    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 testExtract() throws Exception {
+        KryoContentSerializer kryoContentSerializer = new KryoContentSerializer("kryo");
+        DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, "/libs");
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        NavigableMap<String, List<String>> nodeFilters = new TreeMap<String, List<String>>();
+        NavigableMap<String, List<String>> propertyFilters = new TreeMap<String, List<String>>();
+        try {
+            DistributionExportFilter filter = DistributionExportFilter.createFilter(request, nodeFilters, propertyFilters);
+            kryoContentSerializer.exportToStream(resourceResolver, new DistributionExportOptions(request, filter), outputStream);
+            byte[] bytes = outputStream.toByteArray();
+            assertNotNull(bytes);
+            assertTrue(bytes.length > 0);
+        } finally {
+            outputStream.close();
+        }
+    }
+
+    @Test
+    public void testImport() throws Exception {
+        KryoContentSerializer kryoContentSerializer = new KryoContentSerializer("avro");
+        InputStream inputStream = getClass().getResourceAsStream("/kryo/dp.kryo");
+        kryoContentSerializer.importFromStream(resourceResolver, inputStream);
+    }
+
+    @Test
+    public void testBuildAndInstallOnSingleDeepPath() throws Exception {
+        String type = "kryo";
+        DistributionContentSerializer contentSerializer = new KryoContentSerializer(type);
+        String tempFilesFolder = "target";
+        String[] nodeFilters = new String[0];
+        String[] propertyFilters = new String[0];
+        DistributionPackageBuilder packageBuilder = new FileDistributionPackageBuilder(type, contentSerializer,
+                tempFilesFolder, null, nodeFilters, propertyFilters);
+        DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, true, "/libs");
+        DistributionPackage distributionPackage = packageBuilder.createPackage(resourceResolver, request);
+
+        Resource resource = resourceResolver.getResource("/libs/sub");
+        resourceResolver.delete(resource);
+        resourceResolver.commit();
+
+        assertTrue(packageBuilder.installPackage(resourceResolver, distributionPackage));
+
+        assertNotNull(resourceResolver.getResource("/libs"));
+        assertNotNull(resourceResolver.getResource("/libs/sub"));
+        assertNotNull(resourceResolver.getResource("/libs/sameLevel"));
+    }
+
+    @Test
+    public void testBuildAndInstallOnSingleShallowPath() throws Exception {
+        String type = "kryo";
+        DistributionContentSerializer contentSerializer = new KryoContentSerializer(type);
+        String tempFilesFolder = "target";
+        String[] nodeFilters = new String[0];
+        String[] propertyFilters = new String[0];
+        DistributionPackageBuilder packageBuilder = new FileDistributionPackageBuilder(type, contentSerializer,
+                tempFilesFolder, null, nodeFilters, propertyFilters);
+        DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, "/libs/sub");
+        DistributionPackage distributionPackage = packageBuilder.createPackage(resourceResolver, request);
+
+        Resource resource = resourceResolver.getResource("/libs/sub");
+        resourceResolver.delete(resource);
+        resourceResolver.commit();
+
+        assertTrue(packageBuilder.installPackage(resourceResolver, distributionPackage));
+
+        assertNotNull(resourceResolver.getResource("/libs"));
+        assertNotNull(resourceResolver.getResource("/libs/sub"));
+        assertNotNull(resourceResolver.getResource("/libs/sameLevel"));
+    }
+
+    @Test
+    public void testBuildAndInstallOnMultipleShallowPaths() throws Exception {
+        String type = "kryo";
+        DistributionContentSerializer contentSerializer = new KryoContentSerializer(type);
+        String tempFilesFolder = "target";
+        String[] nodeFilters = new String[0];
+        String[] propertyFilters = new String[0];
+        DistributionPackageBuilder packageBuilder = new FileDistributionPackageBuilder(type, contentSerializer,
+                tempFilesFolder, null, nodeFilters, propertyFilters);
+        DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, "/libs/sub", "/libs/sameLevel");
+        DistributionPackage distributionPackage = packageBuilder.createPackage(resourceResolver, request);
+
+        Resource resource = resourceResolver.getResource("/libs/sub");
+        resourceResolver.delete(resource);
+        resource = resourceResolver.getResource("/libs/sameLevel");
+        resourceResolver.delete(resource);
+        resourceResolver.commit();
+
+        assertTrue(packageBuilder.installPackage(resourceResolver, distributionPackage));
+
+        assertNotNull(resourceResolver.getResource("/libs"));
+        assertNotNull(resourceResolver.getResource("/libs/sub"));
+        assertNotNull(resourceResolver.getResource("/libs/sameLevel"));
+    }
+
+}
diff --git a/src/test/resources/kryo/dp.kryo b/src/test/resources/kryo/dp.kryo
new file mode 100644
index 0000000..bff4a8c
Binary files /dev/null and b/src/test/resources/kryo/dp.kryo differ

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.