Author: tommaso
Date: Fri Dec  5 09:19:24 2014
New Revision: 1643201

URL: http://svn.apache.org/viewvc?rev=1643201&view=rev
Log:
SLING-4153 - fixed transport API to just expose the secret

Added:
    
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransport.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransport.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransport.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/UserCredentialsDistributionTransportSecretProvider.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java
   (with props)
    
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
    
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.osgi.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json

Added: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,56 @@
+/*
+ * 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.transport;
+
+import javax.annotation.CheckForNull;
+import java.io.InputStream;
+import java.util.Map;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * The secret to be transported for authenticating transport layer connecting 
two instances.
+ * <p/>
+ * Secrets can take different forms, like e.g. username and password, tokens, 
public keys, etc. and are meant to be used
+ * by transport implementations lying under {@link 
org.apache.sling.distribution.packaging.DistributionPackageImporter importers}
+ * and / or {@link 
org.apache.sling.distribution.packaging.DistributionPackageExporter exporters}.
+ */
+@ConsumerType
+public interface DistributionTransportSecret {
+
+    /**
+     * Get the secret as a {@link java.util.Map} of credentials, this can 
contain, for example, entries holding information
+     * about username and password for HTTP authentication.
+     *
+     * @return the credentials as a {@link java.util.Map}, or {@code null} if 
{@code secret} cannot be represented in terms
+     * of a set of key -> value entries
+     */
+    @CheckForNull
+    Map<String, String> asCredentialsMap();
+
+    /**
+     * Get the secrete as a raw {@link java.io.InputStream binary}.
+     * Note that each call to this method will create a new stream, so the 
caller will be responsible of closing it.
+     *
+     * @return the secret as an {@link java.io.InputStream}, or {@code null} 
if such a secret cannot represented as a stream.
+     */
+    @CheckForNull
+    InputStream asStream();
+
+}

Propchange: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecret.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,44 @@
+/*
+ * 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.transport;
+
+import javax.annotation.CheckForNull;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * A provider for {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret}s
+ * <p/>
+ * Such providers can be used by {@link 
org.apache.sling.distribution.packaging.DistributionPackageExporter exporters} 
or
+ * {@link org.apache.sling.distribution.packaging.DistributionPackageImporter 
importers} implementations in order to plug
+ * in different types of {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret secrets} to 
be used
+ * to authenticate the underlying Sling instances.
+ */
+@ConsumerType
+public interface DistributionTransportSecretProvider {
+
+    /**
+     * Get a {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret}
+     *
+     * @return a {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret secret}, or 
{@code null} if
+     * that cannot be obtained
+     */
+    @CheckForNull
+    DistributionTransportSecret getSecret();
+}

Propchange: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/DistributionTransportSecretProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+@Version("0.1.0")
+package org.apache.sling.distribution.transport;
+
+import aQute.bnd.annotation.Version;
+

Propchange: 
sling/trunk/contrib/extensions/distribution/api/src/main/java/org/apache/sling/distribution/transport/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,67 @@
+/*
+ * 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.transport;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.communication.DistributionRequest;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+
+/**
+ * A transport layer implementation to transport data between two (or 
eventually more) Sling instances.
+ * <p/>
+ * Each implementation is meant to be stateful in the sense that it will hide 
the details about the sending / receiving
+ * endpoints of the transport.
+ */
+public interface DistributionTransport {
+
+    /**
+     * Deliver a {@link 
org.apache.sling.distribution.packaging.DistributionPackage} to a target 
instance using this
+     * transport layer implementation.
+     *
+     * @param resourceResolver    a resolver used to eventually access local 
resources needed by the transport algorithm
+     * @param distributionPackage a {@link 
org.apache.sling.distribution.packaging.DistributionPackage} to transport
+     * @param secret              the {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret} used to 
authenticate
+     *                            against the target instance according to an 
authentication algorithm implemented by the transport.
+     * @throws DistributionTransportException if the {@link 
org.apache.sling.distribution.packaging.DistributionPackage}
+     *                                        fails to be delivered to the 
target instance (e.g. because of network, I/O issues)
+     */
+    void deliverPackage(@Nonnull ResourceResolver resourceResolver, @Nonnull 
DistributionPackage
+            distributionPackage, @Nonnull DistributionTransportSecret secret) 
throws DistributionTransportException;
+
+    /**
+     * Retrieve {@link 
org.apache.sling.distribution.packaging.DistributionPackage}s from a target 
Sling instance, which
+     * will create them according to {@link 
org.apache.sling.distribution.communication.DistributionRequest}.
+     *
+     * @param resourceResolver a resolver used to eventually access local 
resources needed by the transport algorithm
+     * @param request          a {@link 
org.apache.sling.distribution.communication.DistributionRequest} to be 
forwarded to the target
+     *                         instance
+     * @param secret           the {@link 
org.apache.sling.distribution.transport.DistributionTransportSecret} used to 
authenticate
+     *                         against the target instance according to an 
authentication algorithm implemented by the transport.
+     * @return an {@link java.lang.Iterable} of {@link 
org.apache.sling.distribution.packaging.DistributionPackage}s fetched
+     * from the target instance.
+     * @throws DistributionTransportException if the {@link 
org.apache.sling.distribution.packaging.DistributionPackage}s
+     *                                        fail to be retrieved from the 
target instance
+     */
+    @Nonnull
+    Iterable<DistributionPackage> retrievePackages(@Nonnull ResourceResolver 
resourceResolver, @Nonnull DistributionRequest
+            request, @Nonnull DistributionTransportSecret secret) throws 
DistributionTransportException;
+
+}

