From 42e2b371bc649cfa5c82fb248d5f6e7e8e18baec Mon Sep 17 00:00:00 2001
From: Henry Lee
Date: Thu, 30 Nov 2023 20:22:57 +0900
Subject: [PATCH] refactor(java): maven-shared-io
---
Java-base/maven-shared-io/Dockerfile | 28 +
Java-base/maven-shared-io/src/Jenkinsfile | 20 +
Java-base/maven-shared-io/src/README.md | 99 +++
Java-base/maven-shared-io/src/pom.xml | 123 ++++
.../io/download/DefaultDownloadManager.java | 213 ++++++
.../io/download/DownloadFailedException.java | 63 ++
.../shared/io/download/DownloadManager.java | 58 ++
.../shared/io/location/ArtifactLocation.java | 42 ++
.../io/location/ArtifactLocatorStrategy.java | 193 ++++++
.../ClasspathResourceLocatorStrategy.java | 83 +++
.../shared/io/location/FileLocation.java | 176 +++++
.../io/location/FileLocatorStrategy.java | 53 ++
.../maven/shared/io/location/Location.java | 76 +++
.../maven/shared/io/location/Locator.java | 117 ++++
.../shared/io/location/LocatorStrategy.java | 38 ++
.../maven/shared/io/location/URLLocation.java | 82 +++
.../io/location/URLLocatorStrategy.java | 80 +++
.../io/logging/DefaultMessageHolder.java | 616 ++++++++++++++++++
.../shared/io/logging/MessageHolder.java | 290 +++++++++
.../shared/io/logging/MessageLevels.java | 117 ++++
.../maven/shared/io/logging/MessageSink.java | 55 ++
.../maven/shared/io/logging/MojoLogSink.java | 73 +++
.../shared/io/logging/PlexusLoggerSink.java | 71 ++
.../AbstractResourceInclusionScanner.java | 95 +++
.../io/scan/InclusionScanException.java | 45 ++
.../io/scan/ResourceInclusionScanner.java | 46 ++
.../scan/SimpleResourceInclusionScanner.java | 64 ++
.../shared/io/scan/StaleResourceScanner.java | 123 ++++
.../io/scan/mapping/SingleTargetMapping.java | 63 ++
.../shared/io/scan/mapping/SourceMapping.java | 41 ++
.../shared/io/scan/mapping/SuffixMapping.java | 77 +++
.../resources/META-INF/plexus/components.xml | 33 +
.../src/src/site/resources/download.cgi | 22 +
.../maven-shared-io/src/src/site/site.xml | 37 ++
.../src/src/site/xdoc/download.xml.vm | 126 ++++
.../org/apache/maven/shared/io/Utils.java | 55 ++
.../download/DefaultDownloadManagerTest.java | 559 ++++++++++++++++
.../download/DownloadFailedExceptionTest.java | 44 ++
.../io/location/ArtifactLocationTest.java | 81 +++
.../location/ArtifactLocatorStrategyTest.java | 507 ++++++++++++++
.../ClasspathResourceLocatorStrategyTest.java | 59 ++
.../shared/io/location/FileLocationTest.java | 180 +++++
.../io/location/FileLocatorStrategyTest.java | 70 ++
.../maven/shared/io/location/LocatorTest.java | 138 ++++
.../shared/io/location/URLLocationTest.java | 81 +++
.../io/location/URLLocatorStrategyTest.java | 79 +++
.../io/logging/DefaultMessageHolderTest.java | 304 +++++++++
.../io/scan/mapping/SuffixMappingTest.java | 130 ++++
.../resources/META-INF/maven/test.properties | 17 +
49 files changed, 5842 insertions(+)
create mode 100644 Java-base/maven-shared-io/Dockerfile
create mode 100644 Java-base/maven-shared-io/src/Jenkinsfile
create mode 100644 Java-base/maven-shared-io/src/README.md
create mode 100644 Java-base/maven-shared-io/src/pom.xml
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DefaultDownloadManager.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadFailedException.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadManager.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocation.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategy.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategy.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocation.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocatorStrategy.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Location.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Locator.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/LocatorStrategy.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocation.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocatorStrategy.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageHolder.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageLevels.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageSink.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MojoLogSink.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/PlexusLoggerSink.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/AbstractResourceInclusionScanner.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/InclusionScanException.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/ResourceInclusionScanner.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/SimpleResourceInclusionScanner.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/StaleResourceScanner.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SingleTargetMapping.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SourceMapping.java
create mode 100644 Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SuffixMapping.java
create mode 100644 Java-base/maven-shared-io/src/src/main/resources/META-INF/plexus/components.xml
create mode 100644 Java-base/maven-shared-io/src/src/site/resources/download.cgi
create mode 100644 Java-base/maven-shared-io/src/src/site/site.xml
create mode 100644 Java-base/maven-shared-io/src/src/site/xdoc/download.xml.vm
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/Utils.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DefaultDownloadManagerTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DownloadFailedExceptionTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocationTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategyTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategyTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocationTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocatorStrategyTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/LocatorTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocationTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocatorStrategyTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/scan/mapping/SuffixMappingTest.java
create mode 100644 Java-base/maven-shared-io/src/src/test/resources/META-INF/maven/test.properties
diff --git a/Java-base/maven-shared-io/Dockerfile b/Java-base/maven-shared-io/Dockerfile
new file mode 100644
index 000000000..e208c4890
--- /dev/null
+++ b/Java-base/maven-shared-io/Dockerfile
@@ -0,0 +1,28 @@
+FROM ubuntu:22.04
+
+RUN export DEBIAN_FRONTEND=noninteractive \
+ && apt-get update \
+ && apt-get install -y software-properties-common \
+ && add-apt-repository ppa:deadsnakes/ppa \
+ && apt-get update \
+ && apt-get install -y \
+ build-essential \
+ git \
+ vim \
+ jq \
+ && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/list/*
+
+RUN apt-get -y install sudo \
+ openjdk-8-jdk \
+ maven
+
+RUN bash -c "echo 2 | update-alternatives --config java"
+
+COPY src /workspace
+WORKDIR /workspace
+
+RUN mvn install -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false
+
+RUN mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100
+
+ENV TZ=Asia/Seoul
diff --git a/Java-base/maven-shared-io/src/Jenkinsfile b/Java-base/maven-shared-io/src/Jenkinsfile
new file mode 100644
index 000000000..09ac70f12
--- /dev/null
+++ b/Java-base/maven-shared-io/src/Jenkinsfile
@@ -0,0 +1,20 @@
+/**
+ * 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.
+ */
+
+asfMavenTlpStdBuild()
diff --git a/Java-base/maven-shared-io/src/README.md b/Java-base/maven-shared-io/src/README.md
new file mode 100644
index 000000000..cc76fa9f2
--- /dev/null
+++ b/Java-base/maven-shared-io/src/README.md
@@ -0,0 +1,99 @@
+
+Contributing to [Apache Maven Shared IO](https://maven.apache.org/shared/maven-shared-io/)
+======================
+
+[![ASF Jira](https://img.shields.io/endpoint?url=https%3A%2F%2Fmaven.apache.org%2Fbadges%2Fasf_jira-MSHARED.json)][jira]
+[![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/apache/maven.svg?label=License)][license]
+[![Maven Central](https://img.shields.io/maven-central/v/org.apache.maven.shared/maven-shared-io.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.maven.shared/maven-shared-io)
+[![Jenkins Status](https://img.shields.io/jenkins/s/https/builds.apache.org/job/maven-box/job/maven-shared-io/job/master.svg)][build]
+[![Jenkins tests](https://img.shields.io/jenkins/t/https/builds.apache.org/job/maven-box/job/maven-shared-io/job/master.svg)][test-results]
+
+
+You have found a bug or you have an idea for a cool new feature? Contributing
+code is a great way to give something back to the open source community. Before
+you dig right into the code, there are a few guidelines that we need
+contributors to follow so that we can have a chance of keeping on top of
+things.
+
+Getting Started
+---------------
+
++ Make sure you have a [JIRA account](https://issues.apache.org/jira/).
++ Make sure you have a [GitHub account](https://github.com/signup/free).
++ If you're planning to implement a new feature, it makes sense to discuss your changes
+ on the [dev list][ml-list] first.
+ This way you can make sure you're not wasting your time on something that isn't
+ considered to be in Apache Maven's scope.
++ Submit a ticket for your issue, assuming one does not already exist.
+ + Clearly describe the issue, including steps to reproduce when it is a bug.
+ + Make sure you fill in the earliest version that you know has the issue.
++ Fork the repository on GitHub.
+
+Making and Submitting Changes
+--------------
+
+We accept Pull Requests via GitHub. The [developer mailing list][ml-list] is the
+main channel of communication for contributors.
+There are some guidelines which will make applying PRs easier for us:
++ Create a topic branch from where you want to base your work (this is usually the master branch).
+ Push your changes to a topic branch in your fork of the repository.
++ Make commits of logical units.
++ Respect the original code style: by using the same [codestyle][code-style],
+ patches should only highlight the actual difference, not being disturbed by any formatting issues:
+ + Only use spaces for indentation.
+ + Create minimal diffs - disable on save actions like reformat source code or organize imports.
+ If you feel the source code should be reformatted, create a separate PR for this change.
+ + Check for unnecessary whitespace with `git diff --check` before committing.
++ Make sure your commit messages are in the proper format. Your commit message should contain the key of the JIRA issue.
+```
+[MSHARED-XXX] - Subject of the JIRA Ticket
+ Optional supplemental description.
+```
++ Make sure you have added the necessary tests (JUnit/IT) for your changes.
++ Run all the tests with `mvn -Prun-its verify` to assure nothing else was accidentally broken.
++ Submit a pull request to the repository in the Apache organization.
++ Update your JIRA ticket and include a link to the pull request in the ticket.
+
+If you plan to contribute on a regular basis, please consider filing a [contributor license agreement][cla].
+
+Making Trivial Changes
+----------------------
+
+For changes of a trivial nature to comments and documentation, it is not always
+necessary to create a new ticket in JIRA. In this case, it is appropriate to
+start the first line of a commit with '(doc)' instead of a ticket number.
+
+Additional Resources
+--------------------
+
++ [Contributing patches](https://maven.apache.org/guides/development/guide-maven-development.html#Creating_and_submitting_a_patch)
++ [Apache Maven Shared Components project page][jira]
++ [Contributor License Agreement][cla]
++ [General GitHub documentation](https://help.github.com/)
++ [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
++ [Apache Maven Twitter Account](https://twitter.com/ASFMavenProject)
++ #Maven IRC channel on freenode.org
+
+[jira]: https://issues.apache.org/jira/projects/MSHARED/
+[license]: https://www.apache.org/licenses/LICENSE-2.0
+[ml-list]: https://maven.apache.org/mailing-lists.html
+[code-style]: https://maven.apache.org/developers/conventions/code.html
+[cla]: https://www.apache.org/licenses/#clas
+[maven-wiki]: https://cwiki.apache.org/confluence/display/MAVEN/Index
+[test-results]: https://builds.apache.org/job/maven-box/job/maven-shared-io/job/master/lastCompletedBuild/testReport/
+[build]: https://builds.apache.org/job/maven-box/job/maven-shared-io/job/master/
diff --git a/Java-base/maven-shared-io/src/pom.xml b/Java-base/maven-shared-io/src/pom.xml
new file mode 100644
index 000000000..5e5ab5db9
--- /dev/null
+++ b/Java-base/maven-shared-io/src/pom.xml
@@ -0,0 +1,123 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven.shared
+ maven-shared-components
+ 34
+ ../../pom/maven/maven-shared-components/pom.xml
+
+
+ maven-shared-io
+ 3.0.1-SNAPSHOT
+
+ Apache Maven Shared I/O API
+ API for I/O support like logging, download or file scanning.
+
+
+
+ Joakim Erdfelt
+ joakim@erdfelt.com
+
+
+
+
+ scm:git:https://gitbox.apache.org/repos/asf/maven-shared-io.git
+ scm:git:https://gitbox.apache.org/repos/asf/maven-shared-io.git
+ https://github.com/apache/maven-shared-io/tree/${project.scm.tag}
+ HEAD
+
+
+ jira
+ https://issues.apache.org/jira/browse/MSHARED/component/12326440
+
+
+ Jenkins
+ https://builds.apache.org/job/maven-box/job/maven-shared-io/
+
+
+
+ apache.website
+ scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path}
+
+
+
+
+ 3.0
+ 7
+ RedundantThrows,NewlineAtEndOfFile,ParameterNumber,MethodLength,FileLength,JavadocType
+ 2020-04-04T09:03:59Z
+
+
+
+
+
+ org.apache.maven
+ maven-core
+ ${mavenVersion}
+
+
+ org.apache.maven
+ maven-artifact
+ ${mavenVersion}
+
+
+ org.apache.maven
+ maven-compat
+ ${mavenVersion}
+
+
+ org.apache.maven.wagon
+ wagon-provider-api
+ 3.0.0
+
+
+ org.apache.maven
+ maven-plugin-api
+ ${mavenVersion}
+
+
+ org.apache.maven.shared
+ maven-shared-utils
+ 3.2.1
+
+
+ org.sonatype.sisu
+ sisu-inject-plexus
+ 1.4.2
+
+
+
+ org.easymock
+ easymock
+ 3.2
+ test
+
+
+ junit
+ junit
+ 4.13
+ test
+
+
+
+
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DefaultDownloadManager.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DefaultDownloadManager.java
new file mode 100644
index 000000000..5cf008720
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DefaultDownloadManager.java
@@ -0,0 +1,213 @@
+package org.apache.maven.shared.io.download;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.shared.io.logging.MessageHolder;
+import org.apache.maven.wagon.ConnectionException;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.UnsupportedProtocolException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authentication.AuthenticationException;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.repository.Repository;
+
+/**
+ * The Implementation of the {@link DownloadManager}
+ *
+ */
+public class DefaultDownloadManager
+ implements DownloadManager
+{
+
+ /**
+ * Role hint.
+ */
+ public static final String ROLE_HINT = "default";
+
+ private WagonManager wagonManager;
+
+ private Map cache = new HashMap();
+
+ /**
+ * Create an instance of the {@code DefaultDownloadManager}.
+ */
+ public DefaultDownloadManager()
+ {
+ }
+
+ /**
+ * @param wagonManager {@link org.apache.maven.repository.legacy.WagonManager}
+ */
+ public DefaultDownloadManager( WagonManager wagonManager )
+ {
+ this.wagonManager = wagonManager;
+ }
+
+ /** {@inheritDoc} */
+ public File download( String url, MessageHolder messageHolder )
+ throws DownloadFailedException
+ {
+ return download( url, Collections.emptyList(), messageHolder );
+ }
+
+ /** {@inheritDoc} */
+ public File download( String url, List transferListeners, MessageHolder messageHolder )
+ throws DownloadFailedException
+ {
+ File downloaded = (File) cache.get( url );
+
+ if ( downloaded != null && downloaded.exists() )
+ {
+ messageHolder.addMessage( "Using cached download: " + downloaded.getAbsolutePath() );
+
+ return downloaded;
+ }
+
+ URL sourceUrl;
+ try
+ {
+ sourceUrl = new URL( url );
+ }
+ catch ( MalformedURLException e )
+ {
+ throw new DownloadFailedException( url, "Download failed due to invalid URL. Reason: " + e.getMessage(),
+ e );
+ }
+
+ Wagon wagon = null;
+
+ // Retrieve the correct Wagon instance used to download the remote archive
+ try
+ {
+ wagon = wagonManager.getWagon( sourceUrl.getProtocol() );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+
+ messageHolder.addMessage( "Using wagon: " + wagon + " to download: " + url );
+
+ try
+ {
+ // create the landing file in /tmp for the downloaded source archive
+ downloaded = File.createTempFile( "download-", null );
+
+ // delete when the JVM exits, to avoid polluting the temp dir...
+ downloaded.deleteOnExit();
+ }
+ catch ( IOException e )
+ {
+ throw new DownloadFailedException( url, "Failed to create temporary file target for download. Reason: "
+ + e.getMessage(), e );
+ }
+
+ messageHolder.addMessage( "Download target is: " + downloaded.getAbsolutePath() );
+
+ // split the download URL into base URL and remote path for connecting, then retrieving.
+ String remotePath = sourceUrl.getPath();
+ String baseUrl = url.substring( 0, url.length() - remotePath.length() );
+
+ for ( Iterator it = transferListeners.iterator(); it.hasNext(); )
+ {
+ wagon.addTransferListener( it.next() );
+ }
+
+ // connect to the remote site, and retrieve the archive. Note the separate methods in which
+ // base URL and remote path are used.
+ Repository repo = new Repository( sourceUrl.getHost(), baseUrl );
+
+ messageHolder.addMessage( "Connecting to: " + repo.getHost() + "(baseUrl: " + repo.getUrl() + ")" );
+
+ try
+ {
+ wagon.connect( repo, wagonManager.getAuthenticationInfo( repo.getId() ),
+ wagonManager.getProxy( sourceUrl.getProtocol() ) );
+ }
+ catch ( ConnectionException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+ catch ( AuthenticationException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+
+ messageHolder.addMessage( "Getting: " + remotePath );
+
+ try
+ {
+ wagon.get( remotePath, downloaded );
+
+ // cache this for later download requests to the same instance...
+ cache.put( url, downloaded );
+
+ return downloaded;
+ }
+ catch ( TransferFailedException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+ catch ( ResourceDoesNotExistException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+ catch ( AuthorizationException e )
+ {
+ throw new DownloadFailedException( url, "Download failed. Reason: " + e.getMessage(), e );
+ }
+ finally
+ {
+ // ensure the Wagon instance is closed out properly.
+ if ( wagon != null )
+ {
+ try
+ {
+ messageHolder.addMessage( "Disconnecting." );
+
+ wagon.disconnect();
+ }
+ catch ( ConnectionException e )
+ {
+ messageHolder.addMessage( "Failed to disconnect wagon for: " + url, e );
+ }
+
+ for ( Iterator it = transferListeners.iterator(); it.hasNext(); )
+ {
+ wagon.removeTransferListener( it.next() );
+ }
+ }
+ }
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadFailedException.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadFailedException.java
new file mode 100644
index 000000000..669ce8bca
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadFailedException.java
@@ -0,0 +1,63 @@
+package org.apache.maven.shared.io.download;
+
+/*
+ * 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.
+ */
+
+/**
+ * The Download Failed Exception.
+ *
+ */
+public class DownloadFailedException
+ extends Exception
+{
+
+ private static final long serialVersionUID = 1L;
+
+ private String url;
+
+ /**
+ * @param url The url.
+ * @param message The message.
+ * @param cause The cause of the problem.
+ */
+ public DownloadFailedException( String url, String message, Throwable cause )
+ {
+ super( message, cause );
+ this.url = url;
+ }
+
+ /**
+ * @param url The url.
+ * @param message The message.
+ */
+ public DownloadFailedException( String url, String message )
+ {
+ super( message );
+ this.url = url;
+ }
+
+ /**
+ * @return The url.
+ */
+ public String getUrl()
+ {
+ return url;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadManager.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadManager.java
new file mode 100644
index 000000000..6d2e91a81
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/download/DownloadManager.java
@@ -0,0 +1,58 @@
+package org.apache.maven.shared.io.download;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.shared.io.logging.MessageHolder;
+import org.apache.maven.wagon.events.TransferListener;
+
+/**
+ * The Download Manager interface.
+ *
+ */
+public interface DownloadManager
+{
+ /**
+ * The Role.
+ */
+ String ROLE = DownloadManager.class.getName();
+
+ /**
+ * @param url The URL.
+ * @param messageHolder {@link MessageHolder}
+ * @return {@link File}
+ * @throws DownloadFailedException in case of exception.
+ */
+ File download( String url, MessageHolder messageHolder )
+ throws DownloadFailedException;
+
+ /**
+ * @param url The URL.
+ * @param transferListeners {@link TransferListener}
+ * @param messageHolder {@link MessageHolder}
+ * @return {@link File}
+ * @throws DownloadFailedException in case of exception.
+ */
+ File download( String url, List transferListeners, MessageHolder messageHolder )
+ throws DownloadFailedException;
+
+}
\ No newline at end of file
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocation.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocation.java
new file mode 100644
index 000000000..dea6e68b6
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocation.java
@@ -0,0 +1,42 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * The artifact location.
+ *
+ */
+public class ArtifactLocation
+ extends FileLocation
+{
+
+ /**
+ * @param artifact {@link Artifact}
+ * @param specification The specification.
+ */
+ public ArtifactLocation( Artifact artifact, String specification )
+ {
+ super( specification );
+ setFile( artifact.getFile() );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategy.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategy.java
new file mode 100644
index 000000000..634b37105
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategy.java
@@ -0,0 +1,193 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * The locator strategy.
+ *
+ */
+public class ArtifactLocatorStrategy
+ implements LocatorStrategy
+{
+ private final ArtifactFactory factory;
+
+ private final ArtifactResolver resolver;
+
+ private String defaultArtifactType = "jar";
+
+ private final ArtifactRepository localRepository;
+
+ private final List remoteRepositories;
+
+ private String defaultClassifier = null;
+
+ /**
+ * @param factory {@link ArtifactFactory}
+ * @param resolver {@link ArtifactResolver}
+ * @param localRepository {@link ArtifactRepository}
+ * @param remoteRepositories {@link ArtifactRepository}
+ */
+ public ArtifactLocatorStrategy( ArtifactFactory factory, ArtifactResolver resolver,
+ ArtifactRepository localRepository, List remoteRepositories )
+ {
+ this.factory = factory;
+ this.resolver = resolver;
+ this.localRepository = localRepository;
+ this.remoteRepositories = remoteRepositories;
+ }
+
+ /**
+ * @param factory {@link ArtifactFactory}
+ * @param resolver {@link ArtifactResolver}
+ * @param localRepository {@link ArtifactRepository}
+ * @param remoteRepositories {@link ArtifactRepository}
+ * @param defaultArtifactType default artifact type.
+ */
+ public ArtifactLocatorStrategy( ArtifactFactory factory, ArtifactResolver resolver,
+ ArtifactRepository localRepository, List remoteRepositories,
+ String defaultArtifactType )
+ {
+ this.factory = factory;
+ this.resolver = resolver;
+ this.localRepository = localRepository;
+ this.remoteRepositories = remoteRepositories;
+ this.defaultArtifactType = defaultArtifactType;
+ }
+
+ /**
+ * @param factory {@link ArtifactFactory}
+ * @param resolver {@link ArtifactResolver}
+ * @param localRepository {@link ArtifactRepository}
+ * @param remoteRepositories {@link ArtifactRepository}
+ * @param defaultArtifactType default artifact type.
+ * @param defaultClassifier default classifier.
+ */
+ public ArtifactLocatorStrategy( ArtifactFactory factory, ArtifactResolver resolver,
+ ArtifactRepository localRepository, List remoteRepositories,
+ String defaultArtifactType, String defaultClassifier )
+ {
+ this.factory = factory;
+ this.resolver = resolver;
+ this.localRepository = localRepository;
+ this.remoteRepositories = remoteRepositories;
+ this.defaultArtifactType = defaultArtifactType;
+ this.defaultClassifier = defaultClassifier;
+ }
+
+ /**
+ * Assumes artifact identity is given in a set of comma-delimited tokens of
+ * the form: groupId:artifactId:version:type:classifier
, where
+ * type and classifier are optional.
+ * @param locationSpecification location spec.
+ * @param messageHolder {@link MessageHolder}
+ * @return location.
+ */
+ public Location resolve( String locationSpecification, MessageHolder messageHolder )
+ {
+ String[] parts = locationSpecification.split( ":" );
+
+ Location location = null;
+
+ if ( parts.length > 2 )
+ {
+ String groupId = parts[0];
+ String artifactId = parts[1];
+ String version = parts[2];
+
+ String type = defaultArtifactType;
+ if ( parts.length > 3 )
+ {
+ if ( parts[3].trim().length() > 0 )
+ {
+ type = parts[3];
+ }
+ }
+
+ String classifier = defaultClassifier;
+ if ( parts.length > 4 )
+ {
+ classifier = parts[4];
+ }
+
+ if ( parts.length > 5 )
+ {
+ messageHolder.newMessage().append( "Location specification has unused tokens: \'" );
+
+ for ( int i = 5; i < parts.length; i++ )
+ {
+ messageHolder.append( ":" + parts[i] );
+ }
+ }
+
+ Artifact artifact;
+ if ( classifier == null )
+ {
+ artifact = factory.createArtifact( groupId, artifactId, version, null, type );
+ }
+ else
+ {
+ artifact = factory.createArtifactWithClassifier( groupId, artifactId, version, type, classifier );
+ }
+
+ try
+ {
+ resolver.resolve( artifact, remoteRepositories, localRepository );
+
+ if ( artifact.getFile() != null )
+ {
+ location = new ArtifactLocation( artifact, locationSpecification );
+ }
+ else
+ {
+ messageHolder.addMessage( "Supposedly resolved artifact: " + artifact.getId()
+ + " does not have an associated file." );
+ }
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ messageHolder.addMessage( "Failed to resolve artifact: " + artifact.getId() + " for location: "
+ + locationSpecification, e );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ messageHolder.addMessage( "Failed to resolve artifact: " + artifact.getId() + " for location: "
+ + locationSpecification, e );
+ }
+ }
+ else
+ {
+ messageHolder.addMessage( "Invalid artifact specification: \'" + locationSpecification
+ + "\'. Must contain at least three fields, separated by ':'." );
+ }
+
+ return location;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategy.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategy.java
new file mode 100644
index 000000000..4d850cfa6
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategy.java
@@ -0,0 +1,83 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.net.URL;
+
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * classpath resource locator strategy.
+ *
+ */
+public class ClasspathResourceLocatorStrategy
+ implements LocatorStrategy
+{
+
+ private String tempFilePrefix = "location.";
+
+ private String tempFileSuffix = ".cpurl";
+
+ private boolean tempFileDeleteOnExit = true;
+
+ /**
+ * Create instance.
+ */
+ public ClasspathResourceLocatorStrategy()
+ {
+ }
+
+ /**
+ * @param tempFilePrefix Prefix.
+ * @param tempFileSuffix Suffix.
+ * @param tempFileDeleteOnExit delete on exit.
+ */
+ public ClasspathResourceLocatorStrategy( String tempFilePrefix, String tempFileSuffix,
+ boolean tempFileDeleteOnExit )
+ {
+ this.tempFilePrefix = tempFilePrefix;
+ this.tempFileSuffix = tempFileSuffix;
+ this.tempFileDeleteOnExit = tempFileDeleteOnExit;
+ }
+
+ /** {@inheritDoc} */
+ public Location resolve( String locationSpecification, MessageHolder messageHolder )
+ {
+ ClassLoader cloader = Thread.currentThread().getContextClassLoader();
+
+ URL resource = cloader.getResource( locationSpecification );
+
+ Location location = null;
+
+ if ( resource != null )
+ {
+ location = new URLLocation( resource, locationSpecification, tempFilePrefix, tempFileSuffix,
+ tempFileDeleteOnExit );
+ }
+ else
+ {
+ messageHolder.addMessage( "Failed to resolve classpath resource: " + locationSpecification
+ + " from classloader: " + cloader );
+ }
+
+ return location;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocation.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocation.java
new file mode 100644
index 000000000..a8a62e3ec
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocation.java
@@ -0,0 +1,176 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+
+/**
+ * file location implementation.
+ *
+ */
+public class FileLocation
+ implements Location
+{
+
+ private File file;
+ private FileChannel channel;
+ private final String specification;
+ private FileInputStream stream;
+
+ /**
+ * @param file {@link File}
+ * @param specification spec.
+ */
+ public FileLocation( File file, String specification )
+ {
+ this.file = file;
+ this.specification = specification;
+ }
+
+ /**
+ * @param specification spec.
+ */
+ protected FileLocation( String specification )
+ {
+ this.specification = specification;
+ }
+
+ /** {@inheritDoc} */
+ public void close()
+ {
+ if ( ( channel != null ) && channel.isOpen() )
+ {
+ try
+ {
+ channel.close();
+ }
+ catch ( IOException e )
+ {
+ //swallow it.
+ }
+ }
+
+ if ( stream != null )
+ {
+ try
+ {
+ stream.close();
+ }
+ catch ( IOException e )
+ {
+ // swallow it.
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public File getFile()
+ throws IOException
+ {
+ initFile();
+
+ return unsafeGetFile();
+ }
+
+ /**
+ * @return {@link File}
+ */
+ protected File unsafeGetFile()
+ {
+ return file;
+ }
+
+ /**
+ * initialize file.
+ * @throws IOException in case error.
+ */
+ protected void initFile()
+ throws IOException
+ {
+ // TODO: Log this in the debug log-level...
+ if ( file == null )
+ {
+ file = new File( specification );
+ }
+ }
+
+ /**
+ * @param file {@link File}
+ */
+ protected void setFile( File file )
+ {
+ if ( channel != null )
+ {
+ throw new IllegalStateException( "Location is already open; cannot setFile(..)." );
+ }
+
+ this.file = file;
+ }
+
+ /** {@inheritDoc} */
+ public String getSpecification()
+ {
+ return specification;
+ }
+
+ /** {@inheritDoc} */
+ public void open()
+ throws IOException
+ {
+ if ( stream == null )
+ {
+ initFile();
+
+ stream = new FileInputStream( file );
+ channel = stream.getChannel();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public int read( ByteBuffer buffer )
+ throws IOException
+ {
+ open();
+ return channel.read( buffer );
+ }
+
+ /** {@inheritDoc} */
+ public int read( byte[] buffer )
+ throws IOException
+ {
+ open();
+ return channel.read( ByteBuffer.wrap( buffer ) );
+ }
+
+ /** {@inheritDoc} */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ open();
+ return stream;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocatorStrategy.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocatorStrategy.java
new file mode 100644
index 000000000..92aa3dd38
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/FileLocatorStrategy.java
@@ -0,0 +1,53 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * file locator strategy.
+ *
+ */
+public class FileLocatorStrategy
+ implements LocatorStrategy
+{
+
+ /** {@inheritDoc} */
+ public Location resolve( String locationSpecification, MessageHolder messageHolder )
+ {
+ File file = new File( locationSpecification );
+
+ Location location = null;
+
+ if ( file.exists() )
+ {
+ location = new FileLocation( file, locationSpecification );
+ }
+ else
+ {
+ messageHolder.addMessage( "File: " + file.getAbsolutePath() + " does not exist." );
+ }
+
+ return location;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Location.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Location.java
new file mode 100644
index 000000000..cfbd4ae4a
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Location.java
@@ -0,0 +1,76 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * The location interface.
+ *
+ */
+public interface Location
+{
+
+ /**
+ * @return {@link File}.
+ * @throws IOException in case of an error.
+ */
+ File getFile() throws IOException;
+
+ /**
+ * open the location.
+ * @throws IOException in case of an error.
+ */
+ void open() throws IOException;
+
+ /**
+ * Close the location.
+ */
+ void close();
+
+ /**
+ * @param buffer The buffer.
+ * @return number of read bytes.
+ * @throws IOException in case of an error.
+ */
+ int read( ByteBuffer buffer ) throws IOException;
+
+ /**
+ * @param buffer The buffer.
+ * @return number of read bytes.
+ * @throws IOException in case of an error.
+ */
+ int read( byte[] buffer ) throws IOException;
+
+ /**
+ * @return the resulting input stream.
+ * @throws IOException in case of an error.
+ */
+ InputStream getInputStream() throws IOException;
+
+ /**
+ * @return spec.
+ */
+ String getSpecification();
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Locator.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Locator.java
new file mode 100644
index 000000000..45f27aff5
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/Locator.java
@@ -0,0 +1,117 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * The Locator.
+ *
+ */
+public final class Locator
+{
+
+ private List strategies;
+ private final MessageHolder messageHolder;
+
+ /**
+ * @param strategies List of strategies.
+ * @param messageHolder {@link MessageHolder}
+ */
+ public Locator( List strategies, MessageHolder messageHolder )
+ {
+ this.messageHolder = messageHolder;
+ this.strategies = new ArrayList( strategies );
+ }
+
+ /**
+ * Create instance.
+ */
+ public Locator()
+ {
+ this.messageHolder = new DefaultMessageHolder();
+ this.strategies = new ArrayList();
+ }
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ public MessageHolder getMessageHolder()
+ {
+ return messageHolder;
+ }
+
+ /**
+ * @param strategy The strategy to be added.
+ */
+ public void addStrategy( LocatorStrategy strategy )
+ {
+ this.strategies.add( strategy );
+ }
+
+ /**
+ * @param strategy the strategy to remove.
+ */
+ public void removeStrategy( LocatorStrategy strategy )
+ {
+ this.strategies.remove( strategy );
+ }
+
+ /**
+ * @param strategies the strategies to be set.
+ */
+ public void setStrategies( List strategies )
+ {
+ this.strategies.clear();
+ this.strategies.addAll( strategies );
+ }
+
+ /**
+ * @return list of strategies.
+ */
+ public List getStrategies()
+ {
+ return strategies;
+ }
+
+ /**
+ * @param locationSpecification location spec.
+ * @return {@link Location}
+ */
+ public Location resolve( String locationSpecification )
+ {
+ Location location = null;
+
+ for ( Iterator it = strategies.iterator(); location == null && it.hasNext(); )
+ {
+ LocatorStrategy strategy = (LocatorStrategy) it.next();
+
+ location = strategy.resolve( locationSpecification, messageHolder );
+ }
+
+ return location;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/LocatorStrategy.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/LocatorStrategy.java
new file mode 100644
index 000000000..03e9d23cd
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/LocatorStrategy.java
@@ -0,0 +1,38 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * Locator Strategy interface.
+ *
+ */
+public interface LocatorStrategy
+{
+
+ /**
+ * @param locationSpecification the specification.
+ * @param messageHolder {@link MessageHolder}
+ * @return {@link Location}
+ */
+ Location resolve( String locationSpecification, MessageHolder messageHolder );
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocation.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocation.java
new file mode 100644
index 000000000..cca1f24b7
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocation.java
@@ -0,0 +1,82 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.maven.shared.utils.io.FileUtils;
+
+/**
+ * The URL Location.
+ *
+ */
+public class URLLocation
+ extends FileLocation
+{
+
+ private final URL url;
+
+ private final String tempFilePrefix;
+
+ private final String tempFileSuffix;
+
+ private final boolean tempFileDeleteOnExit;
+
+ /**
+ * @param url The URL.
+ * @param specification The spec.
+ * @param tempFilePrefix the prefix.
+ * @param tempFileSuffix The suffix.
+ * @param tempFileDeleteOnExit delete on exit.
+ */
+ public URLLocation( URL url, String specification, String tempFilePrefix, String tempFileSuffix,
+ boolean tempFileDeleteOnExit )
+ {
+ super( specification );
+
+ this.url = url;
+ this.tempFilePrefix = tempFilePrefix;
+ this.tempFileSuffix = tempFileSuffix;
+ this.tempFileDeleteOnExit = tempFileDeleteOnExit;
+ }
+
+ /** {@inheritDoc} */
+ protected void initFile()
+ throws IOException
+ {
+ // TODO: Log this in the debug log-level...
+ if ( unsafeGetFile() == null )
+ {
+ File tempFile = File.createTempFile( tempFilePrefix, tempFileSuffix );
+
+ if ( tempFileDeleteOnExit )
+ {
+ tempFile.deleteOnExit();
+ }
+
+ FileUtils.copyURLToFile( url, tempFile );
+
+ setFile( tempFile );
+ }
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocatorStrategy.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocatorStrategy.java
new file mode 100644
index 000000000..e7d259d09
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/location/URLLocatorStrategy.java
@@ -0,0 +1,80 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+/**
+ * URL Locator Strategy.
+ *
+ */
+public class URLLocatorStrategy
+ implements LocatorStrategy
+{
+
+ private String tempFilePrefix = "location.";
+
+ private String tempFileSuffix = ".url";
+
+ private boolean tempFileDeleteOnExit = true;
+
+ /**
+ * Create instance.
+ */
+ public URLLocatorStrategy()
+ {
+ }
+
+ /**
+ * @param tempFilePrefix prefix.
+ * @param tempFileSuffix suffix.
+ * @param tempFileDeleteOnExit delete on exit.
+ */
+ public URLLocatorStrategy( String tempFilePrefix, String tempFileSuffix, boolean tempFileDeleteOnExit )
+ {
+ this.tempFilePrefix = tempFilePrefix;
+ this.tempFileSuffix = tempFileSuffix;
+ this.tempFileDeleteOnExit = tempFileDeleteOnExit;
+ }
+
+ /** {@inheritDoc} */
+ public Location resolve( String locationSpecification, MessageHolder messageHolder )
+ {
+ Location location = null;
+
+ try
+ {
+ URL url = new URL( locationSpecification );
+
+ location = new URLLocation( url, locationSpecification, tempFilePrefix, tempFileSuffix,
+ tempFileDeleteOnExit );
+ }
+ catch ( MalformedURLException e )
+ {
+ messageHolder.addMessage( "Building URL from location: " + locationSpecification, e );
+ }
+
+ return location;
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java
new file mode 100644
index 000000000..97eeb065f
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/DefaultMessageHolder.java
@@ -0,0 +1,616 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Default Message Holder.
+ *
+ */
+public class DefaultMessageHolder
+ implements MessageHolder
+{
+
+ private List messages = new ArrayList();
+
+ private Message currentMessage;
+
+ private int defaultMessageLevel = MessageLevels.LEVEL_INFO;
+
+ private boolean[] messageLevelStates;
+
+ private MessageSink onDemandSink;
+
+ /**
+ * Create instance.
+ */
+ public DefaultMessageHolder()
+ {
+ this.messageLevelStates = MessageLevels.getLevelStates( MessageLevels.LEVEL_INFO );
+ }
+
+ /**
+ * @param maxMessageLevel max message level.
+ * @param defaultMessageLevel default message level.
+ */
+ public DefaultMessageHolder( int maxMessageLevel, int defaultMessageLevel )
+ {
+ this.defaultMessageLevel = defaultMessageLevel;
+ this.messageLevelStates = MessageLevels.getLevelStates( maxMessageLevel );
+ }
+
+ /**
+ * @param maxMessageLevel max message level.
+ * @param defaultMessageLevel default message level.
+ * @param onDemandSink {@link MessageSink}
+ */
+ public DefaultMessageHolder( int maxMessageLevel, int defaultMessageLevel, MessageSink onDemandSink )
+ {
+ this.defaultMessageLevel = defaultMessageLevel;
+ this.onDemandSink = onDemandSink;
+ this.messageLevelStates = MessageLevels.getLevelStates( maxMessageLevel );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( defaultMessageLevel, messagePart, error );
+ }
+
+ /**
+ * @param level Level.
+ * @param messagePart Message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ protected MessageHolder addMessage( int level, CharSequence messagePart, Throwable error )
+ {
+ newMessage( level );
+ append( messagePart.toString() );
+ append( error );
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addMessage( CharSequence messagePart )
+ {
+ return addMessage( defaultMessageLevel, messagePart );
+ }
+
+ /**
+ * @param level level.
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ protected MessageHolder addMessage( int level, CharSequence messagePart )
+ {
+ newMessage( level );
+ append( messagePart.toString() );
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addMessage( Throwable error )
+ {
+ return addMessage( defaultMessageLevel, error );
+ }
+
+ /**
+ * @param level level.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ protected MessageHolder addMessage( int level, Throwable error )
+ {
+ newMessage( level );
+ append( error );
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder append( CharSequence messagePart )
+ {
+ if ( currentMessage == null )
+ {
+ newMessage();
+ }
+
+ currentMessage.append( messagePart.toString() );
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder append( Throwable error )
+ {
+ if ( currentMessage == null )
+ {
+ newMessage();
+ }
+
+ currentMessage.setError( error );
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isEmpty()
+ {
+ return messages.isEmpty();
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newMessage()
+ {
+ newMessage( defaultMessageLevel );
+
+ return this;
+ }
+
+ /**
+ * @param messageLevel message level.
+ */
+ protected void newMessage( int messageLevel )
+ {
+ if ( onDemandSink != null && currentMessage != null )
+ {
+ renderTo( currentMessage, onDemandSink );
+ }
+
+ currentMessage = new Message( messageLevel, onDemandSink );
+ messages.add( currentMessage );
+ }
+
+ /** {@inheritDoc} */
+ public String render()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ int counter = 1;
+ for ( Iterator it = messages.iterator(); it.hasNext(); )
+ {
+ Message message = (Message) it.next();
+
+ int ml = message.getMessageLevel();
+
+ if ( ml >= messageLevelStates.length || ml < 0 )
+ {
+ ml = MessageLevels.LEVEL_DEBUG;
+ }
+
+ if ( !messageLevelStates[ml] )
+ {
+ continue;
+ }
+
+ CharSequence content = message.render();
+ String label = MessageLevels.getLevelLabel( message.getMessageLevel() );
+
+ if ( content.length() > label.length() + 3 )
+ {
+ buffer.append( '[' ).append( counter++ ).append( "] " );
+ buffer.append( content.toString() );
+
+ if ( it.hasNext() )
+ {
+ buffer.append( "\n\n" );
+ }
+ }
+ }
+
+ return buffer.toString();
+ }
+
+ /** {@inheritDoc} */
+ public int size()
+ {
+ return messages.size();
+ }
+
+ private static final class Message
+ {
+ private StringBuffer message = new StringBuffer();
+
+ private Throwable error;
+
+ private final int messageLevel;
+
+ private final MessageSink onDemandSink;
+
+ Message( int messageLevel, MessageSink onDemandSink )
+ {
+ this.messageLevel = messageLevel;
+
+ this.onDemandSink = onDemandSink;
+ }
+
+ public Message setError( Throwable pError )
+ {
+ this.error = pError;
+ return this;
+ }
+
+ public Message append( CharSequence pMessage )
+ {
+ this.message.append( pMessage.toString() );
+ return this;
+ }
+
+ /**
+ * @return message level.
+ */
+ public int getMessageLevel()
+ {
+ return messageLevel;
+ }
+
+ /**
+ * @return Sequence.
+ */
+ public CharSequence render()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ if ( onDemandSink == null )
+ {
+ buffer.append( '[' ).append( MessageLevels.getLevelLabel( messageLevel ) ).append( "] " );
+ }
+ if ( message != null && message.length() > 0 )
+ {
+ buffer.append( message );
+
+ if ( error != null )
+ {
+ buffer.append( '\n' );
+ }
+ }
+
+ if ( error != null )
+ {
+ buffer.append( "Error:\n" );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+ error.printStackTrace( pw );
+
+ buffer.append( sw.toString() );
+ }
+
+ return buffer;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addDebugMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_DEBUG, messagePart, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addDebugMessage( CharSequence messagePart )
+ {
+ return addMessage( MessageLevels.LEVEL_DEBUG, messagePart );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addDebugMessage( Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_DEBUG, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addErrorMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_ERROR, messagePart, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addErrorMessage( CharSequence messagePart )
+ {
+ return addMessage( MessageLevels.LEVEL_ERROR, messagePart );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addErrorMessage( Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_ERROR, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addInfoMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_INFO, messagePart, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addInfoMessage( CharSequence messagePart )
+ {
+ return addMessage( MessageLevels.LEVEL_INFO, messagePart );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addInfoMessage( Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_INFO, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addSevereMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_SEVERE, messagePart, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addSevereMessage( CharSequence messagePart )
+ {
+ return addMessage( MessageLevels.LEVEL_SEVERE, messagePart );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addSevereMessage( Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_SEVERE, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addWarningMessage( CharSequence messagePart, Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_WARNING, messagePart, error );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addWarningMessage( CharSequence messagePart )
+ {
+ return addMessage( MessageLevels.LEVEL_WARNING, messagePart );
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder addWarningMessage( Throwable error )
+ {
+ return addMessage( MessageLevels.LEVEL_WARNING, error );
+ }
+
+ /** {@inheritDoc} */
+ public int countDebugMessages()
+ {
+ return countMessagesOfType( MessageLevels.LEVEL_DEBUG );
+ }
+
+ /** {@inheritDoc} */
+ public int countErrorMessages()
+ {
+ return countMessagesOfType( MessageLevels.LEVEL_ERROR );
+ }
+
+ /** {@inheritDoc} */
+ public int countInfoMessages()
+ {
+ return countMessagesOfType( MessageLevels.LEVEL_INFO );
+ }
+
+ /** {@inheritDoc} */
+ public int countMessages()
+ {
+ return size();
+ }
+
+ /** {@inheritDoc} */
+ public int countSevereMessages()
+ {
+ return countMessagesOfType( MessageLevels.LEVEL_SEVERE );
+ }
+
+ /** {@inheritDoc} */
+ public int countWarningMessages()
+ {
+ return countMessagesOfType( MessageLevels.LEVEL_WARNING );
+ }
+
+ /**
+ * @param messageLevel leve.
+ * @return number of messages.
+ */
+ private int countMessagesOfType( int messageLevel )
+ {
+ int count = 0;
+
+ for ( Message message : messages )
+ {
+ if ( messageLevel == message.getMessageLevel() )
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isDebugEnabled()
+ {
+ return messageLevelStates[MessageLevels.LEVEL_DEBUG];
+ }
+
+ /** {@inheritDoc} */
+ public boolean isErrorEnabled()
+ {
+ return messageLevelStates[MessageLevels.LEVEL_ERROR];
+ }
+
+ /** {@inheritDoc} */
+ public boolean isInfoEnabled()
+ {
+ return messageLevelStates[MessageLevels.LEVEL_INFO];
+ }
+
+ /** {@inheritDoc} */
+ public boolean isSevereEnabled()
+ {
+ return messageLevelStates[MessageLevels.LEVEL_SEVERE];
+ }
+
+ /** {@inheritDoc} */
+ public boolean isWarningEnabled()
+ {
+ return messageLevelStates[MessageLevels.LEVEL_WARNING];
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newDebugMessage()
+ {
+ if ( isDebugEnabled() )
+ {
+ newMessage( MessageLevels.LEVEL_DEBUG );
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newErrorMessage()
+ {
+ if ( isErrorEnabled() )
+ {
+ newMessage( MessageLevels.LEVEL_ERROR );
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newInfoMessage()
+ {
+ if ( isInfoEnabled() )
+ {
+ newMessage( MessageLevels.LEVEL_INFO );
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newSevereMessage()
+ {
+ if ( isSevereEnabled() )
+ {
+ newMessage( MessageLevels.LEVEL_SEVERE );
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public MessageHolder newWarningMessage()
+ {
+ if ( isWarningEnabled() )
+ {
+ newMessage( MessageLevels.LEVEL_WARNING );
+ }
+
+ return this;
+ }
+
+ /** {@inheritDoc} */
+ public void setDebugEnabled( boolean enabled )
+ {
+ messageLevelStates[MessageLevels.LEVEL_DEBUG] = enabled;
+ }
+
+ /** {@inheritDoc} */
+ public void setErrorEnabled( boolean enabled )
+ {
+ messageLevelStates[MessageLevels.LEVEL_ERROR] = enabled;
+ }
+
+ /** {@inheritDoc} */
+ public void setInfoEnabled( boolean enabled )
+ {
+ messageLevelStates[MessageLevels.LEVEL_INFO] = enabled;
+ }
+
+ /** {@inheritDoc} */
+ public void setSevereEnabled( boolean enabled )
+ {
+ messageLevelStates[MessageLevels.LEVEL_SEVERE] = enabled;
+ }
+
+ /** {@inheritDoc} */
+ public void setWarningEnabled( boolean enabled )
+ {
+ messageLevelStates[MessageLevels.LEVEL_WARNING] = enabled;
+ }
+
+ /** {@inheritDoc} */
+ public void flush()
+ {
+ if ( onDemandSink != null && currentMessage != null )
+ {
+ renderTo( currentMessage, onDemandSink );
+ currentMessage = null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void render( MessageSink sink )
+ {
+ for ( Message message : messages )
+ {
+ renderTo( message, sink );
+ }
+ }
+
+ /**
+ * @param message {@link Message}
+ * @param sink {@link MessageSink}
+ */
+ protected void renderTo( Message message, MessageSink sink )
+ {
+ switch ( message.getMessageLevel() )
+ {
+ case ( MessageLevels.LEVEL_SEVERE ):
+ sink.severe( message.render().toString() );
+ break;
+
+ case ( MessageLevels.LEVEL_ERROR ):
+ sink.error( message.render().toString() );
+ break;
+
+ case ( MessageLevels.LEVEL_WARNING ):
+ sink.warning( message.render().toString() );
+ break;
+
+ case ( MessageLevels.LEVEL_INFO ):
+ sink.info( message.render().toString() );
+ break;
+
+ default:
+ sink.debug( message.render().toString() );
+ }
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageHolder.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageHolder.java
new file mode 100644
index 000000000..be4f83394
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageHolder.java
@@ -0,0 +1,290 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+/**
+ * Message Holder class.
+ *
+ */
+public interface MessageHolder
+{
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newMessage();
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newDebugMessage();
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newInfoMessage();
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newWarningMessage();
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newErrorMessage();
+
+ /**
+ * @return {@link MessageHolder}
+ */
+ MessageHolder newSevereMessage();
+
+ /**
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder append( CharSequence messagePart );
+
+ /**
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder append( Throwable error );
+
+ /**
+ * @param messagePart Message Part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addMessage( CharSequence messagePart );
+
+ /**
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addMessage( Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addDebugMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart messages part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addDebugMessage( CharSequence messagePart );
+
+ /**
+ * @param error messages part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addDebugMessage( Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addInfoMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart messages part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addInfoMessage( CharSequence messagePart );
+
+ /**
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addInfoMessage( Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addWarningMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addWarningMessage( CharSequence messagePart );
+
+ /**
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addWarningMessage( Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addErrorMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addErrorMessage( CharSequence messagePart );
+
+ /**
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addErrorMessage( Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @param error {@link Throwable}
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addSevereMessage( CharSequence messagePart, Throwable error );
+
+ /**
+ * @param messagePart message part.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addSevereMessage( CharSequence messagePart );
+
+ /**
+ * @param error The error.
+ * @return {@link MessageHolder}
+ */
+ MessageHolder addSevereMessage( Throwable error );
+
+ /**
+ * @return the size.
+ */
+ int size();
+
+ /**
+ * @return count number of messages.
+ */
+ int countMessages();
+
+ /**
+ * @return count number of debug messages.
+ */
+ int countDebugMessages();
+
+ /**
+ * @return count number of info messages.
+ */
+ int countInfoMessages();
+
+ /**
+ * @return count number of warning messages.
+ */
+ int countWarningMessages();
+
+ /**
+ * @return count number of error messages.
+ */
+ int countErrorMessages();
+
+ /**
+ * @return count number of server messages.
+ */
+ int countSevereMessages();
+
+ /**
+ * @return true / false.
+ */
+ boolean isDebugEnabled();
+
+ /**
+ * @param enabled enable debug
+ */
+ void setDebugEnabled( boolean enabled );
+
+ /**
+ * @return true if info is enabled false otherwise.
+ */
+ boolean isInfoEnabled();
+
+ /**
+ * @param enabled true info enable false otherwise.
+ */
+ void setInfoEnabled( boolean enabled );
+
+ /**
+ * @return true if warning is enabled false otherwise.
+ */
+ boolean isWarningEnabled();
+
+ /**
+ * @param enabled enable warning or disable.
+ */
+ void setWarningEnabled( boolean enabled );
+
+ /**
+ * @return true if error is enabled false otherwise.
+ */
+ boolean isErrorEnabled();
+
+ /**
+ * @param enabled enable error or disable.
+ */
+ void setErrorEnabled( boolean enabled );
+
+ /**
+ * @return true if server is enabled false otherwise.
+ */
+ boolean isSevereEnabled();
+
+ /**
+ * @param enabled enable server or disable.
+ */
+ void setSevereEnabled( boolean enabled );
+
+ /**
+ * @return true if empty false otherwise.
+ */
+ boolean isEmpty();
+
+ /**
+ * @return rendered.
+ */
+ String render();
+
+ /**
+ * @param sink {@link MessageSink}
+ */
+ void render( MessageSink sink );
+
+ /**
+ * flush.
+ */
+ void flush();
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageLevels.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageLevels.java
new file mode 100644
index 000000000..06fe3de87
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageLevels.java
@@ -0,0 +1,117 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ */
+public final class MessageLevels
+{
+
+ /**
+ * Debug.
+ */
+ public static final int LEVEL_DEBUG = 0;
+ /**
+ * Info
+ */
+ public static final int LEVEL_INFO = 1;
+ /**
+ * Warning.
+ */
+ public static final int LEVEL_WARNING = 2;
+ /**
+ * Error
+ */
+ public static final int LEVEL_ERROR = 3;
+ /**
+ * Severe
+ */
+ public static final int LEVEL_SEVERE = 4;
+ /**
+ * Disabled.
+ */
+ public static final int LEVEL_DISABLED = 5;
+
+ private static final List LEVEL_NAMES;
+
+ static
+ {
+ List names = new ArrayList();
+ names.add( "DEBUG" );
+ names.add( "INFO" );
+ names.add( "WARN" );
+ names.add( "ERROR" );
+ names.add( "SEVERE" );
+
+ LEVEL_NAMES = Collections.unmodifiableList( names );
+ }
+
+ private MessageLevels()
+ {
+ }
+
+ /**
+ * @param maxMessageLevel for which level.
+ * @return level states.
+ */
+ public static boolean[] getLevelStates( int maxMessageLevel )
+ {
+ boolean[] states = new boolean[5];
+
+ Arrays.fill( states, false );
+
+ switch ( maxMessageLevel )
+ {
+ case ( LEVEL_DEBUG ):
+ states[LEVEL_DEBUG] = true;
+ case ( LEVEL_INFO ):
+ states[LEVEL_INFO] = true;
+ case ( LEVEL_WARNING ):
+ states[LEVEL_WARNING] = true;
+ case ( LEVEL_ERROR ):
+ states[LEVEL_ERROR] = true;
+ case ( LEVEL_SEVERE ):
+ states[LEVEL_SEVERE] = true;
+ default:
+ }
+
+ return states;
+ }
+
+ /**
+ * @param messageLevel the message leve.
+ * @return The label.
+ */
+ public static String getLevelLabel( int messageLevel )
+ {
+ if ( messageLevel > -1 && LEVEL_NAMES.size() > messageLevel )
+ {
+ return (String) LEVEL_NAMES.get( messageLevel );
+ }
+
+ throw new IllegalArgumentException( "Invalid message level: " + messageLevel );
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageSink.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageSink.java
new file mode 100644
index 000000000..3856e2158
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MessageSink.java
@@ -0,0 +1,55 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+
+/**
+ * Message Sink interface.
+ *
+ */
+public interface MessageSink
+{
+
+ /**
+ * @param message The message.
+ */
+ void debug( String message );
+
+ /**
+ * @param message The message.
+ */
+ void info( String message );
+
+ /**
+ * @param message The message.
+ */
+ void warning( String message );
+
+ /**
+ * @param message The message.
+ */
+ void error( String message );
+
+ /**
+ * @param message The message.
+ */
+ void severe( String message );
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MojoLogSink.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MojoLogSink.java
new file mode 100644
index 000000000..f98e818ca
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/MojoLogSink.java
@@ -0,0 +1,73 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.plugin.logging.Log;
+
+
+/**
+ * The Mojo Log Sink.
+ *
+ */
+public class MojoLogSink
+ implements MessageSink
+{
+
+ private final Log logger;
+
+ /**
+ * @param logger {@link Log}
+ */
+ public MojoLogSink( Log logger )
+ {
+ this.logger = logger;
+ }
+
+ /** {@inheritDoc} */
+ public void debug( String message )
+ {
+ logger.debug( message );
+ }
+
+ /** {@inheritDoc} */
+ public void error( String message )
+ {
+ logger.error( message );
+ }
+
+ /** {@inheritDoc} */
+ public void info( String message )
+ {
+ logger.info( message );
+ }
+
+ /** {@inheritDoc} */
+ public void severe( String message )
+ {
+ logger.error( message );
+ }
+
+ /** {@inheritDoc} */
+ public void warning( String message )
+ {
+ logger.warn( message );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/PlexusLoggerSink.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/PlexusLoggerSink.java
new file mode 100644
index 000000000..e49374c13
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/logging/PlexusLoggerSink.java
@@ -0,0 +1,71 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * The plexus logger sink implementation.
+ */
+public class PlexusLoggerSink
+ implements MessageSink
+{
+
+ private final Logger logger;
+
+ /**
+ * @param logger The logger.
+ */
+ public PlexusLoggerSink( Logger logger )
+ {
+ this.logger = logger;
+ }
+
+ /** {@inheritDoc} */
+ public void debug( String message )
+ {
+ logger.debug( message );
+ }
+
+ /** {@inheritDoc} */
+ public void error( String message )
+ {
+ logger.error( message );
+ }
+
+ /** {@inheritDoc} */
+ public void info( String message )
+ {
+ logger.info( message );
+ }
+
+ /** {@inheritDoc} */
+ public void severe( String message )
+ {
+ logger.fatalError( message );
+ }
+
+ /** {@inheritDoc} */
+ public void warning( String message )
+ {
+ logger.warn( message );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/AbstractResourceInclusionScanner.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/AbstractResourceInclusionScanner.java
new file mode 100644
index 000000000..2f05f091a
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/AbstractResourceInclusionScanner.java
@@ -0,0 +1,95 @@
+package org.apache.maven.shared.io.scan;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.shared.io.scan.mapping.SourceMapping;
+import org.apache.maven.shared.utils.io.DirectoryScanner;
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public abstract class AbstractResourceInclusionScanner
+ implements ResourceInclusionScanner
+{
+ private final List sourceMappings = new ArrayList();
+
+ /** {@inheritDoc} */
+ public final void addSourceMapping( SourceMapping sourceMapping )
+ {
+ sourceMappings.add( sourceMapping );
+ }
+
+ /**
+ * @return The source mapping.
+ */
+ protected final List getSourceMappings()
+ {
+ return Collections.unmodifiableList( sourceMappings );
+ }
+
+ /**
+ * @param sourceDir {@link File}
+ * @param sourceIncludes source includes.
+ * @param sourceExcludes source excludes.
+ * @return The resulting sources.
+ */
+ protected String[] scanForSources( File sourceDir, Set sourceIncludes, Set sourceExcludes )
+ {
+ DirectoryScanner ds = new DirectoryScanner();
+ ds.setFollowSymlinks( true );
+ ds.setBasedir( sourceDir );
+
+ String[] includes;
+ if ( sourceIncludes.isEmpty() )
+ {
+ includes = new String[0];
+ }
+ else
+ {
+ includes = (String[]) sourceIncludes.toArray( new String[sourceIncludes.size()] );
+ }
+
+ ds.setIncludes( includes );
+
+ String[] excludes;
+ if ( sourceExcludes.isEmpty() )
+ {
+ excludes = new String[0];
+ }
+ else
+ {
+ excludes = (String[]) sourceExcludes.toArray( new String[sourceExcludes.size()] );
+ }
+
+ ds.setExcludes( excludes );
+ ds.addDefaultExcludes();
+
+ ds.scan();
+
+ return ds.getIncludedFiles();
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/InclusionScanException.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/InclusionScanException.java
new file mode 100644
index 000000000..88434277e
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/InclusionScanException.java
@@ -0,0 +1,45 @@
+package org.apache.maven.shared.io.scan;
+
+/*
+ * 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.
+ */
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public class InclusionScanException
+ extends Exception
+{
+ /**
+ * @param message The message.
+ */
+ public InclusionScanException( String message )
+ {
+ super( message );
+ }
+
+ /**
+ * @param message The message.
+ * @param cause The cause of the error.
+ */
+ public InclusionScanException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/ResourceInclusionScanner.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/ResourceInclusionScanner.java
new file mode 100644
index 000000000..51711249d
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/ResourceInclusionScanner.java
@@ -0,0 +1,46 @@
+package org.apache.maven.shared.io.scan;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.io.scan.mapping.SourceMapping;
+
+import java.io.File;
+import java.util.Set;
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public interface ResourceInclusionScanner
+{
+ /**
+ * @param sourceMapping {@link SourceMapping}
+ */
+ void addSourceMapping( SourceMapping sourceMapping );
+
+ /**
+ * @param sourceDir {@link File}
+ * @param targetDir {@link File}
+ * @return The included sources.
+ * @throws InclusionScanException in case of an error.
+ */
+ Set getIncludedSources( File sourceDir, File targetDir )
+ throws InclusionScanException;
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/SimpleResourceInclusionScanner.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/SimpleResourceInclusionScanner.java
new file mode 100644
index 000000000..c0aed2535
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/SimpleResourceInclusionScanner.java
@@ -0,0 +1,64 @@
+package org.apache.maven.shared.io.scan;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.shared.io.scan.mapping.SourceMapping;
+
+/**
+ * @author Trygve Laugstøl
+ * @version $Id$
+ */
+public class SimpleResourceInclusionScanner
+ extends AbstractResourceInclusionScanner
+{
+ private Set sourceIncludes;
+
+ private Set sourceExcludes;
+
+ /**
+ * @param sourceIncludes The source includes.
+ * @param sourceExcludes The source excludes.
+ */
+ public SimpleResourceInclusionScanner( Set sourceIncludes, Set sourceExcludes )
+ {
+ this.sourceIncludes = sourceIncludes;
+
+ this.sourceExcludes = sourceExcludes;
+ }
+
+ /** {@inheritDoc} */
+ public Set getIncludedSources( File sourceDir, File targetDir )
+ throws InclusionScanException
+ {
+ List srcMappings = getSourceMappings();
+
+ if ( srcMappings.isEmpty() )
+ {
+ return Collections.emptySet();
+ }
+
+ return Collections.singleton( scanForSources( sourceDir, sourceIncludes, sourceExcludes ) );
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/StaleResourceScanner.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/StaleResourceScanner.java
new file mode 100644
index 000000000..62358bead
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/StaleResourceScanner.java
@@ -0,0 +1,123 @@
+package org.apache.maven.shared.io.scan;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.shared.io.scan.mapping.SourceMapping;
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public class StaleResourceScanner
+ extends AbstractResourceInclusionScanner
+{
+ private final long lastUpdatedWithinMsecs;
+
+ private final Set sourceIncludes;
+
+ private final Set sourceExcludes;
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Create instance with defaults.
+ */
+ public StaleResourceScanner()
+ {
+ this( 0, Collections.singleton( "**/*" ), Collections.emptySet() );
+ }
+
+ /**
+ * @param lastUpdatedWithinMsecs last update within milli seconds.
+ */
+ public StaleResourceScanner( long lastUpdatedWithinMsecs )
+ {
+ this( lastUpdatedWithinMsecs, Collections.singleton( "**/*" ), Collections.emptySet() );
+ }
+
+ /**
+ * @param lastUpdatedWithinMsecs last update within milli seconds.
+ * @param sourceIncludes source includes.
+ * @param sourceExcludes source excludes.
+ */
+ public StaleResourceScanner( long lastUpdatedWithinMsecs, Set sourceIncludes, Set sourceExcludes )
+ {
+ this.lastUpdatedWithinMsecs = lastUpdatedWithinMsecs;
+
+ this.sourceIncludes = sourceIncludes;
+
+ this.sourceExcludes = sourceExcludes;
+ }
+
+ // ----------------------------------------------------------------------
+ // SourceInclusionScanner Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public Set getIncludedSources( File sourceDir, File targetDir )
+ throws InclusionScanException
+ {
+ List srcMappings = getSourceMappings();
+
+ if ( srcMappings.isEmpty() )
+ {
+ return Collections.emptySet();
+ }
+
+ String[] potentialIncludes = scanForSources( sourceDir, sourceIncludes, sourceExcludes );
+
+ Set matchingSources = new HashSet();
+
+ for ( int i = 0; i < potentialIncludes.length; i++ )
+ {
+ String path = potentialIncludes[i];
+
+ File sourceFile = new File( sourceDir, path );
+
+ staleSourceFileTesting: for ( SourceMapping mapping : srcMappings )
+ {
+ Set targetFiles = mapping.getTargetFiles( targetDir, path );
+
+ // never include files that don't have corresponding target mappings.
+ // the targets don't have to exist on the filesystem, but the
+ // mappers must tell us to look for them.
+ for ( File targetFile : targetFiles )
+ {
+ if ( !targetFile.exists()
+ || ( targetFile.lastModified() + lastUpdatedWithinMsecs < sourceFile.lastModified() ) )
+ {
+ matchingSources.add( sourceFile );
+ break staleSourceFileTesting;
+ }
+ }
+ }
+ }
+
+ return matchingSources;
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SingleTargetMapping.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SingleTargetMapping.java
new file mode 100644
index 000000000..2d1f3378a
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SingleTargetMapping.java
@@ -0,0 +1,63 @@
+package org.apache.maven.shared.io.scan.mapping;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.io.scan.InclusionScanException;
+
+import java.util.Set;
+import java.util.Collections;
+import java.io.File;
+
+/**
+ * Maps a set of input files to a single output file.
+ *
+ * @author Trygve Laugstøl
+ * @version $Id$
+ */
+public class SingleTargetMapping
+ implements SourceMapping
+{
+ private String sourceSuffix;
+
+ private String outputFile;
+
+ /**
+ * @param sourceSuffix source suffix.
+ * @param outputFile output file.
+ */
+ public SingleTargetMapping( String sourceSuffix, String outputFile )
+ {
+ this.sourceSuffix = sourceSuffix;
+
+ this.outputFile = outputFile;
+ }
+
+ /** {@inheritDoc} */
+ public Set getTargetFiles( File targetDir, String source )
+ throws InclusionScanException
+ {
+ if ( !source.endsWith( sourceSuffix ) )
+ {
+ return Collections.emptySet();
+ }
+
+ return Collections.singleton( new File( targetDir, outputFile ) );
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SourceMapping.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SourceMapping.java
new file mode 100644
index 000000000..7defc0ba4
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SourceMapping.java
@@ -0,0 +1,41 @@
+package org.apache.maven.shared.io.scan.mapping;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Set;
+
+import org.apache.maven.shared.io.scan.InclusionScanException;
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public interface SourceMapping
+{
+ /**
+ * @param targetDir target directory.
+ * @param source source.
+ * @return list of target files.
+ * @throws InclusionScanException in case of an error.
+ */
+ Set getTargetFiles( File targetDir, String source )
+ throws InclusionScanException;
+}
diff --git a/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SuffixMapping.java b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SuffixMapping.java
new file mode 100644
index 000000000..75aa461fd
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/java/org/apache/maven/shared/io/scan/mapping/SuffixMapping.java
@@ -0,0 +1,77 @@
+package org.apache.maven.shared.io.scan.mapping;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author jdcasey
+ * @version $Id$
+ */
+public final class SuffixMapping
+ implements SourceMapping
+{
+ private final String sourceSuffix;
+
+ private final Set targetSuffixes;
+
+ /**
+ * @param sourceSuffix source suffix.
+ * @param targetSuffix target suffix.
+ */
+ public SuffixMapping( String sourceSuffix, String targetSuffix )
+ {
+ this.sourceSuffix = sourceSuffix;
+
+ this.targetSuffixes = Collections.singleton( targetSuffix );
+ }
+
+ /**
+ * @param sourceSuffix source suffix.
+ * @param targetSuffixes target suffixes.
+ */
+ public SuffixMapping( String sourceSuffix, Set targetSuffixes )
+ {
+ this.sourceSuffix = sourceSuffix;
+
+ this.targetSuffixes = targetSuffixes;
+ }
+
+ /** {@inheritDoc} */
+ public Set getTargetFiles( File targetDir, String source )
+ {
+ Set targetFiles = new HashSet();
+
+ if ( source.endsWith( sourceSuffix ) )
+ {
+ String base = source.substring( 0, source.length() - sourceSuffix.length() );
+
+ for ( String suffix : targetSuffixes )
+ {
+ targetFiles.add( new File( targetDir, base + suffix ) );
+ }
+ }
+
+ return targetFiles;
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/main/resources/META-INF/plexus/components.xml b/Java-base/maven-shared-io/src/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 000000000..648a391b9
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ org.apache.maven.shared.io.download.DownloadManager
+ default
+ org.apache.maven.shared.io.download.DefaultDownloadManager
+
+
+ org.apache.maven.artifact.manager.WagonManager
+
+
+
+
+
\ No newline at end of file
diff --git a/Java-base/maven-shared-io/src/src/site/resources/download.cgi b/Java-base/maven-shared-io/src/src/site/resources/download.cgi
new file mode 100644
index 000000000..1b178d2e6
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/site/resources/download.cgi
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# 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.
+#
+# Just call the standard mirrors.cgi script. It will use download.html
+# as the input template.
+exec /www/www.apache.org/dyn/mirrors/mirrors.cgi $*
\ No newline at end of file
diff --git a/Java-base/maven-shared-io/src/src/site/site.xml b/Java-base/maven-shared-io/src/src/site/site.xml
new file mode 100644
index 000000000..a18a2a646
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/site/site.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Java-base/maven-shared-io/src/src/site/xdoc/download.xml.vm b/Java-base/maven-shared-io/src/src/site/xdoc/download.xml.vm
new file mode 100644
index 000000000..666d997c4
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/site/xdoc/download.xml.vm
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ Download ${project.name} Source
+
+
+
+
+ ${project.name} ${project.version} is distributed in source format. Use a source archive if you intend to build
+ ${project.name} yourself. Otherwise, simply use the ready-made binary artifacts from central repository.
+
+ You will be prompted for a mirror - if the file is not found on yours, please be patient, as it may take 24
+ hours to reach all mirrors.
+
+ In order to guard against corrupted downloads/installations, it is highly recommended to
+ verify the signature
+ of the release bundles against the public KEYS used by the Apache Maven
+ developers.
+
+ ${project.name} is distributed under the Apache License, version 2.0.
+
+ We strongly encourage our users to configure a Maven repository mirror closer to their location, please read How to Use Mirrors for Repositories.
+
+
+
+
+
+ [if-any logo]
+
+
+
+ [end]
+ The currently selected mirror is
+ [preferred].
+ If you encounter a problem with this mirror,
+ please select another mirror.
+ If all mirrors are failing, there are
+ backup
+ mirrors
+ (at the end of the mirrors list) that should be available.
+
+
+
+
+
+ You may also consult the
+ complete list of
+ mirrors.
+
+
+
+
+
+
+ This is the current stable version of ${project.name}.
+
+
+
+
+
+
+ Older non-recommended releases can be found on our archive site.
+
+
+
+
+
+
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/Utils.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/Utils.java
new file mode 100644
index 000000000..59e6c7f17
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/Utils.java
@@ -0,0 +1,55 @@
+package org.apache.maven.shared.io;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.apache.maven.shared.utils.WriterFactory;
+
+public final class Utils
+{
+
+ private Utils()
+ {
+ }
+
+ public static void writeFileWithEncoding( File file, String content, String encoding )
+ throws IOException
+ {
+ try ( Writer writer = WriterFactory.newWriter( file, encoding ))
+ {
+ writer.write( content );
+ }
+ }
+
+ public static String toString( Throwable error )
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ error.printStackTrace( pw );
+
+ return sw.toString();
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DefaultDownloadManagerTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DefaultDownloadManagerTest.java
new file mode 100644
index 000000000..f84608948
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DefaultDownloadManagerTest.java
@@ -0,0 +1,559 @@
+package org.apache.maven.shared.io.download;
+
+/*
+ * 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.
+ */
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.shared.io.Utils;
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+import org.apache.maven.wagon.ConnectionException;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.UnsupportedProtocolException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authentication.AuthenticationException;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.repository.Repository;
+import org.codehaus.plexus.PlexusTestCase;
+
+public class DefaultDownloadManagerTest
+ extends PlexusTestCase
+{
+
+ private WagonManager wagonManager;
+
+ private Wagon wagon;
+
+ public void setUp()
+ throws Exception
+ {
+ super.setUp();
+
+ wagonManager = createMock( WagonManager.class );
+ wagon = createMock( Wagon.class );
+ }
+
+ public void testShouldConstructWithNoParamsAndHaveNonNullMessageHolder()
+ {
+ new DefaultDownloadManager();
+ }
+
+ public void testShouldConstructWithWagonManager()
+ {
+ replay( wagonManager );
+
+ new DefaultDownloadManager( wagonManager );
+
+ verify( wagonManager );
+ }
+
+ public void testShouldLookupInstanceDefaultRoleHint()
+ throws Exception
+ {
+ lookup( DownloadManager.ROLE, DefaultDownloadManager.ROLE_HINT );
+ }
+
+ public void testShouldFailToDownloadMalformedURL()
+ {
+ replay( wagonManager );
+
+ DownloadManager mgr = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ mgr.download( "://nothing.com/index.html", new DefaultMessageHolder() );
+
+ fail( "Should not download with invalid URL." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( e.getMessage().indexOf( "invalid URL" ) > -1 );
+ }
+
+ verify( wagonManager );
+ }
+
+ public void testShouldDownloadFromTempFileWithNoTransferListeners()
+ throws IOException, DownloadFailedException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupDefaultMockConfiguration();
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldDownloadFromTempFileTwiceAndUseCache()
+ throws IOException, DownloadFailedException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupDefaultMockConfiguration();
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ File first = downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ File second = downloadManager.download( tempFile.toURL().toExternalForm(), mh );
+
+ assertSame( first, second );
+ assertEquals( 1, mh.size() );
+ assertTrue( mh.render().indexOf( "Using cached" ) > -1 );
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldDownloadFromTempFileWithOneTransferListener()
+ throws IOException, DownloadFailedException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupDefaultMockConfiguration();
+
+ TransferListener transferListener = createMock( TransferListener.class );
+
+ wagon.addTransferListener( transferListener );
+
+ wagon.removeTransferListener( transferListener );
+
+ replay( wagon, wagonManager, transferListener );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ downloadManager.download( tempFile.toURL().toExternalForm(), Collections.singletonList( transferListener ),
+ new DefaultMessageHolder() );
+
+ verify( wagon, wagonManager, transferListener );
+ }
+
+ public void testShouldFailToDownloadWhenWagonProtocolNotFound()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonManagerGetException( new UnsupportedProtocolException( "not supported" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to retrieve wagon." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "UnsupportedProtocolException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonConnectThrowsConnectionException()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonConnectionException( new ConnectionException( "connect error" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to connect wagon." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "ConnectionException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonConnectThrowsAuthenticationException()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonConnectionException( new AuthenticationException( "bad credentials" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to connect wagon." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "AuthenticationException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonGetThrowsTransferFailedException()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonGetException( new TransferFailedException( "bad transfer" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to get resource." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "TransferFailedException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonGetThrowsResourceDoesNotExistException()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonGetException( new ResourceDoesNotExistException( "bad resource" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to get resource." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "ResourceDoesNotExistException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonGetThrowsAuthorizationException()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonGetException( new AuthorizationException( "bad transfer" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ try
+ {
+ downloadManager.download( tempFile.toURL().toExternalForm(), new DefaultMessageHolder() );
+
+ fail( "should have failed to get resource." );
+ }
+ catch ( DownloadFailedException e )
+ {
+ assertTrue( Utils.toString( e ).indexOf( "AuthorizationException" ) > -1 );
+ }
+
+ verify( wagon, wagonManager );
+ }
+
+ public void testShouldFailToDownloadWhenWagonDisconnectThrowsConnectionException()
+ throws IOException, DownloadFailedException
+ {
+ File tempFile = File.createTempFile( "download-source", "test" );
+ tempFile.deleteOnExit();
+
+ setupMocksWithWagonDisconnectException( new ConnectionException( "not connected" ) );
+
+ replay( wagon, wagonManager );
+
+ DownloadManager downloadManager = new DefaultDownloadManager( wagonManager );
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ downloadManager.download( tempFile.toURL().toExternalForm(), mh );
+
+ assertTrue( mh.render().indexOf( "ConnectionException" ) > -1 );
+
+ verify( wagon, wagonManager );
+ }
+
+ private void setupDefaultMockConfiguration()
+ {
+ try
+ {
+ expect( wagonManager.getWagon( "file" ) ).andReturn( wagon );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ expect( wagonManager.getAuthenticationInfo( anyString() ) ).andReturn( null );
+
+ expect( wagonManager.getProxy( anyString() ) ).andReturn( null );
+
+ try
+ {
+ wagon.connect( anyObject( Repository.class ) , anyObject( AuthenticationInfo.class ), anyObject( ProxyInfo.class ) );
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthenticationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.get( anyString(), anyObject( File.class ) );
+ }
+ catch ( TransferFailedException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( ResourceDoesNotExistException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthorizationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.disconnect();
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ }
+
+ private void setupMocksWithWagonManagerGetException( Throwable error )
+ {
+ try
+ {
+ expect( wagonManager.getWagon( "file" ) ).andThrow( error );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ }
+
+ private void setupMocksWithWagonConnectionException( Throwable error )
+ {
+ try
+ {
+ expect( wagonManager.getWagon( "file" ) ).andReturn( wagon );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ expect( wagonManager.getAuthenticationInfo( anyString() ) ).andReturn( null );
+
+ expect( wagonManager.getProxy( anyString() ) ).andReturn( null );
+
+ try
+ {
+ wagon.connect( anyObject( Repository.class ) , anyObject( AuthenticationInfo.class ), anyObject( ProxyInfo.class ) );
+ expectLastCall().andThrow( error );
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthenticationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ }
+
+ private void setupMocksWithWagonGetException( Throwable error )
+ {
+ try
+ {
+ expect( wagonManager.getWagon( "file" ) ).andReturn( wagon );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ expect( wagonManager.getAuthenticationInfo( anyString() ) ).andReturn( null );
+
+ expect( wagonManager.getProxy( anyString() ) ).andReturn( null );
+
+ try
+ {
+ wagon.connect( anyObject( Repository.class ) , anyObject( AuthenticationInfo.class ), anyObject( ProxyInfo.class ) );
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthenticationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.get( anyString(), anyObject( File.class ) );
+ expectLastCall().andThrow( error );
+ }
+ catch ( TransferFailedException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( ResourceDoesNotExistException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthorizationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.disconnect();
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ }
+
+ private void setupMocksWithWagonDisconnectException( Throwable error )
+ {
+ try
+ {
+ expect( wagonManager.getWagon( "file" ) ).andReturn( wagon );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ expect( wagonManager.getAuthenticationInfo( anyString() ) ).andReturn( null );
+
+ expect( wagonManager.getProxy( anyString() ) ).andReturn( null );
+
+ try
+ {
+ wagon.connect( anyObject( Repository.class ) , anyObject( AuthenticationInfo.class ), anyObject( ProxyInfo.class ) );
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthenticationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.get( anyString(), anyObject( File.class ) );
+ }
+ catch ( TransferFailedException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( ResourceDoesNotExistException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ catch ( AuthorizationException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+
+ try
+ {
+ wagon.disconnect();
+ expectLastCall().andThrow( error );
+ }
+ catch ( ConnectionException e )
+ {
+ fail( "This shouldn't happen!!" );
+ }
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DownloadFailedExceptionTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DownloadFailedExceptionTest.java
new file mode 100644
index 000000000..a6c957c1f
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/download/DownloadFailedExceptionTest.java
@@ -0,0 +1,44 @@
+package org.apache.maven.shared.io.download;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+public class DownloadFailedExceptionTest
+ extends TestCase
+{
+
+ public void testShouldConstructWithUrlAndMessage()
+ {
+ new DownloadFailedException( "http://www.google.com", "can't find." );
+ }
+
+ public void testShouldConstructWithUrlMessageAndException()
+ {
+ new DownloadFailedException( "http://www.google.com", "can't find.", new NullPointerException() );
+ }
+
+ public void testShouldRetrieveUrlFromConstructor()
+ {
+ String url = "http://www.google.com";
+ assertEquals( url, new DownloadFailedException( url, "can't find." ).getUrl() );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocationTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocationTest.java
new file mode 100644
index 000000000..ff742dec5
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocationTest.java
@@ -0,0 +1,81 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.shared.io.Utils;
+
+public class ArtifactLocationTest
+ extends TestCase
+{
+
+ public void testShouldConstructFromTempFileSpecification()
+ throws IOException
+ {
+ File f = File.createTempFile( "artifact-location.", ".test" );
+ f.deleteOnExit();
+
+ Artifact a = new DefaultArtifact( "group", "artifact", VersionRange.createFromVersion( "1" ), null, "jar",
+ null, new DefaultArtifactHandler() );
+
+ a.setFile( f );
+
+ ArtifactLocation location = new ArtifactLocation( a, f.getAbsolutePath() );
+
+ assertSame( f, location.getFile() );
+ }
+
+ public void testShouldRead()
+ throws IOException
+ {
+ File f = File.createTempFile( "url-location.", ".test" );
+ f.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( f, testStr, "US-ASCII" );
+
+ Artifact a = new DefaultArtifact( "group", "artifact", VersionRange.createFromVersion( "1" ), null, "jar",
+ null, new DefaultArtifactHandler() );
+
+ a.setFile( f );
+
+ ArtifactLocation location = new ArtifactLocation( a, f.getAbsolutePath() );
+
+ location.open();
+
+ byte[] buffer = new byte[testStr.length()];
+
+ int read = location.read( buffer );
+
+ assertEquals( testStr.length(), read );
+
+ assertEquals( testStr, new String( buffer, "US-ASCII" ) );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategyTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategyTest.java
new file mode 100644
index 000000000..540797776
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ArtifactLocatorStrategyTest.java
@@ -0,0 +1,507 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+import static org.easymock.EasyMock.*;
+
+public class ArtifactLocatorStrategyTest
+ extends TestCase
+{
+
+ private ArtifactFactory factory;
+
+ private ArtifactResolver resolver;
+
+ private ArtifactRepository localRepository;
+
+ public void setUp()
+ {
+ factory = createMock( ArtifactFactory.class );
+ resolver = createMock( ArtifactResolver.class );
+ localRepository = createMock( ArtifactRepository.class );
+ }
+
+ public void testShouldConstructWithoutDefaultArtifactType()
+ {
+ replay( factory, resolver, localRepository );
+
+ new ArtifactLocatorStrategy( factory, resolver, localRepository, Collections.EMPTY_LIST );
+
+ verify( factory, resolver, localRepository );
+ }
+
+ public void testShouldConstructWithDefaultArtifactType()
+ {
+ replay( factory, resolver, localRepository );
+
+ new ArtifactLocatorStrategy( factory, resolver, localRepository, Collections.EMPTY_LIST, "zip" );
+
+ verify( factory, resolver, localRepository );
+ }
+
+ public void testShouldFailToResolveSpecWithOneToken()
+ {
+ replay( factory, resolver, localRepository );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST, "zip" );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "one-token", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+
+ verify( factory, resolver, localRepository );
+ }
+
+ public void testShouldFailToResolveSpecWithTwoTokens()
+ {
+ replay( factory, resolver, localRepository );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST, "zip" );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "two:tokens", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+
+ verify( factory, resolver, localRepository );
+ }
+
+ public void testShouldResolveSpecWithThreeTokensUsingDefaultType()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "jar" ) ).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldResolveSpecWithThreeTokensUsingCustomizedDefaultType()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "zip" ) ).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST, "zip" );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldResolveSpecWithFourTokens()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "zip" ) ).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version:zip", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldResolveSpecWithFiveTokens()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifactWithClassifier( "group", "artifact", "version", "zip", "classifier" ) )
+ .andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version:zip:classifier", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldResolveSpecWithFiveTokensAndEmptyTypeToken()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifactWithClassifier( "group", "artifact", "version", "jar", "classifier" ) )
+ .andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version::classifier", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldResolveSpecWithMoreThanFiveTokens()
+ throws IOException
+ {
+ File tempFile = File.createTempFile( "artifact-location.", ".temp" );
+ tempFile.deleteOnExit();
+
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( tempFile );
+ expect( artifact.getFile() ).andReturn( tempFile );
+
+ expect( factory.createArtifactWithClassifier( "group", "artifact", "version", "zip", "classifier" ) )
+ .andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version:zip:classifier:six:seven", mh );
+
+ assertNotNull( location );
+ assertEquals( 1, mh.size() );
+
+ assertTrue( mh.render().indexOf( ":six:seven" ) > -1 );
+
+ assertSame( tempFile, location.getFile() );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldNotResolveSpecToArtifactWithNullFile()
+ throws IOException
+ {
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getFile() ).andReturn( null );
+ expect( artifact.getId() ).andReturn( "" );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "jar" )).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+
+ assertTrue( mh.render().indexOf( "" ) > -1 );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldNotResolveWhenArtifactNotFoundExceptionThrown()
+ throws IOException
+ {
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getId() ).andReturn( "" );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "jar" ) ).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ expectLastCall().andThrow( new ArtifactNotFoundException( "not found", "group", "artifact", "version",
+ "jar", null, Collections.emptyList(),
+ "http://nowhere.com", Collections.emptyList(),
+ new NullPointerException() ) );
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+
+ assertTrue( mh.render().indexOf( "" ) > -1 );
+ assertTrue( mh.render().indexOf( "not found" ) > -1 );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+ public void testShouldNotResolveWhenArtifactResolutionExceptionThrown()
+ throws IOException
+ {
+ Artifact artifact = createMock( Artifact.class );
+
+ expect( artifact.getId() ).andReturn( "" );
+
+ expect( factory.createArtifact( "group", "artifact", "version", null, "jar" ) ).andReturn( artifact );
+
+ try
+ {
+ resolver.resolve( artifact, Collections.emptyList(), localRepository );
+ expectLastCall().andThrow( new ArtifactResolutionException( "resolution failed", "group", "artifact",
+ "version", "jar", null, Collections.emptyList(),
+ Collections.emptyList(),
+ new NullPointerException() ) );
+
+ }
+ catch ( ArtifactResolutionException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+ catch ( ArtifactNotFoundException e )
+ {
+ // should never happen
+ fail( "This should NEVER happen. It's a mock!" );
+ }
+
+ replay( factory, resolver, localRepository, artifact );
+
+ LocatorStrategy strategy = new ArtifactLocatorStrategy( factory, resolver, localRepository,
+ Collections.EMPTY_LIST );
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = strategy.resolve( "group:artifact:version", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+
+ assertTrue( mh.render().indexOf( "" ) > -1 );
+ assertTrue( mh.render().indexOf( "resolution failed" ) > -1 );
+
+ verify( factory, resolver, localRepository, artifact );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategyTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategyTest.java
new file mode 100644
index 000000000..e4cd734c8
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/ClasspathResourceLocatorStrategyTest.java
@@ -0,0 +1,59 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+import junit.framework.TestCase;
+
+public class ClasspathResourceLocatorStrategyTest
+ extends TestCase
+{
+
+ public void testShouldConstructWithNoParams()
+ {
+ new ClasspathResourceLocatorStrategy();
+ }
+
+ public void testShouldConstructWithTempFileOptions()
+ {
+ new ClasspathResourceLocatorStrategy( "prefix.", ".suffix", true );
+ }
+
+ public void testShouldFailToResolveMissingClasspathResource()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+ Location location = new ClasspathResourceLocatorStrategy().resolve( "/some/missing/path", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+ }
+
+ public void testShouldResolveExistingClasspathResourceWithoutPrecedingSlash()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+ Location location = new ClasspathResourceLocatorStrategy().resolve( "META-INF/maven/test.properties", mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocationTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocationTest.java
new file mode 100644
index 000000000..467833a41
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocationTest.java
@@ -0,0 +1,180 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.shared.io.Utils;
+import org.apache.maven.shared.utils.io.IOUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+import junit.framework.TestCase;
+
+public class FileLocationTest
+ extends TestCase
+{
+
+ public void testShouldConstructWithFileThenRetrieveSameFile() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ FileLocation location = new FileLocation( file, file.getAbsolutePath() );
+
+ assertSame( file, location.getFile() );
+ assertEquals( file.getAbsolutePath(), location.getSpecification() );
+ }
+
+ public void testShouldReadFileContentsUsingByteBuffer() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( file, testStr, "US-ASCII" );
+
+ FileLocation location = new FileLocation( file, file.getAbsolutePath() );
+
+ location.open();
+
+ ByteBuffer buffer = ByteBuffer.allocate( testStr.length() );
+ location.read( buffer );
+
+ assertEquals( testStr, new String( buffer.array(), "US-ASCII" ) );
+ }
+
+ public void testShouldReadFileContentsUsingStream() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( file, testStr, "US-ASCII" );
+
+ FileLocation location = new FileLocation( file, file.getAbsolutePath() );
+
+ location.open();
+
+ try ( InputStream stream = location.getInputStream() ) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IOUtil.copy( stream, out );
+
+ assertEquals( testStr, new String(out.toByteArray(), "US-ASCII" ) );
+ }
+ }
+
+ public void testShouldReadFileContentsUsingByteArray() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( file, testStr, "US-ASCII" );
+
+ FileLocation location = new FileLocation( file, file.getAbsolutePath() );
+
+ location.open();
+
+ byte[] buffer = new byte[ testStr.length() ];
+ location.read( buffer );
+
+ assertEquals( testStr, new String( buffer, "US-ASCII" ) );
+ }
+
+ public void testShouldReadThenClose() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( file, testStr, "US-ASCII" );
+
+ FileLocation location = new FileLocation( file, file.getAbsolutePath() );
+
+ location.open();
+
+ byte[] buffer = new byte[ testStr.length() ];
+ location.read( buffer );
+
+ assertEquals( testStr, new String( buffer, "US-ASCII" ) );
+
+ location.close();
+ }
+
+ public void testShouldOpenThenFailToSetFile() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ TestFileLocation location = new TestFileLocation( file.getAbsolutePath() );
+
+ location.open();
+
+ try
+ {
+ location.setFile( file );
+
+ fail( "should not succeed." );
+ }
+ catch( IllegalStateException e )
+ {
+ }
+ }
+
+ public void testShouldConstructWithoutFileThenSetFileThenOpen() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ TestFileLocation location = new TestFileLocation( file.getAbsolutePath() );
+
+ location.setFile( file );
+ location.open();
+ }
+
+ public void testShouldConstructWithLocationThenRetrieveEquivalentFile() throws IOException
+ {
+ File file = File.createTempFile( "test.", ".file-location" );
+ file.deleteOnExit();
+
+ Location location = new TestFileLocation( file.getAbsolutePath() );
+
+ assertEquals( file, location.getFile() );
+ assertEquals( file.getAbsolutePath(), location.getSpecification() );
+ }
+
+ private static final class TestFileLocation extends FileLocation
+ {
+
+ TestFileLocation( String specification )
+ {
+ super( specification );
+ }
+
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocatorStrategyTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocatorStrategyTest.java
new file mode 100644
index 000000000..96a899d83
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/FileLocatorStrategyTest.java
@@ -0,0 +1,70 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+import junit.framework.TestCase;
+
+public class FileLocatorStrategyTest
+ extends TestCase
+{
+
+ public void testShouldResolveExistingTempFileLocation() throws IOException
+ {
+ File f = File.createTempFile( "file-locator.", ".test" );
+ f.deleteOnExit();
+
+ FileLocatorStrategy fls = new FileLocatorStrategy();
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = fls.resolve( f.getAbsolutePath(), mh );
+
+ assertNotNull( location );
+
+ assertTrue( mh.isEmpty() );
+
+ assertEquals( f, location.getFile() );
+ }
+
+ public void testShouldFailToResolveNonExistentFileLocation() throws IOException
+ {
+ File f = File.createTempFile( "file-locator.", ".test" );
+ f.delete();
+
+ FileLocatorStrategy fls = new FileLocatorStrategy();
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = fls.resolve( f.getAbsolutePath(), mh );
+
+ assertNull( location );
+
+ System.out.println( mh.render() );
+
+ assertEquals( 1, mh.size() );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/LocatorTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/LocatorTest.java
new file mode 100644
index 000000000..ab976ecc8
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/LocatorTest.java
@@ -0,0 +1,138 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class LocatorTest
+ extends TestCase
+{
+
+ public void testShouldConstructWithNoParams()
+ {
+ new Locator();
+ }
+
+ public void testShouldConstructWithStrategyStackAndMessageHolder()
+ {
+ new Locator( Collections.emptyList(), new DefaultMessageHolder() );
+ }
+
+ public void testShouldAllowModificationOfStrategiesAfterConstructionWithUnmodifiableStack()
+ {
+ Locator locator = new Locator( Collections.unmodifiableList( Collections.emptyList() ),
+ new DefaultMessageHolder() );
+
+ locator.addStrategy( new FileLocatorStrategy() );
+
+ assertEquals( 1, locator.getStrategies().size() );
+ }
+
+ public void testShouldRetrieveNonNullMessageHolderWhenConstructedWithoutParams()
+ {
+ assertNotNull( new Locator().getMessageHolder() );
+ }
+
+ public void testSetStrategiesShouldClearAnyPreExistingStrategiesOut()
+ {
+ LocatorStrategy originalStrategy = createMock( LocatorStrategy.class );
+ LocatorStrategy replacementStrategy = createMock( LocatorStrategy.class );
+
+ replay( originalStrategy, replacementStrategy );
+
+ Locator locator = new Locator();
+ locator.addStrategy( originalStrategy );
+
+ locator.setStrategies( Collections.singletonList( replacementStrategy ) );
+
+ List strategies = locator.getStrategies();
+
+ assertFalse( strategies.contains( originalStrategy ) );
+ assertTrue( strategies.contains( replacementStrategy ) );
+
+ verify( originalStrategy, replacementStrategy );
+ }
+
+ public void testShouldRemovePreviouslyAddedStrategy()
+ {
+ LocatorStrategy originalStrategy = createMock( LocatorStrategy.class );
+
+ replay( originalStrategy );
+
+ Locator locator = new Locator();
+ locator.addStrategy( originalStrategy );
+
+ List strategies = locator.getStrategies();
+
+ assertTrue( strategies.contains( originalStrategy ) );
+
+ locator.removeStrategy( originalStrategy );
+
+ strategies = locator.getStrategies();
+
+ assertFalse( strategies.contains( originalStrategy ) );
+
+ verify( originalStrategy );
+ }
+
+ public void testResolutionFallsThroughStrategyStackAndReturnsNullIfNotResolved()
+ {
+ List strategies = new ArrayList();
+
+ strategies.add( new LoggingLocatorStrategy() );
+ strategies.add( new LoggingLocatorStrategy() );
+ strategies.add( new LoggingLocatorStrategy() );
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Locator locator = new Locator( strategies, mh );
+
+ Location location = locator.resolve( "some-specification" );
+
+ assertNull( location );
+
+ assertEquals( 3, mh.size() );
+ }
+
+ public static final class LoggingLocatorStrategy implements LocatorStrategy
+ {
+
+ static int instanceCounter = 0;
+
+ int counter = instanceCounter++;
+
+ public Location resolve( String locationSpecification, MessageHolder messageHolder )
+ {
+ messageHolder.addMessage( "resolve hit on strategy-" + (counter) );
+ return null;
+ }
+
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocationTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocationTest.java
new file mode 100644
index 000000000..f63321a74
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocationTest.java
@@ -0,0 +1,81 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.maven.shared.io.Utils;
+
+import junit.framework.TestCase;
+
+public class URLLocationTest
+ extends TestCase
+{
+
+ public void testShouldConstructFromUrlAndTempFileSpecifications() throws IOException
+ {
+ File f = File.createTempFile( "url-location.", ".test" );
+ f.deleteOnExit();
+
+ URL url = f.toURL();
+
+ new URLLocation( url, f.getAbsolutePath(), "prefix.", ".suffix", true );
+ }
+
+ public void testShouldTransferFromTempFile() throws IOException
+ {
+ File f = File.createTempFile( "url-location.", ".test" );
+ f.deleteOnExit();
+
+ URL url = f.toURL();
+
+ URLLocation location = new URLLocation( url, f.getAbsolutePath(), "prefix.", ".suffix", true );
+
+ assertNotNull( location.getFile() );
+ assertFalse( f.equals( location.getFile() ) );
+ }
+
+ public void testShouldTransferFromTempFileThenRead() throws IOException
+ {
+ File f = File.createTempFile( "url-location.", ".test" );
+ f.deleteOnExit();
+
+ String testStr = "This is a test";
+
+ Utils.writeFileWithEncoding( f, testStr, "US-ASCII" );
+
+ URL url = f.toURL();
+
+ URLLocation location = new URLLocation( url, f.getAbsolutePath(), "prefix.", ".suffix", true );
+
+ location.open();
+
+ byte[] buffer = new byte[ testStr.length() ];
+
+ int read = location.read( buffer );
+
+ assertEquals( testStr.length(), read );
+
+ assertEquals( testStr, new String( buffer, "US-ASCII" ) );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocatorStrategyTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocatorStrategyTest.java
new file mode 100644
index 000000000..210cfe5a7
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/location/URLLocatorStrategyTest.java
@@ -0,0 +1,79 @@
+package org.apache.maven.shared.io.location;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.shared.io.Utils;
+import org.apache.maven.shared.io.logging.DefaultMessageHolder;
+import org.apache.maven.shared.io.logging.MessageHolder;
+
+public class URLLocatorStrategyTest
+ extends TestCase
+{
+
+ public void testShouldConstructWithNoParams()
+ {
+ new URLLocatorStrategy();
+ }
+
+ public void testShouldConstructWithTempFileOptions()
+ {
+ new URLLocatorStrategy( "prefix.", ".suffix", true );
+ }
+
+ public void testShouldFailToResolveWithMalformedUrl()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = new URLLocatorStrategy().resolve( "://www.google.com", mh );
+
+ assertNull( location );
+ assertEquals( 1, mh.size() );
+ }
+
+ public void testShouldResolveUrlForTempFile() throws IOException
+ {
+ File tempFile = File.createTempFile( "prefix.", ".suffix" );
+ tempFile.deleteOnExit();
+
+ String testStr = "This is a test.";
+
+ Utils.writeFileWithEncoding( tempFile, testStr, "US-ASCII" );
+
+ MessageHolder mh = new DefaultMessageHolder();
+
+ Location location = new URLLocatorStrategy().resolve( tempFile.toURL().toExternalForm(), mh );
+
+ assertNotNull( location );
+ assertEquals( 0, mh.size() );
+
+ location.open();
+
+ byte[] buffer = new byte[testStr.length()];
+ location.read( buffer );
+
+ assertEquals( testStr, new String( buffer, "US-ASCII" ) );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java
new file mode 100644
index 000000000..ea3b80565
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/logging/DefaultMessageHolderTest.java
@@ -0,0 +1,304 @@
+package org.apache.maven.shared.io.logging;
+
+/*
+ * 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.
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+public class DefaultMessageHolderTest
+ extends TestCase
+{
+
+ // MessageHolder newMessage();
+ // int size();
+ // String render();
+ public void testNewMessageIncrementsSizeWhenEmpty()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ MessageHolder test = mh.newMessage();
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ assertEquals( "", mh.render() );
+ }
+
+ // MessageHolder append( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testAppendCreatesNewMessageIfNoneCurrent()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ MessageHolder test = mh.append( "test" );
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ assertEquals( "[1] [INFO] test", mh.render() );
+ }
+
+ // MessageHolder append( Throwable error );
+ // int size();
+ // String render();
+ public void testAppendErrorCreatesNewMessageIfNoneCurrent()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ NullPointerException npe = new NullPointerException();
+
+ MessageHolder test = mh.append( npe );
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ npe.printStackTrace( pw );
+
+ assertEquals( "[1] [INFO] Error:\n" + sw.toString(), mh.render() );
+ }
+
+ // MessageHolder newMessage();
+ // MessageHolder append( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testNewMessageThenAppendOnlyIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ MessageHolder test = mh.newMessage();
+
+ assertSame( mh, test );
+
+ test = mh.append( "test" );
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ assertEquals( "[1] [INFO] test", mh.render() );
+ }
+
+ // MessageHolder newMessage();
+ // MessageHolder append( CharSequence messagePart );
+ // MessageHolder append( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testNewMessageThenAppendTwiceOnlyIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ MessageHolder test = mh.newMessage();
+
+ assertSame( mh, test );
+
+ test = mh.append( "test" );
+
+ assertSame( mh, test );
+
+ test = mh.append( " again" );
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ assertEquals( "[1] [INFO] test again", mh.render() );
+ }
+
+ // MessageHolder newMessage();
+ // MessageHolder append( CharSequence messagePart );
+ // MessageHolder append( Throwable error );
+ // int size();
+ // String render();
+ public void testNewMessageThenAppendBothMessageAndErrorOnlyIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ assertEquals( 0, mh.size() );
+
+ MessageHolder test = mh.newMessage();
+
+ assertSame( mh, test );
+
+ test = mh.append( "test" );
+
+ assertSame( mh, test );
+
+ NullPointerException npe = new NullPointerException();
+
+ test = mh.append( npe );
+
+ assertSame( mh, test );
+
+ assertEquals( 1, mh.size() );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ npe.printStackTrace( pw );
+
+ assertEquals( "[1] [INFO] test\nError:\n" + sw.toString(), mh.render() );
+ }
+
+ // MessageHolder addMessage( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testAddMessageIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+ MessageHolder check = mh.addMessage( "test" );
+
+ assertSame( mh, check );
+
+ assertEquals( 1, mh.size() );
+ assertEquals( "[1] [INFO] test", mh.render() );
+ }
+
+ // MessageHolder addMessage( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testAddMessageTwiceIncrementsSizeByTwo()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+ MessageHolder check = mh.addMessage( "test" );
+
+ assertSame( mh, check );
+
+ check = mh.addMessage( "test2" );
+
+ assertSame( mh, check );
+
+ assertEquals( 2, mh.size() );
+ assertEquals( "[1] [INFO] test\n\n[2] [INFO] test2", mh.render() );
+ }
+
+ // MessageHolder addMessage( CharSequence messagePart, Throwable error );
+ // int size();
+ // String render();
+ public void testAddMessageWithErrorIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ NullPointerException npe = new NullPointerException();
+
+ MessageHolder check = mh.addMessage( "test", npe );
+
+ assertSame( mh, check );
+
+ assertEquals( 1, mh.size() );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ npe.printStackTrace( pw );
+
+ assertEquals( "[1] [INFO] test\nError:\n" + sw.toString(), mh.render() );
+ }
+
+ // MessageHolder addMessage( CharSequence messagePart, Throwable error );
+ // MessageHolder addMessage( CharSequence messagePart );
+ // int size();
+ // String render();
+ public void testAddMessageWithErrorThenWithJustMessageIncrementsSizeByTwo()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ NullPointerException npe = new NullPointerException();
+
+ MessageHolder check = mh.addMessage( "test", npe );
+
+ assertSame( mh, check );
+
+ check = mh.addMessage( "test2" );
+
+ assertSame( mh, check );
+
+ assertEquals( 2, mh.size() );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ npe.printStackTrace( pw );
+
+ assertEquals( "[1] [INFO] test\nError:\n" + sw.toString() + "\n\n[2] [INFO] test2", mh.render() );
+ }
+
+ // MessageHolder addMessage( Throwable error );
+ // int size();
+ // String render();
+ public void testAddMessageWithJustErrorIncrementsSizeByOne()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+
+ NullPointerException npe = new NullPointerException();
+
+ MessageHolder check = mh.addMessage( npe );
+
+ assertSame( mh, check );
+
+ assertEquals( 1, mh.size() );
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+
+ npe.printStackTrace( pw );
+
+ assertEquals( "[1] [INFO] Error:\n" + sw.toString(), mh.render() );
+ }
+
+ // boolean isEmpty();
+ public void testIsEmptyAfterConstruction()
+ {
+ assertTrue( new DefaultMessageHolder().isEmpty() );
+ }
+
+ // boolean isEmpty();
+ public void testIsNotEmptyAfterConstructionAndNewMessageCall()
+ {
+ assertFalse( new DefaultMessageHolder().newMessage().isEmpty() );
+ }
+
+ public void testAppendCharSequence()
+ {
+ MessageHolder mh = new DefaultMessageHolder();
+ mh.newMessage().append( new StringBuffer( "This is a test" ) );
+
+ assertTrue( mh.render().indexOf( "This is a test" ) > -1 );
+ }
+
+}
diff --git a/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/scan/mapping/SuffixMappingTest.java b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/scan/mapping/SuffixMappingTest.java
new file mode 100644
index 000000000..197aad6c2
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/java/org/apache/maven/shared/io/scan/mapping/SuffixMappingTest.java
@@ -0,0 +1,130 @@
+package org.apache.maven.shared.io.scan.mapping;
+
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.maven.shared.io.scan.InclusionScanException;
+import org.junit.Test;
+
+/**
+ * @author jdcasey
+ */
+public class SuffixMappingTest
+{
+ @Test
+ public void testShouldReturnSingleClassFileForSingleJavaFile()
+ throws InclusionScanException
+ {
+ String base = "path/to/file";
+
+ File basedir = new File( "." );
+
+ System.out.println( "basedir:" + basedir.getAbsolutePath() );
+ SuffixMapping mapping = new SuffixMapping( ".java", ".class" );
+
+ Set results = mapping.getTargetFiles( basedir, base + ".java" );
+
+ assertEquals( "Returned wrong number of target files.", 1, results.size() );
+
+ assertEquals( "Target file is wrong.", new File( basedir, base + ".class" ), results.iterator().next() );
+ }
+
+ @Test
+ public void testShouldNotReturnClassFileWhenSourceFileHasWrongSuffix()
+ throws InclusionScanException
+ {
+ String base = "path/to/file";
+
+ File basedir = new File( "." );
+
+ SuffixMapping mapping = new SuffixMapping( ".java", ".class" );
+
+ Set results = mapping.getTargetFiles( basedir, base + ".xml" );
+
+ assertTrue( "Returned wrong number of target files.", results.isEmpty() );
+ }
+
+ @Test
+ public void testShouldReturnOneClassFileAndOneXmlFileForSingleJavaFile()
+ throws InclusionScanException
+ {
+ String base = "path/to/file";
+
+ File basedir = new File( "." );
+
+ Set targets = new HashSet();
+ targets.add( ".class" );
+ targets.add( ".xml" );
+
+ SuffixMapping mapping = new SuffixMapping( ".java", targets );
+
+ Set results = mapping.getTargetFiles( basedir, base + ".java" );
+
+ assertEquals( "Returned wrong number of target files.", 2, results.size() );
+
+ assertTrue( "Targets do not contain class target.", results.contains( new File( basedir, base + ".class" ) ) );
+
+ assertTrue( "Targets do not contain class target.", results.contains( new File( basedir, base + ".xml" ) ) );
+ }
+
+ @Test
+ public void testShouldReturnNoTargetFilesWhenSourceFileHasWrongSuffix()
+ throws InclusionScanException
+ {
+ String base = "path/to/file";
+
+ File basedir = new File( "." );
+
+ Set targets = new HashSet();
+ targets.add( ".class" );
+ targets.add( ".xml" );
+
+ SuffixMapping mapping = new SuffixMapping( ".java", targets );
+
+ Set results = mapping.getTargetFiles( basedir, base + ".apt" );
+
+ assertTrue( "Returned wrong number of target files.", results.isEmpty() );
+ }
+
+ @Test
+ public void testSingleTargetMapper()
+ throws InclusionScanException
+ {
+ String base = "path/to/file";
+
+ File basedir = new File( "target/" );
+
+ SingleTargetMapping mapping = new SingleTargetMapping( ".cs", "/foo" );
+
+ Set results = mapping.getTargetFiles( basedir, base + ".apt" );
+
+ assertTrue( results.isEmpty() );
+
+ results = mapping.getTargetFiles( basedir, base + ".cs" );
+
+ assertEquals( 1, results.size() );
+ }
+}
diff --git a/Java-base/maven-shared-io/src/src/test/resources/META-INF/maven/test.properties b/Java-base/maven-shared-io/src/src/test/resources/META-INF/maven/test.properties
new file mode 100644
index 000000000..379c6dbf2
--- /dev/null
+++ b/Java-base/maven-shared-io/src/src/test/resources/META-INF/maven/test.properties
@@ -0,0 +1,17 @@
+# 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.
+test=successful