Author: cziegeler
Date: Thu Jun  1 11:17:23 2017
New Revision: 1797191

URL: http://svn.apache.org/viewvc?rev=1797191&view=rev
Log:
Add new support module

Added:
    sling/whiteboard/cziegeler/feature-support/
    sling/whiteboard/cziegeler/feature-support/pom.xml   (with props)
    sling/whiteboard/cziegeler/feature-support/src/
    sling/whiteboard/cziegeler/feature-support/src/main/
    sling/whiteboard/cziegeler/feature-support/src/main/java/
    sling/whiteboard/cziegeler/feature-support/src/main/java/org/
    sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/
    sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
   (with props)
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
   (with props)
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
   (with props)
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
   (with props)
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
   (with props)
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
   (with props)
    sling/whiteboard/cziegeler/feature-support/src/test/
    sling/whiteboard/cziegeler/feature-support/src/test/java/
    sling/whiteboard/cziegeler/feature-support/src/test/java/org/
    sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/
    sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/
    
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/
    
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/
    
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
   (with props)

Added: sling/whiteboard/cziegeler/feature-support/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/pom.xml?rev=1797191&view=auto
==============================================================================
--- sling/whiteboard/cziegeler/feature-support/pom.xml (added)
+++ sling/whiteboard/cziegeler/feature-support/pom.xml Thu Jun  1 11:17:23 2017
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+    <!--
+        Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license
+        agreements. See the NOTICE file distributed with this work for 
additional information
+        regarding copyright ownership. The ASF licenses this file to you under 
the Apache License,
+        Version 2.0 (the "License"); you may not use this file except in 
compliance with the
+        License. You may obtain a copy of the License at 
http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software 
distributed under the
+        License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND,
+        either express or implied. See the License for the specific language 
governing permissions
+        and limitations under the License.
+    -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>30</version>
+        <relativePath />
+    </parent>
+
+    <artifactId>org.apache.sling.feature.support</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <name>Apache Sling Feature Launcher</name>
+    <description>
+        Support classes for the feature tools
+    </description>
+
+    <properties>
+        <sling.java.version>8</sling.java.version>
+    </properties>
+
+    <scm>
+        
<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/tooling/support/feature-support</connection>
+        
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/tooling/support/feature-support</developerConnection>
+        
<url>http://svn.apache.org/viewvc/sling/trunk/tooling/support/feature-support</url>
+    </scm>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>2.8.9</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