Propchange: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/DistributionTransport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransport.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransport.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransport.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransport.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,180 @@
+/*
+ * 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.transport.impl;
+
+import javax.annotation.Nonnull;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.fluent.Content;
+import org.apache.http.client.fluent.Executor;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.client.fluent.Response;
+import org.apache.http.entity.ContentType;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+import org.apache.sling.distribution.serialization.DistributionPackageBuilder;
+import org.apache.sling.distribution.transport.DistributionTransportException;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Advanced HTTP {@link 
org.apache.sling.distribution.transport.DistributionTransport} supporting 
custom HTTP headers
+ * and body.
+ */
+public class AdvancedHttpDistributionTransport extends 
SimpleHttpDistributionTransport {
+
+    private static final String PATH_VARIABLE_NAME = "{path}";
+
+    private static final Logger log = 
LoggerFactory.getLogger(AdvancedHttpDistributionTransport.class);
+
+    private final DistributionEndpoint distributionEndpoint;
+
+    private final boolean useCustomHeaders;
+
+    private final String[] customHeaders;
+
+    private final boolean useCustomBody;
+
+    private final String customBody;
+
+    public AdvancedHttpDistributionTransport(boolean useCustomHeaders,
+                                             String[] customHeaders,
+                                             boolean useCustomBody,
+                                             String customBody,
+                                             DistributionEndpoint 
distributionEndpoint,
+                                             DistributionPackageBuilder 
packageBuilder,
+                                             int maxNoOfPackages) {
+
+
+        super(distributionEndpoint, packageBuilder, maxNoOfPackages);
+        this.useCustomHeaders = useCustomHeaders;
+        this.customHeaders = customHeaders;
+        this.useCustomBody = useCustomBody;
+        this.customBody = customBody;
+
+        this.distributionEndpoint = distributionEndpoint;
+    }
+
+    @Override
+    public void deliverPackage(@Nonnull ResourceResolver resourceResolver, 
@Nonnull DistributionPackage distributionPackage,
+                               @Nonnull DistributionTransportSecret secret) 
throws DistributionTransportException {
+        log.info("delivering package {} to {} using auth {}",
+                new Object[]{distributionPackage.getId(),
+                        distributionEndpoint.getUri(), secret});
+
+        try {
+            Executor executor = authenticate(secret, Executor.newInstance());
+
+            deliverPackage(executor, distributionPackage, 
distributionEndpoint);
+
+        } catch (Exception ex) {
+            throw new DistributionTransportException(ex);
+        }
+
+    }
+
+    public static String[] getCustomizedHeaders(String[] additionalHeaders, 
String action, String[] paths) {
+        List<String> headers = new ArrayList<String>();
+
+        for (String additionalHeader : additionalHeaders) {
+            int idx = additionalHeader.indexOf("->");
+
+            if (idx < 0) {
+                headers.add(additionalHeader);
+            } else {
+                String actionSelector = additionalHeader.substring(0, 
idx).trim();
+                String header = additionalHeader.substring(idx + 2).trim();
+
+                if (actionSelector.equalsIgnoreCase(action) || 
actionSelector.equals("*")) {
+                    headers.add(header);
+                }
+            }
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        if (paths != null && paths.length > 0) {
+            sb.append(paths[0]);
+            for (int i = 1; i < paths.length; i++) {
+                sb.append(", ").append(paths[i]);
+            }
+        }
+
+        String path = sb.toString();
+
+        List<String> boundHeaders = new ArrayList<String>();
+
+        for (String header : headers) {
+            boundHeaders.add(header.replace(PATH_VARIABLE_NAME, path));
+        }
+
+        return boundHeaders.toArray(new String[boundHeaders.size()]);
+    }
+
+    private void deliverPackage(Executor executor, DistributionPackage 
distributionPackage,
+                                                       DistributionEndpoint 
distributionEndpoint) throws IOException {
+        String type = distributionPackage.getType();
+
+        Request req = 
Request.Post(distributionEndpoint.getUri()).useExpectContinue();
+
+        if (useCustomHeaders) {
+            String[] customizedHeaders = getCustomizedHeaders(customHeaders, 
distributionPackage.getInfo().getRequestType().name(),
+                    distributionPackage.getInfo().getPaths());
+            for (String header : customizedHeaders) {
+                addHeader(req, header);
+            }
+        }
+
+        InputStream inputStream = null;
+        Response response = null;
+        try {
+            if (useCustomBody) {
+                String body = customBody == null ? "" : customBody;
+                inputStream = new ByteArrayInputStream(body.getBytes("UTF-8"));
+            } else {
+                inputStream = distributionPackage.createInputStream();
+            }
+
+            req = req.bodyStream(inputStream, 
ContentType.APPLICATION_OCTET_STREAM);
+
+            response = executor.execute(req);
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+        }
+
+        Content content = response.returnContent();
+        log.info("Distribution content of type {} for {} delivered: {}", new 
Object[]{
+                type, 
Arrays.toString(distributionPackage.getInfo().getPaths()), content});
+    }
+
+    private static void addHeader(Request req, String header) {
+        int idx = header.indexOf(":");
+        if (idx < 0) return;
+        String headerName = header.substring(0, idx).trim();
+        String headerValue = header.substring(idx + 1).trim();
+        req.addHeader(headerName, headerValue);
+    }
+}
\ No newline at end of file

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

Added: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransport.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransport.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransport.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransport.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,92 @@
+/*
+ * 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.transport.impl;
+
+import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.communication.DistributionRequest;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+import org.apache.sling.distribution.transport.DistributionTransport;
+import org.apache.sling.distribution.transport.DistributionTransportException;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+
+/**
+ * {@link org.apache.sling.distribution.transport.DistributionTransport} 
supporting delivery / retrieval from multiple
+ * endpoints.
+ */
+public class MultipleEndpointDistributionTransport implements 
DistributionTransport {
+
+    private final List<DistributionTransport> transportHelpers;
+    private final TransportEndpointStrategyType endpointStrategyType;
+    private int lastSuccessfulEndpointId = 0;
+
+    public MultipleEndpointDistributionTransport(List<DistributionTransport> 
transportHelpers,
+                                                 TransportEndpointStrategyType 
endpointStrategyType) {
+        this.transportHelpers = transportHelpers;
+        this.endpointStrategyType = endpointStrategyType;
+    }
+
+    private List<DistributionPackage> doTransport(ResourceResolver 
resourceResolver, DistributionRequest distributionRequest,
+                                                  DistributionPackage 
distributionPackage, DistributionTransportSecret secret) throws 
DistributionTransportException {
+
+        int offset = 0;
+        if (endpointStrategyType.equals(TransportEndpointStrategyType.One)) {
+            offset = lastSuccessfulEndpointId;
+        }
+
+        int length = transportHelpers.size();
+        List<DistributionPackage> result = new 
ArrayList<DistributionPackage>();
+
+        for (int i = 0; i < length; i++) {
+            int currentId = (offset + i) % length;
+
+            DistributionTransport transportHelper = 
transportHelpers.get(currentId);
+            if (distributionPackage != null) {
+                transportHelper.deliverPackage(resourceResolver, 
distributionPackage, secret);
+            } else if (distributionRequest != null) {
+                Iterable<DistributionPackage> distributionPackages = 
transportHelper.retrievePackages(resourceResolver, distributionRequest, secret);
+                for (DistributionPackage retrievedPackage : 
distributionPackages) {
+                    result.add(retrievedPackage);
+                }
+            }
+
+            lastSuccessfulEndpointId = currentId;
+            if (endpointStrategyType.equals(TransportEndpointStrategyType.One))
+                break;
+        }
+
+        return result;
+    }
+
+    public void deliverPackage(@Nonnull ResourceResolver resourceResolver, 
@Nonnull DistributionPackage distributionPackage,
+                                                      @Nonnull 
DistributionTransportSecret secret) throws DistributionTransportException {
+        doTransport(resourceResolver, null, distributionPackage, secret);
+    }
+
+    @Nonnull
+    public List<DistributionPackage> retrievePackages(@Nonnull 
ResourceResolver resourceResolver, @Nonnull DistributionRequest 
distributionRequest,
+                                                      @Nonnull 
DistributionTransportSecret secret) throws DistributionTransportException {
+        return doTransport(resourceResolver, distributionRequest, null, 
secret);
+    }
+
+
+}

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

Added: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransport.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransport.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransport.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransport.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,185 @@
+/*
+ * 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.transport.impl;
+
+import javax.annotation.Nonnull;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.fluent.Content;
+import org.apache.http.client.fluent.Executor;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.client.fluent.Response;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.entity.ContentType;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.communication.DistributionRequest;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+import org.apache.sling.distribution.serialization.DistributionPackageBuilder;
+import org.apache.sling.distribution.transport.DistributionTransport;
+import org.apache.sling.distribution.transport.DistributionTransportException;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+import org.apache.sling.distribution.util.RequestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SimpleHttpDistributionTransport implements DistributionTransport {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final DistributionEndpoint distributionEndpoint;
+    private final DistributionPackageBuilder packageBuilder;
+    private final int maxNumberOfPackages;
+
+    public SimpleHttpDistributionTransport(DistributionEndpoint 
distributionEndpoint,
+                                           DistributionPackageBuilder 
packageBuilder,
+                                           int maxNumberOfPackages) {
+
+        this.distributionEndpoint = distributionEndpoint;
+        this.packageBuilder = packageBuilder;
+        this.maxNumberOfPackages = maxNumberOfPackages;
+    }
+
+    public void deliverPackage(@Nonnull ResourceResolver resourceResolver, 
@Nonnull DistributionPackage distributionPackage,
+                               @Nonnull DistributionTransportSecret secret) 
throws DistributionTransportException {
+        String hostAndPort = getHostAndPort(distributionEndpoint.getUri());
+
+        URI packageOrigin = distributionPackage.getInfo().getOrigin();
+        if (packageOrigin != null && 
hostAndPort.equals(getHostAndPort(packageOrigin))) {
+            log.info("skipping distribution of package {} to same origin {}", 
distributionPackage.getId(), hostAndPort);
+        } else {
+            log.info("delivering package {} to {} using secret {}", new 
Object[]{
+                    distributionPackage.getId(),
+                    distributionEndpoint.getUri(),
+                    secret
+            });
+
+            try {
+                Executor executor = Executor.newInstance();
+
+                executor = authenticate(secret, executor);
+
+                Request req = 
Request.Post(distributionEndpoint.getUri()).useExpectContinue();
+
+                InputStream inputStream = null;
+                Response response = null;
+                try {
+                    inputStream = distributionPackage.createInputStream();
+
+                    req = req.bodyStream(inputStream, 
ContentType.APPLICATION_OCTET_STREAM);
+                    response = executor.execute(req);
+                } finally {
+                    IOUtils.closeQuietly(inputStream);
+                }
+
+                Content content = response.returnContent();
+                log.info("distribution content of type {} for {} delivered: 
{}", new Object[]{
+                        distributionPackage.getType(),
+                        
Arrays.toString(distributionPackage.getInfo().getPaths()),
+                        content
+                });
+            } catch (Exception ex) {
+                throw new DistributionTransportException(ex);
+            }
+        }
+
+    }
+
+    @Nonnull
+    public List<DistributionPackage> retrievePackages(@Nonnull 
ResourceResolver resourceResolver, @Nonnull DistributionRequest
+            distributionRequest, @Nonnull DistributionTransportSecret secret) 
throws DistributionTransportException {
+        log.debug("pulling from {}", distributionEndpoint.getUri());
+
+        try {
+            URI distributionURI = 
RequestUtils.appendDistributionRequest(distributionEndpoint.getUri(), 
distributionRequest);
+            List<DistributionPackage> result = new 
ArrayList<DistributionPackage>();
+
+            // TODO : executor should be cached and reused
+
+            Executor executor = Executor.newInstance();
+
+            executor = authenticate(secret, executor);
+
+            Request req = Request.Post(distributionURI).useExpectContinue();
+
+            // TODO : add queue parameter
+
+            // continuously requests package streams as long as type header is 
received with the response (meaning there's a package of a certain type)
+            HttpResponse httpResponse;
+            try {
+
+                int pulls = 0;
+                while ((httpResponse = executor.execute(req).returnResponse())
+                        .getStatusLine().getStatusCode() == 200
+                        && pulls < maxNumberOfPackages) {
+                    HttpEntity entity = httpResponse.getEntity();
+                    if (entity != null) {
+                        final DistributionPackage responsePackage = 
packageBuilder.readPackage(resourceResolver, entity.getContent());
+                        if (responsePackage != null) {
+                            
responsePackage.getInfo().setOrigin(distributionURI);
+                            result.add(responsePackage);
+                        } else {
+                            log.warn("responsePackage is null");
+                        }
+
+                        pulls++;
+                    } else {
+                        log.info("");
+                        break;
+                    }
+                }
+
+                log.info("pulled {} packages from {}", pulls, 
distributionEndpoint.getUri());
+
+            } catch (HttpHostConnectException e) {
+                log.info("could not connect to {} - skipping", 
distributionEndpoint.getUri());
+            }
+
+            return result;
+
+        } catch (Exception ex) {
+            throw new DistributionTransportException(ex);
+        }
+
+    }
+
+    protected Executor authenticate(DistributionTransportSecret secret, 
Executor executor) {
+        Map<String, String> credentialsMap = secret.asCredentialsMap();
+        if (credentialsMap != null) {
+            executor = executor.auth(new 
HttpHost(distributionEndpoint.getUri().getHost(), 
distributionEndpoint.getUri().getPort()),
+                    credentialsMap.get("username"), 
credentialsMap.get("password")).authPreemptive(
+                    new HttpHost(distributionEndpoint.getUri().getHost(), 
distributionEndpoint.getUri().getPort()));
+            log.debug("authenticated executor HTTP client with user and 
password");
+        }
+        return executor;
+    }
+
+    private String getHostAndPort(URI uri) {
+        return uri.getHost() + ":" + uri.getPort();
+    }
+
+}

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

Added: 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/UserCredentialsDistributionTransportSecretProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/UserCredentialsDistributionTransportSecretProvider.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/UserCredentialsDistributionTransportSecretProvider.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/main/java/org/apache/sling/distribution/transport/impl/UserCredentialsDistributionTransportSecretProvider.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,87 @@
+/*
+ * 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.transport.impl;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+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.commons.osgi.PropertiesUtil;
+import org.apache.sling.distribution.component.impl.DistributionComponentUtils;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+import 
org.apache.sling.distribution.transport.DistributionTransportSecretProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(label = "User Credentials based 
DistributionTransportSecretProvider",
+        configurationFactory = true,
+        specVersion = "1.1",
+        policy = ConfigurationPolicy.REQUIRE)
+@Service(value = DistributionTransportSecretProvider.class)
+public class UserCredentialsDistributionTransportSecretProvider implements
+        DistributionTransportSecretProvider {
+
+    /**
+     * name of this component.
+     */
+    @Property
+    public static final String NAME = DistributionComponentUtils.PN_NAME;
+
+    @Property
+    public final static String USERNAME = "username";
+
+    @Property
+    public final static String PASSWORD = "password";
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private String username;
+    private String password;
+
+    @Activate
+    protected void activate(Map<String, Object> config) {
+        username = PropertiesUtil.toString(config.get(USERNAME), "").trim();
+        password = PropertiesUtil.toString(config.get(PASSWORD), "").trim();
+    }
+
+    public DistributionTransportSecret getSecret() {
+        return new DistributionTransportSecret() {
+            public String asToken() {
+                return null;
+            }
+
+            public InputStream asStream() {
+                return null;
+            }
+
+            public Map<String, String> asCredentialsMap() {
+                Map<String, String> map = new HashMap<String, String>();
+                map.put(USERNAME, username);
+                map.put(PASSWORD, password);
+                return Collections.unmodifiableMap(map);
+            }
+        };
+    }
+}

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

