]> source.dussan.org Git - archiva.git/commitdiff
all tests pass so move out metadata-store-cassandra from sandbox
authorOlivier Lamy <olamy@apache.org>
Mon, 10 Jun 2013 10:59:20 +0000 (10:59 +0000)
committerOlivier Lamy <olamy@apache.org>
Mon, 10 Jun 2013 10:59:20 +0000 (10:59 +0000)
git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1491410 13f79535-47bb-0310-9956-ffa450edef68

16 files changed:
archiva-modules/plugins/metadata-store-cassandra/pom.xml [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraEntityManagerFactory.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/DefaultCassandraEntityManagerFactory.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ArtifactMetadataModel.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/MetadataFacetModel.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Namespace.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Project.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ProjectVersionMetadataModel.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Repository.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/main/resources/META-INF/spring-context.xml [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/test/filtered-resources/META-INF/spring-context.xml [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/RepositoriesNamespaceTest.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-cassandra/src/test/resources/log4j2-test.xml [new file with mode: 0644]

diff --git a/archiva-modules/plugins/metadata-store-cassandra/pom.xml b/archiva-modules/plugins/metadata-store-cassandra/pom.xml
new file mode 100644 (file)
index 0000000..80028d5
--- /dev/null
@@ -0,0 +1,305 @@
+<?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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>plugins</artifactId>
+    <groupId>org.apache.archiva</groupId>
+    <version>1.4.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>metadata-store-cassandra</artifactId>
+  <packaging>bundle</packaging>
+  <name>Archiva Core Plugins :: Cassandra JPA Storage for Metadata</name>
+
+  <properties>
+    <cassandraVersion>1.2.5</cassandraVersion>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-repository-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-repository-api</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>archiva-test-utils</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>net.sf.beanlib</groupId>
+      <artifactId>beanlib</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>cglib</groupId>
+          <artifactId>cglib</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>aopalliance</groupId>
+          <artifactId>aopalliance</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>log4j</groupId>
+          <artifactId>log4j</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jpa_2.0_spec</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.netflix.astyanax</groupId>
+      <artifactId>astyanax-entity-mapper</artifactId>
+      <version>1.56.37</version>
+      <exclusions>
+        <exclusion>
+          <groupId>stax</groupId>
+          <artifactId>stax-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>log4j</groupId>
+          <artifactId>log4j</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-log4j12</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.cassandra</groupId>
+          <artifactId>cassandra-thrift</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>javax.persistence</groupId>
+          <artifactId>persistence-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.netty</groupId>
+          <artifactId>netty</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>com.netflix.astyanax</groupId>
+      <artifactId>astyanax-core</artifactId>
+      <version>1.56.37</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.netflix.astyanax</groupId>
+      <artifactId>astyanax-thrift</artifactId>
+      <version>1.56.37</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.cassandra</groupId>
+          <artifactId>cassandra-thrift</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.cassandra</groupId>
+      <artifactId>cassandra-all</artifactId>
+      <version>${cassandraVersion}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>log4j</groupId>
+          <artifactId>log4j</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-log4j12</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.mortbay.jetty</groupId>
+          <artifactId>jetty</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-jcl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easytesting</groupId>
+      <artifactId>fest-assert-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-1.2-api</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.lmax</groupId>
+      <artifactId>disruptor</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-core-asl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-mapper-asl</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+  <build>
+    <testResources>
+      <testResource>
+        <directory>src/test/filtered-resources</directory>
+        <filtering>true</filtering>
+      </testResource>
+    </testResources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>org.apache.archiva.metadata.repository.cassandra</Bundle-SymbolicName>
+            <Bundle-Version>${project.version}</Bundle-Version>
+            <Export-Package>
+              org.apache.archiva.metadata.repository.cassandra;version=${project.version};-split-package:=merge-first
+            </Export-Package>
+            <Import-Package>
+
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>reserve-ports</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>reserve-network-port</goal>
+            </goals>
+            <configuration>
+              <portNames>
+                <portName>cassandraPort</portName>
+              </portNames>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- TODO use dynamic port -->
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>cassandra-maven-plugin</artifactId>
+        <version>1.2.1-1</version>
+        <executions>
+          <execution>
+            <id>start-cassandra</id>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>start</goal>
+            </goals>
+            <configuration>
+              <rpcPort>${cassandraPort}</rpcPort>
+            </configuration>
+          </execution>
+          <execution>
+            <id>stop-cassandra</id>
+            <phase>test</phase>
+            <goals>
+              <goal>stop</goal>
+            </goals>
+          </execution>
+        </executions>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.cassandra</groupId>
+            <artifactId>cassandra-all</artifactId>
+            <version>${cassandraVersion}</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <systemPropertyVariables>
+              <cassandraPort>${cassandraPort}</cassandraPort>
+            </systemPropertyVariables>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <repositories>
+    <repository>
+      <id>archiva.snapshots</id>
+      <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/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraEntityManagerFactory.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraEntityManagerFactory.java
new file mode 100644 (file)
index 0000000..da5a8b6
--- /dev/null
@@ -0,0 +1,31 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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 com.netflix.astyanax.Keyspace;
+
+/**
+ * @author Olivier Lamy
+ */
+public interface CassandraEntityManagerFactory
+{
+    Keyspace getKeyspace();
+
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java
new file mode 100644 (file)
index 0000000..33d7378
--- /dev/null
@@ -0,0 +1,1889 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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 com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.netflix.astyanax.Keyspace;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.connectionpool.exceptions.NotFoundException;
+import com.netflix.astyanax.entitystore.DefaultEntityManager;
+import com.netflix.astyanax.entitystore.EntityManager;
+import net.sf.beanlib.provider.replicator.BeanReplicator;
+import org.apache.archiva.configuration.ArchivaConfiguration;
+import org.apache.archiva.metadata.model.ArtifactMetadata;
+import org.apache.archiva.metadata.model.FacetedMetadata;
+import org.apache.archiva.metadata.model.MetadataFacet;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.ProjectMetadata;
+import org.apache.archiva.metadata.model.ProjectVersionMetadata;
+import org.apache.archiva.metadata.model.ProjectVersionReference;
+import org.apache.archiva.metadata.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataRepositoryException;
+import org.apache.archiva.metadata.repository.MetadataResolutionException;
+import org.apache.archiva.metadata.repository.cassandra.model.ArtifactMetadataModel;
+import org.apache.archiva.metadata.repository.cassandra.model.MetadataFacetModel;
+import org.apache.archiva.metadata.repository.cassandra.model.Namespace;
+import org.apache.archiva.metadata.repository.cassandra.model.Project;
+import org.apache.archiva.metadata.repository.cassandra.model.ProjectVersionMetadataModel;
+import org.apache.archiva.metadata.repository.cassandra.model.Repository;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.PersistenceException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * @author Olivier Lamy
+ */
+public class CassandraMetadataRepository
+    implements MetadataRepository
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private ArchivaConfiguration configuration;
+
+    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
+
+    private Keyspace keyspace;
+
+    private EntityManager<Repository, String> repositoryEntityManager;
+
+    private EntityManager<Namespace, String> namespaceEntityManager;
+
+    private EntityManager<Project, String> projectEntityManager;
+
+    private EntityManager<ArtifactMetadataModel, String> artifactMetadataModelEntityManager;
+
+    private EntityManager<MetadataFacetModel, String> metadataFacetModelEntityManager;
+
+    private EntityManager<ProjectVersionMetadataModel, String> projectVersionMetadataModelEntityManager;
+
+    public CassandraMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
+                                        ArchivaConfiguration configuration, Keyspace keyspace )
+    {
+        this.metadataFacetFactories = metadataFacetFactories;
+        this.configuration = configuration;
+
+        this.keyspace = keyspace;
+
+        try
+        {
+            Properties properties = keyspace.getKeyspaceProperties();
+            logger.info( "keyspace properties: {}", properties );
+        }
+        catch ( ConnectionException e )
+        {
+            // FIXME better logging !
+            logger.warn( e.getMessage(), e );
+        }
+
+        try
+        {
+            repositoryEntityManager =
+                new DefaultEntityManager.Builder<Repository, String>().withEntityType( Repository.class ).withKeyspace(
+                    keyspace ).build();
+            boolean exists = columnFamilyExists( "repository" );
+            // TODO very basic test we must test model change too
+            if ( !exists )
+            {
+                repositoryEntityManager.createStorage( null );
+            }
+
+            namespaceEntityManager =
+                new DefaultEntityManager.Builder<Namespace, String>().withEntityType( Namespace.class ).withKeyspace(
+                    keyspace ).build();
+
+            exists = columnFamilyExists( "namespace" );
+            if ( !exists )
+            {
+                namespaceEntityManager.createStorage( null );
+            }
+
+            projectEntityManager =
+                new DefaultEntityManager.Builder<Project, String>().withEntityType( Project.class ).withKeyspace(
+                    keyspace ).build();
+
+            exists = columnFamilyExists( "project" );
+            if ( !exists )
+            {
+                projectEntityManager.createStorage( null );
+            }
+
+            artifactMetadataModelEntityManager =
+                new DefaultEntityManager.Builder<ArtifactMetadataModel, String>().withEntityType(
+                    ArtifactMetadataModel.class ).withKeyspace( keyspace ).build();
+
+            exists = columnFamilyExists( "artifactmetadatamodel" );
+            if ( !exists )
+            {
+                artifactMetadataModelEntityManager.createStorage( null );
+            }
+
+            metadataFacetModelEntityManager =
+                new DefaultEntityManager.Builder<MetadataFacetModel, String>().withEntityType(
+                    MetadataFacetModel.class ).withKeyspace( keyspace ).build();
+
+            exists = columnFamilyExists( "metadatafacetmodel" );
+            if ( !exists )
+            {
+                metadataFacetModelEntityManager.createStorage( null );
+            }
+
+            projectVersionMetadataModelEntityManager =
+                new DefaultEntityManager.Builder<ProjectVersionMetadataModel, String>().withEntityType(
+                    ProjectVersionMetadataModel.class ).withKeyspace( keyspace ).build();
+
+            exists = columnFamilyExists( "projectversionmetadatamodel" );
+            if ( !exists )
+            {
+                projectVersionMetadataModelEntityManager.createStorage( null );
+            }
+
+        }
+        catch ( PersistenceException e )
+        {
+            // FIXME report exception
+            logger.error( e.getMessage(), e );
+        }
+        catch ( ConnectionException e )
+        {
+            // FIXME report exception
+            logger.error( e.getMessage(), e );
+        }
+    }
+
+    private boolean columnFamilyExists( String columnFamilyName )
+        throws ConnectionException
+    {
+        try
+        {
+            Properties properties = keyspace.getColumnFamilyProperties( columnFamilyName );
+            logger.debug( "getColumnFamilyProperties for {}: {}", columnFamilyName, properties );
+            return true;
+        }
+        catch ( NotFoundException e )
+        {
+            return false;
+        }
+    }
+
+    public EntityManager<Repository, String> getRepositoryEntityManager()
+    {
+        return repositoryEntityManager;
+    }
+
+    public EntityManager<Namespace, String> getNamespaceEntityManager()
+    {
+        return namespaceEntityManager;
+    }
+
+    public void setRepositoryEntityManager( EntityManager<Repository, String> repositoryEntityManager )
+    {
+        this.repositoryEntityManager = repositoryEntityManager;
+    }
+
+    public void setNamespaceEntityManager( EntityManager<Namespace, String> namespaceEntityManager )
+    {
+        this.namespaceEntityManager = namespaceEntityManager;
+    }
+
+    public EntityManager<Project, String> getProjectEntityManager()
+    {
+        return projectEntityManager;
+    }
+
+    public void setProjectEntityManager( EntityManager<Project, String> projectEntityManager )
+    {
+        this.projectEntityManager = projectEntityManager;
+    }
+
+    public EntityManager<ArtifactMetadataModel, String> getArtifactMetadataModelEntityManager()
+    {
+        return artifactMetadataModelEntityManager;
+    }
+
+    public void setArtifactMetadataModelEntityManager(
+        EntityManager<ArtifactMetadataModel, String> artifactMetadataModelEntityManager )
+    {
+        this.artifactMetadataModelEntityManager = artifactMetadataModelEntityManager;
+    }
+
+    public EntityManager<MetadataFacetModel, String> getMetadataFacetModelEntityManager()
+    {
+        return metadataFacetModelEntityManager;
+    }
+
+    public void setMetadataFacetModelEntityManager(
+        EntityManager<MetadataFacetModel, String> metadataFacetModelEntityManager )
+    {
+        this.metadataFacetModelEntityManager = metadataFacetModelEntityManager;
+    }
+
+    public EntityManager<ProjectVersionMetadataModel, String> getProjectVersionMetadataModelEntityManager()
+    {
+        return projectVersionMetadataModelEntityManager;
+    }
+
+    public void setProjectVersionMetadataModelEntityManager(
+        EntityManager<ProjectVersionMetadataModel, String> projectVersionMetadataModelEntityManager )
+    {
+        this.projectVersionMetadataModelEntityManager = projectVersionMetadataModelEntityManager;
+    }
+
+    @Override
+    public void updateNamespace( String repositoryId, String namespaceId )
+        throws MetadataRepositoryException
+    {
+        updateOrAddNamespace( repositoryId, namespaceId );
+
+    }
+
+    public Namespace updateOrAddNamespace( String repositoryId, String namespaceId )
+        throws MetadataRepositoryException
+    {
+        try
+        {
+            Repository repository = this.repositoryEntityManager.get( repositoryId );
+
+            if ( repository == null )
+            {
+                repository = new Repository( repositoryId );
+
+                Namespace namespace = new Namespace( namespaceId, repository );
+                this.repositoryEntityManager.put( repository );
+
+                this.namespaceEntityManager.put( namespace );
+            }
+            // FIXME add a Namespace id builder
+            Namespace namespace = namespaceEntityManager.get(
+                new Namespace.KeyBuilder().withNamespace( namespaceId ).withRepositoryId( repositoryId ).build() );
+            if ( namespace == null )
+            {
+                namespace = new Namespace( namespaceId, repository );
+                namespaceEntityManager.put( namespace );
+            }
+            return namespace;
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+
+    }
+
+
+    @Override
+    public void removeNamespace( String repositoryId, String namespaceId )
+        throws MetadataRepositoryException
+    {
+        try
+        {
+            Namespace namespace = namespaceEntityManager.get(
+                new Namespace.KeyBuilder().withNamespace( namespaceId ).withRepositoryId( repositoryId ).build() );
+            if ( namespace != null )
+            {
+                namespaceEntityManager.remove( namespace );
+            }
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+    }
+
+
+    @Override
+    public void removeRepository( final String repositoryId )
+        throws MetadataRepositoryException
+    {
+        try
+        {
+            final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+
+            // remove data related to the repository
+            this.artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+            {
+                @Override
+                public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+                {
+                    if ( artifactMetadataModel != null )
+                    {
+                        if ( StringUtils.equals( artifactMetadataModel.getRepositoryId(), repositoryId ) )
+                        {
+                            artifactMetadataModels.add( artifactMetadataModel );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            artifactMetadataModelEntityManager.remove( artifactMetadataModels );
+
+            final List<Namespace> namespaces = new ArrayList<Namespace>();
+
+            namespaceEntityManager.visitAll( new Function<Namespace, Boolean>()
+            {
+                @Override
+                public Boolean apply( Namespace namespace )
+                {
+                    if ( namespace != null )
+                    {
+                        if ( StringUtils.equals( namespace.getRepository().getId(), repositoryId ) )
+                        {
+                            namespaces.add( namespace );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            namespaceEntityManager.remove( namespaces );
+
+            final List<Project> projects = new ArrayList<Project>();
+            projectEntityManager.visitAll( new Function<Project, Boolean>()
+            {
+                @Override
+                public Boolean apply( Project project )
+                {
+                    if ( project != null )
+                    {
+                        if ( StringUtils.equals( project.getNamespace().getRepository().getId(), repositoryId ) )
+                        {
+                            projects.add( project );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            projectEntityManager.remove( projects );
+
+            // TODO  cleanup or not
+            //final List<MetadataFacetModel> metadataFacetModels = new ArrayList<MetadataFacetModel>(  );
+            //metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+
+            final List<ProjectVersionMetadataModel> projectVersionMetadataModels =
+                new ArrayList<ProjectVersionMetadataModel>();
+
+            projectVersionMetadataModelEntityManager.visitAll( new Function<ProjectVersionMetadataModel, Boolean>()
+            {
+                @Override
+                public Boolean apply( ProjectVersionMetadataModel projectVersionMetadataModel )
+                {
+                    if ( projectVersionMetadataModel != null )
+                    {
+                        if ( StringUtils.equals( projectVersionMetadataModel.getNamespace().getRepository().getId(),
+                                                 repositoryId ) )
+                        {
+                            projectVersionMetadataModels.add( projectVersionMetadataModel );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            projectVersionMetadataModelEntityManager.remove( projectVersionMetadataModels );
+
+            Repository repository = repositoryEntityManager.get( repositoryId );
+            if ( repository != null )
+            {
+                repositoryEntityManager.remove( repository );
+            }
+
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+    }
+
+    @Override
+    public Collection<String> getRepositories()
+        throws MetadataRepositoryException
+    {
+        try
+        {
+            logger.debug( "getRepositories" );
+
+            List<Repository> repositories = repositoryEntityManager.getAll();
+            if ( repositories == null )
+            {
+                return Collections.emptyList();
+            }
+            List<String> repoIds = new ArrayList<String>( repositories.size() );
+            for ( Repository repository : repositories )
+            {
+                repoIds.add( repository.getName() );
+            }
+            logger.debug( "getRepositories found: {}", repoIds );
+            return repoIds;
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+
+    }
+
+
+    @Override
+    public Collection<String> getRootNamespaces( final String repoId )
+        throws MetadataResolutionException
+    {
+        try
+        {
+            final Set<String> namespaces = new HashSet<String>();
+
+            namespaceEntityManager.visitAll( new Function<Namespace, Boolean>()
+            {
+                // @Nullable add dependency ?
+                @Override
+                public Boolean apply( Namespace namespace )
+                {
+                    if ( namespace != null && namespace.getRepository() != null && StringUtils.equalsIgnoreCase( repoId,
+                                                                                                                 namespace.getRepository().getId() ) )
+                    {
+                        String name = namespace.getName();
+                        if ( StringUtils.isNotEmpty( name ) )
+                        {
+                            namespaces.add( StringUtils.substringBefore( name, "." ) );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            return namespaces;
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataResolutionException( e.getMessage(), e );
+        }
+    }
+
+    @Override
+    public Collection<String> getNamespaces( final String repoId, final String namespaceId )
+        throws MetadataResolutionException
+    {
+        try
+        {
+            final Set<String> namespaces = new HashSet<String>();
+
+            namespaceEntityManager.visitAll( new Function<Namespace, Boolean>()
+            {
+                // @Nullable add dependency ?
+                @Override
+                public Boolean apply( Namespace namespace )
+                {
+                    if ( namespace != null && namespace.getRepository() != null && StringUtils.equalsIgnoreCase( repoId,
+                                                                                                                 namespace.getRepository().getId() ) )
+                    {
+                        String currentNamespace = namespace.getName();
+                        // we only return childs
+                        if ( StringUtils.startsWith( currentNamespace, namespaceId ) && (
+                            StringUtils.length( currentNamespace ) > StringUtils.length( namespaceId ) ) )
+                        {
+                            // store after namespaceId '.' but before next '.'
+                            // call org namespace org.apache.maven.shared -> stored apache
+
+                            String calledNamespace =
+                                StringUtils.endsWith( namespaceId, "." ) ? namespaceId : namespaceId + ".";
+                            String storedNamespace = StringUtils.substringAfter( currentNamespace, calledNamespace );
+
+                            storedNamespace = StringUtils.substringBefore( storedNamespace, "." );
+
+                            namespaces.add( storedNamespace );
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            return namespaces;
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataResolutionException( e.getMessage(), e );
+        }
+
+    }
+
+    public List<String> getNamespaces( final String repoId )
+        throws MetadataResolutionException
+    {
+        try
+        {
+            logger.debug( "getNamespaces for repository '{}'", repoId );
+            //TypedQuery<Repository> typedQuery =
+            //    entityManager.createQuery( "select n from Namespace n where n.repository_id=:id", Namespace.class );
+
+            //List<Repository> namespaces = typedQuery.setParameter( "id", repoId ).getResultList();
+
+            Repository repository = repositoryEntityManager.get( repoId );
+
+            if ( repository == null )
+            {
+                return Collections.emptyList();
+            }
+
+            // FIXME find correct cql query
+            //String query = "select * from namespace where repository.id = '" + repoId + "';";
+
+            //List<Namespace> namespaces = namespaceEntityManager.find( query );
+
+            final Set<Namespace> namespaces = new HashSet<Namespace>();
+
+            namespaceEntityManager.visitAll( new Function<Namespace, Boolean>()
+            {
+                // @Nullable add dependency ?
+                @Override
+                public Boolean apply( Namespace namespace )
+                {
+                    if ( namespace != null && namespace.getRepository() != null && StringUtils.equalsIgnoreCase( repoId,
+                                                                                                                 namespace.getRepository().getId() ) )
+                    {
+                        namespaces.add( namespace );
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            repository.setNamespaces( new ArrayList<Namespace>( namespaces ) );
+
+            if ( repository == null || repository.getNamespaces().isEmpty() )
+            {
+                return Collections.emptyList();
+            }
+            List<String> namespaceIds = new ArrayList<String>( repository.getNamespaces().size() );
+
+            for ( Namespace n : repository.getNamespaces() )
+            {
+                namespaceIds.add( n.getName() );
+            }
+
+            logger.debug( "getNamespaces for repository '{}' found {}", repoId, namespaceIds.size() );
+            return namespaceIds;
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataResolutionException( e.getMessage(), e );
+        }
+    }
+
+
+    @Override
+    public void updateProject( String repositoryId, ProjectMetadata projectMetadata )
+        throws MetadataRepositoryException
+    {
+
+        // project exists ? if yes return
+        String projectKey = new Project.KeyBuilder().withProjectId( projectMetadata.getId() ).withNamespace(
+            new Namespace( projectMetadata.getNamespace(), new Repository( repositoryId ) ) ).build();
+
+        Project project = projectEntityManager.get( projectKey );
+        if ( project != null )
+        {
+            return;
+        }
+
+        String namespaceKey = new Namespace.KeyBuilder().withRepositoryId( repositoryId ).withNamespace(
+            projectMetadata.getNamespace() ).build();
+        Namespace namespace = namespaceEntityManager.get( namespaceKey );
+        if ( namespace == null )
+        {
+            namespace = updateOrAddNamespace( repositoryId, projectMetadata.getNamespace() );
+        }
+
+        project = new Project( projectKey, projectMetadata.getId(), namespace );
+
+        try
+        {
+            projectEntityManager.put( project );
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+
+    }
+
+    @Override
+    public void removeProject( final String repositoryId, final String namespaceId, final String projectId )
+        throws MetadataRepositoryException
+    {
+
+        // cleanup ArtifactMetadataModel
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( artifactMetadataModel.getRepositoryId(), repositoryId )
+                        && StringUtils.equals( artifactMetadataModel.getNamespace(), namespaceId )
+                        && StringUtils.equals( artifactMetadataModel.getProject(), projectId ) )
+                    {
+                        artifactMetadataModels.add( artifactMetadataModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        artifactMetadataModelEntityManager.remove( artifactMetadataModels );
+
+        Namespace namespace = new Namespace( namespaceId, new Repository( repositoryId ) );
+
+        final List<ProjectVersionMetadataModel> projectVersionMetadataModels =
+            new ArrayList<ProjectVersionMetadataModel>();
+
+        projectVersionMetadataModelEntityManager.visitAll( new Function<ProjectVersionMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ProjectVersionMetadataModel projectVersionMetadataModel )
+            {
+                if ( projectVersionMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repositoryId,
+                                             projectVersionMetadataModel.getNamespace().getRepository().getName() )
+                        && StringUtils.equals( namespaceId, projectVersionMetadataModel.getNamespace().getName() )
+                        && StringUtils.equals( projectId, projectVersionMetadataModel.getProjectId() ) )
+                    {
+                        projectVersionMetadataModels.add( projectVersionMetadataModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        if ( !projectVersionMetadataModels.isEmpty() )
+        {
+            projectVersionMetadataModelEntityManager.remove( projectVersionMetadataModels );
+        }
+
+        String key = new Project.KeyBuilder().withNamespace( namespace ).withProjectId( projectId ).build();
+
+        Project project = projectEntityManager.get( key );
+        if ( project == null )
+        {
+            logger.debug( "removeProject notfound" );
+            return;
+        }
+        logger.debug( "removeProject {}", project );
+
+        projectEntityManager.remove( project );
+    }
+
+    @Override
+    public Collection<String> getProjectVersions( final String repoId, final String namespace, final String projectId )
+        throws MetadataResolutionException
+    {
+        final Set<String> versions = new HashSet<String>();
+        projectVersionMetadataModelEntityManager.visitAll( new Function<ProjectVersionMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ProjectVersionMetadataModel projectVersionMetadataModel )
+            {
+                if ( projectVersionMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId,
+                                             projectVersionMetadataModel.getNamespace().getRepository().getName() )
+                        && StringUtils.startsWith( projectVersionMetadataModel.getNamespace().getName(), namespace )
+                        && StringUtils.equals( projectId, projectVersionMetadataModel.getProjectId() ) )
+                    {
+                        versions.add( projectVersionMetadataModel.getId() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        // FIXME use cql query
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId, artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        namespace, artifactMetadataModel.getNamespace() ) && StringUtils.equals( projectId,
+                                                                                                 artifactMetadataModel.getProject() ) )
+                    {
+                        versions.add( artifactMetadataModel.getProjectVersion() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        return versions;
+    }
+
+    @Override
+    public void updateArtifact( String repositoryId, String namespaceId, String projectId, String projectVersion,
+                                ArtifactMetadata artifactMeta )
+        throws MetadataRepositoryException
+    {
+        String namespaceKey =
+            new Namespace.KeyBuilder().withRepositoryId( repositoryId ).withNamespace( namespaceId ).build();
+        // create the namespace if not exists
+        Namespace namespace = namespaceEntityManager.get( namespaceKey );
+        if ( namespace == null )
+        {
+            namespace = updateOrAddNamespace( repositoryId, namespaceId );
+        }
+
+        // create the project if not exist
+        String projectKey = new Project.KeyBuilder().withNamespace( namespace ).withProjectId( projectId ).build();
+
+        Project project = projectEntityManager.get( projectKey );
+        if ( project == null )
+        {
+            project = new Project( projectKey, projectId, namespace );
+            try
+            {
+                projectEntityManager.put( project );
+            }
+            catch ( PersistenceException e )
+            {
+                throw new MetadataRepositoryException( e.getMessage(), e );
+            }
+        }
+
+        String key = new ArtifactMetadataModel.KeyBuilder().withNamespace( namespace ).withProject( projectId ).withId(
+            artifactMeta.getId() ).withProjectVersion( projectVersion ).build();
+
+        ArtifactMetadataModel artifactMetadataModel = artifactMetadataModelEntityManager.get( key );
+        if ( artifactMetadataModel == null )
+        {
+            artifactMetadataModel = new ArtifactMetadataModel( key, artifactMeta.getId(), repositoryId, namespaceId,
+                                                               artifactMeta.getProject(), projectVersion,
+                                                               artifactMeta.getVersion(),
+                                                               artifactMeta.getFileLastModified(),
+                                                               artifactMeta.getSize(), artifactMeta.getMd5(),
+                                                               artifactMeta.getSha1(), artifactMeta.getWhenGathered() );
+
+        }
+        else
+        {
+            artifactMetadataModel.setFileLastModified( artifactMeta.getFileLastModified().getTime() );
+            artifactMetadataModel.setWhenGathered( artifactMeta.getWhenGathered().getTime() );
+            artifactMetadataModel.setSize( artifactMeta.getSize() );
+            artifactMetadataModel.setMd5( artifactMeta.getMd5() );
+            artifactMetadataModel.setSha1( artifactMeta.getSha1() );
+            artifactMetadataModel.setVersion( artifactMeta.getVersion() );
+        }
+
+        try
+        {
+            artifactMetadataModelEntityManager.put( artifactMetadataModel );
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+
+        key = new ProjectVersionMetadataModel.KeyBuilder().withRepository( repositoryId ).withNamespace(
+            namespace ).withProjectId( projectId ).withId( projectVersion ).build();
+
+        ProjectVersionMetadataModel projectVersionMetadataModel = projectVersionMetadataModelEntityManager.get( key );
+
+        if ( projectVersionMetadataModel == null )
+        {
+            projectVersionMetadataModel = new ProjectVersionMetadataModel();
+            projectVersionMetadataModel.setRowId( key );
+            projectVersionMetadataModel.setProjectId( projectId );
+            projectVersionMetadataModel.setId( projectVersion );
+            projectVersionMetadataModel.setNamespace( namespace );
+
+            projectVersionMetadataModelEntityManager.put( projectVersionMetadataModel );
+
+        }
+
+        // now facets
+        updateFacets( artifactMeta, artifactMetadataModel );
+
+    }
+
+    @Override
+    public Collection<String> getArtifactVersions( final String repoId, final String namespace, final String projectId,
+                                                   final String projectVersion )
+        throws MetadataResolutionException
+    {
+        final Set<String> versions = new HashSet<String>();
+        // FIXME use cql query
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId, artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        namespace, artifactMetadataModel.getNamespace() ) && StringUtils.equals( projectId,
+                                                                                                 artifactMetadataModel.getProject() )
+                        && StringUtils.equals( projectVersion, artifactMetadataModel.getProjectVersion() ) )
+                    {
+                        versions.add( artifactMetadataModel.getVersion() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        return versions;
+    }
+
+    /**
+     * iterate over available facets to remove/add from the artifactMetadata
+     *
+     * @param facetedMetadata
+     * @param artifactMetadataModel only use for the key
+     */
+    private void updateFacets( final FacetedMetadata facetedMetadata,
+                               final ArtifactMetadataModel artifactMetadataModel )
+    {
+
+        for ( final String facetId : metadataFacetFactories.keySet() )
+        {
+            MetadataFacet metadataFacet = facetedMetadata.getFacet( facetId );
+            if ( metadataFacet == null )
+            {
+                continue;
+            }
+            // clean first
+
+            final List<MetadataFacetModel> metadataFacetModels = new ArrayList<MetadataFacetModel>();
+
+            metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+            {
+                @Override
+                public Boolean apply( MetadataFacetModel metadataFacetModel )
+                {
+                    ArtifactMetadataModel tmp = metadataFacetModel.getArtifactMetadataModel();
+                    if ( StringUtils.equals( metadataFacetModel.getFacetId(), facetId ) && StringUtils.equals(
+                        tmp.getRepositoryId(), artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        tmp.getNamespace(), artifactMetadataModel.getNamespace() ) && StringUtils.equals(
+                        tmp.getProject(), artifactMetadataModel.getProject() ) )
+                    {
+                        metadataFacetModels.add( metadataFacetModel );
+                    }
+                    return Boolean.TRUE;
+                }
+            } );
+
+            metadataFacetModelEntityManager.remove( metadataFacetModels );
+
+            Map<String, String> properties = metadataFacet.toProperties();
+
+            final List<MetadataFacetModel> metadataFacetModelsToAdd =
+                new ArrayList<MetadataFacetModel>( properties.size() );
+
+            for ( Map.Entry<String, String> entry : properties.entrySet() )
+            {
+                String key = new MetadataFacetModel.KeyBuilder().withKey( entry.getKey() ).withArtifactMetadataModel(
+                    artifactMetadataModel ).withFacetId( facetId ).withName( metadataFacet.getName() ).build();
+                MetadataFacetModel metadataFacetModel =
+                    new MetadataFacetModel( key, artifactMetadataModel, facetId, entry.getKey(), entry.getValue(),
+                                            metadataFacet.getName() );
+                metadataFacetModelsToAdd.add( metadataFacetModel );
+            }
+
+            metadataFacetModelEntityManager.put( metadataFacetModelsToAdd );
+
+        }
+    }
+
+    @Override
+    public void updateProjectVersion( String repositoryId, String namespaceId, String projectId,
+                                      ProjectVersionMetadata versionMetadata )
+        throws MetadataRepositoryException
+    {
+        String namespaceKey =
+            new Namespace.KeyBuilder().withRepositoryId( repositoryId ).withNamespace( namespaceId ).build();
+        Namespace namespace = namespaceEntityManager.get( namespaceKey );
+        if ( namespace == null )
+        {
+            namespace = updateOrAddNamespace( repositoryId, namespaceId );
+        }
+
+        String key = new Project.KeyBuilder().withNamespace( namespace ).withProjectId( projectId ).build();
+
+        Project project = projectEntityManager.get( key );
+        if ( project == null )
+        {
+            project = new Project( key, projectId, namespace );
+            projectEntityManager.put( project );
+        }
+
+        // we don't test of repository and namespace really exist !
+        key = new ProjectVersionMetadataModel.KeyBuilder().withRepository( repositoryId ).withNamespace(
+            namespaceId ).withProjectId( projectId ).withId( versionMetadata.getId() ).build();
+
+        ProjectVersionMetadataModel projectVersionMetadataModel = projectVersionMetadataModelEntityManager.get( key );
+
+        if ( projectVersionMetadataModel == null )
+        {
+            projectVersionMetadataModel =
+                new BeanReplicator().replicateBean( versionMetadata, ProjectVersionMetadataModel.class );
+            projectVersionMetadataModel.setRowId( key );
+        }
+        projectVersionMetadataModel.setProjectId( projectId );
+        projectVersionMetadataModel.setNamespace( new Namespace( namespaceId, new Repository( repositoryId ) ) );
+        projectVersionMetadataModel.setCiManagement( versionMetadata.getCiManagement() );
+        projectVersionMetadataModel.setIssueManagement( versionMetadata.getIssueManagement() );
+        projectVersionMetadataModel.setOrganization( versionMetadata.getOrganization() );
+        projectVersionMetadataModel.setScm( versionMetadata.getScm() );
+
+        projectVersionMetadataModel.setMailingLists( versionMetadata.getMailingLists() );
+        projectVersionMetadataModel.setDependencies( versionMetadata.getDependencies() );
+        projectVersionMetadataModel.setLicenses( versionMetadata.getLicenses() );
+
+
+        try
+        {
+            projectVersionMetadataModelEntityManager.put( projectVersionMetadataModel );
+
+            ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
+            artifactMetadataModel.setArtifactMetadataModelId(
+                new ArtifactMetadataModel.KeyBuilder().withId( versionMetadata.getId() ).withRepositoryId(
+                    repositoryId ).withNamespace( namespaceId ).withProjectVersion(
+                    versionMetadata.getVersion() ).build() );
+            artifactMetadataModel.setRepositoryId( repositoryId );
+            artifactMetadataModel.setNamespace( namespaceId );
+            artifactMetadataModel.setProject( projectId );
+            artifactMetadataModel.setProjectVersion( versionMetadata.getVersion() );
+            artifactMetadataModel.setVersion( versionMetadata.getVersion() );
+            // facets etc...
+            updateFacets( versionMetadata, artifactMetadataModel );
+        }
+        catch ( PersistenceException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+    }
+
+
+    private static class BooleanHolder
+    {
+        private boolean value = false;
+    }
+
+    @Override
+    public List<String> getMetadataFacets( final String repositoryId, final String facetId )
+        throws MetadataRepositoryException
+    {
+        // FIXME use cql query !!
+        final List<String> facets = new ArrayList<String>();
+        this.metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( metadataFacetModel.getArtifactMetadataModel().getRepositoryId(),
+                                             repositoryId ) && StringUtils.equals( metadataFacetModel.getFacetId(),
+                                                                                   facetId ) )
+                    {
+                        facets.add( metadataFacetModel.getName() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        return facets;
+
+    }
+
+    @Override
+    public boolean hasMetadataFacet( String repositoryId, String facetId )
+        throws MetadataRepositoryException
+    {
+        return !getMetadataFacets( repositoryId, facetId ).isEmpty();
+    }
+
+    @Override
+    public MetadataFacet getMetadataFacet( final String repositoryId, final String facetId, final String name )
+        throws MetadataRepositoryException
+    {
+        // FIXME use cql query !!
+        final List<MetadataFacetModel> facets = new ArrayList<MetadataFacetModel>();
+        this.metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( metadataFacetModel.getArtifactMetadataModel().getRepositoryId(),
+                                             repositoryId ) && StringUtils.equals( metadataFacetModel.getFacetId(),
+                                                                                   facetId ) && StringUtils.equals(
+                        metadataFacetModel.getName(), name ) )
+                    {
+                        facets.add( metadataFacetModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        if ( facets.isEmpty() )
+        {
+            return null;
+        }
+
+        MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
+        if ( metadataFacetFactory == null )
+        {
+            return null;
+        }
+        MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
+        Map<String, String> map = new HashMap<String, String>( facets.size() );
+        for ( MetadataFacetModel metadataFacetModel : facets )
+        {
+            map.put( metadataFacetModel.getKey(), metadataFacetModel.getValue() );
+        }
+        metadataFacet.fromProperties( map );
+        return metadataFacet;
+    }
+
+    @Override
+    public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
+        throws MetadataRepositoryException
+    {
+
+        if ( metadataFacet == null )
+        {
+            return;
+        }
+
+        if ( metadataFacet.toProperties().isEmpty() )
+        {
+            String key = new MetadataFacetModel.KeyBuilder().withRepositoryId( repositoryId ).withFacetId(
+                metadataFacet.getFacetId() ).withName( metadataFacet.getName() ).build();
+            MetadataFacetModel metadataFacetModel = metadataFacetModelEntityManager.get( key );
+            if ( metadataFacetModel == null )
+            {
+                metadataFacetModel = new MetadataFacetModel();
+            }
+            // we need to store the repositoryId
+            ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
+            artifactMetadataModel.setRepositoryId( repositoryId );
+            metadataFacetModel.setArtifactMetadataModel( artifactMetadataModel );
+            metadataFacetModel.setId( key );
+            metadataFacetModel.setFacetId( metadataFacet.getFacetId() );
+            metadataFacetModel.setName( metadataFacet.getName() );
+
+            try
+            {
+                metadataFacetModelEntityManager.put( metadataFacetModel );
+            }
+            catch ( PersistenceException e )
+            {
+                throw new MetadataRepositoryException( e.getMessage(), e );
+            }
+        }
+        else
+        {
+            for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
+            {
+
+                String key = new MetadataFacetModel.KeyBuilder().withRepositoryId( repositoryId ).withFacetId(
+                    metadataFacet.getFacetId() ).withName( metadataFacet.getName() ).withKey( entry.getKey() ).build();
+
+                MetadataFacetModel metadataFacetModel = metadataFacetModelEntityManager.get( key );
+                if ( metadataFacetModel == null )
+                {
+                    metadataFacetModel = new MetadataFacetModel();
+                    // we need to store the repositoryId
+                    ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
+                    artifactMetadataModel.setRepositoryId( repositoryId );
+                    metadataFacetModel.setArtifactMetadataModel( artifactMetadataModel );
+                    metadataFacetModel.setId( key );
+                    metadataFacetModel.setKey( entry.getKey() );
+                    metadataFacetModel.setFacetId( metadataFacet.getFacetId() );
+                    metadataFacetModel.setName( metadataFacet.getName() );
+                }
+                metadataFacetModel.setValue( entry.getValue() );
+                try
+                {
+                    metadataFacetModelEntityManager.put( metadataFacetModel );
+                }
+                catch ( PersistenceException e )
+                {
+                    throw new MetadataRepositoryException( e.getMessage(), e );
+                }
+
+            }
+        }
+    }
+
+    @Override
+    public void removeMetadataFacets( final String repositoryId, final String facetId )
+        throws MetadataRepositoryException
+    {
+        logger.debug( "removeMetadataFacets repositoryId: '{}', facetId: '{}'", repositoryId, facetId );
+        final List<MetadataFacetModel> toRemove = new ArrayList<MetadataFacetModel>();
+
+        // FIXME cql query
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( metadataFacetModel.getArtifactMetadataModel().getRepositoryId(),
+                                             repositoryId ) && StringUtils.equals( metadataFacetModel.getFacetId(),
+                                                                                   facetId ) )
+                    {
+                        toRemove.add( metadataFacetModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        logger.debug( "removeMetadataFacets repositoryId: '{}', facetId: '{}', toRemove: {}", repositoryId, facetId,
+                      toRemove );
+        metadataFacetModelEntityManager.remove( toRemove );
+    }
+
+    @Override
+    public void removeMetadataFacet( final String repositoryId, final String facetId, final String name )
+        throws MetadataRepositoryException
+    {
+        logger.debug( "removeMetadataFacets repositoryId: '{}', facetId: '{}'", repositoryId, facetId );
+        final List<MetadataFacetModel> toRemove = new ArrayList<MetadataFacetModel>();
+
+        // FIXME cql query
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( metadataFacetModel.getArtifactMetadataModel().getRepositoryId(),
+                                             repositoryId ) && StringUtils.equals( metadataFacetModel.getFacetId(),
+                                                                                   facetId ) && StringUtils.equals(
+                        metadataFacetModel.getName(), name ) )
+                    {
+                        toRemove.add( metadataFacetModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        logger.debug( "removeMetadataFacets repositoryId: '{}', facetId: '{}', toRemove: {}", repositoryId, facetId,
+                      toRemove );
+        metadataFacetModelEntityManager.remove( toRemove );
+    }
+
+    @Override
+    public List<ArtifactMetadata> getArtifactsByDateRange( final String repositoryId, final Date startTime,
+                                                           final Date endTime )
+        throws MetadataRepositoryException
+    {
+
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+
+        // FIXME cql query
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( artifactMetadataModel.getRepositoryId(), repositoryId )
+                        && artifactMetadataModel.getNamespace() != null &&
+                        artifactMetadataModel.getProject() != null && artifactMetadataModel.getId() != null )
+                    {
+
+                        Date when = artifactMetadataModel.getWhenGathered();
+                        if ( ( startTime != null ? when.getTime() >= startTime.getTime() : true ) && ( endTime != null ?
+                            when.getTime() <= endTime.getTime() : true ) )
+                        {
+                            logger.debug( "getArtifactsByDateRange visitAll found: {}", artifactMetadataModel );
+                            artifactMetadataModels.add( artifactMetadataModel );
+                        }
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        List<ArtifactMetadata> artifactMetadatas = new ArrayList<ArtifactMetadata>( artifactMetadataModels.size() );
+
+        for ( ArtifactMetadataModel model : artifactMetadataModels )
+        {
+            ArtifactMetadata artifactMetadata = new BeanReplicator().replicateBean( model, ArtifactMetadata.class );
+            populateFacets( artifactMetadata );
+            artifactMetadatas.add( artifactMetadata );
+        }
+
+        // FIXME facets ?
+
+        logger.debug( "getArtifactsByDateRange repositoryId: {}, startTime: {}, endTime: {}, artifactMetadatas: {}",
+                      repositoryId, startTime, endTime, artifactMetadatas );
+
+        return artifactMetadatas;
+    }
+
+    protected void populateFacets( final ArtifactMetadata artifactMetadata )
+    {
+        final List<MetadataFacetModel> metadataFacetModels = new ArrayList<MetadataFacetModel>();
+
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    ArtifactMetadataModel artifactMetadataModel = metadataFacetModel.getArtifactMetadataModel();
+                    if ( artifactMetadataModel != null )
+                    {
+                        if ( StringUtils.equals( artifactMetadata.getRepositoryId(),
+                                                 artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                            artifactMetadata.getNamespace(), artifactMetadataModel.getNamespace() )
+                            && StringUtils.equals( artifactMetadata.getRepositoryId(),
+                                                   artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                            artifactMetadata.getProject(), artifactMetadataModel.getProject() ) && StringUtils.equals(
+                            artifactMetadata.getId(), artifactMetadataModel.getId() ) )
+                        {
+                            metadataFacetModels.add( metadataFacetModel );
+                        }
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        Map<String, Map<String, String>> facetValuesPerFacet = new HashMap<String, Map<String, String>>();
+
+        for ( MetadataFacetModel model : metadataFacetModels )
+        {
+            Map<String, String> values = facetValuesPerFacet.get( model.getName() );
+            if ( values == null )
+            {
+                values = new HashMap<String, String>();
+            }
+            values.put( model.getKey(), model.getValue() );
+            facetValuesPerFacet.put( model.getName(), values );
+        }
+
+        for ( Map.Entry<String, Map<String, String>> entry : facetValuesPerFacet.entrySet() )
+        {
+            MetadataFacetFactory factory = metadataFacetFactories.get( entry.getKey() );
+            if ( factory == null )
+            {
+                continue;
+            }
+            MetadataFacet metadataFacet =
+                factory.createMetadataFacet( artifactMetadata.getRepositoryId(), entry.getKey() );
+            metadataFacet.fromProperties( entry.getValue() );
+            artifactMetadata.addFacet( metadataFacet );
+        }
+    }
+
+    @Override
+    public List<ArtifactMetadata> getArtifactsByChecksum( final String repositoryId, final String checksum )
+        throws MetadataRepositoryException
+    {
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+
+        if ( logger.isDebugEnabled() )
+        {
+            logger.debug( "all ArtifactMetadataModel: {}", artifactMetadataModelEntityManager.getAll() );
+        }
+
+        // FIXME cql query
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( artifactMetadataModel.getRepositoryId(), repositoryId )
+                        && artifactMetadataModel.getNamespace() != null &&
+                        artifactMetadataModel.getProject() != null && artifactMetadataModel.getId() != null )
+                    {
+
+                        if ( StringUtils.equals( checksum, artifactMetadataModel.getMd5() ) || StringUtils.equals(
+                            checksum, artifactMetadataModel.getSha1() ) )
+                        {
+                            artifactMetadataModels.add( artifactMetadataModel );
+                        }
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        List<ArtifactMetadata> artifactMetadatas = new ArrayList<ArtifactMetadata>( artifactMetadataModels.size() );
+
+        for ( ArtifactMetadataModel model : artifactMetadataModels )
+        {
+            ArtifactMetadata artifactMetadata = new BeanReplicator().replicateBean( model, ArtifactMetadata.class );
+            populateFacets( artifactMetadata );
+            artifactMetadatas.add( artifactMetadata );
+        }
+
+        logger.debug( "getArtifactsByChecksum repositoryId: {}, checksum: {}, artifactMetadatas: {}", repositoryId,
+                      checksum, artifactMetadatas );
+
+        return artifactMetadatas;
+    }
+
+    @Override
+    public void removeArtifact( final String repositoryId, final String namespace, final String project,
+                                final String version, final String id )
+        throws MetadataRepositoryException
+    {
+        logger.debug( "removeArtifact repositoryId: '{}', namespace: '{}', project: '{}', version: '{}', id: '{}'",
+                      repositoryId, namespace, project, version, id );
+        String key =
+            new ArtifactMetadataModel.KeyBuilder().withRepositoryId( repositoryId ).withNamespace( namespace ).withId(
+                id ).withProjectVersion( version ).withProject( project ).build();
+
+        ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
+        artifactMetadataModel.setArtifactMetadataModelId( key );
+
+        artifactMetadataModelEntityManager.remove( artifactMetadataModel );
+
+        key =
+            new ProjectVersionMetadataModel.KeyBuilder().withId( version ).withRepository( repositoryId ).withNamespace(
+                namespace ).withProjectId( project ).build();
+
+        ProjectVersionMetadataModel projectVersionMetadataModel = new ProjectVersionMetadataModel();
+        projectVersionMetadataModel.setRowId( key );
+
+        projectVersionMetadataModelEntityManager.remove( projectVersionMetadataModel );
+    }
+
+    @Override
+    public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
+        throws MetadataRepositoryException
+    {
+        logger.debug( "removeArtifact repositoryId: '{}', namespace: '{}', project: '{}', version: '{}', id: '{}'",
+                      artifactMetadata.getRepositoryId(), artifactMetadata.getNamespace(),
+                      artifactMetadata.getProject(), baseVersion, artifactMetadata.getId() );
+        String key =
+            new ArtifactMetadataModel.KeyBuilder().withRepositoryId( artifactMetadata.getRepositoryId() ).withNamespace(
+                artifactMetadata.getNamespace() ).withId( artifactMetadata.getId() ).withProjectVersion(
+                baseVersion ).withProject( artifactMetadata.getProject() ).build();
+
+        ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
+        artifactMetadataModel.setArtifactMetadataModelId( key );
+
+        artifactMetadataModelEntityManager.remove( artifactMetadataModel );
+    }
+
+    @Override
+    public void removeArtifact( final String repositoryId, final String namespace, final String project,
+                                final String version, final MetadataFacet metadataFacet )
+        throws MetadataRepositoryException
+    {
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repositoryId, artifactMetadataModel.getRepositoryId() )
+                        && StringUtils.equals( namespace, artifactMetadataModel.getNamespace() ) && StringUtils.equals(
+                        project, artifactMetadataModel.getProject() ) && StringUtils.equals( project,
+                                                                                             artifactMetadataModel.getVersion() ) )
+                    {
+                        artifactMetadataModels.add( artifactMetadataModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        artifactMetadataModelEntityManager.remove( artifactMetadataModels );
+        /*
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    ArtifactMetadataModel artifactMetadataModel = metadataFacetModel.getArtifactMetadataModel();
+                    if ( artifactMetadataModel != null )
+                    {
+                        if ( StringUtils.equals( repositoryId, artifactMetadataModel.getRepositoryId() )
+                            && StringUtils.equals( namespace, artifactMetadataModel.getNamespace() )
+                            && StringUtils.equals( project, artifactMetadataModel.getProject() ) && StringUtils.equals(
+                            version, artifactMetadataModel.getVersion() ) )
+                        {
+                            if ( StringUtils.equals( metadataFacetModel.getFacetId(), metadataFacet.getFacetId() )
+                                && StringUtils.equals( metadataFacetModel.getName(), metadataFacet.getName() ) )
+                            {
+                                metadataFacetModels.add( metadataFacetModel );
+                            }
+                        }
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        metadataFacetModelEntityManager.remove( metadataFacetModels );
+        */
+    }
+
+
+    @Override
+    public List<ArtifactMetadata> getArtifacts( final String repositoryId )
+        throws MetadataRepositoryException
+    {
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+        // FIXME use cql query !
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repositoryId, artifactMetadataModel.getRepositoryId() ) )
+                    {
+                        artifactMetadataModels.add( artifactMetadataModel );
+                    }
+                }
+
+                return Boolean.TRUE;
+            }
+        } );
+
+        List<ArtifactMetadata> artifactMetadatas = new ArrayList<ArtifactMetadata>( artifactMetadataModels.size() );
+
+        for ( ArtifactMetadataModel model : artifactMetadataModels )
+        {
+            ArtifactMetadata artifactMetadata = new BeanReplicator().replicateBean( model, ArtifactMetadata.class );
+            populateFacets( artifactMetadata );
+            artifactMetadatas.add( artifactMetadata );
+        }
+
+        return artifactMetadatas;
+    }
+
+    @Override
+    public ProjectMetadata getProject( final String repoId, final String namespace, final String id )
+        throws MetadataResolutionException
+    {
+        //basically just checking it exists
+        // FIXME use cql query
+
+        final BooleanHolder booleanHolder = new BooleanHolder();
+
+        projectEntityManager.visitAll( new Function<Project, Boolean>()
+        {
+            @Override
+            public Boolean apply( Project project )
+            {
+                if ( project != null )
+                {
+                    if ( StringUtils.equals( repoId, project.getNamespace().getRepository().getName() )
+                        && StringUtils.equals( namespace, project.getNamespace().getName() ) && StringUtils.equals( id,
+                                                                                                                    project.getProjectId() ) )
+                    {
+                        booleanHolder.value = true;
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        if ( !booleanHolder.value )
+        {
+            return null;
+        }
+
+        ProjectMetadata projectMetadata = new ProjectMetadata();
+        projectMetadata.setId( id );
+        projectMetadata.setNamespace( namespace );
+
+        logger.debug( "getProject repoId: {}, namespace: {}, projectId: {} -> {}", repoId, namespace, id,
+                      projectMetadata );
+
+        return projectMetadata;
+    }
+
+    @Override
+    public ProjectVersionMetadata getProjectVersion( final String repoId, final String namespace,
+                                                     final String projectId, final String projectVersion )
+        throws MetadataResolutionException
+    {
+        String key = new ProjectVersionMetadataModel.KeyBuilder().withRepository( repoId ).withNamespace(
+            namespace ).withProjectId( projectId ).withId( projectVersion ).build();
+
+        ProjectVersionMetadataModel projectVersionMetadataModel = projectVersionMetadataModelEntityManager.get( key );
+
+        if ( projectVersionMetadataModel == null )
+        {
+            logger.debug(
+                "getProjectVersion repoId: '{}', namespace: '{}', projectId: '{}', projectVersion: {} -> not found",
+                repoId, namespace, projectId, projectVersion );
+            return null;
+        }
+
+        ProjectVersionMetadata projectVersionMetadata =
+            new BeanReplicator().replicateBean( projectVersionMetadataModel, ProjectVersionMetadata.class );
+
+        logger.debug( "getProjectVersion repoId: '{}', namespace: '{}', projectId: '{}', projectVersion: {} -> {}",
+                      repoId, namespace, projectId, projectVersion, projectVersionMetadata );
+
+        projectVersionMetadata.setCiManagement( projectVersionMetadataModel.getCiManagement() );
+        projectVersionMetadata.setIssueManagement( projectVersionMetadataModel.getIssueManagement() );
+        projectVersionMetadata.setOrganization( projectVersionMetadataModel.getOrganization() );
+        projectVersionMetadata.setScm( projectVersionMetadataModel.getScm() );
+
+        // FIXME complete collections !!
+
+        // facets
+        final List<MetadataFacetModel> metadataFacetModels = new ArrayList<MetadataFacetModel>();
+        // FIXME use cql query
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( repoId, metadataFacetModel.getArtifactMetadataModel().getRepositoryId() )
+                        && StringUtils.equals( namespace, metadataFacetModel.getArtifactMetadataModel().getNamespace() )
+                        && StringUtils.equals( projectId, metadataFacetModel.getArtifactMetadataModel().getProject() )
+                        && StringUtils.equals( projectVersion,
+                                               metadataFacetModel.getArtifactMetadataModel().getProjectVersion() ) )
+                    {
+                        metadataFacetModels.add( metadataFacetModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        Map<String, Map<String, String>> metadataFacetsPerFacetIds = new HashMap<String, Map<String, String>>();
+        for ( MetadataFacetModel metadataFacetModel : metadataFacetModels )
+        {
+
+            Map<String, String> metaValues = metadataFacetsPerFacetIds.get( metadataFacetModel.getFacetId() );
+            if ( metaValues == null )
+            {
+                metaValues = new HashMap<String, String>();
+                metadataFacetsPerFacetIds.put( metadataFacetModel.getFacetId(), metaValues );
+            }
+            metaValues.put( metadataFacetModel.getKey(), metadataFacetModel.getValue() );
+
+        }
+
+        if ( !metadataFacetsPerFacetIds.isEmpty() )
+        {
+            for ( Map.Entry<String, Map<String, String>> entry : metadataFacetsPerFacetIds.entrySet() )
+            {
+                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
+                if ( metadataFacetFactory != null )
+                {
+                    MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet( repoId, entry.getKey() );
+                    metadataFacet.fromProperties( entry.getValue() );
+                    projectVersionMetadata.addFacet( metadataFacet );
+                }
+            }
+        }
+
+        return projectVersionMetadata;
+    }
+
+
+    @Override
+    public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
+                                                                     String projectVersion )
+        throws MetadataResolutionException
+    {
+        // FIXME implement this
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Collection<String> getProjects( final String repoId, final String namespace )
+        throws MetadataResolutionException
+    {
+        final Set<String> projects = new HashSet<String>();
+
+        // FIXME use cql query
+        projectEntityManager.visitAll( new Function<Project, Boolean>()
+        {
+            @Override
+            public Boolean apply( Project project )
+            {
+                if ( project != null )
+                {
+                    if ( StringUtils.equals( repoId, project.getNamespace().getRepository().getName() )
+                        && StringUtils.startsWith( project.getNamespace().getName(), namespace ) )
+                    {
+                        projects.add( project.getProjectId() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        /*
+
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId, artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        namespace, artifactMetadataModel.getNamespace() ) )
+                    {
+                        projects.add( artifactMetadataModel.getProject() );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+        */
+        return projects;
+    }
+
+
+    @Override
+    public void removeProjectVersion( final String repoId, final String namespace, final String projectId,
+                                      final String projectVersion )
+        throws MetadataRepositoryException
+    {
+
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+
+        // FIXME use cql query
+
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId, artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        namespace, artifactMetadataModel.getNamespace() ) && StringUtils.equals( projectId,
+                                                                                                 artifactMetadataModel.getProject() )
+                        && StringUtils.equals( projectVersion, artifactMetadataModel.getProjectVersion() ) )
+                    {
+                        artifactMetadataModels.add( artifactMetadataModel );
+                    }
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        logger.debug( "removeProjectVersions:{}", artifactMetadataModels );
+        if ( artifactMetadataModels.isEmpty() )
+        {
+            return;
+        }
+
+        artifactMetadataModelEntityManager.remove( artifactMetadataModels );
+
+        String key = new ProjectVersionMetadataModel.KeyBuilder().withProjectId( projectId ).withId(
+            projectVersion ).withRepository( repoId ).withNamespace( namespace ).build();
+
+        ProjectVersionMetadataModel projectVersionMetadataModel = new ProjectVersionMetadataModel();
+        projectVersionMetadataModel.setRowId( key );
+
+        projectVersionMetadataModelEntityManager.remove( projectVersionMetadataModel );
+    }
+
+    @Override
+    public Collection<ArtifactMetadata> getArtifacts( final String repoId, final String namespace,
+                                                      final String projectId, final String projectVersion )
+        throws MetadataResolutionException
+    {
+        final List<ArtifactMetadataModel> artifactMetadataModels = new ArrayList<ArtifactMetadataModel>();
+        // FIXME use cql query !
+        artifactMetadataModelEntityManager.visitAll( new Function<ArtifactMetadataModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( ArtifactMetadataModel artifactMetadataModel )
+            {
+                if ( artifactMetadataModel != null )
+                {
+                    if ( StringUtils.equals( repoId, artifactMetadataModel.getRepositoryId() ) && StringUtils.equals(
+                        namespace, artifactMetadataModel.getNamespace() ) && StringUtils.equals( projectId,
+                                                                                                 artifactMetadataModel.getProject() )
+                        && StringUtils.equals( projectVersion, artifactMetadataModel.getProjectVersion() ) )
+                    {
+                        artifactMetadataModels.add( artifactMetadataModel );
+                    }
+                }
+
+                return Boolean.TRUE;
+            }
+        } );
+
+        List<ArtifactMetadata> artifactMetadatas = new ArrayList<ArtifactMetadata>( artifactMetadataModels.size() );
+
+        for ( ArtifactMetadataModel model : artifactMetadataModels )
+        {
+            ArtifactMetadata artifactMetadata = new BeanReplicator().replicateBean( model, ArtifactMetadata.class );
+            populateFacets( artifactMetadata );
+            artifactMetadatas.add( artifactMetadata );
+        }
+
+        // retrieve facets
+        final List<MetadataFacetModel> metadataFacetModels = new ArrayList<MetadataFacetModel>();
+        metadataFacetModelEntityManager.visitAll( new Function<MetadataFacetModel, Boolean>()
+        {
+            @Override
+            public Boolean apply( MetadataFacetModel metadataFacetModel )
+            {
+                if ( metadataFacetModel != null )
+                {
+                    if ( StringUtils.equals( repoId, metadataFacetModel.getArtifactMetadataModel().getRepositoryId() )
+                        && StringUtils.equals( namespace, metadataFacetModel.getArtifactMetadataModel().getNamespace() )
+                        && StringUtils.equals( projectId, metadataFacetModel.getArtifactMetadataModel().getProject() )
+                        && StringUtils.equals( projectVersion,
+                                               metadataFacetModel.getArtifactMetadataModel().getProjectVersion() ) )
+                    {
+                        metadataFacetModels.add( metadataFacetModel );
+                    }
+
+                }
+                return Boolean.TRUE;
+            }
+        } );
+
+        // rebuild MetadataFacet for artifacts
+
+        for ( final ArtifactMetadata artifactMetadata : artifactMetadatas )
+        {
+            Iterable<MetadataFacetModel> metadataFacetModelIterable =
+                Iterables.filter( metadataFacetModels, new Predicate<MetadataFacetModel>()
+                {
+                    @Override
+                    public boolean apply( MetadataFacetModel metadataFacetModel )
+                    {
+                        if ( metadataFacetModel != null )
+                        {
+                            return StringUtils.equals( artifactMetadata.getVersion(),
+                                                       metadataFacetModel.getArtifactMetadataModel().getVersion() );
+                        }
+                        return false;
+                    }
+                } );
+            Iterator<MetadataFacetModel> iterator = metadataFacetModelIterable.iterator();
+            Map<String, List<MetadataFacetModel>> metadataFacetValuesPerFacetId =
+                new HashMap<String, List<MetadataFacetModel>>();
+            while ( iterator.hasNext() )
+            {
+                MetadataFacetModel metadataFacetModel = iterator.next();
+                List<MetadataFacetModel> values = metadataFacetValuesPerFacetId.get( metadataFacetModel.getName() );
+                if ( values == null )
+                {
+                    values = new ArrayList<MetadataFacetModel>();
+                    metadataFacetValuesPerFacetId.put( metadataFacetModel.getFacetId(), values );
+                }
+                values.add( metadataFacetModel );
+
+            }
+
+            for ( Map.Entry<String, List<MetadataFacetModel>> entry : metadataFacetValuesPerFacetId.entrySet() )
+            {
+                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
+                if ( metadataFacetFactory != null )
+                {
+                    List<MetadataFacetModel> facetModels = entry.getValue();
+                    if ( !facetModels.isEmpty() )
+                    {
+                        MetadataFacet metadataFacet =
+                            metadataFacetFactory.createMetadataFacet( repoId, facetModels.get( 0 ).getName() );
+                        Map<String, String> props = new HashMap<String, String>( facetModels.size() );
+                        for ( MetadataFacetModel metadataFacetModel : facetModels )
+                        {
+                            props.put( metadataFacetModel.getKey(), metadataFacetModel.getValue() );
+                        }
+                        metadataFacet.fromProperties( props );
+                        artifactMetadata.addFacet( metadataFacet );
+                    }
+                }
+            }
+
+
+        }
+
+        return artifactMetadatas;
+    }
+
+    @Override
+    public void save()
+    {
+        logger.trace( "save" );
+    }
+
+    @Override
+    public void close()
+        throws MetadataRepositoryException
+    {
+        logger.trace( "close" );
+    }
+
+    @Override
+    public void revert()
+    {
+        logger.warn( "CassandraMetadataRepository cannot revert" );
+    }
+
+    @Override
+    public boolean canObtainAccess( Class<?> aClass )
+    {
+        return false;
+    }
+
+    @Override
+    public <T> T obtainAccess( Class<T> aClass )
+        throws MetadataRepositoryException
+    {
+        throw new IllegalArgumentException(
+            "Access using " + aClass + " is not supported on the cassandra metadata storage" );
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java
new file mode 100644 (file)
index 0000000..2e7f621
--- /dev/null
@@ -0,0 +1,87 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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.configuration.ArchivaConfiguration;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.repository.MetadataResolver;
+import org.apache.archiva.metadata.repository.RepositorySession;
+import org.apache.archiva.metadata.repository.RepositorySessionFactory;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Olivier Lamy
+ */
+@Service( "repositorySessionFactory#cassandra" )
+public class CassandraRepositorySessionFactory
+    implements RepositorySessionFactory
+{
+
+    private Map<String, MetadataFacetFactory> metadataFacetFactories;
+
+    @Inject
+    @Named( value = "archivaConfiguration#default" )
+    private ArchivaConfiguration configuration;
+
+    @Inject
+    private MetadataResolver metadataResolver;
+
+    @Inject
+    private ApplicationContext applicationContext;
+
+    @Inject
+    private CassandraEntityManagerFactory cassandraEntityManagerFactory;
+
+    @PostConstruct
+    public void initialize()
+    {
+        Map<String, MetadataFacetFactory> tmpMetadataFacetFactories =
+            applicationContext.getBeansOfType( MetadataFacetFactory.class );
+        // olamy with spring the "id" is now "metadataFacetFactory#hint"
+        // whereas was only hint with plexus so let remove  metadataFacetFactory#
+        metadataFacetFactories = new HashMap<String, MetadataFacetFactory>( tmpMetadataFacetFactories.size() );
+
+        for ( Map.Entry<String, MetadataFacetFactory> entry : tmpMetadataFacetFactories.entrySet() )
+        {
+            metadataFacetFactories.put( StringUtils.substringAfterLast( entry.getKey(), "#" ), entry.getValue() );
+        }
+
+
+    }
+
+
+    @Override
+    public RepositorySession createSession()
+    {
+        CassandraMetadataRepository metadataRepository =
+            new CassandraMetadataRepository( metadataFacetFactories, configuration,
+                                             cassandraEntityManagerFactory.getKeyspace() );
+        return new RepositorySession( metadataRepository, metadataResolver );
+    }
+
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/DefaultCassandraEntityManagerFactory.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/DefaultCassandraEntityManagerFactory.java
new file mode 100644 (file)
index 0000000..da24f17
--- /dev/null
@@ -0,0 +1,95 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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 com.google.common.collect.ImmutableMap;
+import com.netflix.astyanax.AstyanaxContext;
+import com.netflix.astyanax.Keyspace;
+import com.netflix.astyanax.connectionpool.NodeDiscoveryType;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.connectionpool.impl.ConnectionPoolConfigurationImpl;
+import com.netflix.astyanax.connectionpool.impl.ConnectionPoolType;
+import com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor;
+import com.netflix.astyanax.impl.AstyanaxConfigurationImpl;
+import com.netflix.astyanax.thrift.ThriftFamilyFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+/**
+ * FIXME make all configuration not hardcoded :-)
+ *
+ * @author Olivier Lamy
+ */
+@Service("archivaEntityManagerFactory#cassandra")
+public class DefaultCassandraEntityManagerFactory
+    implements CassandraEntityManagerFactory
+{
+
+    @Inject
+    private ApplicationContext applicationContext;
+
+    private static final String CLUSTER_NAME = "archiva";
+
+    private static final String KEYSPACE_NAME = "ArchivaKeySpace";
+
+    private Keyspace keyspace;
+
+    private AstyanaxContext<Keyspace> keyspaceContext;
+
+
+    @PostConstruct
+    public void initialize()
+        throws ConnectionException
+    {
+        String cassandraHost = System.getProperty( "cassandraHost", "localhost" );
+        String cassandraPort = System.getProperty( "cassandraPort" );
+        keyspaceContext = new AstyanaxContext.Builder().forCluster( CLUSTER_NAME ).forKeyspace(
+            KEYSPACE_NAME ).withAstyanaxConfiguration(
+            new AstyanaxConfigurationImpl().setDiscoveryType( NodeDiscoveryType.RING_DESCRIBE ).setConnectionPoolType(
+                ConnectionPoolType.TOKEN_AWARE ) ).withConnectionPoolConfiguration(
+            new ConnectionPoolConfigurationImpl( CLUSTER_NAME + "_" + KEYSPACE_NAME ).setSocketTimeout(
+                30000 ).setMaxTimeoutWhenExhausted( 2000 ).setMaxConnsPerHost( 20 ).setInitConnsPerHost( 10 ).setSeeds(
+                cassandraHost + ":" + cassandraPort ) ).withConnectionPoolMonitor(
+            new CountingConnectionPoolMonitor() ).buildKeyspace( ThriftFamilyFactory.getInstance() );
+
+        keyspaceContext.start();
+
+        keyspace = keyspaceContext.getClient();
+
+        ImmutableMap<String, Object> options = ImmutableMap.<String, Object>builder().put( "strategy_options",
+                                                                                           ImmutableMap.<String, Object>builder().put(
+                                                                                               "replication_factor",
+                                                                                               "1" ).build() ).put(
+            "strategy_class", "SimpleStrategy" ).build();
+
+        keyspace.createKeyspace( options );
+
+    }
+
+
+    @Override
+    public Keyspace getKeyspace()
+    {
+        return keyspace;
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ArtifactMetadataModel.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ArtifactMetadataModel.java
new file mode 100644 (file)
index 0000000..aa635e9
--- /dev/null
@@ -0,0 +1,331 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Cassandra storage model for {@link org.apache.archiva.metadata.model.ArtifactMetadata}
+ *
+ * @author Olivier Lamy
+ */
+@Entity
+public class ArtifactMetadataModel
+    implements Serializable
+{
+
+    // repositoryId + namespaceId + project + projectVersion + id
+    @Id
+    private String artifactMetadataModelId;
+
+    @Column(name = "id")
+    private String id;
+
+    @Column(name = "repositoryId")
+    private String repositoryId;
+
+    @Column(name = "namespace")
+    private String namespace;
+
+    @Column(name = "project")
+    private String project;
+
+    @Column(name = "projectVersion")
+    private String projectVersion;
+
+    @Column(name = "version")
+    private String version;
+
+    @Column(name = "fileLastModified")
+    private long fileLastModified;
+
+    @Column(name = "size")
+    private long size;
+
+    @Column(name = "md5")
+    private String md5;
+
+    @Column(name = "sha1")
+    private String sha1;
+
+    @Column(name = "whenGathered")
+    private long whenGathered;
+
+    public ArtifactMetadataModel()
+    {
+        // no op
+    }
+
+    public ArtifactMetadataModel( String artifactMetadataModelId, String id, String repositoryId, String namespace,
+                                  String project, String projectVersion, String version, Date fileLastModified,
+                                  long size, String md5, String sha1, Date whenGathered )
+    {
+        this.artifactMetadataModelId = artifactMetadataModelId;
+        this.id = id;
+        this.repositoryId = repositoryId;
+        this.namespace = namespace;
+        this.project = project;
+        this.projectVersion = projectVersion;
+        this.version = version;
+        this.fileLastModified = ( fileLastModified != null ? fileLastModified.getTime() : 0 );
+        this.size = size;
+        this.md5 = md5;
+        this.sha1 = sha1;
+        this.whenGathered = whenGathered != null ? whenGathered.getTime() : new Date().getTime();
+    }
+
+    public String getArtifactMetadataModelId()
+    {
+        return artifactMetadataModelId;
+    }
+
+    public void setArtifactMetadataModelId( String artifactMetadataModelId )
+    {
+        this.artifactMetadataModelId = artifactMetadataModelId;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public String getRepositoryId()
+    {
+        return repositoryId;
+    }
+
+    public void setRepositoryId( String repositoryId )
+    {
+        this.repositoryId = repositoryId;
+    }
+
+    public String getNamespace()
+    {
+        return namespace;
+    }
+
+    public void setNamespace( String namespace )
+    {
+        this.namespace = namespace;
+    }
+
+    public String getProject()
+    {
+        return project;
+    }
+
+    public void setProject( String project )
+    {
+        this.project = project;
+    }
+
+    public String getProjectVersion()
+    {
+        return projectVersion;
+    }
+
+    public void setProjectVersion( String projectVersion )
+    {
+        this.projectVersion = projectVersion;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion( String version )
+    {
+        this.version = version;
+    }
+
+    public long getFileLastModified()
+    {
+        return fileLastModified;
+    }
+
+    public void setFileLastModified( long fileLastModified )
+    {
+        this.fileLastModified = fileLastModified;
+    }
+
+    public long getSize()
+    {
+        return size;
+    }
+
+    public void setSize( long size )
+    {
+        this.size = size;
+    }
+
+    public String getMd5()
+    {
+        return md5;
+    }
+
+    public void setMd5( String md5 )
+    {
+        this.md5 = md5;
+    }
+
+    public String getSha1()
+    {
+        return sha1;
+    }
+
+    public void setSha1( String sha1 )
+    {
+        this.sha1 = sha1;
+    }
+
+    public Date getWhenGathered()
+    {
+        return new Date( whenGathered );
+    }
+
+    public void setWhenGathered( long whenGathered )
+    {
+        this.whenGathered = whenGathered;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        ArtifactMetadataModel that = (ArtifactMetadataModel) o;
+
+        if ( !artifactMetadataModelId.equals( that.artifactMetadataModelId ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return artifactMetadataModelId.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "ArtifactMetadataModel{" );
+        sb.append( "artifactMetadataModelId='" ).append( artifactMetadataModelId ).append( '\'' );
+        sb.append( ", id='" ).append( id ).append( '\'' );
+        sb.append( ", repositoryId='" ).append( repositoryId ).append( '\'' );
+        sb.append( ", namespace='" ).append( namespace ).append( '\'' );
+        sb.append( ", project='" ).append( project ).append( '\'' );
+        sb.append( ", projectVersion='" ).append( projectVersion ).append( '\'' );
+        sb.append( ", version='" ).append( version ).append( '\'' );
+        sb.append( ", fileLastModified=" ).append( fileLastModified );
+        sb.append( ", size=" ).append( size );
+        sb.append( ", md5='" ).append( md5 ).append( '\'' );
+        sb.append( ", sha1='" ).append( sha1 ).append( '\'' );
+        sb.append( ", whenGathered=" ).append( whenGathered );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    public static class KeyBuilder
+    {
+
+        private String project;
+
+        private String id;
+
+        private String namespaceId;
+
+        private String repositoryId;
+
+        private String projectVersion;
+
+        public KeyBuilder()
+        {
+
+        }
+
+        public KeyBuilder withId( String id )
+        {
+            this.id = id;
+            return this;
+        }
+
+
+        public KeyBuilder withNamespace( Namespace namespace )
+        {
+            this.namespaceId = namespace.getName();
+            this.repositoryId = namespace.getRepository().getId();
+            return this;
+        }
+
+        public KeyBuilder withNamespace( String namespaceId )
+        {
+            this.namespaceId = namespaceId;
+            return this;
+        }
+
+        public KeyBuilder withProject( String project )
+        {
+            this.project = project;
+            return this;
+        }
+
+        public KeyBuilder withProjectVersion( String projectVersion )
+        {
+            this.projectVersion = projectVersion;
+            return this;
+        }
+
+        public KeyBuilder withRepositoryId( String repositoryId )
+        {
+            this.repositoryId = repositoryId;
+            return this;
+        }
+
+        public String build()
+        {
+            //repositoryId + namespaceId + project + projectVersion + id
+            // FIXME add some controls
+            return this.repositoryId + "-" + this.namespaceId + "-" + this.project + "-" + this.projectVersion + "-"
+                + this.id;
+        }
+    }
+
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/MetadataFacetModel.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/MetadataFacetModel.java
new file mode 100644 (file)
index 0000000..545787f
--- /dev/null
@@ -0,0 +1,229 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+/**
+ * Cassandra storage model for {@link org.apache.archiva.metadata.model.MetadataFacet}
+ *
+ * @author Olivier Lamy
+ */
+@Entity
+public class MetadataFacetModel
+{
+    // id is repositoryId + namespaceId + projectId + facetId + name + mapKey
+    @Id
+    @Column( name = "id" )
+    private String id;
+
+    @Column( name = "artifactMetadataModel" )
+    private ArtifactMetadataModel artifactMetadataModel;
+
+    @Column( name = "facetId" )
+    private String facetId;
+
+    @Column( name = "name" )
+    private String name;
+
+    @Column( name = "key" )
+    private String key;
+
+    @Column( name = "value" )
+    private String value;
+
+    public MetadataFacetModel()
+    {
+        // no op
+    }
+
+    public MetadataFacetModel( String id, ArtifactMetadataModel artifactMetadataModel, String facetId, String key,
+                               String value, String name )
+    {
+        this.id = id;
+        this.artifactMetadataModel = artifactMetadataModel;
+        this.key = key;
+        this.value = value;
+        this.name = name;
+        this.facetId = facetId;
+    }
+
+    public String getFacetId()
+    {
+        return facetId;
+    }
+
+    public void setFacetId( String facetId )
+    {
+        this.facetId = facetId;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public ArtifactMetadataModel getArtifactMetadataModel()
+    {
+        return artifactMetadataModel;
+    }
+
+    public void setArtifactMetadataModel( ArtifactMetadataModel artifactMetadataModel )
+    {
+        this.artifactMetadataModel = artifactMetadataModel;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    public String getKey()
+    {
+        return key;
+    }
+
+    public void setKey( String key )
+    {
+        this.key = key;
+    }
+
+    public String getValue()
+    {
+        return value;
+    }
+
+    public void setValue( String value )
+    {
+        this.value = value;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        MetadataFacetModel that = (MetadataFacetModel) o;
+
+        if ( !id.equals( that.id ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return id.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "MetadataFacetModel{" );
+        sb.append( "id='" ).append( id ).append( '\'' );
+        sb.append( ", artifactMetadataModel=" ).append( artifactMetadataModel );
+        sb.append( ", key='" ).append( key ).append( '\'' );
+        sb.append( ", value='" ).append( value ).append( '\'' );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    public static class KeyBuilder
+    {
+
+        private ArtifactMetadataModel artifactMetadataModel;
+
+        private String key;
+
+        private String name;
+
+        private String facetId;
+
+        private String repositoryId;
+
+        public KeyBuilder()
+        {
+
+        }
+
+        public KeyBuilder withArtifactMetadataModel( ArtifactMetadataModel artifactMetadataModel )
+        {
+            this.artifactMetadataModel = artifactMetadataModel;
+            return this;
+        }
+
+        public KeyBuilder withKey( String key )
+        {
+            this.key = key;
+            return this;
+        }
+
+        public KeyBuilder withName( String name )
+        {
+            this.name = name;
+            return this;
+        }
+
+        public KeyBuilder withFacetId( String facetId )
+        {
+            this.facetId = facetId;
+            return this;
+        }
+
+        public KeyBuilder withRepositoryId( String repositoryId )
+        {
+            this.repositoryId = repositoryId;
+            return this;
+        }
+
+        public String build()
+        {
+            // FIXME add some controls
+            // getArtifactMetadataModelId can have no namespace, no project and no projectid for statistics
+            // only repositoryId with artifactMetadataModel
+            return ( this.artifactMetadataModel == null
+                ? this.repositoryId
+                : this.artifactMetadataModel.getArtifactMetadataModelId() ) + "-" + this.facetId + "-" + this.name + "-"
+                + this.key;
+        }
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Namespace.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Namespace.java
new file mode 100644 (file)
index 0000000..fb42b0b
--- /dev/null
@@ -0,0 +1,190 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+
+/**
+ * @author Olivier Lamy
+ */
+@Entity
+//@Table( name = "namespace", schema = "ArchivaKeySpace@archiva")
+public class Namespace
+    implements Serializable
+{
+
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @Column(name = "id")
+    private String id;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "repository")
+    private Repository repository;
+
+    //@ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
+    //@JoinColumn(name = "repository_id")
+    //private transient Repository repository;
+
+
+    public Namespace()
+    {
+        // no op
+    }
+
+
+    public Namespace( String id, Repository repository )
+    {
+        this.id = new KeyBuilder().withNamespace( id ).withRepositoryId( repository.getId() ).build();
+        this.name = id;
+        this.repository = repository;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    public Repository getRepository()
+    {
+        return repository;
+    }
+
+    public void setRepository( Repository repository )
+    {
+        this.repository = repository;
+    }
+
+    /*
+    public String getRepositoryId()
+    {
+        return repositoryId;
+    }
+
+    public void setRepositoryId( String repositoryId )
+    {
+        this.repositoryId = repositoryId;
+    }*/
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Namespace namespace = (Namespace) o;
+
+        if ( !id.equals( namespace.id ) )
+        {
+            return false;
+        }
+        if ( !repository.getId().equals( namespace.repository.getId() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = id.hashCode();
+        result = 31 * result + repository.getId().hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "Namespace{" );
+        sb.append( "id='" ).append( id ).append( '\'' );
+        sb.append( ", name='" ).append( name ).append( '\'' );
+        sb.append( ", repository='" ).append( repository ).append( '\'' );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    public static class KeyBuilder
+    {
+
+        private String namespace;
+
+        private String repositoryId;
+
+        public KeyBuilder()
+        {
+
+        }
+
+        public KeyBuilder withNamespace( Namespace namespace )
+        {
+            this.namespace = namespace.getName();
+            this.repositoryId = namespace.getRepository().getId();
+            return this;
+        }
+
+        public KeyBuilder withNamespace( String namespace )
+        {
+            this.namespace = namespace;
+            return this;
+        }
+
+        public KeyBuilder withRepositoryId( String repositoryId )
+        {
+            this.repositoryId = repositoryId;
+            return this;
+        }
+
+        public String build()
+        {
+            // FIXME add some controls
+            return this.repositoryId + "-" + this.namespace;
+        }
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Project.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Project.java
new file mode 100644 (file)
index 0000000..4a167a4
--- /dev/null
@@ -0,0 +1,163 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+/**
+ * @author Olivier Lamy
+ */
+@Entity
+public class Project
+    implements Serializable
+{
+    @Id
+    @Column( name = "projectKey" )
+    private String projectKey;
+
+    @Column( name = "projectId" )
+    private String projectId;
+
+
+    @Column( name = "repository" )
+    private Namespace namespace;
+
+    public Project()
+    {
+        // no op
+    }
+
+    public Project( String projectKey, String projectId, Namespace namespace )
+    {
+        this.projectId = projectId;
+        this.projectKey = projectKey;
+        this.namespace = namespace;
+    }
+
+    public String getProjectKey()
+    {
+        return projectKey;
+    }
+
+    public void setProjectKey( String projectKey )
+    {
+        this.projectKey = projectKey;
+    }
+
+    public Namespace getNamespace()
+    {
+        return namespace;
+    }
+
+    public void setNamespace( Namespace namespace )
+    {
+        this.namespace = namespace;
+    }
+
+    public String getProjectId()
+    {
+        return projectId;
+    }
+
+    public void setProjectId( String projectId )
+    {
+        this.projectId = projectId;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Project project = (Project) o;
+
+        if ( !projectKey.equals( project.projectKey ) )
+        {
+            return false;
+        }
+        if ( !namespace.equals( project.namespace ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = projectKey.hashCode();
+        result = 31 * result + namespace.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "Project{" );
+        sb.append( "projectKey='" ).append( projectKey ).append( '\'' );
+        sb.append( ", projectId='" ).append( projectId ).append( '\'' );
+        sb.append( ", namespace=" ).append( namespace );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    public static class KeyBuilder
+    {
+
+        private Namespace namespace;
+
+        private String projectId;
+
+        public KeyBuilder()
+        {
+            // no op
+        }
+
+        public KeyBuilder withNamespace( Namespace namespace )
+        {
+            this.namespace = namespace;
+            return this;
+        }
+
+        public KeyBuilder withProjectId( String projectId )
+        {
+            this.projectId = projectId;
+            return this;
+        }
+
+
+        public String build()
+        {
+            // FIXME add some controls
+            return new Namespace.KeyBuilder().withNamespace( this.namespace ).build() + "-" + this.projectId;
+        }
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ProjectVersionMetadataModel.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/ProjectVersionMetadataModel.java
new file mode 100644 (file)
index 0000000..aaa9fc4
--- /dev/null
@@ -0,0 +1,354 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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.metadata.model.CiManagement;
+import org.apache.archiva.metadata.model.Dependency;
+import org.apache.archiva.metadata.model.IssueManagement;
+import org.apache.archiva.metadata.model.License;
+import org.apache.archiva.metadata.model.MailingList;
+import org.apache.archiva.metadata.model.Organization;
+import org.apache.archiva.metadata.model.Scm;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Olivier Lamy
+ */
+@Entity
+public class ProjectVersionMetadataModel
+{
+    // repositoryId + namespace + projectId + id (version)
+    @Id
+    private String rowId;
+
+    @Column( name = "namespace" )
+    private Namespace namespace;
+
+    /**
+     * id is the version
+     */
+    @Column( name = "id" )
+    private String id;
+
+    @Column( name = "projectId" )
+    private String projectId;
+
+    @Column(name = "url")
+    private String url;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "description")
+    private String description;
+
+    @Column(name = "organization")
+    private Organization organization;
+
+    @Column(name = "issueManagement")
+    private IssueManagement issueManagement;
+
+    @Column(name = "scm")
+    private Scm scm;
+
+    @Column(name = "ciManagement")
+    private CiManagement ciManagement;
+
+    // FIXME store those values in a separate table
+    @Column(name = "licenses")
+    private List<License> licenses = new ArrayList<License>();
+
+    @Column(name = "mailingLists")
+    private List<MailingList> mailingLists = new ArrayList<MailingList>();
+
+    @Column(name = "dependencies")
+    private List<Dependency> dependencies = new ArrayList<Dependency>();
+
+    @Column(name = "incomplete")
+    private boolean incomplete;
+
+    public String getProjectId()
+    {
+        return projectId;
+    }
+
+    public void setProjectId( String projectId )
+    {
+        this.projectId = projectId;
+    }
+
+    public String getRowId()
+    {
+        return rowId;
+    }
+
+    public void setRowId( String rowId )
+    {
+        this.rowId = rowId;
+    }
+
+    // FIXME must be renamed getVersion !!!
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public String getUrl()
+    {
+        return url;
+    }
+
+    public void setUrl( String url )
+    {
+        this.url = url;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    public String getDescription()
+    {
+        return description;
+    }
+
+    public void setDescription( String description )
+    {
+        this.description = description;
+    }
+
+    public Organization getOrganization()
+    {
+        return organization;
+    }
+
+    public void setOrganization( Organization organization )
+    {
+        this.organization = organization;
+    }
+
+    public IssueManagement getIssueManagement()
+    {
+        return issueManagement;
+    }
+
+    public void setIssueManagement( IssueManagement issueManagement )
+    {
+        this.issueManagement = issueManagement;
+    }
+
+    public Scm getScm()
+    {
+        return scm;
+    }
+
+    public void setScm( Scm scm )
+    {
+        this.scm = scm;
+    }
+
+    public CiManagement getCiManagement()
+    {
+        return ciManagement;
+    }
+
+    public void setCiManagement( CiManagement ciManagement )
+    {
+        this.ciManagement = ciManagement;
+    }
+
+    public boolean isIncomplete()
+    {
+        return incomplete;
+    }
+
+    public void setIncomplete( boolean incomplete )
+    {
+        this.incomplete = incomplete;
+    }
+
+    public Namespace getNamespace()
+    {
+        return namespace;
+    }
+
+    public void setNamespace( Namespace namespace )
+    {
+        this.namespace = namespace;
+    }
+
+    public List<License> getLicenses()
+    {
+        return licenses;
+    }
+
+    public void setLicenses( List<License> licenses )
+    {
+        this.licenses = licenses;
+    }
+
+    public List<MailingList> getMailingLists()
+    {
+        return mailingLists;
+    }
+
+    public void setMailingLists( List<MailingList> mailingLists )
+    {
+        this.mailingLists = mailingLists;
+    }
+
+    public List<Dependency> getDependencies()
+    {
+        return dependencies;
+    }
+
+    public void setDependencies( List<Dependency> dependencies )
+    {
+        this.dependencies = dependencies;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "ProjectVersionMetadataModel{" );
+        sb.append( "rowId='" ).append( rowId ).append( '\'' );
+        sb.append( ", namespace=" ).append( namespace );
+        sb.append( ", id='" ).append( id ).append( '\'' );
+        sb.append( ", projectId='" ).append( projectId ).append( '\'' );
+        sb.append( ", url='" ).append( url ).append( '\'' );
+        sb.append( ", name='" ).append( name ).append( '\'' );
+        sb.append( ", description='" ).append( description ).append( '\'' );
+        sb.append( ", organization=" ).append( organization );
+        sb.append( ", issueManagement=" ).append( issueManagement );
+        sb.append( ", scm=" ).append( scm );
+        sb.append( ", ciManagement=" ).append( ciManagement );
+        sb.append( ", incomplete=" ).append( incomplete );
+        sb.append( '}' );
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        ProjectVersionMetadataModel that = (ProjectVersionMetadataModel) o;
+
+        if ( !rowId.equals( that.rowId ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    @Override
+    public int hashCode()
+    {
+        return rowId.hashCode();
+    }
+
+    public static class KeyBuilder
+    {
+
+        private String namespace;
+
+        private String repositoryId;
+
+        private String projectId;
+
+        private String id;
+
+        public KeyBuilder()
+        {
+
+        }
+
+        public KeyBuilder withNamespace( Namespace namespace )
+        {
+            this.namespace = namespace.getName();
+            this.repositoryId = namespace.getRepository().getId();
+            return this;
+        }
+
+        public KeyBuilder withNamespace( String namespace )
+        {
+            this.namespace = namespace;
+            return this;
+        }
+
+        public KeyBuilder withRepository( String repositoryId )
+        {
+            this.repositoryId = repositoryId;
+            return this;
+        }
+
+        public KeyBuilder withRepository( Repository repository )
+        {
+            this.repositoryId = repository.getId();
+            return this;
+        }
+
+        public KeyBuilder withProjectId( String projectId )
+        {
+            this.projectId = projectId;
+            return this;
+        }
+
+        public KeyBuilder withId( String id )
+        {
+            this.id = id;
+            return this;
+        }
+
+        public String build()
+        {
+            // FIXME add some controls
+            return this.repositoryId + "-" + this.namespace + "-" + this.projectId + ( this.id == null
+                ? ""
+                : "-" + this.id );
+        }
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Repository.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/model/Repository.java
new file mode 100644 (file)
index 0000000..25f8281
--- /dev/null
@@ -0,0 +1,136 @@
+package org.apache.archiva.metadata.repository.cassandra.model;
+
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * @author Olivier Lamy
+ */
+@Entity
+@Table(name = "repository", schema = "ArchivaKeySpace@archiva")
+public class Repository
+    implements Serializable
+{
+
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @Column( name = "id" )
+    private String id;
+
+    @Column(name = "name")
+    private String name;
+
+    private transient List<Namespace> namespaces = new ArrayList<Namespace>();
+
+    public Repository()
+    {
+        // no op
+    }
+
+    public Repository( String id )
+    {
+        this.id = id;
+        this.name = id;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public void setId( String id )
+    {
+        this.id = id;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    public List<Namespace> getNamespaces()
+    {
+        if ( this.namespaces == null )
+        {
+            this.namespaces = new ArrayList<Namespace>();
+        }
+        return namespaces;
+    }
+
+    public void setNamespaces( List<Namespace> namespaces )
+    {
+        this.namespaces = namespaces;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Repository that = (Repository) o;
+
+        if ( !id.equals( that.id ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return id.hashCode();
+    }
+
+
+    @Override
+    public String toString()
+    {
+        final StringBuilder sb = new StringBuilder( "Repository{" );
+        sb.append( "id='" ).append( id ).append( '\'' );
+        sb.append( ", name='" ).append( name ).append( '\'' );
+        sb.append( ", namespaces=" ).append( namespaces );
+        sb.append( '}' );
+        return sb.toString();
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/resources/META-INF/spring-context.xml b/archiva-modules/plugins/metadata-store-cassandra/src/main/resources/META-INF/spring-context.xml
new file mode 100644 (file)
index 0000000..e1c2c24
--- /dev/null
@@ -0,0 +1,33 @@
+<?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.0.xsd
+           http://www.springframework.org/schema/context 
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+       default-lazy-init="true">
+
+  <context:annotation-config/>
+  <context:component-scan base-package="org.apache.archiva.metadata.repository.cassandra"/>
+
+</beans>
\ No newline at end of file
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/test/filtered-resources/META-INF/spring-context.xml b/archiva-modules/plugins/metadata-store-cassandra/src/test/filtered-resources/META-INF/spring-context.xml
new file mode 100644 (file)
index 0000000..74bb024
--- /dev/null
@@ -0,0 +1,25 @@
+<?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.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+</beans>
\ No newline at end of file
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java b/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java
new file mode 100644 (file)
index 0000000..bdf303f
--- /dev/null
@@ -0,0 +1,113 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
+import org.apache.archiva.metadata.repository.cassandra.model.ArtifactMetadataModel;
+import org.apache.archiva.metadata.repository.cassandra.model.MetadataFacetModel;
+import org.apache.archiva.metadata.repository.cassandra.model.Namespace;
+import org.apache.archiva.metadata.repository.cassandra.model.Project;
+import org.apache.archiva.metadata.repository.cassandra.model.ProjectVersionMetadataModel;
+import org.apache.archiva.metadata.repository.cassandra.model.Repository;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Olivier Lamy
+ */
+public class CassandraMetadataRepositoryTest
+    extends AbstractMetadataRepositoryTest
+{
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    @Inject
+    @Named( value = "archivaEntityManagerFactory#cassandra" )
+    CassandraEntityManagerFactory cassandraEntityManagerFactory;
+
+    CassandraMetadataRepository cmr;
+
+    @Before
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        File directory = new File( "target/test-repositories" );
+        if ( directory.exists() )
+        {
+            FileUtils.deleteDirectory( directory );
+        }
+
+        Map<String, MetadataFacetFactory> factories = createTestMetadataFacetFactories();
+
+        this.cmr = new CassandraMetadataRepository( factories, null, cassandraEntityManagerFactory.getKeyspace() );
+        this.repository = this.cmr;
+
+        clearReposAndNamespace();
+    }
+
+
+    @After
+    public void shutdown()
+        throws Exception
+    {
+        clearReposAndNamespace();
+        super.tearDown();
+    }
+
+    protected void clearReposAndNamespace()
+        throws Exception
+    {
+        List<Project> projects = cmr.getProjectEntityManager().getAll();
+
+        cmr.getProjectEntityManager().remove( projects );
+
+        List<Namespace> namespaces = cmr.getNamespaceEntityManager().getAll();
+
+        cmr.getNamespaceEntityManager().remove( namespaces );
+
+        List<Repository> repositories = cmr.getRepositoryEntityManager().getAll();
+
+        cmr.getRepositoryEntityManager().remove( repositories );
+
+        List<ArtifactMetadataModel> artifactMetadataModels = cmr.getArtifactMetadataModelEntityManager().getAll();
+        cmr.getArtifactMetadataModelEntityManager().remove( artifactMetadataModels );
+
+        List<MetadataFacetModel> metadataFacetModels = cmr.getMetadataFacetModelEntityManager().getAll();
+        cmr.getMetadataFacetModelEntityManager().remove( metadataFacetModels );
+
+        List<ProjectVersionMetadataModel> projectVersionMetadataModels =
+            cmr.getProjectVersionMetadataModelEntityManager().getAll();
+        cmr.getProjectVersionMetadataModelEntityManager().remove( projectVersionMetadataModels );
+
+
+    }
+
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/RepositoriesNamespaceTest.java b/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/RepositoriesNamespaceTest.java
new file mode 100644 (file)
index 0000000..2edffd9
--- /dev/null
@@ -0,0 +1,133 @@
+package org.apache.archiva.metadata.repository.cassandra;
+
+/*
+ * 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.metadata.repository.cassandra.model.Namespace;
+import org.apache.archiva.metadata.repository.cassandra.model.Project;
+import org.apache.archiva.metadata.repository.cassandra.model.Repository;
+import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
+import org.fest.assertions.api.Assertions;
+import org.junit.After;
+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 javax.inject.Inject;
+import javax.inject.Named;
+import java.util.List;
+
+/**
+ * @author Olivier Lamy
+ */
+@RunWith(ArchivaSpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" })
+public class RepositoriesNamespaceTest
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    @Inject
+    @Named(value = "archivaEntityManagerFactory#cassandra")
+    CassandraEntityManagerFactory cassandraEntityManagerFactory;
+
+
+    CassandraMetadataRepository cmr;
+
+    @Before
+    public void setup()
+        throws Exception
+    {
+
+        cmr = new CassandraMetadataRepository( null, null, cassandraEntityManagerFactory.getKeyspace() );
+        clearReposAndNamespace();
+
+    }
+
+    @After
+    public void shutdown()
+        throws Exception
+    {
+        clearReposAndNamespace();
+    }
+
+
+    @Test
+    public void testMetadataRepo()
+        throws Exception
+    {
+
+        Repository r = null;
+        Namespace n = null;
+
+        try
+        {
+
+            cmr.updateNamespace( "release", "org" );
+
+            r = cmr.getRepositoryEntityManager().get( "release" );
+
+            Assertions.assertThat( r ).isNotNull();
+
+            Assertions.assertThat( cmr.getRepositories() ).isNotEmpty().hasSize( 1 );
+            Assertions.assertThat( cmr.getNamespaces( "release" ) ).isNotEmpty().hasSize( 1 );
+
+            n = cmr.getNamespaceEntityManager().get( "release" + "-" + "org" );
+
+            Assertions.assertThat( n ).isNotNull();
+            Assertions.assertThat( n.getRepository() ).isNotNull();
+
+            cmr.updateNamespace( "release", "org.apache" );
+
+            r = cmr.getRepositoryEntityManager().get( "release" );
+
+            Assertions.assertThat( r ).isNotNull();
+            Assertions.assertThat( cmr.getNamespaces( "release" ) ).isNotEmpty().hasSize( 2 );
+        }
+        catch ( Exception e )
+        {
+            logger.error( e.getMessage(), e );
+            throw e;
+        }
+        finally
+        {
+            clearReposAndNamespace();
+        }
+    }
+
+    protected void clearReposAndNamespace()
+        throws Exception
+    {
+        List<Project> projects = cmr.getProjectEntityManager().getAll();
+
+        cmr.getProjectEntityManager().remove( projects );
+
+        List<Namespace> namespaces = cmr.getNamespaceEntityManager().getAll();
+
+        cmr.getNamespaceEntityManager().remove( namespaces );
+
+        List<Repository> repositories = cmr.getRepositoryEntityManager().getAll();
+
+        cmr.getRepositoryEntityManager().remove( repositories );
+
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/test/resources/log4j2-test.xml b/archiva-modules/plugins/metadata-store-cassandra/src/test/resources/log4j2-test.xml
new file mode 100644 (file)
index 0000000..eda9468
--- /dev/null
@@ -0,0 +1,44 @@
+<?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 status="debug">
+
+
+
+  <appenders>
+    <Console name="console" target="SYSTEM_OUT">
+      <!--PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/-->
+      <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n}" />
+    </Console>
+
+  </appenders>
+  <loggers>
+
+
+    <logger name="org.apache.archiva.metadata.repository.cassandra.CassandraMetadataRepository" level="debug"/>
+
+    <root level="info" includeLocation="true">
+      <appender-ref ref="console"/>
+    </root>
+  </loggers>
+</configuration>
+
+