Propchange: sling/whiteboard/cziegeler/feature-support/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/whiteboard/cziegeler/feature-support/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Id

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,42 @@
+/*
+ * 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.feature.support;
+
+import java.io.File;
+
+/**
+ * A handler provides a file object for an artifact.
+ */
+public class ArtifactHandler {
+
+    private final String url;
+
+    private final File file;
+
+    public ArtifactHandler(final String url, final File file) {
+        this.url = url;
+        this.file = file;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public File getFile() {
+        return file;
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactHandler.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,360 @@
+/*
+ * 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.feature.support;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.support.spi.ArtifactProvider;
+import org.apache.sling.feature.support.spi.ArtifactProviderContext;
+
+/**
+ * The artifact manager is the central service to get artifacts.
+ * It uses {@link ArtifactProvider}s to get artifacts. The
+ * providers are loaded using the service loader.
+ */
+public class ArtifactManager {
+
+    /** The map of providers. */
+    private final Map<String, ArtifactProvider> providers;
+
+    /** The configuration */
+    private final ArtifactManagerConfig config;
+
+    /**
+     * Get an artifact manager based on the configuration
+     * @param config The configuration
+     * @return The artifact manager
+     * @throws IOException If the manager can't be initialized
+     */
+    public static ArtifactManager getArtifactManager(final 
ArtifactManagerConfig config) throws IOException {
+        final ServiceLoader<ArtifactProvider> loader = 
ServiceLoader.load(ArtifactProvider.class);
+        final Map<String, ArtifactProvider> providers = new HashMap<>();
+        for(final ArtifactProvider provider : loader) {
+            providers.put(provider.getProtocol(), provider);
+        }
+
+        final String[] repositoryURLs = new 
String[config.getRepositoryUrls().length];
+        int index = 0;
+        for(final String urlString : config.getRepositoryUrls()) {
+            repositoryURLs[index] = urlString;
+            index++;
+        }
+        // default
+        if ( !providers.containsKey("*") ) {
+            providers.put("*", new DefaultArtifactHandler());
+        }
+
+        return new ArtifactManager(config, providers);
+    }
+
+    ArtifactManager(final ArtifactManagerConfig config, final Map<String, 
ArtifactProvider> providers)
+    throws IOException {
+        this.config = config;
+        this.providers = providers;
+        try {
+            for(final ArtifactProvider provider : this.providers.values()) {
+                provider.init(config);
+            }
+        } catch ( final IOException io) {
+            shutdown();
+            throw io;
+        }
+    }
+
+    /**
+     * Shutdown the artifact manager.
+     */
+    public void shutdown() {
+        for(final ArtifactProvider provider : this.providers.values()) {
+            provider.shutdown();
+        }
+        this.providers.clear();
+    }
+
+    private final File getArtifactFromProviders(final String url, final String 
relativeCachePath) throws IOException {
+        final int pos = url.indexOf(":");
+        final String scheme = url.substring(0, pos);
+
+        ArtifactProvider provider = this.providers.get(scheme);
+        if ( provider == null ) {
+            provider = this.providers.get("*");
+        }
+        if ( provider == null ) {
+            throw new IOException("No URL provider found for " + url);
+        }
+        return provider.getArtifact(url, relativeCachePath);
+    }
+
+    /**
+     * Get the full artifact url and file for an artifact.
+     * @param url Artifact url or relative path.
+     * @return Absolute url and file in the form of a handler.
+     * @throws IOException If something goes wrong.
+     */
+    public ArtifactHandler getArtifactHandler(final String url) throws 
IOException {
+        Logger.LOG.debug("Trying to get artifact for " + url);
+
+        final String path;
+
+        if ( url.startsWith("mvn:") ) {
+            // mvn url
+            path = ArtifactId.fromMvnUrl(url).toMvnPath();
+
+        } else if ( url.startsWith(":") ) {
+            // repository path
+            path = url.substring(1);
+
+        } else if ( url.indexOf(":/") > 0 ) {
+
+            // absolute URL
+            int pos = url.indexOf(":/") + 2;
+            while ( url.charAt(pos) == '/') {
+                pos++;
+            }
+            final File file = this.getArtifactFromProviders(url, 
url.substring(pos));
+            if ( file == null || !file.exists()) {
+                throw new IOException("Artifact " + url + " not found.");
+            }
+            return new ArtifactHandler(url, file);
+
+        } else {
+            // file (either relative or absolute)
+            final File f = new File(url);
+            if ( !f.exists()) {
+                throw new IOException("Artifact " + url + " not found.");
+            }
+            return new ArtifactHandler(f.toURI().toString(), f);
+        }
+        Logger.LOG.debug("Querying repositories for " + path);
+
+        for(final String repoUrl : this.config.getRepositoryUrls()) {
+            final StringBuilder builder = new StringBuilder();
+            builder.append(repoUrl);
+            builder.append('/');
+            builder.append(path);
+
+            final String artifactUrl = builder.toString();
+            final int pos = artifactUrl.indexOf(":");
+            final String scheme = artifactUrl.substring(0, pos);
+
+            ArtifactProvider handler = this.providers.get(scheme);
+            if ( handler == null ) {
+                handler = this.providers.get("*");
+            }
+            if ( handler == null ) {
+                throw new IOException("No URL handler found for " + 
artifactUrl);
+            }
+
+            Logger.LOG.debug("Checking " + handler + " to get artifact from " 
+ artifactUrl);
+
+            final File file = handler.getArtifact(artifactUrl, path);
+            if ( file != null ) {
+                Logger.LOG.debug("Found artifact " + artifactUrl);
+                return new ArtifactHandler(artifactUrl, file);
+            }
+
+            // check for SNAPSHOT
+            final int lastSlash = artifactUrl.lastIndexOf('/');
+            final int startSnapshot = artifactUrl.indexOf("-SNAPSHOT", 
lastSlash + 1);
+
+            if ( startSnapshot > -1 ) {
+                // special snapshot handling
+                final String metadataUrl = artifactUrl.substring(0, lastSlash) 
+ "/maven-metadata.xml";
+                try {
+                    final ArtifactHandler metadataHandler = 
this.getArtifactHandler(metadataUrl);
+
+                    final String contents = getFileContents(metadataHandler);
+
+                    final String latestVersion = getLatestSnapshot(contents);
+                    if ( latestVersion != null ) {
+                        final String name = artifactUrl.substring(lastSlash); 
// includes slash
+                        final String fullURL = artifactUrl.substring(0, 
lastSlash) + name.replace("SNAPSHOT", latestVersion);
+                        int pos2 = fullURL.indexOf(":/") + 2;
+                        while ( fullURL.charAt(pos2) == '/') {
+                            pos2++;
+                        }
+                        final File file2 = 
this.getArtifactFromProviders(fullURL, path);
+                        if ( file2 == null || !file2.exists()) {
+                            throw new IOException("Artifact " + fullURL + " 
not found.");
+                        }
+                        return new ArtifactHandler(artifactUrl, file2);
+                    }
+                } catch ( final IOException ignore ) {
+                    // we ignore this but report the original 404
+                }
+            }
+        }
+
+        throw new IOException("Artifact " + url + " not found in any 
repository.");
+    }
+
+    protected String getFileContents(final ArtifactHandler handler) throws 
IOException {
+        final StringBuilder sb = new StringBuilder();
+        for(final String line : 
Files.readAllLines(handler.getFile().toPath())) {
+            sb.append(line).append('\n');
+        }
+
+        return sb.toString();
+    }
+
+    public static String getValue(final String xml, final String[] xpath) {
+        String value = null;
+        int pos = 0;
+        for(final String name : xpath) {
+            final String element = '<' + name + '>';
+
+            pos = xml.indexOf(element, pos);
+            if ( pos == -1 ) {
+                final String elementWithAttributes = '<' + name + ' ';
+                pos = xml.indexOf(elementWithAttributes, pos);
+                if ( pos == -1 ) {
+                    break;
+                }
+            }
+            pos = xml.indexOf('>', pos) + 1;
+        }
+        if ( pos != -1 ) {
+            final int endPos = xml.indexOf("</", pos);
+            if ( endPos != -1 ) {
+                value = xml.substring(pos, endPos).trim();
+            }
+        }
+        return value;
+    }
+    public static String getLatestSnapshot(final String mavenMetadata) {
+        final String timestamp = getValue(mavenMetadata, new String[] 
{"metadata", "versioning", "snapshot", "timestamp"});
+        final String buildNumber = getValue(mavenMetadata, new String[] 
{"metadata", "versioning", "snapshot", "buildNumber"});
+
+        if ( timestamp != null && buildNumber != null ) {
+            return timestamp + '-' + buildNumber;
+        }
+
+        return null;
+    }
+
+    private static final class DefaultArtifactHandler implements 
ArtifactProvider {
+
+        private volatile File cacheDir;
+
+        private volatile ArtifactProviderContext config;
+
+        @Override
+        public String getProtocol() {
+            return "*";
+        }
+
+        @Override
+        public void init(final ArtifactProviderContext config) throws 
IOException {
+            this.cacheDir = config.getCacheDirectory();
+            this.config = config;
+        }
+
+        @Override
+        public void shutdown() {
+            this.config = null;
+            this.cacheDir = null;
+        }
+
+        @Override
+        public File getArtifact(final String url, final String 
relativeCachePath) {
+            Logger.LOG.debug("Checking url to be local file " + url);
+            // check if this is already a local file
+            try {
+                final File f = new File(new URL(url).toURI());
+                if ( f.exists() ) {
+                    this.config.incLocalArtifacts();
+                    return f;
+                }
+                return null;
+            } catch ( final URISyntaxException ise) {
+                // ignore
+            } catch ( final IllegalArgumentException iae) {
+                // ignore
+            } catch ( final MalformedURLException mue) {
+                // ignore
+            }
+            Logger.LOG.debug("Checking remote url " + url);
+            try {
+                // check for url
+                if ( url.indexOf(":") == -1 ) {
+                    return null;
+                }
+
+                final String filePath = (this.cacheDir.getAbsolutePath() + 
File.separatorChar + relativeCachePath).replace('/', File.separatorChar);
+                final File cacheFile = new File(filePath);
+
+                if ( !cacheFile.exists() ) {
+                    cacheFile.getParentFile().mkdirs();
+                    final URL u = new URL(url);
+                    final URLConnection con = u.openConnection();
+                    con.connect();
+
+                    final InputStream readIS = con.getInputStream();
+                    final byte[] buffer = new byte[32768];
+                    int l;
+                    OutputStream os = null;
+                    try {
+                        os = new FileOutputStream(cacheFile);
+                        while ( (l = readIS.read(buffer)) >= 0 ) {
+                            os.write(buffer, 0, l);
+                        }
+                    } finally {
+                        try {
+                            readIS.close();
+                        } catch ( final IOException ignore) {
+                            // ignore
+                        }
+                        if ( os != null ) {
+                            try {
+                                os.close();
+                            } catch ( final IOException ignore ) {
+                                // ignore
+
+                            }
+                        }
+                    }
+                    this.config.incDownloadedArtifacts();
+                } else {
+                    this.config.incCachedArtifacts();
+                }
+                return cacheFile;
+            } catch ( final Exception e) {
+                e.printStackTrace();
+                // ignore for now
+                return null;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "DefaultArtifactHandler";
+        }
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,125 @@
+/*
+ * 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.feature.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.apache.sling.feature.support.spi.ArtifactProviderContext;
+
+/**
+ * This class holds the configuration of artifact manager.
+ */
+public class ArtifactManagerConfig implements ArtifactProviderContext {
+
+    /** The repository urls. */
+    private volatile String[] repositoryUrls;
+
+    /** The cache directory. */
+    private volatile File cacheDirectory;
+
+    private volatile long cachedArtifacts;
+
+    private volatile long downloadedArtifacts;
+
+    private volatile long localArtifacts;
+
+    /**
+     * Create a new configuration object.
+     * Set the default values
+     */
+    public ArtifactManagerConfig() {
+        // set defaults
+        this.repositoryUrls = new String[] {
+                "file://" + System.getProperty("user.home") + 
"/.m2/repository",
+                "https://repo.maven.apache.org/maven2/";
+                };
+        try {
+            this.cacheDirectory = 
Files.createTempDirectory("slingfeature").toFile();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Set the repository urls
+     * @param repositoryUrl The repository urls
+     */
+    public void setRepositoryUrls(final String[] urls) {
+        if ( urls == null || urls.length == 0 ) {
+            this.repositoryUrls = null;
+        } else {
+            this.repositoryUrls = new String[urls.length];
+            System.arraycopy(urls, 0, this.repositoryUrls, 0, urls.length);
+            for(int i=0; i<this.repositoryUrls.length; i++) {
+                if ( this.repositoryUrls[i].endsWith("/") ) {
+                    this.repositoryUrls[i] = 
this.repositoryUrls[i].substring(0, this.repositoryUrls[i].length() - 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the repository urls.
+     * A repository url does not end with a slash.
+     * @return The repository urls.
+     */
+    public String[] getRepositoryUrls() {
+        return repositoryUrls;
+    }
+
+    /**
+     * Get the cache directory
+     * @return The cache directory.
+     */
+    @Override
+    public File getCacheDirectory() {
+        return cacheDirectory;
+    }
+
+    public void setCacheDirectory(final File dir) {
+        this.cacheDirectory = dir;
+    }
+
+    @Override
+    public void incCachedArtifacts() {
+        this.cachedArtifacts++;
+    }
+
+    @Override
+    public void incDownloadedArtifacts() {
+        this.downloadedArtifacts++;
+    }
+
+    @Override
+    public void incLocalArtifacts() {
+        this.localArtifacts++;
+    }
+
+    public long getCachedArtifacts() {
+        return this.cachedArtifacts;
+    }
+
+    public long getDownloadedArtifacts() {
+        return this.downloadedArtifacts;
+    }
+
+    public long getLocalArtifacts() {
+        return this.localArtifacts;
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ArtifactManagerConfig.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,112 @@
+/*
+ * 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.feature.support;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+
+/**
+ * A simple logger to be used by extensions for the launcher.
+ * Extensions should get the logger through the shared instance {@link #LOG}
+ * The returned logger instance is not thread-safe, it is assumed
+ * that all launching is single threaded!
+ */
+public class Logger {
+
+    /**
+     * The shared logger instance.
+     */
+    public static Logger LOG = new Logger();
+
+    /** Flag if debug is enabled. */
+    private volatile boolean isDebug = false;
+
+    /** Flag if info is enabled. */
+    private final boolean isInfo = true;
+
+    /** Flag if warn is enabled. */
+    private final boolean isWarn = true;
+
+    public boolean isDebugEnabled() {
+        return isDebug;
+    }
+
+    public boolean isInfoEnabled() {
+        return isInfo;
+    }
+
+    public boolean isWarnEnabled() {
+        return isWarn;
+    }
+
+    public void debug(final String msg, final Throwable t) {
+        if ( isDebug ) {
+            final StringWriter sw = new StringWriter();
+            final PrintWriter pw = new PrintWriter(sw);
+            t.printStackTrace(pw);
+            pw.flush();
+            log("[DEBUG]", msg);
+            log("[DEBUG]", sw.toString());
+        }
+    }
+
+    public void debug(final String msg, final Object... params) {
+        if ( isDebug ) {
+            log("[DEBUG]", msg, params);
+        }
+    }
+
+    public void info(final String msg, final Object... params) {
+        if ( isInfo ) {
+            log("[INFO]", msg, params);
+        }
+    }
+
+    public void warn(final String msg, final Object... params) {
+        if ( isWarn ) {
+            log("[WARN]", msg, params);
+        }
+    }
+
+    public void error(final String msg, final Throwable t, final Object... 
params) {
+        log("[ERROR]", msg, params);
+        final StringWriter sw = new StringWriter();
+        final PrintWriter pw = new PrintWriter(sw);
+        t.printStackTrace(pw);
+        pw.flush();
+        log("[ERROR]", sw.toString());
+    }
+
+    public void error(final String msg, final Object... params) {
+        log("[ERROR]", msg, params);
+    }
+
+    public void log(final String msg, final Object... params) {
+        System.out.println(MessageFormat.format(msg, params));
+    }
+
+    private void log(final String prefix, final String msg, final Object... 
params) {
+        System.out.print(prefix);
+        System.out.print(' ');
+        System.out.println(MessageFormat.format(msg, params));
+    }
+
+    public void setDebug(final boolean b) {
+       this.isDebug = b;
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/Logger.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,55 @@
+/*
+ * 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.feature.support.spi;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * The artifact provider is an extension point for providing artifacts
+ * from different sources, like for example s3.
+ */
+public interface ArtifactProvider {
+
+    /**
+     * The protocol name of the provider, e.g. "s3"
+     * @return The protocol name.
+     */
+    String getProtocol();
+
+    /**
+     * Initialize the provider.
+     * @param context The context
+     * @throws IOException If the provider can't be initialized.
+     */
+    void init(ArtifactProviderContext context) throws IOException;
+
+    /**
+     * Shutdown the provider.
+     */
+    void shutdown();
+
+    /**
+     * Get a local file for the artifact URL.
+     *
+     * @param url Artifact url
+     * @param relativeCachePath A relative path that can be used as a cache 
path
+     *                          by the provider. The path does not start with 
a slash.
+     * @return A file if the artifact exists or {@code null}
+     */
+    File getArtifact(String url, String relativeCachePath);
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProvider.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,46 @@
+/*
+ * 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.feature.support.spi;
+
+import java.io.File;
+
+/**
+ * This is the context for the artifact providers
+ */
+public interface ArtifactProviderContext {
+
+    /**
+     * Get the cache directory
+     * @return The cache directory.
+     */
+    File getCacheDirectory();
+
+    /**
+     * Inform about an artifact found in the cache.
+     */
+    void incCachedArtifacts();
+
+    /**
+     * Inform about an artifact being downloaded
+     */
+    void incDownloadedArtifacts();
+
+    /**
+     * Inform about an artifact found locally.
+     */
+    void incLocalArtifacts();
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/spi/ArtifactProviderContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java?rev=1797191&view=auto
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
 (added)
+++ 
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
 Thu Jun  1 11:17:23 2017
@@ -0,0 +1,99 @@
+/*
+ * 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.feature.support;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.feature.support.spi.ArtifactProvider;
+import org.junit.Test;
+
+public class ArtifactManagerTest {
+
+    private static final String METADATA = "<metadata 
modelVersion=\"1.1.0\">\n" +
+            "<groupId>org.apache.sling.samples</groupId>\n" +
+            "<artifactId>slingshot</artifactId>\n" +
+            "<version>0-DEFAULT-SNAPSHOT</version>\n" +
+            "<versioning>\n" +
+                "<snapshot>\n" +
+                    "<timestamp>20160321.103951</timestamp>\n" +
+                    "<buildNumber>1</buildNumber>\n" +
+                "</snapshot>\n" +
+                "<lastUpdated>20160321103951</lastUpdated>\n" +
+                "<snapshotVersions>\n" +
+                    "<snapshotVersion>\n" +
+                        "<extension>txt</extension>\n" +
+                        "<value>0-DEFAULT-20160321.103951-1</value>\n" +
+                        "<updated>20160321103951</updated>\n" +
+                    "</snapshotVersion>\n" +
+                    "<snapshotVersion>\n" +
+                        "<extension>pom</extension>\n" +
+                        "<value>0-DEFAULT-20160321.103951-1</value>\n" +
+                        "<updated>20160321103951</updated>\n" +
+                    "</snapshotVersion>\n" +
+                "</snapshotVersions>\n" +
+            "</versioning></metadata>";
+
+    @Test public void testMetadataParsing() {
+        final String version = ArtifactManager.getLatestSnapshot(METADATA);
+        assertEquals("20160321.103951-1", version);
+    }
+
+    @Test public void testSnapshotHandling() throws IOException {
+        final String REPO = "http://org.apache.sling";;
+        final ArtifactManagerConfig config = mock(ArtifactManagerConfig.class);
+        when(config.getRepositoryUrls()).thenReturn(new String[] {REPO});
+
+        final File metadataFile = mock(File.class);
+        when(metadataFile.exists()).thenReturn(true);
+        when(metadataFile.getPath()).thenReturn("/maven-metadata.xml");
+
+        final File artifactFile = mock(File.class);
+        when(artifactFile.exists()).thenReturn(true);
+
+        final ArtifactProvider provider = mock(ArtifactProvider.class);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt", 
"group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt")).thenReturn(null);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/maven-metadata.xml", 
"org.apache.sling/group/artifact/1.0.0-SNAPSHOT/maven-metadata.xml")).thenReturn(metadataFile);
+        when(provider.getArtifact(REPO + 
"/group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-20160321.103951-1.txt", 
"group/artifact/1.0.0-SNAPSHOT/artifact-1.0.0-SNAPSHOT.txt")).thenReturn(artifactFile);
+
+        final Map<String, ArtifactProvider> providers = new HashMap<>();
+        providers.put("*", provider);
+
+        final ArtifactManager mgr = new ArtifactManager(config, providers) {
+
+            @Override
+            protected String getFileContents(final ArtifactHandler handler) 
throws IOException {
+                final String path = handler.getFile().getPath();
+                if ( "/maven-metadata.xml".equals(path) ) {
+                    return METADATA;
+                }
+                return super.getFileContents(handler);
+            }
+        };
+
+        final ArtifactHandler handler = 
mgr.getArtifactHandler("mvn:group/artifact/1.0.0-SNAPSHOT/txt");
+        assertNotNull(handler);
+        assertEquals(artifactFile, handler.getFile());
+    }
+}

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/ArtifactManagerTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url


Reply via email to