cstamas commented on code in PR #26:
URL: 
https://github.com/apache/maven-remote-resources-plugin/pull/26#discussion_r1149036584


##########
src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java:
##########
@@ -0,0 +1,1358 @@
+package org.apache.maven.plugin.resources.remote;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.commons.io.output.DeferredFileOutputStream;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.archiver.MavenArchiver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Reader;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.SupplementalDataModelXpp3Reader;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import 
org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
+import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
+import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
+import 
org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
+import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
+import org.apache.maven.shared.filtering.MavenFileFilter;
+import org.apache.maven.shared.filtering.MavenFileFilterRequest;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.codehaus.plexus.resource.ResourceManager;
+import org.codehaus.plexus.resource.loader.FileResourceLoader;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * <p>
+ * Pull down resourceBundles containing remote resources and process the 
resources contained inside. When that is done,
+ * the resources are injected into the current (in-memory) Maven project, 
making them available to the process-resources
+ * phase.
+ * </p>
+ * <p>
+ * Resources that end in ".vm" are treated as Velocity templates. For those, 
the ".vm" is stripped off for the final
+ * artifact name and it's fed through Velocity to have properties expanded, 
conditions processed, etc...
+ * </p>
+ * Resources that don't end in ".vm" are copied "as is".
+ * <p>
+ * This is a support abstract class, with two non-aggregating and aggregating 
implementations.
+ * </p>
+ */
+public abstract class AbstractProcessRemoteResourcesMojo
+        extends AbstractMojo
+{
+    private static final String TEMPLATE_SUFFIX = ".vm";
+
+    /**
+     * <p>
+     * In cases where a local resource overrides one from a remote resource 
bundle, that resource should be filtered if
+     * the resource set specifies it. In those cases, this parameter defines 
the list of delimiters for filterable
+     * expressions. These delimiters are specified in the form 
'beginToken*endToken'. If no '*' is given, the delimiter
+     * is assumed to be the same for start and end.
+     * </p>
+     * <p>
+     * So, the default filtering delimiters might be specified as:
+     * </p>
+     *
+     * <pre>
+     * &lt;delimiters&gt;
+     *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
+     *   &lt;delimiter&gt;@&lt;/delimiter&gt;
+     * &lt;/delimiters&gt;
+     * </pre>
+     * Since the '@' delimiter is the same on both ends, we don't need to 
specify '@*@' (though we can).
+     *
+     * @since 1.1
+     */
+    @Parameter
+    protected List<String> filterDelimiters;
+
+    /**
+     * @since 1.1
+     */
+    @Parameter( defaultValue = "true" )
+    protected boolean useDefaultFilterDelimiters;
+
+    /**
+     * The character encoding scheme to be applied when filtering resources.
+     */
+    @Parameter( property = "encoding", defaultValue = 
"${project.build.sourceEncoding}" )
+    protected String encoding;
+
+    /**
+     * The directory where processed resources will be placed for packaging.
+     */
+    @Parameter( defaultValue = 
"${project.build.directory}/maven-shared-archive-resources" )
+    private File outputDirectory;
+
+    /**
+     * The directory containing extra information appended to the generated 
resources.
+     */
+    @Parameter( defaultValue = "${basedir}/src/main/appended-resources" )
+    private File appendedResourcesDirectory;
+
+    /**
+     * Supplemental model data. Useful when processing
+     * artifacts with incomplete POM metadata.
+     * <p/>
+     * By default, this Mojo looks for supplemental model data in the file
+     * "<code>${appendedResourcesDirectory}/supplemental-models.xml</code>".
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter
+    private String[] supplementalModels;
+
+    /**
+     * List of artifacts that are added to the search path when looking
+     * for supplementalModels, expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     *
+     * @since 1.1
+     */
+    @Parameter
+    private List<String> supplementalModelArtifacts;
+
+    /**
+     * The resource bundles that will be retrieved and processed,
+     * expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     */
+    @Parameter( required = true )
+    private List<String> resourceBundles;
+
+    /**
+     * Skip remote-resource processing
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter( property = "remoteresources.skip", defaultValue = "false" )
+    private boolean skip;
+
+    /**
+     * Attaches the resources to the main build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToMain" )
+    private boolean attachToMain;
+
+    /**
+     * Attaches the resources to the test build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToTest" )
+    private boolean attachToTest;
+
+    /**
+     * Additional properties to be passed to Velocity.
+     * Several properties are automatically added:<ul>
+     * <li><code>project</code> - the current MavenProject </li>
+     * <li><code>projects</code> - the list of dependency projects</li>
+     * <li><code>projectsSortedByOrganization</code> - the list of dependency 
projects sorted by organization</li>
+     * <li><code>projectTimespan</code> - the timespan of the current project 
(requires inceptionYear in pom)</li>
+     * <li><code>locator</code> - the ResourceManager that can be used to 
retrieve additional resources</li>
+     * </ul>
+     * See <a
+     * 
href="https://maven.apache.org/ref/current/maven-project/apidocs/org/apache/maven/project/MavenProject.html";>
 the
+     * javadoc for MavenProject</a> for information about the properties on 
the MavenProject.
+     */
+    @Parameter
+    protected Map<String, Object> properties = new HashMap<>();
+
+    /**
+     * Whether to include properties defined in the project when filtering 
resources.
+     *
+     * @since 1.2
+     */
+    @Parameter( defaultValue = "false" )
+    protected boolean includeProjectProperties = false;
+
+    /**
+     * When the result of velocity transformation fits in memory, it is 
compared with the actual contents on disk
+     * to eliminate unnecessary destination file overwrite. This improves 
build times since further build steps
+     * typically rely on the modification date.
+     *
+     * @since 1.6
+     */
+    @Parameter( defaultValue = "5242880" )
+    protected int velocityFilterInMemoryThreshold = 5 * 1024 * 1024;
+
+    /**
+     * The Maven session.
+     */
+    @Parameter( defaultValue = "${session}", readonly = true, required = true )
+    protected MavenSession mavenSession;
+
+    /**
+     * The current project.
+     */
+    @Parameter( defaultValue = "${project}", readonly = true, required = true )
+    protected MavenProject project;
+
+    /**
+     * Scope to include. An Empty string indicates all scopes (default is 
"runtime").
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "includeScope", defaultValue = "runtime" )
+    protected String includeScope;
+
+    /**
+     * Scope to exclude. An Empty string indicates no scopes (default).
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "excludeScope", defaultValue = "" )
+    protected String excludeScope;
+
+    /**
+     * When resolving project dependencies, specify the scopes to include.
+     * The default is the same as "includeScope" if there are no exclude 
scopes set.
+     * Otherwise, it defaults to "test" to grab all the dependencies so the
+     * exclude filters can filter out what is not needed.
+     *
+     * @since 1.5
+     */
+    @Parameter
+    protected String[] resolveScopes;
+
+    /**
+     * Comma separated list of Artifact names to exclude.
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "excludeArtifactIds", defaultValue = "" )
+    protected String excludeArtifactIds;
+
+    /**
+     * Comma separated list of Artifact names to include.
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "includeArtifactIds", defaultValue = "" )
+    protected String includeArtifactIds;
+
+    /**
+     * Comma separated list of GroupId Names to exclude.
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "excludeGroupIds", defaultValue = "" )
+    protected String excludeGroupIds;
+
+    /**
+     * Comma separated list of GroupIds to include.
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "includeGroupIds", defaultValue = "" )
+    protected String includeGroupIds;
+
+    /**
+     * If we should exclude transitive dependencies
+     *
+     * @since 1.0
+     */
+    @Parameter( property = "excludeTransitive", defaultValue = "false" )
+    protected boolean excludeTransitive;
+
+    /**
+     * Timestamp for reproducible output archive entries, either formatted as 
ISO 8601
+     * <code>yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds 
since the epoch (like
+     * <a 
href="https://reproducible-builds.org/docs/source-date-epoch/";>SOURCE_DATE_EPOCH</a>).
+     */
+    @Parameter( defaultValue = "${project.build.outputTimestamp}" )
+    private String outputTimestamp;
+
+    @Component
+    protected RepositorySystem repositorySystem;
+
+    /**
+     * Filtering support, for local resources that override those in the 
remote bundle.
+     */
+    @Component
+    private MavenFileFilter fileFilter;
+
+    @Component
+    private ResourceManager locator;
+
+    @Component
+    private ProjectBuilder projectBuilder;
+
+    @Component
+    private ArtifactHandlerManager artifactHandlerManager;
+
+    /**
+     * Map of artifacts to supplemental project object models.
+     */
+    private Map<String, Model> supplementModels;
+
+    /**
+     * Merges supplemental data model with artifact metadata. Useful when 
processing artifacts with
+     * incomplete POM metadata.
+     */
+    private final ModelInheritanceAssembler inheritanceAssembler = new 
ModelInheritanceAssembler();
+
+    private VelocityEngine velocity;
+
+    @Override
+    public void execute()
+            throws MojoExecutionException
+    {
+        if ( skip )
+        {
+            getLog().info( "Skipping remote resources execution." );
+            return;
+        }
+
+        if ( StringUtils.isEmpty( encoding ) )
+        {
+            getLog().warn( "File encoding has not been set, using platform 
encoding " + ReaderFactory.FILE_ENCODING
+                    + ", i.e. build is platform dependent!" );
+        }
+
+        if ( resolveScopes == null )
+        {
+            resolveScopes =
+                    new String[] {StringUtils.isEmpty( this.includeScope ) ? 
JavaScopes.TEST : this.includeScope};
+        }
+
+        if ( supplementalModels == null )
+        {
+            File sups = new File( appendedResourcesDirectory, 
"supplemental-models.xml" );
+            if ( sups.exists() )
+            {
+                try
+                {
+                    supplementalModels = new String[] 
{sups.toURI().toURL().toString()};
+                }
+                catch ( MalformedURLException e )
+                {
+                    // ignore
+                    getLog().debug( "URL issue with supplemental-models.xml: " 
+ e );
+                }
+            }
+        }
+
+        configureLocator();
+
+        if ( includeProjectProperties )
+        {
+            final Properties projectProperties = project.getProperties();
+            for ( Object key : projectProperties.keySet() )
+            {
+                properties.put( key.toString(), projectProperties.get( key 
).toString() );
+            }
+        }
+
+        ClassLoader origLoader = 
Thread.currentThread().getContextClassLoader();
+        try
+        {
+            validate();
+
+            List<File> resourceBundleArtifacts = downloadBundles( 
resourceBundles );
+            supplementModels = loadSupplements( supplementalModels );
+
+            ClassLoader classLoader = initalizeClassloader( 
resourceBundleArtifacts );
+
+            Thread.currentThread().setContextClassLoader( classLoader );
+
+            velocity = new VelocityEngine();
+            velocity.setProperty( "resource.loaders", "classpath" );
+            velocity.setProperty( "resource.loader.classpath.class", 
ClasspathResourceLoader.class.getName() );
+            velocity.init();
+
+            VelocityContext context = buildVelocityContext( properties );
+
+            processResourceBundles( classLoader, context );
+
+            if ( outputDirectory.exists() )
+            {
+                // 
----------------------------------------------------------------------------
+                // Push our newly generated resources directory into the 
MavenProject so that
+                // these resources can be picked up by the process-resources 
phase.
+                // 
----------------------------------------------------------------------------
+                Resource resource = new Resource();
+                resource.setDirectory( outputDirectory.getAbsolutePath() );
+                // MRRESOURCES-61 handle main and test resources separately
+                if ( attachToMain )
+                {
+                    project.getResources().add( resource );
+                }
+                if ( attachToTest )
+                {
+                    project.getTestResources().add( resource );
+                }
+
+                // 
----------------------------------------------------------------------------
+                // Write out archiver dot file
+                // 
----------------------------------------------------------------------------
+                try
+                {
+                    File dotFile = new File( 
project.getBuild().getDirectory(), ".plxarc" );
+                    FileUtils.mkdir( dotFile.getParentFile().getAbsolutePath() 
);
+                    FileUtils.fileWrite( dotFile.getAbsolutePath(), 
outputDirectory.getName() );
+                }
+                catch ( IOException e )
+                {
+                    throw new MojoExecutionException( "Error creating dot file 
for archiving instructions.", e );
+                }
+            }
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader( origLoader );
+        }
+    }
+
+    private void configureLocator()
+            throws MojoExecutionException
+    {
+        if ( supplementalModelArtifacts != null && 
!supplementalModelArtifacts.isEmpty() )
+        {
+            List<File> artifacts = downloadBundles( supplementalModelArtifacts 
);
+
+            for ( File artifact : artifacts )
+            {
+                if ( artifact.isDirectory() )
+                {
+                    locator.addSearchPath( FileResourceLoader.ID, 
artifact.getAbsolutePath() );
+                }
+                else
+                {
+                    try
+                    {
+                        locator.addSearchPath( "jar", "jar:" + 
artifact.toURI().toURL().toExternalForm() );
+                    }
+                    catch ( MalformedURLException e )
+                    {
+                        throw new MojoExecutionException( "Could not use jar " 
+ artifact.getAbsolutePath(), e );
+                    }
+                }
+            }
+
+        }
+
+        locator.addSearchPath( FileResourceLoader.ID, 
project.getFile().getParentFile().getAbsolutePath() );
+        if ( appendedResourcesDirectory != null )
+        {
+            locator.addSearchPath( FileResourceLoader.ID, 
appendedResourcesDirectory.getAbsolutePath() );
+        }
+        locator.addSearchPath( "url", "" );
+        locator.setOutputDirectory( new File( 
project.getBuild().getDirectory() ) );
+    }
+
+    protected List<MavenProject> getProjects()
+    {
+        List<MavenProject> projects = new ArrayList<>();
+
+        // add filters in well known order, least specific to most specific
+        FilterArtifacts filter = new FilterArtifacts();
+
+        Set<Artifact> artifacts = new LinkedHashSet<>();
+        artifacts.addAll( getAllDependencies() );
+        if ( this.excludeTransitive )
+        {
+            filter.addFilter( new ProjectTransitivityFilter( 
getDirectDependencies(), true ) );
+        }
+
+        filter.addFilter( new ScopeFilter( this.includeScope, 
this.excludeScope ) );
+        filter.addFilter( new GroupIdFilter( this.includeGroupIds, 
this.excludeGroupIds ) );
+        filter.addFilter( new ArtifactIdFilter( this.includeArtifactIds, 
this.excludeArtifactIds ) );
+
+        // perform filtering
+        try
+        {
+            artifacts = filter.filter( artifacts );
+        }
+        catch ( ArtifactFilterException e )
+        {
+            throw new IllegalStateException( e.getMessage(), e );
+        }
+
+        getLog().debug( "PROJECTS: " + artifacts );
+
+        for ( Artifact artifact : artifacts )
+        {
+            if ( artifact.isSnapshot() )
+            {
+                artifact.setVersion( artifact.getBaseVersion() );
+            }
+
+            getLog().debug( "Building project for " + artifact );
+            MavenProject p;
+            try
+            {
+                ProjectBuildingRequest req = new 
DefaultProjectBuildingRequest()
+                        .setValidationLevel( 
ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL )
+                        .setProcessPlugins( false )
+                        .setRepositorySession( 
mavenSession.getRepositorySession() )
+                        .setSystemProperties( 
mavenSession.getSystemProperties() )
+                        .setUserProperties( mavenSession.getUserProperties() )
+                        .setLocalRepository( mavenSession.getLocalRepository() 
)
+                        .setRemoteRepositories( 
project.getRemoteArtifactRepositories() );
+                ProjectBuildingResult res = projectBuilder.build( artifact, 
req );
+                p = res.getProject();
+            }
+            catch ( ProjectBuildingException e )
+            {
+                getLog().warn( "Invalid project model for artifact [" + 
artifact.getGroupId() + ":"
+                        + artifact.getArtifactId() + ":" + 
artifact.getVersion() + "]. "
+                        + "It will be ignored by the remote resources Mojo." );
+                continue;
+            }
+
+            String supplementKey =
+                    generateSupplementMapKey( p.getModel().getGroupId(), 
p.getModel().getArtifactId() );
+
+            if ( supplementModels.containsKey( supplementKey ) )
+            {
+                Model mergedModel = mergeModels( p.getModel(), 
supplementModels.get( supplementKey ) );
+                MavenProject mergedProject = new MavenProject( mergedModel );
+                projects.add( mergedProject );
+                mergedProject.setArtifact( artifact );
+                mergedProject.setVersion( artifact.getVersion() );
+                getLog().debug( "Adding project with groupId [" + 
mergedProject.getGroupId() + "] (supplemented)" );
+            }
+            else
+            {
+                projects.add( p );
+                getLog().debug( "Adding project with groupId [" + 
p.getGroupId() + "]" );
+            }
+        }
+        projects.sort( new ProjectComparator() );
+        return projects;
+    }
+
+    /**
+     * Returns all the transitive hull of all the involved maven projects.
+     */
+    protected abstract Set<Artifact> getAllDependencies();
+
+    /**
+     * Returns all the direct dependencies of all the involved maven projects.
+     */
+    protected abstract Set<Artifact> getDirectDependencies();
+
+    protected Map<Organization, List<MavenProject>> 
getProjectsSortedByOrganization( List<MavenProject> projects )
+    {
+        Map<Organization, List<MavenProject>> organizations =
+                new TreeMap<>( new OrganizationComparator() );
+        List<MavenProject> unknownOrganization = new ArrayList<>();
+
+        for ( MavenProject p : projects )
+        {
+            if ( p.getOrganization() != null && StringUtils.isNotEmpty( 
p.getOrganization().getName() ) )
+            {
+                List<MavenProject> sortedProjects = organizations.get( 
p.getOrganization() );
+                if ( sortedProjects == null )
+                {
+                    sortedProjects = new ArrayList<>();
+                }
+                sortedProjects.add( p );
+
+                organizations.put( p.getOrganization(), sortedProjects );
+            }
+            else
+            {
+                unknownOrganization.add( p );
+            }
+        }
+        if ( !unknownOrganization.isEmpty() )
+        {
+            Organization unknownOrg = new Organization();
+            unknownOrg.setName( "an unknown organization" );
+            organizations.put( unknownOrg, unknownOrganization );
+        }
+
+        return organizations;
+    }
+
+    protected boolean copyResourceIfExists( File file, String relFileName, 
VelocityContext context )
+            throws IOException, MojoExecutionException
+    {
+        for ( Resource resource : project.getResources() )
+        {
+            File resourceDirectory = new File( resource.getDirectory() );
+
+            if ( !resourceDirectory.exists() )
+            {
+                continue;
+            }
+
+            // TODO - really should use the resource includes/excludes and 
name mapping
+            File source = new File( resourceDirectory, relFileName );
+            File templateSource = new File( resourceDirectory, relFileName + 
TEMPLATE_SUFFIX );
+
+            if ( !source.exists() && templateSource.exists() )
+            {
+                source = templateSource;
+            }
+
+            if ( source.exists() && !source.equals( file ) )
+            {
+                if ( source == templateSource )
+                {
+                    try ( DeferredFileOutputStream os =
+                                  new DeferredFileOutputStream( 
velocityFilterInMemoryThreshold, file ) )
+                    {
+                        try ( Reader reader = getReader( source ); Writer 
writer = getWriter( os ) )
+                        {
+                            velocity.evaluate( context, writer, "", reader );
+                        }
+                        catch ( ParseErrorException | 
MethodInvocationException | ResourceNotFoundException e )
+                        {
+                            throw new MojoExecutionException( "Error rendering 
velocity resource: " + source, e );
+                        }
+                        fileWriteIfDiffers( os );
+                    }
+                }
+                else if ( resource.isFiltering() )
+                {
+
+                    MavenFileFilterRequest req = setupRequest( resource, 
source, file );
+
+                    try
+                    {
+                        fileFilter.copyFile( req );
+                    }
+                    catch ( MavenFilteringException e )
+                    {
+                        throw new MojoExecutionException( "Error filtering 
resource: " + source, e );
+                    }
+                }
+                else
+                {
+                    FileUtils.copyFile( source, file );
+                }
+
+                // exclude the original (so eclipse doesn't complain about 
duplicate resources)
+                resource.addExclude( relFileName );
+
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    private Reader getReader( File source ) throws IOException
+    {
+        if ( encoding != null )
+        {
+            return new InputStreamReader( Files.newInputStream( 
source.toPath() ), encoding );
+        }
+        else
+        {
+            return ReaderFactory.newPlatformReader( source );
+        }
+    }
+
+    private Writer getWriter( OutputStream os ) throws IOException
+    {
+        if ( encoding != null )
+        {
+            return new OutputStreamWriter( os, encoding );
+        }
+        else
+        {
+            return WriterFactory.newPlatformWriter( os );
+        }
+    }
+
+    /**
+     * If the transformation result fits in memory and the destination file 
already exists
+     * then both are compared.
+     * <p>If destination file is byte-by-byte equal, then it is not 
overwritten.
+     * This improves subsequent compilation times since upstream plugins 
property see that
+     * the resource was not modified.
+     * <p>Note: the method should be called after {@link 
DeferredFileOutputStream#close}
+     *
+     * @param outStream Deferred stream
+     * @throws IOException On IO error.
+     */
+    private void fileWriteIfDiffers( DeferredFileOutputStream outStream )
+            throws IOException
+    {
+        File file = outStream.getFile();
+        if ( outStream.isThresholdExceeded() )
+        {
+            getLog().info(
+                    "File " + file + " was overwritten due to content limit 
threshold " + outStream.getThreshold()
+                            + " reached" );
+            return;
+        }
+        boolean needOverwrite = true;
+
+        if ( file.exists() )
+        {
+            try ( InputStream is = Files.newInputStream( file.toPath() );
+                  InputStream newContents = new ByteArrayInputStream( 
outStream.getData() ) )
+            {
+                needOverwrite = !IOUtil.contentEquals( is, newContents );
+                if ( getLog().isDebugEnabled() )
+                {
+                    getLog().debug( "File " + file + " contents " + ( 
needOverwrite ? "differs" : "does not differ" ) );
+                }
+            }
+        }
+
+        if ( !needOverwrite )
+        {
+            getLog().debug( "File " + file + " is up to date" );
+            return;
+        }
+        getLog().debug( "Writing " + file );
+
+        try ( OutputStream os = Files.newOutputStream( file.toPath() ) )
+        {
+            outStream.writeTo( os );
+        }
+    }
+
+    private MavenFileFilterRequest setupRequest( Resource resource, File 
source, File file )
+    {
+        MavenFileFilterRequest req = new MavenFileFilterRequest();
+        req.setFrom( source );
+        req.setTo( file );
+        req.setFiltering( resource.isFiltering() );
+
+        req.setMavenProject( project );
+        req.setMavenSession( mavenSession );
+        req.setInjectProjectBuildFilters( true );
+
+        if ( encoding != null )
+        {
+            req.setEncoding( encoding );
+        }
+
+        if ( filterDelimiters != null && !filterDelimiters.isEmpty() )
+        {
+            LinkedHashSet<String> delims = new LinkedHashSet<>();
+            if ( useDefaultFilterDelimiters )
+            {
+                delims.addAll( req.getDelimiters() );
+            }
+
+            for ( String delim : filterDelimiters )
+            {
+                if ( delim == null )
+                {
+                    delims.add( "${*}" );
+                }
+                else
+                {
+                    delims.add( delim );
+                }
+            }
+
+            req.setDelimiters( delims );
+        }
+
+        return req;
+    }
+
+    protected void validate()
+            throws MojoExecutionException
+    {
+        int bundleCount = 1;
+
+        for ( String artifactDescriptor : resourceBundles )
+        {
+            // groupId:artifactId:version, groupId:artifactId:version:type
+            // or groupId:artifactId:version:type:classifier
+            String[] s = StringUtils.split( artifactDescriptor, ":" );
+
+            if ( s.length < 3 || s.length > 5 )
+            {
+                String position;
+
+                if ( bundleCount == 1 )
+                {
+                    position = "1st";
+                }
+                else if ( bundleCount == 2 )
+                {
+                    position = "2nd";
+                }
+                else if ( bundleCount == 3 )
+                {
+                    position = "3rd";
+                }
+                else
+                {
+                    position = bundleCount + "th";
+                }
+
+                throw new MojoExecutionException( "The " + position
+                        + " resource bundle configured must specify a groupId, 
artifactId, "
+                        + " version and, optionally, type and classifier for a 
remote resource bundle. "
+                        + "Must be of the form 
<resourceBundle>groupId:artifactId:version</resourceBundle>, "
+                        + 
"<resourceBundle>groupId:artifactId:version:type</resourceBundle> or "
+                        + 
"<resourceBundle>groupId:artifactId:version:type:classifier</resourceBundle>" );
+            }
+
+            bundleCount++;
+        }
+
+    }
+
+    private static final String KEY_PROJECTS = "projects";
+    private static final String KEY_PROJECTS_ORGS = 
"projectsSortedByOrganization";
+
+    protected VelocityContext buildVelocityContext( Map<String, Object> 
properties )
+    {
+        // the following properties are expensive to calculate, so we provide 
them lazily
+        VelocityContext context = new VelocityContext( properties )
+        {
+            @Override
+            public Object internalGet( String key )
+            {
+                Object result = super.internalGet( key );
+                if ( result == null && key != null && key.startsWith( 
KEY_PROJECTS ) && containsKey( key ) )
+                {
+                    // calculate and put projects* properties
+                    List<MavenProject> projects = getProjects();
+                    put( KEY_PROJECTS, projects );
+                    put( KEY_PROJECTS_ORGS, getProjectsSortedByOrganization( 
projects ) );
+                    return super.internalGet( key );
+                }
+                return result;
+            }
+        };
+        // to have a consistent getKeys()/containsKey() behaviour, keys must 
be present from the start
+        context.put( KEY_PROJECTS, null );
+        context.put( KEY_PROJECTS_ORGS, null );
+        // the following properties are cheap to calculate, so we provide them 
eagerly
+
+        // Reproducible Builds: try to use reproducible output timestamp 
+        MavenArchiver archiver = new MavenArchiver();
+        Date outputDate = archiver.parseOutputTimestamp( outputTimestamp );
+
+        String inceptionYear = project.getInceptionYear();
+        String year = new SimpleDateFormat( "yyyy" ).format( ( outputDate == 
null ) ? new Date() : outputDate );
+
+        if ( StringUtils.isEmpty( inceptionYear ) )
+        {
+            if ( getLog().isDebugEnabled() )
+            {
+                getLog().debug( "inceptionYear not specified, defaulting to " 
+ year );
+            }
+
+            inceptionYear = year;
+        }
+        context.put( "project", project );
+        context.put( "presentYear", year );
+        context.put( "locator", locator );
+
+        if ( inceptionYear.equals( year ) )
+        {
+            context.put( "projectTimespan", year );
+        }
+        else
+        {
+            context.put( "projectTimespan", inceptionYear + "-" + year );
+        }
+        return context;
+    }
+
+    private List<File> downloadBundles( List<String> bundles )
+            throws MojoExecutionException
+    {
+        List<File> bundleArtifacts = new ArrayList<>();
+
+        for ( String artifactDescriptor : bundles )
+        {
+            getLog().info( "Preparing remote bundle " + artifactDescriptor );
+            // groupId:artifactId:version[:type[:classifier]]
+            String[] s = artifactDescriptor.split( ":" );
+
+            File artifactFile = null;
+            // check if the artifact is part of the reactor
+            if ( mavenSession != null )
+            {
+                List<MavenProject> list = mavenSession.getProjects();
+                for ( MavenProject p : list )
+                {
+                    if ( s[0].equals( p.getGroupId() ) && s[1].equals( 
p.getArtifactId() )
+                            && s[2].equals( p.getVersion() ) )
+                    {
+                        if ( s.length >= 4 && "test-jar".equals( s[3] ) )
+                        {
+                            artifactFile = new File( 
p.getBuild().getTestOutputDirectory() );
+                        }
+                        else
+                        {
+                            artifactFile = new File( 
p.getBuild().getOutputDirectory() );
+                        }
+                    }
+                }
+            }
+            if ( artifactFile == null || !artifactFile.exists() )
+            {
+                String g = s[0];
+                String a = s[1];
+                String v = s[2];
+                String type = ( s.length >= 4 ? s[3] : "jar" );
+                ArtifactType artifactType = RepositoryUtils.newArtifactType( 
type,
+                        artifactHandlerManager.getArtifactHandler( type ) );
+                String classifier = ( s.length == 5 ? s[4] : 
artifactType.getClassifier() );
+
+                DefaultArtifact artifact = new DefaultArtifact(
+                        g, a, classifier, artifactType.getExtension(), v, 
artifactType );
+
+                try
+                {
+                    ArtifactRequest request = new ArtifactRequest(
+                            artifact,
+                            RepositoryUtils.toRepos( 
project.getRemoteArtifactRepositories() ),
+                            "remote-resources" );
+                    ArtifactResult result = repositorySystem.resolveArtifact(
+                            mavenSession.getRepositorySession(), request );
+                    artifactFile = result.getArtifact().getFile();
+                }
+                catch ( ArtifactResolutionException e )
+                {
+                    throw new MojoExecutionException( "Error processing remote 
resources", e );
+                }
+
+            }
+            bundleArtifacts.add( artifactFile );
+        }
+
+        return bundleArtifacts;
+    }
+
+    private ClassLoader initalizeClassloader( List<File> artifacts )
+            throws MojoExecutionException
+    {
+        RemoteResourcesClassLoader cl = new RemoteResourcesClassLoader( null );
+        try
+        {
+            for ( File artifact : artifacts )
+            {
+                cl.addURL( artifact.toURI().toURL() );
+            }
+            return cl;
+        }
+        catch ( MalformedURLException e )
+        {
+            throw new MojoExecutionException( "Unable to configure resources 
classloader: " + e.getMessage(), e );

Review Comment:
   This is how it is in original code, did not touch this area.



##########
src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java:
##########
@@ -0,0 +1,1358 @@
+package org.apache.maven.plugin.resources.remote;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.commons.io.output.DeferredFileOutputStream;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.archiver.MavenArchiver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Reader;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.SupplementalDataModelXpp3Reader;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import 
org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
+import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
+import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
+import 
org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
+import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
+import org.apache.maven.shared.filtering.MavenFileFilter;
+import org.apache.maven.shared.filtering.MavenFileFilterRequest;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.codehaus.plexus.resource.ResourceManager;
+import org.codehaus.plexus.resource.loader.FileResourceLoader;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * <p>
+ * Pull down resourceBundles containing remote resources and process the 
resources contained inside. When that is done,
+ * the resources are injected into the current (in-memory) Maven project, 
making them available to the process-resources
+ * phase.
+ * </p>
+ * <p>
+ * Resources that end in ".vm" are treated as Velocity templates. For those, 
the ".vm" is stripped off for the final
+ * artifact name and it's fed through Velocity to have properties expanded, 
conditions processed, etc...
+ * </p>
+ * Resources that don't end in ".vm" are copied "as is".
+ * <p>
+ * This is a support abstract class, with two non-aggregating and aggregating 
implementations.
+ * </p>
+ */
+public abstract class AbstractProcessRemoteResourcesMojo
+        extends AbstractMojo
+{
+    private static final String TEMPLATE_SUFFIX = ".vm";
+
+    /**
+     * <p>
+     * In cases where a local resource overrides one from a remote resource 
bundle, that resource should be filtered if
+     * the resource set specifies it. In those cases, this parameter defines 
the list of delimiters for filterable
+     * expressions. These delimiters are specified in the form 
'beginToken*endToken'. If no '*' is given, the delimiter
+     * is assumed to be the same for start and end.
+     * </p>
+     * <p>
+     * So, the default filtering delimiters might be specified as:
+     * </p>
+     *
+     * <pre>
+     * &lt;delimiters&gt;
+     *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
+     *   &lt;delimiter&gt;@&lt;/delimiter&gt;
+     * &lt;/delimiters&gt;
+     * </pre>
+     * Since the '@' delimiter is the same on both ends, we don't need to 
specify '@*@' (though we can).
+     *
+     * @since 1.1
+     */
+    @Parameter
+    protected List<String> filterDelimiters;
+
+    /**
+     * @since 1.1
+     */
+    @Parameter( defaultValue = "true" )
+    protected boolean useDefaultFilterDelimiters;
+
+    /**
+     * The character encoding scheme to be applied when filtering resources.
+     */
+    @Parameter( property = "encoding", defaultValue = 
"${project.build.sourceEncoding}" )
+    protected String encoding;
+
+    /**
+     * The directory where processed resources will be placed for packaging.
+     */
+    @Parameter( defaultValue = 
"${project.build.directory}/maven-shared-archive-resources" )
+    private File outputDirectory;
+
+    /**
+     * The directory containing extra information appended to the generated 
resources.
+     */
+    @Parameter( defaultValue = "${basedir}/src/main/appended-resources" )
+    private File appendedResourcesDirectory;
+
+    /**
+     * Supplemental model data. Useful when processing
+     * artifacts with incomplete POM metadata.
+     * <p/>
+     * By default, this Mojo looks for supplemental model data in the file
+     * "<code>${appendedResourcesDirectory}/supplemental-models.xml</code>".
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter
+    private String[] supplementalModels;
+
+    /**
+     * List of artifacts that are added to the search path when looking
+     * for supplementalModels, expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     *
+     * @since 1.1
+     */
+    @Parameter
+    private List<String> supplementalModelArtifacts;
+
+    /**
+     * The resource bundles that will be retrieved and processed,
+     * expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     */
+    @Parameter( required = true )
+    private List<String> resourceBundles;
+
+    /**
+     * Skip remote-resource processing
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter( property = "remoteresources.skip", defaultValue = "false" )
+    private boolean skip;
+
+    /**
+     * Attaches the resources to the main build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToMain" )
+    private boolean attachToMain;
+
+    /**
+     * Attaches the resources to the test build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToTest" )
+    private boolean attachToTest;
+
+    /**
+     * Additional properties to be passed to Velocity.
+     * Several properties are automatically added:<ul>
+     * <li><code>project</code> - the current MavenProject </li>
+     * <li><code>projects</code> - the list of dependency projects</li>
+     * <li><code>projectsSortedByOrganization</code> - the list of dependency 
projects sorted by organization</li>
+     * <li><code>projectTimespan</code> - the timespan of the current project 
(requires inceptionYear in pom)</li>
+     * <li><code>locator</code> - the ResourceManager that can be used to 
retrieve additional resources</li>
+     * </ul>
+     * See <a
+     * 
href="https://maven.apache.org/ref/current/maven-project/apidocs/org/apache/maven/project/MavenProject.html";>
 the
+     * javadoc for MavenProject</a> for information about the properties on 
the MavenProject.
+     */
+    @Parameter
+    protected Map<String, Object> properties = new HashMap<>();
+
+    /**
+     * Whether to include properties defined in the project when filtering 
resources.
+     *
+     * @since 1.2
+     */
+    @Parameter( defaultValue = "false" )
+    protected boolean includeProjectProperties = false;

Review Comment:
   This is how it is in original code, did not touch this area.



##########
src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java:
##########
@@ -0,0 +1,1358 @@
+package org.apache.maven.plugin.resources.remote;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.commons.io.output.DeferredFileOutputStream;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.archiver.MavenArchiver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Reader;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.SupplementalDataModelXpp3Reader;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import 
org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
+import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
+import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
+import 
org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
+import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
+import org.apache.maven.shared.filtering.MavenFileFilter;
+import org.apache.maven.shared.filtering.MavenFileFilterRequest;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.codehaus.plexus.resource.ResourceManager;
+import org.codehaus.plexus.resource.loader.FileResourceLoader;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * <p>
+ * Pull down resourceBundles containing remote resources and process the 
resources contained inside. When that is done,
+ * the resources are injected into the current (in-memory) Maven project, 
making them available to the process-resources
+ * phase.
+ * </p>
+ * <p>
+ * Resources that end in ".vm" are treated as Velocity templates. For those, 
the ".vm" is stripped off for the final
+ * artifact name and it's fed through Velocity to have properties expanded, 
conditions processed, etc...
+ * </p>
+ * Resources that don't end in ".vm" are copied "as is".
+ * <p>
+ * This is a support abstract class, with two non-aggregating and aggregating 
implementations.
+ * </p>
+ */
+public abstract class AbstractProcessRemoteResourcesMojo
+        extends AbstractMojo
+{
+    private static final String TEMPLATE_SUFFIX = ".vm";
+
+    /**
+     * <p>
+     * In cases where a local resource overrides one from a remote resource 
bundle, that resource should be filtered if
+     * the resource set specifies it. In those cases, this parameter defines 
the list of delimiters for filterable
+     * expressions. These delimiters are specified in the form 
'beginToken*endToken'. If no '*' is given, the delimiter
+     * is assumed to be the same for start and end.
+     * </p>
+     * <p>
+     * So, the default filtering delimiters might be specified as:
+     * </p>
+     *
+     * <pre>
+     * &lt;delimiters&gt;
+     *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
+     *   &lt;delimiter&gt;@&lt;/delimiter&gt;
+     * &lt;/delimiters&gt;
+     * </pre>
+     * Since the '@' delimiter is the same on both ends, we don't need to 
specify '@*@' (though we can).
+     *
+     * @since 1.1
+     */
+    @Parameter
+    protected List<String> filterDelimiters;
+
+    /**
+     * @since 1.1
+     */
+    @Parameter( defaultValue = "true" )
+    protected boolean useDefaultFilterDelimiters;
+
+    /**
+     * The character encoding scheme to be applied when filtering resources.
+     */
+    @Parameter( property = "encoding", defaultValue = 
"${project.build.sourceEncoding}" )
+    protected String encoding;
+
+    /**
+     * The directory where processed resources will be placed for packaging.
+     */
+    @Parameter( defaultValue = 
"${project.build.directory}/maven-shared-archive-resources" )
+    private File outputDirectory;
+
+    /**
+     * The directory containing extra information appended to the generated 
resources.
+     */
+    @Parameter( defaultValue = "${basedir}/src/main/appended-resources" )
+    private File appendedResourcesDirectory;
+
+    /**
+     * Supplemental model data. Useful when processing
+     * artifacts with incomplete POM metadata.
+     * <p/>
+     * By default, this Mojo looks for supplemental model data in the file
+     * "<code>${appendedResourcesDirectory}/supplemental-models.xml</code>".
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter
+    private String[] supplementalModels;
+
+    /**
+     * List of artifacts that are added to the search path when looking
+     * for supplementalModels, expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     *
+     * @since 1.1
+     */
+    @Parameter
+    private List<String> supplementalModelArtifacts;
+
+    /**
+     * The resource bundles that will be retrieved and processed,
+     * expressed with 
<code>groupId:artifactId:version[:type[:classifier]]</code> format.
+     */
+    @Parameter( required = true )
+    private List<String> resourceBundles;
+
+    /**
+     * Skip remote-resource processing
+     *
+     * @since 1.0-alpha-5
+     */
+    @Parameter( property = "remoteresources.skip", defaultValue = "false" )
+    private boolean skip;
+
+    /**
+     * Attaches the resources to the main build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToMain" )
+    private boolean attachToMain;
+
+    /**
+     * Attaches the resources to the test build of the project as a resource 
directory.
+     *
+     * @since 1.5
+     */
+    @Parameter( defaultValue = "true", property = "attachToTest" )
+    private boolean attachToTest;
+
+    /**
+     * Additional properties to be passed to Velocity.
+     * Several properties are automatically added:<ul>
+     * <li><code>project</code> - the current MavenProject </li>
+     * <li><code>projects</code> - the list of dependency projects</li>
+     * <li><code>projectsSortedByOrganization</code> - the list of dependency 
projects sorted by organization</li>
+     * <li><code>projectTimespan</code> - the timespan of the current project 
(requires inceptionYear in pom)</li>
+     * <li><code>locator</code> - the ResourceManager that can be used to 
retrieve additional resources</li>
+     * </ul>
+     * See <a
+     * 
href="https://maven.apache.org/ref/current/maven-project/apidocs/org/apache/maven/project/MavenProject.html";>
 the
+     * javadoc for MavenProject</a> for information about the properties on 
the MavenProject.
+     */
+    @Parameter
+    protected Map<String, Object> properties = new HashMap<>();
+
+    /**
+     * Whether to include properties defined in the project when filtering 
resources.
+     *
+     * @since 1.2
+     */
+    @Parameter( defaultValue = "false" )
+    protected boolean includeProjectProperties = false;
+
+    /**
+     * When the result of velocity transformation fits in memory, it is 
compared with the actual contents on disk
+     * to eliminate unnecessary destination file overwrite. This improves 
build times since further build steps
+     * typically rely on the modification date.
+     *
+     * @since 1.6
+     */
+    @Parameter( defaultValue = "5242880" )
+    protected int velocityFilterInMemoryThreshold = 5 * 1024 * 1024;

Review Comment:
   This is how it is in original code, did not touch this area.



##########
src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java:
##########
@@ -0,0 +1,1358 @@
+package org.apache.maven.plugin.resources.remote;
+
+/*
+ * 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.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.commons.io.output.DeferredFileOutputStream;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.archiver.MavenArchiver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Reader;
+import 
org.apache.maven.plugin.resources.remote.io.xpp3.SupplementalDataModelXpp3Reader;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+import 
org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
+import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
+import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
+import 
org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
+import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
+import org.apache.maven.shared.filtering.MavenFileFilter;
+import org.apache.maven.shared.filtering.MavenFileFilterRequest;
+import org.apache.maven.shared.filtering.MavenFilteringException;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.codehaus.plexus.resource.ResourceManager;
+import org.codehaus.plexus.resource.loader.FileResourceLoader;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * <p>
+ * Pull down resourceBundles containing remote resources and process the 
resources contained inside. When that is done,
+ * the resources are injected into the current (in-memory) Maven project, 
making them available to the process-resources
+ * phase.
+ * </p>
+ * <p>
+ * Resources that end in ".vm" are treated as Velocity templates. For those, 
the ".vm" is stripped off for the final
+ * artifact name and it's fed through Velocity to have properties expanded, 
conditions processed, etc...
+ * </p>
+ * Resources that don't end in ".vm" are copied "as is".
+ * <p>
+ * This is a support abstract class, with two non-aggregating and aggregating 
implementations.
+ * </p>
+ */
+public abstract class AbstractProcessRemoteResourcesMojo
+        extends AbstractMojo
+{
+    private static final String TEMPLATE_SUFFIX = ".vm";
+
+    /**
+     * <p>
+     * In cases where a local resource overrides one from a remote resource 
bundle, that resource should be filtered if
+     * the resource set specifies it. In those cases, this parameter defines 
the list of delimiters for filterable
+     * expressions. These delimiters are specified in the form 
'beginToken*endToken'. If no '*' is given, the delimiter
+     * is assumed to be the same for start and end.
+     * </p>
+     * <p>
+     * So, the default filtering delimiters might be specified as:
+     * </p>
+     *
+     * <pre>
+     * &lt;delimiters&gt;
+     *   &lt;delimiter&gt;${*}&lt;/delimiter&gt;
+     *   &lt;delimiter&gt;@&lt;/delimiter&gt;
+     * &lt;/delimiters&gt;
+     * </pre>
+     * Since the '@' delimiter is the same on both ends, we don't need to 
specify '@*@' (though we can).
+     *
+     * @since 1.1
+     */
+    @Parameter
+    protected List<String> filterDelimiters;
+
+    /**
+     * @since 1.1
+     */
+    @Parameter( defaultValue = "true" )
+    protected boolean useDefaultFilterDelimiters;
+
+    /**
+     * The character encoding scheme to be applied when filtering resources.
+     */
+    @Parameter( property = "encoding", defaultValue = 
"${project.build.sourceEncoding}" )
+    protected String encoding;
+
+    /**
+     * The directory where processed resources will be placed for packaging.
+     */
+    @Parameter( defaultValue = 
"${project.build.directory}/maven-shared-archive-resources" )
+    private File outputDirectory;
+
+    /**
+     * The directory containing extra information appended to the generated 
resources.
+     */
+    @Parameter( defaultValue = "${basedir}/src/main/appended-resources" )
+    private File appendedResourcesDirectory;

Review Comment:
   This is how it is in original code, did not touch this area.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@maven.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to