consumer to move old releases to an archive location
authorBrett Porter <brett@apache.org>
Fri, 1 Aug 2014 07:28:37 +0000 (07:28 +0000)
committerBrett Porter <brett@apache.org>
Fri, 1 Aug 2014 07:28:37 +0000 (07:28 +0000)
git-svn-id: https://svn.apache.org/repos/asf/archiva/sandbox/trunk@1615046 13f79535-47bb-0310-9956-ffa450edef68

archive-releases-consumer/pom.xml [new file with mode: 0644]
archive-releases-consumer/src/main/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumer.java [new file with mode: 0644]
archive-releases-consumer/src/main/resources/META-INF/spring-context.xml [new file with mode: 0644]
archive-releases-consumer/src/test/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumerTest.java [new file with mode: 0644]
archive-releases-consumer/src/test/resources/log4j2-test.xml [new file with mode: 0644]
archive-releases-consumer/src/test/resources/spring-context.xml [new file with mode: 0644]

diff --git a/archive-releases-consumer/pom.xml b/archive-releases-consumer/pom.xml
new file mode 100644 (file)
index 0000000..a4ed549
--- /dev/null
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.archiva.plugins</groupId>
+  <artifactId>archive-releases-consumer</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <name>Apache Archiva Consumer to Archive Releases</name>
+  <description>
+    This is a simple consumer component which will archive releases over a certain age to an archive directory, removing
+    them from the repository system.
+  </description>
+  <properties>
+    <archiva.version>2.1.1-SNAPSHOT</archiva.version>
+    <slf4j.version>1.7.7</slf4j.version>
+    <log4j.version>2.0</log4j.version>
+    <spring.version>4.0.6.RELEASE</spring.version>
+    <redback.registry.version>2.3</redback.registry.version>
+    <guava.version>16.0.1</guava.version>
+    <springockito.version>1.0.9</springockito.version>
+    <mockito.version>1.9.0</mockito.version>
+    <httpclient.version>4.3.1</httpclient.version>
+    <httpclient.core.version>4.3</httpclient.core.version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-consumer-api</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-configuration</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-repository-admin-api</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-model</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-repository-layer</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-repository-api</artifactId>
+      <version>${archiva.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback.components.registry</groupId>
+      <artifactId>spring-registry-api</artifactId>
+      <version>${redback.registry.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+      <version>1</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.annotation</groupId>
+      <artifactId>jsr250-api</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <version>${spring.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <version>${spring.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>maven2-repository</artifactId>
+      <version>${archiva.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.kubek2k</groupId>
+      <artifactId>springockito</artifactId>
+      <version>${springockito.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <!-- match up with those used by Archiva -->
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>com.google.guava</groupId>
+        <artifactId>guava</artifactId>
+        <version>${guava.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-all</artifactId>
+        <version>${mockito.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpclient</artifactId>
+        <version>${httpclient.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpcore</artifactId>
+        <version>${httpclient.core.version}</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-clean-plugin</artifactId>
+          <version>2.5</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-resources-plugin</artifactId>
+          <version>2.6</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>2.4</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>2.17</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <!--repositories>
+    <repository>
+      <id>archiva.snapshots</id>
+      <name>Archiva VM Snapshots Repository</name>
+      <url>https://archiva-repository.apache.org/archiva/repository/snapshots</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </repository>
+  </repositories-->
+</project>
diff --git a/archive-releases-consumer/src/main/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumer.java b/archive-releases-consumer/src/main/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumer.java
new file mode 100644 (file)
index 0000000..6c52511
--- /dev/null
@@ -0,0 +1,364 @@
+package org.apache.archiva.plugins.archivereleases;
+
+/*
+ * 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.archiva.admin.model.beans.ManagedRepository;
+import org.apache.archiva.configuration.ArchivaConfiguration;
+import org.apache.archiva.configuration.FileTypes;
+import org.apache.archiva.consumers.AbstractMonitoredConsumer;
+import org.apache.archiva.consumers.ConsumerException;
+import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
+import org.apache.archiva.redback.components.registry.Registry;
+import org.apache.archiva.redback.components.registry.RegistryListener;
+import org.codehaus.plexus.util.SelectorUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <code>ArchiveReleasesConsumer</code>
+ */
+@Service("knownRepositoryContentConsumer#archive-releases")
+@Scope("prototype")
+public class ArchiveReleasesConsumer
+    extends AbstractMonitoredConsumer
+    implements KnownRepositoryContentConsumer, RegistryListener
+{
+
+    private Logger log = LoggerFactory.getLogger( ArchiveReleasesConsumer.class );
+
+    private String id = "archive-releases";
+
+    private String description = "Find releases older than a certain age and move to an archived location.";
+
+    @Inject
+    private FileTypes filetypes;
+
+    @Inject
+    private ArchivaConfiguration configuration;
+
+    private List<String> propertyNameTriggers = new ArrayList<>();
+
+    private List<String> includes = new ArrayList<>();
+
+    private ManagedRepository repository;
+
+    /**
+     * Date before which artifacts are archived. Default is 2 years ago.
+     */
+    @Value( "${archivereleases.age:2 years}" )
+    private String age;
+
+    @Value( "#{'${archivereleases.whitelist:**/**}'.split(',')}" )
+    private List<String> whitelist;
+
+    @Value( "#{'${archivereleases.blacklist:}'.split(',')}" )
+    private List<String> blacklist = Collections.emptyList();
+
+    @Value( "${archivereleases.repositoryArchiveBase:}" )
+    private File repositoryArchiveBase;
+
+    @Value( "${archivereleases.dryRun:true}" )
+    private boolean dryRun;
+
+    private File repositoryArchive;
+
+    private long totalSize = 0;
+
+    private Date olderThan;
+
+    public void beginScan( ManagedRepository repository, Date whenGathered )
+        throws ConsumerException
+    {
+        beginScan( repository, whenGathered, true );
+    }
+
+    public void beginScan( ManagedRepository repository, Date whenGathered, boolean executeOnEntireRepo )
+        throws ConsumerException
+    {
+        olderThan = convertAge( age );
+
+        this.repository = repository;
+        log.info( "Beginning scan of repository [" + this.repository.getId() + "]" );
+
+        if ( repositoryArchiveBase == null && !dryRun )
+        {
+            throw new IllegalArgumentException( "Must configure archivereleases.repositoryArchiveBase" );
+        }
+
+        repositoryArchive = new File( repositoryArchiveBase, repository.getId() );
+
+        log.info( "Starting archive run:" +
+                      "\n  - Releases before:   " + olderThan +
+                      "\n  - Archive directory: " + repositoryArchive +
+                      "\n  - Whitelist:         " + whitelist +
+                      "\n  - Blacklist:         " + blacklist +
+                      "\n  - Dry run:           " + dryRun );
+
+        totalSize = 0;
+    }
+
+    private static Date convertAge( String age )
+    {
+        Calendar cal = Calendar.getInstance();
+
+        Matcher m = Pattern.compile( "([0-9]+) (year|month|day)s?( ago)?" ).matcher( age );
+        if ( !m.matches() )
+        {
+            throw new IllegalArgumentException( "Invalid age: " + age );
+        }
+
+        int amount = Integer.parseInt( m.group( 1 ) );
+        String period = m.group( 2 );
+        switch ( period )
+        {
+            case "year":
+                cal.add( Calendar.YEAR, -amount );
+                break;
+            case "month":
+                cal.add( Calendar.MONTH, -amount );
+                break;
+            case "day":
+                cal.add( Calendar.DAY_OF_MONTH, -amount );
+                break;
+            default:
+                throw new IllegalArgumentException( "Unexpected period: " + period );
+        }
+
+        return cal.getTime();
+    }
+
+    public void processFile( String path )
+        throws ConsumerException
+    {
+        processFile( path, true );
+    }
+
+    public void processFile( String path, boolean executeOnEntireRepo )
+        throws ConsumerException
+    {
+        File artifactFile = new File( repository.getLocation(), path );
+
+        // NOTE: as below, assumes a Maven 2 repository layout
+        if ( artifactFile.getParentFile().getName().endsWith( "-SNAPSHOT" ) )
+        {
+            log.debug( "Skipping entry [" + path + "] as it appears to be a snapshot" );
+            return;
+        }
+
+        if ( filetypes.matchesDefaultExclusions( path ) )
+        {
+            log.debug( "Skipping entry [" + path + "] as it is in the default exclusions" );
+            return;
+        }
+
+        if ( !matchesList( whitelist, path ) )
+        {
+            log.debug( "Skipping entry [" + path + "] as it does not match whitelist" );
+            return;
+        }
+
+        if ( matchesList( blacklist, path ) )
+        {
+            log.debug( "Skipping entry [" + path + " as it matches the blacklist" );
+            return;
+        }
+
+        if ( fileNewerThanTarget( artifactFile ) )
+        {
+            log.debug( "Skipping entry [" + path + "] from repository [" + repository.getId()
+                           + "] as it is newer than the target of " + olderThan );
+            return;
+        }
+
+        // look at other files in the directory, if any are new then don't archive
+        // NOTE: this assumes a Maven 2 repository layout - would be good to get the repository API properly extracted
+        //  without depending on the metadata storage
+        File dir = artifactFile.getParentFile();
+        for ( File f : dir.listFiles() )
+        {
+            if ( !filetypes.matchesDefaultExclusions( f.getName() ) )
+            {
+                if ( matchesList( includes, f.getName() ) )
+                {
+                    if ( fileNewerThanTarget( f ) )
+                    {
+                        log.debug( "Skipping entry [" + path + "] from repository [" + repository.getId()
+                                       + "] as another artifact file [" + f.getName() + "] is newer than the target of "
+                                       + olderThan );
+                        return;
+                    }
+                }
+                else
+                {
+                    // File that is not an artifact and not excluded is not going to get found
+                    log.warn( "Skipping entry [" + path + "] from repository [" + repository.getId()
+                                  + "] due to immovable file [" + f.getName() + "]" );
+                    return;
+                }
+            }
+        }
+
+        File targetFile = new File( repositoryArchive, path );
+        if ( dryRun )
+        {
+            log.info( "DRY RUN: would archive file [" + artifactFile.getAbsolutePath() + "] to [" + targetFile + "]" );
+        }
+        else
+        {
+            log.info( "archiving file [" + artifactFile.getAbsolutePath() + "] to [" + targetFile + "]" );
+
+            if ( !artifactFile.renameTo( targetFile ) )
+            {
+                log.error(
+                    "Unknown error moving file [" + artifactFile.getAbsolutePath() + "] to [" + targetFile + "]" );
+            }
+        }
+
+        totalSize += artifactFile.length();
+    }
+
+    private boolean fileNewerThanTarget( File artifactFile )
+    {
+        return new Date( artifactFile.lastModified() ).after( olderThan );
+    }
+
+    private boolean matchesList( List<String> list, String path )
+    {
+        for ( String w : list )
+        {
+            if ( SelectorUtils.matchPath( w, path ) )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void completeScan()
+    {
+        completeScan( true );
+    }
+
+    public void completeScan( boolean executeOnEntireRepo )
+    {
+        log.info( "Finished scan of repository [" + this.repository.getId() + "]" );
+
+        log.info( "Total size of artifacts archived: " + totalSize + " (" + this.repository.getLocation() + ")" );
+    }
+
+    /**
+     * Used by archiva to determine if the consumer wishes to process all of a repository's entries or just those that
+     * have been modified olderThan the last scan.
+     *
+     * @return boolean true if the consumer wishes to process all entries on each scan, false for only those modified
+     * olderThan the last scan
+     */
+    public boolean isProcessUnmodified()
+    {
+        return super.isProcessUnmodified();
+    }
+
+    public void afterConfigurationChange( org.apache.archiva.redback.components.registry.Registry registry,
+                                          String propertyName, Object propertyValue )
+    {
+        if ( propertyNameTriggers.contains( propertyName ) )
+        {
+            initIncludes();
+        }
+    }
+
+    public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
+    {
+        /* do nothing */
+    }
+
+    private void initIncludes()
+    {
+        // Pass through a set to find uniques
+        Set<String> types = new HashSet<>();
+        types.addAll( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) );
+        types.addAll( filetypes.getFileTypePatterns( FileTypes.INDEXABLE_CONTENT ) );
+
+        includes.clear();
+        includes.addAll( types );
+    }
+
+    @PostConstruct
+    public void initialize()
+    {
+        propertyNameTriggers = new ArrayList<>();
+        propertyNameTriggers.add( "repositoryScanning" );
+        propertyNameTriggers.add( "fileTypes" );
+        propertyNameTriggers.add( "fileType" );
+        propertyNameTriggers.add( "patterns" );
+        propertyNameTriggers.add( "pattern" );
+
+        configuration.addChangeListener( this );
+
+        initIncludes();
+    }
+
+    public String getId()
+    {
+        return this.id;
+    }
+
+    public String getDescription()
+    {
+        return this.description;
+    }
+
+    public List<String> getExcludes()
+    {
+        return null;
+    }
+
+    public List<String> getIncludes()
+    {
+        return this.includes;
+    }
+
+    public boolean isPermanent()
+    {
+        return false;
+    }
+
+    public void setRepositoryArchiveBase( File repositoryArchiveBase )
+    {
+        this.repositoryArchiveBase = repositoryArchiveBase;
+    }
+}
diff --git a/archive-releases-consumer/src/main/resources/META-INF/spring-context.xml b/archive-releases-consumer/src/main/resources/META-INF/spring-context.xml
new file mode 100644 (file)
index 0000000..c586ab1
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+           http://www.springframework.org/schema/context 
+           http://www.springframework.org/schema/context/spring-context-3.1.xsd"
+       default-lazy-init="true">
+  <context:annotation-config/>
+  <context:component-scan base-package="org.apache.archiva.plugins.archivereleases"/>
+  <context:property-placeholder
+      location="${appserver.base}/archivereleases.properties,${user.dir}/archivereleases.properties"
+      ignore-resource-not-found="true"
+      ignore-unresolvable="true"
+      system-properties-mode="OVERRIDE"/>
+</beans>
\ No newline at end of file
diff --git a/archive-releases-consumer/src/test/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumerTest.java b/archive-releases-consumer/src/test/java/org/apache/archiva/plugins/archivereleases/ArchiveReleasesConsumerTest.java
new file mode 100644 (file)
index 0000000..ea302ff
--- /dev/null
@@ -0,0 +1,122 @@
+package org.apache.archiva.plugins.archivereleases;
+
+/*
+ * 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.archiva.admin.model.RepositoryAdminException;
+import org.apache.archiva.admin.model.beans.ManagedRepository;
+import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
+import org.apache.archiva.metadata.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.RepositorySession;
+import org.apache.archiva.metadata.repository.RepositorySessionFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * <code>ArchiveReleasesConsumerTest</code>
+ */
+@RunWith( SpringJUnit4ClassRunner.class )
+@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context.xml" } )
+public class ArchiveReleasesConsumerTest
+{
+    @Inject
+    private ArchiveReleasesConsumer consumer;
+
+    @Inject
+    private ManagedRepositoryAdmin managedRepositoryAdmin;
+
+    @Inject
+    private RepositorySessionFactory repositorySessionFactory;
+
+    private ManagedRepository testRepository;
+
+    private Logger log = LoggerFactory.getLogger( ArchiveReleasesConsumer.class );
+
+    @Before
+    public void setUp()
+        throws Exception
+    {
+        setUpMockRepository();
+
+        RepositorySession repositorySession = mock( RepositorySession.class );
+        when( repositorySessionFactory.createSession() ).thenReturn( repositorySession );
+
+        MetadataRepository metadataRepository = mock( MetadataRepository.class );
+        when( repositorySession.getRepository() ).thenReturn( metadataRepository );
+
+        consumer.setRepositoryArchiveBase( new File( "target/archive" ) );
+    }
+
+    private void setUpMockRepository()
+        throws RepositoryAdminException, IOException
+    {
+        File repoDir = new File( "target/test-consumer-repo" );
+        repoDir.mkdirs();
+        repoDir.deleteOnExit();
+
+        createFile( new File( repoDir, "org/simple/test/testartifact/testartifact/1.0/testartifact-1.0.pom" ) );
+        createFile( new File( repoDir, "org/simple/test/testartifact/testartifact/1.1/testartifact-1.1.pom" ) );
+
+        testRepository = new ManagedRepository();
+        testRepository.setName( "Test-Consumer-Repository" );
+        testRepository.setId( "test-consumer-repository" );
+        testRepository.setLocation( repoDir.getAbsolutePath() );
+
+        when( managedRepositoryAdmin.getManagedRepository( testRepository.getId() ) ).thenReturn( testRepository );
+    }
+
+    private void createFile( File file )
+        throws IOException
+    {
+        file.getParentFile().mkdirs();
+        file.createNewFile();
+    }
+
+    @Test
+    public void testBeginScan()
+        throws Exception
+    {
+        log.info( "Beginning scan of repository [test-consumer-repository]" );
+
+        consumer.beginScan( testRepository, new Date() );
+    }
+
+    @Test
+    public void testProcessFile()
+        throws Exception
+    {
+        consumer.beginScan( testRepository, new Date() );
+        consumer.processFile( "org/simple/test/testartifact/testartifact/1.0/testartifact-1.0.pom" );
+        consumer.processFile( "org/simple/test/testartifact/testartifact/1.1/testartifact-1.1.pom" );
+    }
+
+}
diff --git a/archive-releases-consumer/src/test/resources/log4j2-test.xml b/archive-releases-consumer/src/test/resources/log4j2-test.xml
new file mode 100644 (file)
index 0000000..1b662d7
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ 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.
+  -->
+
+
+<configuration>
+  <appenders>
+    <Console name="console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d [%t] %-5p %c %x - %m%n"/>
+    </Console>
+  </appenders>
+  <loggers>
+
+    <logger name="org.springframework" level="error"/>
+
+    <root level="info">
+      <appender-ref ref="console"/>
+    </root>
+  </loggers>
+</configuration>
+
+
diff --git a/archive-releases-consumer/src/test/resources/spring-context.xml b/archive-releases-consumer/src/test/resources/spring-context.xml
new file mode 100644 (file)
index 0000000..f17d5b4
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:mockito="http://www.mockito.org/spring/mockito"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.mockito.org/spring/mockito http://www.mockito.org/spring/mockito.xsd"
+       default-lazy-init="true">
+
+  <mockito:mock id="mockManagedRepositoryAdmin" class="org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin" />
+  <mockito:mock id="mockRemoteRepositoryAdmin" class="org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin" />
+  <mockito:mock id="mockRepositorySessionFactory" class="org.apache.archiva.metadata.repository.RepositorySessionFactory" />
+
+  <alias alias="repositorySessionFactory#jcr" name="mockRepositorySessionFactory" />
+</beans>
\ No newline at end of file