Added: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,79 @@
+/*
+ * 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.transport.impl;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * Testcase for {@link AdvancedHttpDistributionTransport}
+ */
+@RunWith(Parameterized.class)
+public class AdvancedHttpDistributionTransportTest {
+
+    private final String[] inputTransportProperties;
+    private final String inputSelector;
+    private final String[] inputPaths;
+
+    private final String[] outputHeaders;
+
+
+    @Parameterized.Parameters
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {new String[]{}, "", new String[]{},
+                        new String[]{}},
+                {new String[]{}, "add", new String[]{},
+                        new String[]{}},
+                {new String[]{"add -> Header: Add"}, "add", new String[]{},
+                        new String[]{"Header: Add"}},
+                {new String[]{"add -> Header: Add", "Header: Always"}, "add", 
new String[]{},
+                        new String[]{"Header: Add", "Header: Always"}},
+                {new String[]{"add -> Header: Add", "* -> Header: Always", 
"delete -> Header:Del"}, "add", new String[]{},
+                        new String[]{"Header: Add", "Header: Always"}},
+                {new String[]{"add -> Header: Add", "Header: Always"}, 
"delete", new String[]{},
+                        new String[]{"Header: Always"}},
+                {new String[]{"add -> Header: Add", "Header: Always"}, "add", 
new String[]{},
+                        new String[]{"Header: Add", "Header: Always"}},
+                {new String[]{"add -> Header: Add", "Header: Always", 
"PathHeader: {path}"}, "add", new String[]{"/content"},
+                        new String[]{"Header: Add", "Header: Always", 
"PathHeader: /content"}},
+        });
+
+    }
+
+    public AdvancedHttpDistributionTransportTest(String[] 
inputTransportProperties, String inputSelector, String[] inputPaths,
+                                                 String[] outputHeaders) {
+        this.inputTransportProperties = inputTransportProperties;
+        this.inputSelector = inputSelector;
+        this.outputHeaders = outputHeaders;
+        this.inputPaths = inputPaths;
+    }
+
+    @Test
+    public void testHttpTransportProperties() {
+        String[] headers = 
AdvancedHttpDistributionTransport.getCustomizedHeaders(inputTransportProperties,
 inputSelector, inputPaths);
+
+        assertArrayEquals(outputHeaders, headers);
+    }
+}

