http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/maven-search-test-repo/org/apache/felix/org.apache.felix.bundlerepository/1.6.6/org.apache.felix.bundlerepository-1.6.6.pom
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/maven-search-test-repo/org/apache/felix/org.apache.felix.bundlerepository/1.6.6/org.apache.felix.bundlerepository-1.6.6.pom
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/maven-search-test-repo/org/apache/felix/org.apache.felix.bundlerepository/1.6.6/org.apache.felix.bundlerepository-1.6.6.pom
deleted file mode 100644
index 19831ee..0000000
--- 
a/archiva-modules/archiva-base/archiva-indexer/src/test/maven-search-test-repo/org/apache/felix/org.apache.felix.bundlerepository/1.6.6/org.apache.felix.bundlerepository-1.6.6.pom
+++ /dev/null
@@ -1,138 +0,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.
--->
-<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";>
-  <parent>
-    <groupId>org.apache.felix</groupId>
-    <artifactId>felix-parent</artifactId>
-    <version>2.1</version>
-    <relativePath>../pom/pom.xml</relativePath>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <packaging>bundle</packaging>
-  <name>Apache Felix Bundle Repository</name>
-  <description>Bundle repository service.</description>
-  <artifactId>org.apache.felix.bundlerepository</artifactId>
-  <version>1.6.6</version>
-  <scm>
-    
<connection>scm:svn:http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</connection>
-    
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</developerConnection>
-    
<url>http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-1.6.6</url>
-  </scm>
-  <dependencies>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>org.apache.felix.utils</artifactId>
-      <version>1.1.0</version>
-      <optional>true</optional>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>org.osgi.service.obr</artifactId>
-      <version>1.0.2</version>
-      <optional>true</optional>
-    </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>org.apache.felix.shell</artifactId>
-      <version>1.4.1</version>
-      <optional>true</optional>
-    </dependency>
-    <dependency>
-      <groupId>net.sf.kxml</groupId>
-      <artifactId>kxml2</artifactId>
-      <version>2.3.0</version>
-      <optional>true</optional>
-      <exclusions>
-        <exclusion>
-          <groupId>xmlpull</groupId>
-          <artifactId>xmlpull</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-        <groupId>org.osgi</groupId>
-        <artifactId>org.osgi.compendium</artifactId>
-        <version>4.0.0</version>
-        <optional>true</optional>
-    </dependency>
-    <dependency>
-       <groupId>org.osgi</groupId>
-        <artifactId>org.osgi.core</artifactId>
-        <version>4.1.0</version>
-    </dependency>
-    <dependency>
-        <groupId>org.codehaus.woodstox</groupId>
-        <artifactId>woodstox-core-asl</artifactId>
-        <version>4.0.7</version>
-        <optional>true</optional>
-    </dependency>
-    <dependency>
-        <groupId>org.easymock</groupId>
-        <artifactId>easymock</artifactId>
-        <version>2.4</version>
-    </dependency>
-  </dependencies>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.3.4</version>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            
<Export-Package>org.apache.felix.bundlerepository;version="2.0"</Export-Package>
-            <Private-Package>
-                org.kxml2.io,
-                org.xmlpull.v1,
-                org.apache.felix.bundlerepository.impl.*,
-                org.apache.felix.utils.*
-            </Private-Package>
-            
<Import-Package>!javax.xml.parsers,!org.xml.sax,org.osgi.service.log;resolution:=optional,org.osgi.service.obr;resolution:=optional,javax.xml.stream;resolution:=optional,*</Import-Package>
-            
<DynamicImport-Package>org.apache.felix.shell</DynamicImport-Package>
-            
<Bundle-Activator>${project.artifactId}.impl.Activator</Bundle-Activator>
-            
<Bundle-DocURL>http://felix.apache.org/site/apache-felix-osgi-bundle-repository.html</Bundle-DocURL>
-            <Bundle-Url>http://felix.apache.org/site/downloads.cgi</Bundle-Url>
-            
<Bundle-Source>http://felix.apache.org/site/downloads.cgi</Bundle-Source>
-            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
-            <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
-            
<Export-Service>org.apache.felix.bundlerepository.RepositoryAdmin,org.osgi.service.obr.RepositoryAdmin</Export-Service>
-            
<_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
-            
<Include-Resource>META-INF/LICENSE=LICENSE,META-INF/LICENSE.kxml2=LICENSE.kxml2,META-INF/NOTICE=NOTICE,META-INF/DEPENDENCIES=DEPENDENCIES</Include-Resource>
-          </instructions>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.rat</groupId>
-        <artifactId>apache-rat-plugin</artifactId>
-        <configuration>
-          <excludeSubProjects>false</excludeSubProjects>
-          <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
-          <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
-          <excludes>
-            <param>doc/*</param>
-            <param>maven-eclipse.xml</param>
-            <param>.checkstyle</param>
-            <param>.externalToolBuilders/*</param>
-          </excludes>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-</project>

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdt
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdt
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdt
deleted file mode 100644
index 9ab6d4d..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdt
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdx
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdx
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdx
deleted file mode 100644
index a26fbfa..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fdx
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fnm
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fnm
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fnm
deleted file mode 100644
index b9f9243..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.fnm
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvd
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvd
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvd
deleted file mode 100644
index d832c2f..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvd
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvm
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvm
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvm
deleted file mode 100644
index a27cff8..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.nvm
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.si
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.si
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.si
deleted file mode 100644
index 2539c76..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8.si
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.doc
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.doc
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.doc
deleted file mode 100644
index 0a2394b..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.doc
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.pos
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.pos
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.pos
deleted file mode 100644
index 4d9bbaa..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.pos
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tim
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tim
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tim
deleted file mode 100644
index ac84752..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tim
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tip
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tip
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tip
deleted file mode 100644
index d94d9c9..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/_8_Lucene41_0.tip
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments.gen
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments.gen
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments.gen
deleted file mode 100644
index 077a451..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments.gen
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments_9
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments_9
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments_9
deleted file mode 100644
index a01b84f..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/segments_9
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/timestamp
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/timestamp
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/timestamp
deleted file mode 100644
index 9028164..0000000
Binary files 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/timestamp
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/write.lock
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/write.lock
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/repo-release/.index/write.lock
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-indexer/src/test/resources/spring-context.xml
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/spring-context.xml
 
b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/spring-context.xml
deleted file mode 100644
index e0bf5c4..0000000
--- 
a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/spring-context.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?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"; 
xmlns:tx="http://www.springframework.org/schema/tx";
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-           http://www.springframework.org/schema/context
-           
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx.xsd";
-       default-lazy-init="false">
-
-  <context:annotation-config/>
-
-  <bean name="scheduler" 
class="org.apache.archiva.redback.components.scheduler.DefaultScheduler">
-    <property name="properties">
-      <props>
-        <prop key="org.quartz.scheduler.instanceName">scheduler1</prop>
-        <prop 
key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
-        <prop key="org.quartz.threadPool.threadCount">2</prop>
-        <prop key="org.quartz.threadPool.threadPriority">4</prop>
-        <prop 
key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
-      </props>
-    </property>
-  </bean>
-  <alias name="userConfiguration#redback" alias="userConfiguration#default"/>
-
-  <!-- ***
-     JPA settings
-     *** -->
-  <bean name="entityManagerFactory" 
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
-    <property name="jpaVendorAdapter" >
-      <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" />
-    </property>
-    <property name="persistenceXmlLocation" 
value="classpath:META-INF/persistence-hsqldb.xml" />
-    <property name="jpaPropertyMap">
-      <map>
-        <entry key="openjpa.ConnectionURL" 
value="jdbc:hsqldb:mem:redback_database" />
-        <entry key="openjpa.ConnectionDriverName" 
value="org.hsqldb.jdbcDriver" />
-        <entry key="openjpa.ConnectionUserName" value="sa" />
-        <entry key="openjpa.ConnectionPassword" value="" />
-        <entry key="openjpa.Log" 
value="${openjpa.Log:DefaultLevel=INFO,Runtime=ERROR,Tool=ERROR,SQL=ERROR,Schema=ERROR,MetaData=ERROR}"
 />
-        <entry key="openjpa.jdbc.SynchronizeMappings" 
value="buildSchema(ForeignKeys=true)" />
-        <entry key="openjpa.jdbc.MappingDefaults"
-               
value="ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>
-      </map>
-    </property>
-
-  </bean>
-
-  <bean name="transactionManager" 
class="org.springframework.orm.jpa.JpaTransactionManager" >
-    <property name="entityManagerFactory" ref="entityManagerFactory" />
-  </bean>
-
-  <tx:annotation-driven />
-  <!-- ***
-     End of JPA settings
-     *** -->
-
-</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/pom.xml
----------------------------------------------------------------------
diff --git a/archiva-modules/archiva-base/archiva-maven2-indexer/pom.xml 
b/archiva-modules/archiva-base/archiva-maven2-indexer/pom.xml
new file mode 100644
index 0000000..f0a90a5
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-maven2-indexer/pom.xml
@@ -0,0 +1,249 @@
+<?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";>
+  <parent>
+    <groupId>org.apache.archiva</groupId>
+    <artifactId>archiva-base</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>archiva-maven2-indexer</artifactId>
+  <packaging>bundle</packaging>
+  <name>Archiva Base :: Maven2 Indexer</name>
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-repository-admin-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-repository-layer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-digest</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-component-api</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.indexer</groupId>
+      <artifactId>indexer-reader</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.indexer</groupId>
+      <artifactId>indexer-core</artifactId>
+      <classifier>shaded-lucene</classifier>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.lucene</groupId>
+          <artifactId>lucene-queryparser</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.lucene</groupId>
+          <artifactId>lucene-analyzers-common</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.sisu</groupId>
+      <artifactId>org.eclipse.sisu.plexus</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.inject</groupId>
+      <artifactId>guice</artifactId>
+      <classifier>no_aop</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-plexus-bridge</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-scheduler-repository</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-mock</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-configuration</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-repository-admin-default</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-test-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-keys-memory</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-rbac-cached</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-rbac-memory</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-users-memory</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-common-test-resources</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http-lightweight</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xercesImpl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <excludes>
+              <exclude>src/test/maven-search-test-repo*/**</exclude>
+              <exclude>src/test/repo-release*/**</exclude>
+            </excludes>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            
<Bundle-SymbolicName>org.apache.archiva.indexer</Bundle-SymbolicName>
+            <Bundle-Version>${project.version}</Bundle-Version>
+            <Export-Package>
+              
org.apache.archiva.indexer.*;version=${project.version};-split-package:=merge-first
+            </Export-Package>
+            <Import-Package>
+              javax.annotation,
+              javax.inject,
+              com.google.common.io,
+              org.apache.archiva.admin.model*;version=${project.version},
+              
org.apache.archiva.common.plexusbridge;version=${project.version},
+              org.apache.commons.io;version="[1.4,2)",
+              org.apache.commons.lang*;version="[2.4,3)",
+              org.apache.lucene*;version="[3,4)",
+              org.springframework*;version="[3,4)",
+              org.apache.maven.index*,
+              org.apache.archiva.redback.components.scheduler,
+              org.quartz,
+              org.apache.archiva.scheduler,
+              org.slf4j;resolution:=optional
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemPropertyVariables>
+            
<appserver.base>${project.build.directory}/appserver-base</appserver.base>
+            
<plexus.home>${project.build.directory}/appserver-base</plexus.home>
+            
<derby.system.home>${project.build.directory}/appserver-base</derby.system.home>
+            <redback.jdbc.url>${redbackTestJdbcUrl}</redback.jdbc.url>
+            
<redback.jdbc.driver.name>${redbackTestJdbcDriver}</redback.jdbc.driver.name>
+            
<archiva.repositorySessionFactory.id>mock</archiva.repositorySessionFactory.id>
+            <openjpa.Log>${openjpa.Log}</openjpa.Log>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultIndexMerger.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultIndexMerger.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultIndexMerger.java
new file mode 100644
index 0000000..b4daa8b
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultIndexMerger.java
@@ -0,0 +1,173 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * 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.common.utils.FileUtils;
+import org.apache.commons.lang.time.StopWatch;
+import org.apache.maven.index.NexusIndexer;
+import org.apache.maven.index.context.IndexCreator;
+import org.apache.maven.index.context.IndexingContext;
+import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
+import org.apache.maven.index.packer.IndexPacker;
+import org.apache.maven.index.packer.IndexPackingRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * @author Olivier Lamy
+ * @since 1.4-M2
+ */
+@Service("indexMerger#default")
+public class DefaultIndexMerger
+    implements IndexMerger
+{
+
+    private Logger log = LoggerFactory.getLogger( getClass() );
+
+    private final NexusIndexer indexer;
+
+    private final IndexPacker indexPacker;
+
+    private final List<IndexCreator> indexCreators;
+
+    private List<TemporaryGroupIndex> temporaryGroupIndexes = new 
CopyOnWriteArrayList<>();
+
+    private List<String> runningGroups = new CopyOnWriteArrayList<>();
+
+    @Inject
+    public DefaultIndexMerger( NexusIndexer nexusIndexer, IndexPacker 
indexPacker, List<IndexCreator> indexCreators )
+    {
+        this.indexer = nexusIndexer;
+        this.indexPacker = indexPacker;
+        this.indexCreators = indexCreators;
+    }
+
+    @Override
+    public IndexingContext buildMergedIndex( IndexMergerRequest 
indexMergerRequest )
+        throws IndexMergerException
+    {
+        String groupId = indexMergerRequest.getGroupId();
+
+        if ( runningGroups.contains( groupId ) )
+        {
+            log.info( "skip build merge remote indexes for id: '{}' as already 
running", groupId );
+            return null;
+        }
+
+        runningGroups.add( groupId );
+
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.reset();
+        stopWatch.start();
+
+        Path mergedIndexDirectory = 
indexMergerRequest.getMergedIndexDirectory();
+
+        String tempRepoId = mergedIndexDirectory.getFileName().toString();
+
+        try
+        {
+            Path indexLocation = mergedIndexDirectory.resolve( 
indexMergerRequest.getMergedIndexPath() );
+            IndexingContext indexingContext =
+                indexer.addIndexingContext( tempRepoId, tempRepoId, 
mergedIndexDirectory.toFile(), indexLocation.toFile(), null, null,
+                                            indexCreators );
+
+            for ( String repoId : indexMergerRequest.getRepositoriesIds() )
+            {
+                IndexingContext idxToMerge = 
indexer.getIndexingContexts().get( repoId );
+                if ( idxToMerge != null )
+                {
+                    indexingContext.merge( idxToMerge.getIndexDirectory() );
+                }
+            }
+
+            indexingContext.optimize();
+
+            if ( indexMergerRequest.isPackIndex() )
+            {
+                IndexPackingRequest request = new IndexPackingRequest( 
indexingContext, //
+                                                                       
indexingContext.acquireIndexSearcher().getIndexReader(), //
+                                                                       
indexLocation.toFile() );
+                indexPacker.packIndex( request );
+            }
+
+            if ( indexMergerRequest.isTemporary() )
+            {
+                temporaryGroupIndexes.add( new TemporaryGroupIndex( 
mergedIndexDirectory, tempRepoId, groupId,
+                                                                    
indexMergerRequest.getMergedIndexTtl() ) );
+            }
+            stopWatch.stop();
+            log.info( "merged index for repos {} in {} s", 
indexMergerRequest.getRepositoriesIds(),
+                      stopWatch.getTime() );
+            return indexingContext;
+        }
+        catch ( IOException | UnsupportedExistingLuceneIndexException e )
+        {
+            throw new IndexMergerException( e.getMessage(), e );
+        }
+        finally
+        {
+            runningGroups.remove( groupId );
+        }
+    }
+
+    @Async
+    @Override
+    public void cleanTemporaryGroupIndex( TemporaryGroupIndex 
temporaryGroupIndex )
+    {
+        if ( temporaryGroupIndex == null )
+        {
+            return;
+        }
+
+        try
+        {
+            IndexingContext indexingContext = 
indexer.getIndexingContexts().get( temporaryGroupIndex.getIndexId() );
+            if ( indexingContext != null )
+            {
+                indexer.removeIndexingContext( indexingContext, true );
+            }
+            Path directory = temporaryGroupIndex.getDirectory();
+            if ( directory != null && Files.exists(directory) )
+            {
+                FileUtils.deleteDirectory( directory );
+            }
+            temporaryGroupIndexes.remove( temporaryGroupIndex );
+        }
+        catch ( IOException e )
+        {
+            log.warn( "fail to delete temporary group index {}", 
temporaryGroupIndex.getIndexId(), e );
+        }
+    }
+
+    @Override
+    public Collection<TemporaryGroupIndex> getTemporaryGroupIndexes()
+    {
+        return this.temporaryGroupIndexes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultMergedRemoteIndexesScheduler.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultMergedRemoteIndexesScheduler.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultMergedRemoteIndexesScheduler.java
new file mode 100644
index 0000000..f0fbcbd
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/DefaultMergedRemoteIndexesScheduler.java
@@ -0,0 +1,94 @@
+package org.apache.archiva.indexer.merger;
+
+/*
+ * 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.RepositoryGroup;
+import org.apache.archiva.scheduler.MergedRemoteIndexesScheduler;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.support.CronTrigger;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledFuture;
+
+/**
+ * @author Olivier Lamy
+ * @since 2.0.0
+ */
+@Service( "mergedRemoteIndexesScheduler#default" )
+public class DefaultMergedRemoteIndexesScheduler
+    implements MergedRemoteIndexesScheduler
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    @Inject
+    @Named( value = "taskScheduler#mergeRemoteIndexes" )
+    private TaskScheduler taskScheduler;
+
+    @Inject
+    private IndexMerger indexMerger;
+
+    private Map<String, ScheduledFuture> scheduledFutureMap = new 
ConcurrentHashMap<>();
+
+    @Override
+    public void schedule( RepositoryGroup repositoryGroup, Path directory )
+    {
+        if ( StringUtils.isEmpty( repositoryGroup.getCronExpression() ) )
+        {
+            return;
+        }
+        CronTrigger cronTrigger = new CronTrigger( 
repositoryGroup.getCronExpression() );
+
+        List<String> repositories = repositoryGroup.getRepositories();
+
+        IndexMergerRequest indexMergerRequest =
+            new IndexMergerRequest( repositories, true, 
repositoryGroup.getId(), repositoryGroup.getMergedIndexPath(),
+                                    repositoryGroup.getMergedIndexTtl() 
).mergedIndexDirectory( directory );
+
+        MergedRemoteIndexesTaskRequest taskRequest =
+            new MergedRemoteIndexesTaskRequest( indexMergerRequest, 
indexMerger );
+
+        logger.info( "schedule merge remote index for group {} with cron {}", 
repositoryGroup.getId(),
+                     repositoryGroup.getCronExpression() );
+
+        ScheduledFuture scheduledFuture =
+            taskScheduler.schedule( new MergedRemoteIndexesTask( taskRequest 
), cronTrigger );
+        scheduledFutureMap.put( repositoryGroup.getId(), scheduledFuture );
+    }
+
+    @Override
+    public void unschedule( RepositoryGroup repositoryGroup )
+    {
+        ScheduledFuture scheduledFuture = scheduledFutureMap.remove( 
repositoryGroup.getId() );
+        if ( scheduledFuture != null )
+        {
+            scheduledFuture.cancel( true );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMerger.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMerger.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMerger.java
new file mode 100644
index 0000000..756819e
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMerger.java
@@ -0,0 +1,42 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.index.context.IndexingContext;
+
+import java.util.Collection;
+
+/**
+ * @author Olivier Lamy
+ * @since 1.4-M2
+ */
+public interface IndexMerger
+{
+    /**
+     * @param indexMergerRequest
+     * @return a temporary directory with a merge index (directory marked 
deleteOnExit)
+     * @throws IndexMergerException
+     */
+    IndexingContext buildMergedIndex( IndexMergerRequest indexMergerRequest )
+        throws IndexMergerException;
+
+    void cleanTemporaryGroupIndex( TemporaryGroupIndex temporaryGroupIndex );
+
+    Collection<TemporaryGroupIndex> getTemporaryGroupIndexes();
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerException.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerException.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerException.java
new file mode 100644
index 0000000..3930831
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerException.java
@@ -0,0 +1,32 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @author Olivier Lamy
+ * @since 1.4-M2
+ */
+public class IndexMergerException
+    extends Exception
+{
+    public IndexMergerException( String message, Throwable t )
+    {
+        super( message, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerRequest.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerRequest.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerRequest.java
new file mode 100644
index 0000000..0b3803f
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/IndexMergerRequest.java
@@ -0,0 +1,192 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * 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.nio.file.Path;
+import java.util.Collection;
+
+/**
+ * @author Olivier Lamy
+ */
+public class IndexMergerRequest
+{
+    /**
+     * repositories Ids to merge content
+     */
+    private Collection<String> repositoriesIds;
+
+    /**
+     * will generate a downloadable index
+     */
+    private boolean packIndex;
+
+    /**
+     * original groupId (repositoryGroup id)
+     */
+    private String groupId;
+
+    private String mergedIndexPath = ".indexer";
+
+    private int mergedIndexTtl;
+
+    private Path mergedIndexDirectory;
+
+    private boolean temporary;
+
+    public IndexMergerRequest( Collection<String> repositoriesIds, boolean 
packIndex, String groupId )
+    {
+        this.repositoriesIds = repositoriesIds;
+        this.packIndex = packIndex;
+        this.groupId = groupId;
+    }
+
+    /**
+     * @since 1.4-M4
+     */
+    public IndexMergerRequest( Collection<String> repositoriesIds, boolean 
packIndex, String groupId,
+                               String mergedIndexPath, int mergedIndexTtl )
+    {
+        this.repositoriesIds = repositoriesIds;
+        this.packIndex = packIndex;
+        this.groupId = groupId;
+        this.mergedIndexPath = mergedIndexPath;
+        this.mergedIndexTtl = mergedIndexTtl;
+    }
+
+    public Collection<String> getRepositoriesIds()
+    {
+        return repositoriesIds;
+    }
+
+    public void setRepositoriesIds( Collection<String> repositoriesIds )
+    {
+        this.repositoriesIds = repositoriesIds;
+    }
+
+    public boolean isPackIndex()
+    {
+        return packIndex;
+    }
+
+    public void setPackIndex( boolean packIndex )
+    {
+        this.packIndex = packIndex;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    public void setGroupId( String groupId )
+    {
+        this.groupId = groupId;
+    }
+
+    public String getMergedIndexPath()
+    {
+        return mergedIndexPath;
+    }
+
+    public void setMergedIndexPath( String mergedIndexPath )
+    {
+        this.mergedIndexPath = mergedIndexPath;
+    }
+
+    public int getMergedIndexTtl()
+    {
+        return mergedIndexTtl;
+    }
+
+    public void setMergedIndexTtl( int mergedIndexTtl )
+    {
+        this.mergedIndexTtl = mergedIndexTtl;
+    }
+
+    public Path getMergedIndexDirectory()
+    {
+        return mergedIndexDirectory;
+    }
+
+    public void setMergedIndexDirectory( Path mergedIndexDirectory )
+    {
+        this.mergedIndexDirectory = mergedIndexDirectory;
+    }
+
+    public IndexMergerRequest mergedIndexDirectory( Path mergedIndexDirectory )
+    {
+        this.mergedIndexDirectory = mergedIndexDirectory;
+        return this;
+    }
+
+    public boolean isTemporary()
+    {
+        return temporary;
+    }
+
+    public void setTemporary( boolean temporary )
+    {
+        this.temporary = temporary;
+    }
+
+
+    public IndexMergerRequest temporary( boolean temporary )
+    {
+        this.temporary = temporary;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "IndexMergerRequest{" );
+        sb.append( "repositoriesIds=" ).append( repositoriesIds );
+        sb.append( ", packIndex=" ).append( packIndex );
+        sb.append( ", groupId='" ).append( groupId ).append( '\'' );
+        sb.append( ", mergedIndexPath='" ).append( mergedIndexPath ).append( 
'\'' );
+        sb.append( ", mergedIndexTtl=" ).append( mergedIndexTtl );
+        sb.append( ", mergedIndexDirectory=" ).append( mergedIndexDirectory );
+        sb.append( ", temporary=" ).append( temporary );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        IndexMergerRequest that = (IndexMergerRequest) o;
+
+        return groupId.equals( that.groupId );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return groupId.hashCode();
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTask.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTask.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTask.java
new file mode 100644
index 0000000..c67d312
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTask.java
@@ -0,0 +1,89 @@
+package org.apache.archiva.indexer.merger;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.index.context.IndexingContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Olivier Lamy
+ * @since 2.0.0
+ */
+public class MergedRemoteIndexesTask
+    implements Runnable
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private MergedRemoteIndexesTaskRequest mergedRemoteIndexesTaskRequest;
+
+    public MergedRemoteIndexesTask( MergedRemoteIndexesTaskRequest 
mergedRemoteIndexesTaskRequest )
+    {
+        this.mergedRemoteIndexesTaskRequest = mergedRemoteIndexesTaskRequest;
+    }
+
+    @Override
+    public void run()
+    {
+        try
+        {
+            this.execute();
+        }
+        catch ( IndexMergerException e )
+        {
+            logger.error( e.getMessage(), e );
+        }
+    }
+
+    public MergedRemoteIndexesTaskResult execute()
+        throws IndexMergerException
+    {
+        IndexMerger indexMerger = 
mergedRemoteIndexesTaskRequest.getIndexMerger();
+
+        IndexingContext indexingContext =
+            indexMerger.buildMergedIndex( 
mergedRemoteIndexesTaskRequest.getIndexMergerRequest() );
+
+        return new MergedRemoteIndexesTaskResult( indexingContext );
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( !( o instanceof MergedRemoteIndexesTask ) )
+        {
+            return false;
+        }
+
+        MergedRemoteIndexesTask that = (MergedRemoteIndexesTask) o;
+
+        return mergedRemoteIndexesTaskRequest.equals( 
that.mergedRemoteIndexesTaskRequest );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return mergedRemoteIndexesTaskRequest.hashCode();
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskRequest.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskRequest.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskRequest.java
new file mode 100644
index 0000000..bc0663d
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskRequest.java
@@ -0,0 +1,80 @@
+package org.apache.archiva.indexer.merger;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @author Olivier Lamy
+ * @since 2.0.0
+ */
+public class MergedRemoteIndexesTaskRequest
+{
+    private IndexMergerRequest indexMergerRequest;
+
+    private IndexMerger indexMerger;
+
+    public MergedRemoteIndexesTaskRequest( IndexMergerRequest 
indexMergerRequest, IndexMerger indexMerger )
+    {
+        this.indexMergerRequest = indexMergerRequest;
+        this.indexMerger = indexMerger;
+    }
+
+    public IndexMergerRequest getIndexMergerRequest()
+    {
+        return indexMergerRequest;
+    }
+
+    public void setIndexMergerRequest( IndexMergerRequest indexMergerRequest )
+    {
+        this.indexMergerRequest = indexMergerRequest;
+    }
+
+    public IndexMerger getIndexMerger()
+    {
+        return indexMerger;
+    }
+
+    public void setIndexMerger( IndexMerger indexMerger )
+    {
+        this.indexMerger = indexMerger;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        MergedRemoteIndexesTaskRequest that = (MergedRemoteIndexesTaskRequest) 
o;
+
+        return indexMergerRequest.equals( that.indexMergerRequest );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return indexMergerRequest.hashCode();
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskResult.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskResult.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskResult.java
new file mode 100644
index 0000000..b75a292
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/MergedRemoteIndexesTaskResult.java
@@ -0,0 +1,46 @@
+package org.apache.archiva.indexer.merger;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.index.context.IndexingContext;
+
+/**
+ * @author Olivier Lamy
+ * @since 2.0.0
+ */
+public class MergedRemoteIndexesTaskResult
+{
+    private IndexingContext indexingContext;
+
+    public MergedRemoteIndexesTaskResult( IndexingContext indexingContext )
+    {
+        this.indexingContext = indexingContext;
+    }
+
+    public IndexingContext getIndexingContext()
+    {
+        return indexingContext;
+    }
+
+    public void setIndexingContext( IndexingContext indexingContext )
+    {
+        this.indexingContext = indexingContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndex.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndex.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndex.java
new file mode 100644
index 0000000..d0b576b
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndex.java
@@ -0,0 +1,119 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * 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.Serializable;
+import java.nio.file.Path;
+import java.util.Date;
+
+/**
+ * @author Olivier Lamy
+ */
+public class TemporaryGroupIndex
+    implements Serializable
+{
+    private long creationTime = new Date().getTime();
+
+    private Path directory;
+
+    private String indexId;
+
+    private String groupId;
+
+    private int mergedIndexTtl;
+
+    public TemporaryGroupIndex(Path directory, String indexId, String groupId, 
int mergedIndexTtl)
+    {
+        this.directory = directory;
+        this.indexId = indexId;
+        this.groupId = groupId;
+        this.mergedIndexTtl = mergedIndexTtl;
+    }
+
+    public long getCreationTime()
+    {
+        return creationTime;
+    }
+
+    public TemporaryGroupIndex setCreationTime( long creationTime )
+    {
+        this.creationTime = creationTime;
+        return this;
+    }
+
+    public Path getDirectory()
+    {
+        return directory;
+    }
+
+    public TemporaryGroupIndex setDirectory( Path directory )
+    {
+        this.directory = directory;
+        return this;
+    }
+
+    public String getIndexId()
+    {
+        return indexId;
+    }
+
+    public TemporaryGroupIndex setIndexId( String indexId )
+    {
+        this.indexId = indexId;
+        return this;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    public void setGroupId( String groupId )
+    {
+        this.groupId = groupId;
+    }
+
+    public int getMergedIndexTtl() {
+        return mergedIndexTtl;
+    }
+
+    public void setMergedIndexTtl(int mergedIndexTtl) {
+        this.mergedIndexTtl = mergedIndexTtl;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Long.toString( creationTime ).hashCode();
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( !( o instanceof TemporaryGroupIndex ) )
+        {
+            return false;
+        }
+        return this.creationTime == ( (TemporaryGroupIndex) o ).creationTime;
+    }
+}

http://git-wip-us.apache.org/repos/asf/archiva/blob/07d51cc3/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndexCleaner.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndexCleaner.java
 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndexCleaner.java
new file mode 100644
index 0000000..dc7f5c0
--- /dev/null
+++ 
b/archiva-modules/archiva-base/archiva-maven2-indexer/src/main/java/org/apache/archiva/indexer/merger/TemporaryGroupIndexCleaner.java
@@ -0,0 +1,73 @@
+package org.apache.archiva.indexer.merger;
+/*
+ * 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.common.plexusbridge.PlexusSisuBridge;
+import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
+import org.apache.maven.index.NexusIndexer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import java.util.Date;
+
+/**
+ * @author Olivier Lamy
+ * @since 1.4-M2
+ */
+@Service
+public class TemporaryGroupIndexCleaner
+{
+    private Logger log = LoggerFactory.getLogger( getClass() );
+
+    @Inject
+    private IndexMerger indexMerger;
+
+    private NexusIndexer indexer;
+
+    @Inject
+    public TemporaryGroupIndexCleaner( NexusIndexer nexusIndexer )
+        throws PlexusSisuBridgeException
+    {
+        this.indexer = nexusIndexer;
+    }
+
+    // 900000
+    @Scheduled(fixedDelay = 900000)
+    public void cleanTemporaryIndex()
+    {
+
+        indexMerger.getTemporaryGroupIndexes()
+            .stream()
+            .forEach( temporaryGroupIndex ->
+                 {
+                     // cleanup files older than the ttl
+                     if ( new Date().getTime() - 
temporaryGroupIndex.getCreationTime() >
+                         temporaryGroupIndex.getMergedIndexTtl() )
+                     {
+                         log.info( "cleanTemporaryIndex for groupId {}", 
temporaryGroupIndex.getGroupId() );
+                         indexMerger.cleanTemporaryGroupIndex( 
temporaryGroupIndex );
+
+                     }
+                 }
+        );
+    }
+}

Reply via email to