Propchange: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/AdvancedHttpDistributionTransportTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,208 @@
+/*
+ * 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.transport.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.communication.DistributionRequest;
+import org.apache.sling.distribution.communication.DistributionRequestType;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+import org.apache.sling.distribution.transport.DistributionTransport;
+import org.apache.sling.distribution.transport.DistributionTransport;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Testcase for {@link MultipleEndpointDistributionTransport}
+ */
+public class MultipleEndpointDistributionTransportTest {
+
+    @Test
+    public void testDeliverPackageWithoutSubHandlers() throws Exception {
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionPackage distributionPackage = 
mock(DistributionPackage.class);
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        for (TransportEndpointStrategyType strategy : 
TransportEndpointStrategyType.values()) {
+            MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(subHandlers, strategy);
+            
multipleEndpointDistributionTransport.deliverPackage(resourceResolver, 
distributionPackage, secret);
+        }
+    }
+
+    @Test
+    public void testRetrievePackagesWithoutSubHandlers() throws Exception {
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        for (TransportEndpointStrategyType strategy : 
TransportEndpointStrategyType.values()) {
+            MultipleEndpointDistributionTransport 
multipleEndpointdistributionTransport = new 
MultipleEndpointDistributionTransport(subHandlers, strategy);
+            List<DistributionPackage> distributionPackages = 
multipleEndpointdistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+            assertNotNull(distributionPackages);
+            assertTrue(distributionPackages.isEmpty());
+        }
+    }
+
+    @Test
+    public void testDeliverPackageWithSubHandlers() throws Exception {
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport first = mock(DistributionTransport.class);
+        subHandlers.add(first);
+        DistributionTransport second = mock(DistributionTransport.class);
+        subHandlers.add(second);
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionPackage distributionPackage = 
mock(DistributionPackage.class);
+        for (TransportEndpointStrategyType strategy : 
TransportEndpointStrategyType.values()) {
+            MultipleEndpointDistributionTransport 
multipleEndpointdistributionTransport = new 
MultipleEndpointDistributionTransport(subHandlers, strategy);
+            
multipleEndpointdistributionTransport.deliverPackage(resourceResolver, 
distributionPackage, secret);
+        }
+    }
+
+    @Test
+    public void testRetrievePackagesWithSubHandlers() throws Exception {
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport first = mock(DistributionTransport.class);
+        Iterable<DistributionPackage> packages = Collections.emptyList();
+        when(first.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages);
+        subHandlers.add(first);
+        DistributionTransport second = mock(DistributionTransport.class);
+        when(second.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages);
+        subHandlers.add(second);
+        for (TransportEndpointStrategyType strategy : 
TransportEndpointStrategyType.values()) {
+            MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(subHandlers, strategy);
+            List<DistributionPackage> distributionPackages = 
multipleEndpointDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+            assertNotNull(distributionPackages);
+            assertTrue(distributionPackages.isEmpty());
+        }
+    }
+
+    @Test
+    public void testRetrievePackagesWithOneReturningSubHandlerAndAllStrategy() 
throws Exception {
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport handler1 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages1 = new 
ArrayList<DistributionPackage>();
+        packages1.add(mock(DistributionPackage.class));
+        packages1.add(mock(DistributionPackage.class));
+        when(handler1.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages1);
+        subHandlers.add(handler1);
+        MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(
+                subHandlers, TransportEndpointStrategyType.All);
+        List<DistributionPackage> distributionPackages = 
multipleEndpointDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(distributionPackages);
+        assertFalse(distributionPackages.isEmpty());
+        assertEquals(2, distributionPackages.size());
+    }
+
+    @Test
+    public void 
testRetrievePackagesWithOneEmptyOneReturningSubHandlerAndOneStrategy() throws 
Exception {
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport handler = mock(DistributionTransport.class);
+        when(handler.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(new ArrayList<DistributionPackage>());
+        subHandlers.add(handler);
+        DistributionTransport handler2 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages2 = new 
ArrayList<DistributionPackage>();
+        packages2.add(mock(DistributionPackage.class));
+        packages2.add(mock(DistributionPackage.class));
+        when(handler2.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages2);
+        subHandlers.add(handler2);
+        MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(
+                subHandlers, TransportEndpointStrategyType.One);
+        List<DistributionPackage> distributionPackages = 
multipleEndpointDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(distributionPackages);
+        assertTrue(distributionPackages.isEmpty());
+    }
+
+    @Test
+    public void 
testRetrievePackagesWithTwoReturningSubHandlersAndAllStrategy() throws 
Exception {
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport handler1 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages1 = new 
ArrayList<DistributionPackage>();
+        packages1.add(mock(DistributionPackage.class));
+        packages1.add(mock(DistributionPackage.class));
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        when(handler1.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages1);
+        subHandlers.add(handler1);
+
+        DistributionTransport handler2 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages2 = new 
ArrayList<DistributionPackage>();
+        packages2.add(mock(DistributionPackage.class));
+        packages2.add(mock(DistributionPackage.class));
+        packages2.add(mock(DistributionPackage.class));
+        when(handler2.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages2);
+        subHandlers.add(handler2);
+
+        MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(
+                subHandlers, TransportEndpointStrategyType.All);
+        List<DistributionPackage> distributionPackages = 
multipleEndpointDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(distributionPackages);
+        assertFalse(distributionPackages.isEmpty());
+        assertEquals(5, distributionPackages.size());
+    }
+
+    @Test
+    public void 
testRetrievePackagesWithTwoReturningSubHandlersAndOneStrategy() throws 
Exception {
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        List<DistributionTransport> subHandlers = new 
ArrayList<DistributionTransport>();
+        DistributionTransport handler1 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages1 = new 
ArrayList<DistributionPackage>();
+        packages1.add(mock(DistributionPackage.class));
+        packages1.add(mock(DistributionPackage.class));
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        when(handler1.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages1);
+        subHandlers.add(handler1);
+
+        DistributionTransport handler2 = mock(DistributionTransport.class);
+        List<DistributionPackage> packages2 = new 
ArrayList<DistributionPackage>();
+        packages2.add(mock(DistributionPackage.class));
+        packages2.add(mock(DistributionPackage.class));
+        packages2.add(mock(DistributionPackage.class));
+        when(handler2.retrievePackages(resourceResolver, distributionRequest, 
secret)).thenReturn(packages2);
+        subHandlers.add(handler2);
+
+        MultipleEndpointDistributionTransport 
multipleEndpointDistributionTransport = new 
MultipleEndpointDistributionTransport(
+                subHandlers, TransportEndpointStrategyType.One);
+        List<DistributionPackage> distributionPackages = 
multipleEndpointDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(distributionPackages);
+        assertFalse(distributionPackages.isEmpty());
+        assertEquals(2, distributionPackages.size());
+    }
+}
\ No newline at end of file

Propchange: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/MultipleEndpointDistributionTransportTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,142 @@
+/*
+ * 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.transport.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.fluent.Executor;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.client.fluent.Response;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.distribution.communication.DistributionRequest;
+import org.apache.sling.distribution.communication.DistributionRequestType;
+import org.apache.sling.distribution.packaging.DistributionPackage;
+import org.apache.sling.distribution.packaging.DistributionPackageInfo;
+import org.apache.sling.distribution.serialization.DistributionPackageBuilder;
+import org.apache.sling.distribution.transport.DistributionTransportSecret;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Testcase for {@link SimpleHttpDistributionTransport}
+ */
+@Ignore
+public class SimpleHttpDistributionTransportTest {
+
+    @Test
+    public void testDeliverPackage() throws Exception {
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        Map<String, String> credentialsMap = new HashMap<String, String>();
+        credentialsMap.put("username", "foo");
+        credentialsMap.put("password", "foo");
+        when(secret.asCredentialsMap()).thenReturn(credentialsMap);
+        Executor executor = mock(Executor.class);
+        Response response = mock(Response.class);
+        when(executor.execute(any(Request.class))).thenReturn(response);
+        DistributionEndpoint endpoint = new 
DistributionEndpoint("http://127.0.0.1:8080/some/resource";);
+        DistributionPackageBuilder packageBuilder = 
mock(DistributionPackageBuilder.class);
+        int maxNoOfPackages = Integer.MAX_VALUE;
+        SimpleHttpDistributionTransport simpleHttpDistributionTransport = new 
SimpleHttpDistributionTransport(
+                endpoint, packageBuilder, maxNoOfPackages);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionPackage distributionPackage = 
mock(DistributionPackage.class);
+        when(distributionPackage.getInfo()).thenReturn(new 
DistributionPackageInfo());
+        InputStream stream = mock(InputStream.class);
+        when(distributionPackage.createInputStream()).thenReturn(stream);
+        simpleHttpDistributionTransport.deliverPackage(resourceResolver, 
distributionPackage, secret);
+    }
+
+    @Test
+    public void testRetrievePackagesRemotelyFailing() throws Exception {
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        Map<String, String> credentialsMap = new HashMap<String, String>();
+        credentialsMap.put("username", "foo");
+        credentialsMap.put("password", "foo");
+        when(secret.asCredentialsMap()).thenReturn(credentialsMap);
+        Executor executor = mock(Executor.class);
+        Response response = mock(Response.class);
+        HttpResponse httpResponse = mock(HttpResponse.class);
+        StatusLine statusLine = mock(StatusLine.class);
+        when(statusLine.getStatusCode()).thenReturn(404);
+        when(httpResponse.getStatusLine()).thenReturn(statusLine);
+        when(response.returnResponse()).thenReturn(httpResponse);
+        when(executor.execute(any(Request.class))).thenReturn(response);
+        DistributionEndpoint endpoint = new 
DistributionEndpoint("http://127.0.0.1:8080/some/resource";);
+        DistributionPackageBuilder packageBuilder = 
mock(DistributionPackageBuilder.class);
+        int maxNoOfPackages = 1;
+        SimpleHttpDistributionTransport simpleHttpDistributionTransport = new 
SimpleHttpDistributionTransport(
+                endpoint, packageBuilder, maxNoOfPackages);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        List<DistributionPackage> packages = 
simpleHttpDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(packages);
+        assertTrue(packages.isEmpty());
+    }
+
+    @Test
+    public void testRetrievePackagesRemotelyWorking() throws Exception {
+        DistributionTransportSecret secret = 
mock(DistributionTransportSecret.class);
+        Map<String, String> credentialsMap = new HashMap<String, String>();
+        credentialsMap.put("username", "foo");
+        credentialsMap.put("password", "foo");
+        when(secret.asCredentialsMap()).thenReturn(credentialsMap);
+        Executor executor = mock(Executor.class);
+        Response response = mock(Response.class);
+        HttpResponse httpResponse = mock(HttpResponse.class);
+        StatusLine statusLine = mock(StatusLine.class);
+        when(statusLine.getStatusCode()).thenReturn(200);
+        when(httpResponse.getStatusLine()).thenReturn(statusLine);
+        HttpEntity entity = mock(HttpEntity.class);
+        InputStream stream = new ByteArrayInputStream("package binary 
stuff".getBytes("UTF-8"));
+        when(entity.getContent()).thenReturn(stream);
+        when(httpResponse.getEntity()).thenReturn(entity);
+        when(response.returnResponse()).thenReturn(httpResponse);
+        when(executor.execute(any(Request.class))).thenReturn(response);
+        DistributionEndpoint endpoint = new 
DistributionEndpoint("http://127.0.0.1:8080/some/resource";);
+        DistributionPackageBuilder packageBuilder = 
mock(DistributionPackageBuilder.class);
+        DistributionPackage distributionPackage = 
mock(DistributionPackage.class);
+        when(distributionPackage.getInfo()).thenReturn(new 
DistributionPackageInfo());
+        when(packageBuilder.readPackage(any(ResourceResolver.class), 
any(InputStream.class))).thenReturn(distributionPackage);
+        int maxNoOfPackages = 1;
+        SimpleHttpDistributionTransport simpleHttpDistributionTransport = new 
SimpleHttpDistributionTransport(
+                endpoint, packageBuilder, maxNoOfPackages);
+        ResourceResolver resourceResolver = mock(ResourceResolver.class);
+        DistributionRequest distributionRequest = new 
DistributionRequest(DistributionRequestType.ADD, "/");
+        List<DistributionPackage> packages = 
simpleHttpDistributionTransport.retrievePackages(resourceResolver, 
distributionRequest, secret);
+        assertNotNull(packages);
+        assertFalse(packages.isEmpty());
+        assertEquals(1, packages.size());
+        assertNotNull(packages.get(0));
+    }
+}
\ No newline at end of file

Propchange: 
sling/trunk/contrib/extensions/distribution/core/src/test/java/org/apache/sling/distribution/transport/impl/SimpleHttpDistributionTransportTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,6 @@
+{
+    "jcr:primaryType": "sling:OsgiConfig",
+    "name": "publishAdmin",
+    "username": "admin",
+    "password": "admin"
+}
\ No newline at end of file

Added: 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.osgi.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.osgi.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json?rev=1643201&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.osgi.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
 (added)
+++ 
sling/trunk/contrib/extensions/distribution/sample/src/main/resources/SLING-CONTENT/libs/sling/distribution/install.osgi.author/org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider-publishAdmin.json
 Fri Dec  5 09:19:24 2014
@@ -0,0 +1,6 @@
+{
+    "jcr:primaryType": "sling:OsgiConfig",
+    "name": "publishAdmin",
+    "username": "admin",
+    "password": "admin"
+}
\ No newline at end of file


Reply via email to