]> source.dussan.org Git - archiva.git/commitdiff
* Splitting up Constraint into DeclarativeConstraint and SimpleConstraint.
authorJoakim Erdfelt <joakime@apache.org>
Fri, 20 Apr 2007 20:44:32 +0000 (20:44 +0000)
committerJoakim Erdfelt <joakime@apache.org>
Fri, 20 Apr 2007 20:44:32 +0000 (20:44 +0000)
* Adding ArchivaDAO.query(SimpleConstraint).
* Adding UniqueGroupIdConstraint.
* Adding UniqueArtifactId Constraint.
* Adding UniqueVersionConstraint.
* Adding RepositoryBrowsing component.
* Refactoring webapp's BrowseAction groupId filtering into GroupIdFilter class.
* Refactoring BrowseAction to utilize new RepositoryBrowsing component.

git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/branches/archiva-jpox-database-refactor@530911 13f79535-47bb-0310-9956-ffa450edef68

34 files changed:
archiva-database/src/main/java/org/apache/maven/archiva/database/ArchivaDAO.java
archiva-database/src/main/java/org/apache/maven/archiva/database/Constraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/DeclarativeConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/SimpleConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/BrowsingResults.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/DefaultRepositoryBrowsing.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/GroupIdFilter.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsing.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractConstraint.java [deleted file]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractDeclarativeConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractSimpleConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArchivaRepositoryByUrlConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArtifactsBySha1ChecksumConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArtifactsProcessedConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/ArtifactsRelatedConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/OlderArtifactsByAgeConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/OlderSnapshotArtifactsByAgeConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/RecentArtifactsByAgeConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/RepositoryProblemByTypeConstraint.java
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraint.java [new file with mode: 0644]
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoAccess.java
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArchivaDAO.java
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoArtifactDAO.java
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoProjectModelDAO.java
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoRepositoryDAO.java
archiva-database/src/main/java/org/apache/maven/archiva/database/jdo/JdoRepositoryProblemDAO.java
archiva-database/src/test/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsingTest.java [new file with mode: 0644]
archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/AllTests.java [new file with mode: 0644]
archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraintTest.java [new file with mode: 0644]
archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraintTest.java [new file with mode: 0644]
archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraintTest.java [new file with mode: 0644]
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/BrowseAction.java

index fab48a55411b5d3353e2676d356220a17bfa8dbf..d6675c6edae5d6f33dd9f520170c24e4b79f6829 100644 (file)
@@ -19,6 +19,8 @@ package org.apache.maven.archiva.database;
  * under the License.
  */
 
+import java.util.List;
+
 /**
  * ArchivaDAO - The interface for all content within the database.
  *
@@ -29,11 +31,19 @@ public interface ArchivaDAO
 {
     public static final String ROLE = ArchivaDAO.class.getName();
 
+    /**
+     * Perform a simple query against the database.
+     * 
+     * @param constraint the constraint to use.
+     * @return the List of results.
+     */
+    List query( SimpleConstraint constraint );
+
     ArtifactDAO getArtifactDAO();
 
     ProjectModelDAO getProjectModelDAO();
 
     RepositoryDAO getRepositoryDAO();
-    
+
     RepositoryProblemDAO getRepositoryProblemDAO();
 }
index ac23319f4c80904212915374ac9f0ee33e8db0d3..d0a02b248a71bd31e8d70402b6a8481b4733079e 100644 (file)
@@ -1,10 +1,32 @@
 package org.apache.maven.archiva.database;
 
+/*
+ * 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.
+ */
+
+
 /**
- * Constraint 
+ * Constraint - a generic object for dealing with database constraints. 
  *
  * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
  * @version $Id$
+ * @see DeclarativeConstraint
+ * @see SimpleConstraint
  */
 public interface Constraint
 {
@@ -18,52 +40,4 @@ public interface Constraint
      * @return the fetch limits on the object. (can be null) (O/RM specific)
      */
     public String getFetchLimits();
-
-    /**
-     * Get the SELECT WHERE (condition) value for the constraint.
-     * 
-     * @return the equivalent of the SELECT WHERE (condition) value for this constraint. (can be null)
-     */
-    public String getWhereCondition();
-
-    /**
-     * Get the sort column name.
-     * 
-     * @return the sort column name. (can be null)
-     */
-    public String getSortColumn();
-
-    /**
-     * Get the sort direction name.
-     * 
-     * @return the sort direction name. ("ASC" or "DESC") (only valid if {@link #getSortColumn()} is specified.)
-     */
-    public String getSortDirection();
-    
-    /**
-     * Get the declared imports used for this query. (optional)
-     * 
-     * NOTE: This is DAO implementation specific.
-     * 
-     * @return the imports. (can be null)
-     */
-    public String[] getDeclaredImports();
-    
-    /**
-     * Get the declared parameters used for this query. (optional)
-     * 
-     * NOTE: This is DAO implementation specific.
-     * 
-     * @return the parameters. (can be null)
-     */
-    public String[] getDeclaredParameters();
-    
-    /**
-     * Get the parameters used for this query. (required if using {@link #getDeclaredParameters()} )
-     * 
-     * NOTE: This is DAO implementation specific.
-     * 
-     * @return the parameters. (can be null)
-     */
-    public Object[] getParameters();
 }
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/DeclarativeConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/DeclarativeConstraint.java
new file mode 100644 (file)
index 0000000..54b0b47
--- /dev/null
@@ -0,0 +1,77 @@
+package org.apache.maven.archiva.database;
+
+/*
+ * 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.
+ */
+
+/**
+ * DeclarativeConstraint 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public interface DeclarativeConstraint extends Constraint
+{
+    /**
+     * Get the declared imports used for this query. (optional)
+     * 
+     * NOTE: This is DAO implementation specific.
+     * 
+     * @return the imports. (can be null)
+     */
+    public abstract String[] getDeclaredImports();
+
+    /**
+     * Get the declared parameters used for this query. (optional)
+     * 
+     * NOTE: This is DAO implementation specific.
+     * 
+     * @return the parameters. (can be null)
+     */
+    public abstract String[] getDeclaredParameters();
+
+    /**
+     * Get the parameters used for this query. (required if using {@link #getDeclaredParameters()} )
+     * 
+     * NOTE: This is DAO implementation specific.
+     * 
+     * @return the parameters. (can be null)
+     */
+    public abstract Object[] getParameters();
+
+    /**
+     * Get the sort direction name.
+     * 
+     * @return the sort direction name. ("ASC" or "DESC") (only valid if {@link #getSortColumn()} is specified.)
+     */
+    public abstract String getSortDirection();
+
+    /**
+     * Get the sort column name.
+     * 
+     * @return the sort column name. (can be null)
+     */
+    public abstract String getSortColumn();
+
+    /**
+     * Get the SELECT WHERE (condition) value for the constraint.
+     * 
+     * @return the equivalent of the SELECT WHERE (condition) value for this constraint. (can be null)
+     */
+    public abstract String getWhereCondition();
+}
\ No newline at end of file
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/SimpleConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/SimpleConstraint.java
new file mode 100644 (file)
index 0000000..d08c225
--- /dev/null
@@ -0,0 +1,60 @@
+package org.apache.maven.archiva.database;
+
+/*
+ * 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.
+ */
+
+/**
+ * SimpleConstraint 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public interface SimpleConstraint extends Constraint
+{
+    /**
+     * Get the parameters used for this query. (required if using parameterized SQL)
+     * 
+     * NOTE: This is DAO implementation specific.
+     * 
+     * @return the parameters. (can be null)
+     */
+    public Object[] getParameters();
+
+    /**
+     * Get the SELECT query value for the constraint.
+     * 
+     * @return the SELECT value for this constraint. (can be null)
+     */
+    public abstract String getSelectSql();
+
+    /**
+     * For simple Constraints the results class must be specified.
+     * 
+     * @return the result class.
+     */
+    public Class getResultClass();
+    
+    /**
+     * When working with result classes that are not persistable,
+     * it is advisable to tell the underlying DAO to not do the persistable related efforts.
+     * 
+     * @return true if result classes are persistable.
+     */
+    public boolean isResultsPersistable();
+}
\ No newline at end of file
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/BrowsingResults.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/BrowsingResults.java
new file mode 100644 (file)
index 0000000..118c9e1
--- /dev/null
@@ -0,0 +1,114 @@
+package org.apache.maven.archiva.database.browsing;
+
+/*
+ * 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.commons.collections.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * BrowsingResults 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class BrowsingResults
+{
+    private String selectedGroupId;
+    
+    private String selectedArtifactId;
+
+    private List groupIds = null;
+
+    private List artifacts = null;
+
+    private List versions = null;
+
+    public BrowsingResults()
+    {
+        /* do nothing, this is the results of the root */
+    }
+
+    public BrowsingResults( String groupId )
+    {
+        this.selectedGroupId = groupId;
+    }
+    
+    public BrowsingResults( String groupId, String artifactId )
+    {
+        this.selectedGroupId = groupId;
+        this.selectedArtifactId = artifactId;
+    }
+
+    public List getArtifacts()
+    {
+        return artifacts;
+    }
+
+    public List getGroupIds()
+    {
+        return groupIds;
+    }
+
+    public String getSelectedArtifactId()
+    {
+        return selectedArtifactId;
+    }
+
+    public String getSelectedGroupId()
+    {
+        return selectedGroupId;
+    }
+
+    public List getVersions()
+    {
+        return versions;
+    }
+
+    public boolean hasArtifacts()
+    {
+        return CollectionUtils.isNotEmpty( artifacts );
+    }
+
+    public boolean hasGroupIds()
+    {
+        return CollectionUtils.isNotEmpty( groupIds );
+    }
+
+    public boolean hasVersions()
+    {
+        return CollectionUtils.isNotEmpty( versions );
+    }
+
+    public void setArtifacts( List artifacts )
+    {
+        this.artifacts = artifacts;
+    }
+
+    public void setGroupIds( List groupIds )
+    {
+        this.groupIds = groupIds;
+    }
+
+    public void setVersions( List versions )
+    {
+        this.versions = versions;
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/DefaultRepositoryBrowsing.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/DefaultRepositoryBrowsing.java
new file mode 100644 (file)
index 0000000..83c5727
--- /dev/null
@@ -0,0 +1,98 @@
+package org.apache.maven.archiva.database.browsing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.ArchivaDatabaseException;
+import org.apache.maven.archiva.database.ObjectNotFoundException;
+import org.apache.maven.archiva.database.constraints.UniqueArtifactIdConstraint;
+import org.apache.maven.archiva.database.constraints.UniqueGroupIdConstraint;
+import org.apache.maven.archiva.database.constraints.UniqueVersionConstraint;
+import org.apache.maven.archiva.model.ArchivaProjectModel;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import java.util.List;
+
+/**
+ * DefaultRepositoryBrowsing 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ * 
+ * @plexus.component role="org.apache.maven.archiva.database.browsing.RepositoryBrowsing"
+ *                   role-hint="default"
+ */
+public class DefaultRepositoryBrowsing
+    extends AbstractLogEnabled
+    implements RepositoryBrowsing
+{
+    /**
+     * @plexus.requirement
+     */
+    private ArchivaDAO dao;
+
+    public BrowsingResults getRoot()
+    {
+        List groups = dao.query( new UniqueGroupIdConstraint() );
+
+        BrowsingResults results = new BrowsingResults();
+
+        results.setGroupIds( GroupIdFilter.filterGroups( groups ) );
+
+        return results;
+    }
+
+    public BrowsingResults selectArtifactId( String groupId, String artifactId )
+    {
+        // List groups = dao.query( new UniqueGroupIdConstraint( groupId ) );
+        // List artifacts = dao.query( new UniqueArtifactIdConstraint( groupId ) );
+        List versions = dao.query( new UniqueVersionConstraint( groupId, artifactId ) );
+
+        BrowsingResults results = new BrowsingResults( groupId, artifactId );
+
+        // results.setGroupIds( groups );
+        // results.setArtifacts( artifacts );
+        results.setArtifacts( versions );
+
+        return results;
+    }
+
+    public BrowsingResults selectGroupId( String groupId )
+    {
+        List groups = dao.query( new UniqueGroupIdConstraint( groupId ) );
+        List artifacts = dao.query( new UniqueArtifactIdConstraint( groupId ) );
+
+        BrowsingResults results = new BrowsingResults( groupId );
+        results.setGroupIds( groups );
+        results.setArtifacts( artifacts );
+
+        return results;
+    }
+
+    public ArchivaProjectModel selectVersion( String groupId, String artifactId, String version )
+        throws ObjectNotFoundException, ArchivaDatabaseException
+    {
+        ArchivaProjectModel model = dao.getProjectModelDAO().getProjectModel( groupId, artifactId, version );
+
+        // TODO: if the model isn't found. load it from disk, insert into DB, and then return it.
+
+        return model;
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/GroupIdFilter.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/GroupIdFilter.java
new file mode 100644 (file)
index 0000000..a102e9c
--- /dev/null
@@ -0,0 +1,176 @@
+package org.apache.maven.archiva.database.browsing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+/**
+ * GroupIdFilter - utility methods for filtering groupIds. 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class GroupIdFilter
+{
+    private static final String GROUP_SEPARATOR = ".";
+
+    /**
+     * <p>
+     * Filter out excessive groupId naming. (to provide a tree-ish view of the list of groupIds).
+     * </p>
+     * 
+     * <pre>
+     *  // Input List
+     *  commons-lang
+     *  com.jsch
+     *  org.apache.apache
+     *  org.apache.maven
+     *  org.codehaus.modello
+     *  // Filtered List
+     *  commons-lang
+     *  com.jsch
+     *  org
+     * </pre>
+     * 
+     * <pre>
+     *  // Input List
+     *  commons-lang
+     *  commons-io
+     *  commons-pool
+     *  com.jsch
+     *  com.jsch.lib
+     *  com.jsch.providers
+     *  org.apache.apache
+     *  org.apache.maven
+     *  org.apache.maven.archiva
+     *  org.apache.maven.shared
+     *  // Filtered List
+     *  commons-lang
+     *  commons-io
+     *  commons-pool
+     *  com.jsch
+     *  org.apache
+     * </pre>
+     * 
+     * @param groups the list of groupIds.
+     * @return
+     */
+    public static List filterGroups( List groups )
+    {
+        GroupTreeNode tree = buildGroupTree( groups );
+        return collateGroups( tree );
+    }
+
+    public static GroupTreeNode buildGroupTree( List groups )
+    {
+        GroupTreeNode rootNode = new GroupTreeNode();
+
+        // build a tree structure
+        for ( Iterator i = groups.iterator(); i.hasNext(); )
+        {
+            String groupId = (String) i.next();
+
+            StringTokenizer tok = new StringTokenizer( groupId, GROUP_SEPARATOR );
+
+            GroupTreeNode node = rootNode;
+
+            while ( tok.hasMoreTokens() )
+            {
+                String part = tok.nextToken();
+
+                if ( !node.getChildren().containsKey( part ) )
+                {
+                    GroupTreeNode newNode = new GroupTreeNode( part, node );
+                    node.addChild( newNode );
+                    node = newNode;
+                }
+                else
+                {
+                    node = (GroupTreeNode) node.getChildren().get( part );
+                }
+            }
+        }
+
+        return rootNode;
+    }
+
+    private static List collateGroups( GroupTreeNode rootNode )
+    {
+        List groups = new ArrayList();
+        for ( Iterator i = rootNode.getChildren().values().iterator(); i.hasNext(); )
+        {
+            GroupTreeNode node = (GroupTreeNode) i.next();
+
+            while ( node.getChildren().size() == 1 )
+            {
+                node = (GroupTreeNode) node.getChildren().values().iterator().next();
+            }
+
+            groups.add( node.getFullName() );
+        }
+        return groups;
+    }
+
+    private static class GroupTreeNode
+    {
+        private final String name;
+
+        private final String fullName;
+
+        private final Map children = new TreeMap();
+
+        GroupTreeNode()
+        {
+            name = null;
+            fullName = null;
+        }
+
+        GroupTreeNode( String name, GroupTreeNode parent )
+        {
+            this.name = name;
+            this.fullName = parent.fullName != null ? parent.fullName + GROUP_SEPARATOR + name : name;
+        }
+
+        public String getName()
+        {
+            return name;
+        }
+
+        public String getFullName()
+        {
+            return fullName;
+        }
+
+        public Map getChildren()
+        {
+            return children;
+        }
+
+        public void addChild( GroupTreeNode newNode )
+        {
+            children.put( newNode.name, newNode );
+        }
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsing.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsing.java
new file mode 100644 (file)
index 0000000..ead8a79
--- /dev/null
@@ -0,0 +1,42 @@
+package org.apache.maven.archiva.database.browsing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.ArchivaDatabaseException;
+import org.apache.maven.archiva.database.ObjectNotFoundException;
+import org.apache.maven.archiva.model.ArchivaProjectModel;
+
+/**
+ * RepositoryBrowsing 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public interface RepositoryBrowsing
+{
+    public BrowsingResults getRoot();
+
+    public BrowsingResults selectGroupId( String groupId );
+
+    public BrowsingResults selectArtifactId( String groupId, String artifactId );
+
+    public ArchivaProjectModel selectVersion( String groupId, String artifactId, String version )
+        throws ObjectNotFoundException, ArchivaDatabaseException;
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractConstraint.java
deleted file mode 100644 (file)
index 99d057a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.apache.maven.archiva.database.constraints;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.archiva.database.Constraint;
-
-/**
- * AbstractConstraint 
- *
- * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
- * @version $Id$
- */
-public abstract class AbstractConstraint
-    implements Constraint
-{
-    protected String[] declImports;
-    protected String[] declParams;
-    protected Object[] params;
-
-    public String getFetchLimits()
-    {
-        return null;
-    }
-
-    public String[] getDeclaredImports()
-    {
-        return declImports;
-    }
-
-    public String[] getDeclaredParameters()
-    {
-        return declParams;
-    }
-    
-    public Object[] getParameters()
-    {
-        return params;
-    }
-
-    public String getSortDirection()
-    {
-        return Constraint.ASCENDING;
-    }
-
-    public abstract String getSortColumn();
-
-    public abstract String getWhereCondition();
-}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractDeclarativeConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractDeclarativeConstraint.java
new file mode 100644 (file)
index 0000000..48a4a3d
--- /dev/null
@@ -0,0 +1,64 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.Constraint;
+import org.apache.maven.archiva.database.DeclarativeConstraint;
+
+/**
+ * AbstractDeclarativeConstraint 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public abstract class AbstractDeclarativeConstraint
+    implements DeclarativeConstraint
+{
+    protected String[] declImports;
+
+    protected String[] declParams;
+
+    protected Object[] params;
+
+    public String getFetchLimits()
+    {
+        return null;
+    }
+
+    public String[] getDeclaredImports()
+    {
+        return declImports;
+    }
+
+    public String[] getDeclaredParameters()
+    {
+        return declParams;
+    }
+
+    public Object[] getParameters()
+    {
+        return params;
+    }
+
+    public String getSortDirection()
+    {
+        return Constraint.ASCENDING;
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractSimpleConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/AbstractSimpleConstraint.java
new file mode 100644 (file)
index 0000000..b9e76ff
--- /dev/null
@@ -0,0 +1,49 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.SimpleConstraint;
+
+/**
+ * Simple Constraint abstract for working with nearly-raw SQL strings. 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public abstract class AbstractSimpleConstraint
+    implements SimpleConstraint
+{
+    protected Object[] params;
+    
+    public Object[] getParameters()
+    {
+        return params;
+    }
+
+    public String getFetchLimits()
+    {
+        return null;
+    }
+
+    public boolean isResultsPersistable()
+    {
+        return false;
+    }
+}
index 73419a7a25f1171c27dd737dedc052caffd6bae5..9ad4de6051a39a1a65e8bdc04a7c45c1494a3b7a 100644 (file)
@@ -9,7 +9,7 @@ import org.apache.maven.archiva.database.Constraint;
  * @version $Id$
  */
 public class ArchivaRepositoryByUrlConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereCondition;
index 464f75c02ccad4c7d8cc28f7866c6dada7f5af10..e8ac7a539bcb2f8712a7eca33823f54794ecf75b 100644 (file)
@@ -28,7 +28,7 @@ import org.apache.maven.archiva.database.Constraint;
  * @version $Id$
  */
 public class ArtifactsBySha1ChecksumConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index 7a265f40dd35b025413fa8d5a453cfdb8c769ce5..a8b389c5c0b19ec6ccb088068effe3ad9589ec3c 100644 (file)
@@ -30,7 +30,7 @@ import java.util.Date;
  * @version $Id$
  */
 public class ArtifactsProcessedConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index 60c0461dbcf4bd6ea0ff1b01c1f286d7ca94444b..6f544ad597a3d78b234e632d684eab7dc8efb856 100644 (file)
@@ -29,7 +29,7 @@ import org.apache.maven.archiva.database.Constraint;
  * @version $Id$
  */
 public class ArtifactsRelatedConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index b893e690cfcf8e331802ca5264b566e7b750d4fa..55d8cbee8fef0d85293b0dd8884281bc33892188 100644 (file)
@@ -31,7 +31,7 @@ import java.util.Date;
  * @version $Id$
  */
 public class OlderArtifactsByAgeConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index a55907b14c74c97579d7551d2ba17e1b6616792e..31141046347a8a77ab33ff746de56a1381d42267 100644 (file)
@@ -31,7 +31,7 @@ import java.util.Date;
  * @version $Id$
  */
 public class OlderSnapshotArtifactsByAgeConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index e590b015fe3ab2f1054c7953d7bb920d69d9b717..3f2e101b50b53fe642076df5090b87bf687745a1 100644 (file)
@@ -31,7 +31,7 @@ import java.util.Date;
  * @version $Id$
  */
 public class RecentArtifactsByAgeConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
index 6de7788b31ccd4869206ba8f3225838f2a4926f6..6be5f836265a2c62de653fcdd4f51f10b8daff22 100644 (file)
@@ -28,7 +28,7 @@ import org.apache.maven.archiva.database.Constraint;
  * @version $Id$
  */
 public class RepositoryProblemByTypeConstraint
-    extends AbstractConstraint
+    extends AbstractDeclarativeConstraint
     implements Constraint
 {
     private String whereClause;
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraint.java
new file mode 100644 (file)
index 0000000..d8a6e38
--- /dev/null
@@ -0,0 +1,60 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.Constraint;
+import org.apache.maven.archiva.model.ArchivaArtifactModel;
+
+/**
+ * Obtain a set of unique ArtifactIds for the specified groupId.
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueArtifactIdConstraint
+    extends AbstractSimpleConstraint
+    implements Constraint
+{
+    private String sql;
+
+    /**
+     * Obtain a set of unique ArtifactIds for the specified groupId.
+     * 
+     * @param groupId the groupId to search for artifactIds within.
+     */
+    public UniqueArtifactIdConstraint( String groupId )
+    {
+        sql = "SELECT artifactId FROM " + ArchivaArtifactModel.class.getName()
+            + " WHERE groupId == selectedGroupId PARAMETERS String selectedGroupId"
+            + " GROUP BY artifactId ORDER BY artifactId ASCENDING";
+
+        super.params = new Object[] { groupId };
+    }
+
+    public Class getResultClass()
+    {
+        return String.class;
+    }
+
+    public String getSelectSql()
+    {
+        return sql;
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraint.java
new file mode 100644 (file)
index 0000000..246e3e7
--- /dev/null
@@ -0,0 +1,62 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.Constraint;
+import org.apache.maven.archiva.model.ArchivaArtifactModel;
+
+/**
+ * UniqueGroupIdConstraint 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueGroupIdConstraint
+    extends AbstractSimpleConstraint
+    implements Constraint
+{
+    private String sql;
+
+    public UniqueGroupIdConstraint()
+    {
+        /* this assumes search for no groupId prefix */
+        sql = "SELECT groupId FROM " + ArchivaArtifactModel.class.getName()
+            + " GROUP BY groupId ORDER BY groupId ASCENDING";
+    }
+
+    public UniqueGroupIdConstraint( String groupIdPrefix )
+    {
+        sql = "SELECT groupId FROM " + ArchivaArtifactModel.class.getName()
+            + " WHERE groupId.startsWith(groupIdPrefix) PARAMETERS String groupIdPrefix"
+            + " GROUP BY groupId ORDER BY groupId ASCENDING";
+
+        super.params = new Object[] { groupIdPrefix };
+    }
+
+    public Class getResultClass()
+    {
+        return String.class;
+    }
+
+    public String getSelectSql()
+    {
+        return sql;
+    }
+}
diff --git a/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraint.java b/archiva-database/src/main/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraint.java
new file mode 100644 (file)
index 0000000..f39c603
--- /dev/null
@@ -0,0 +1,73 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.maven.archiva.database.Constraint;
+import org.apache.maven.archiva.model.ArchivaArtifactModel;
+
+/**
+ * Obtain the list of version's for specific GroupId and ArtifactId.
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueVersionConstraint
+    extends AbstractSimpleConstraint
+    implements Constraint
+{
+    private String sql;
+
+    /**
+     * Obtain the list of version's for specific GroupId and ArtifactId.
+     * 
+     * @param groupId the selected groupId.
+     * @param artifactId the selected artifactId.
+     */
+    public UniqueVersionConstraint( String groupId, String artifactId )
+    {
+        if ( StringUtils.isBlank( groupId ) )
+        {
+            throw new IllegalArgumentException( "A blank groupId is not allowed." );
+        }
+
+        if ( StringUtils.isBlank( artifactId ) )
+        {
+            throw new IllegalArgumentException( "A blank artifactId is not allowed." );
+        }
+
+        sql = "SELECT version FROM " + ArchivaArtifactModel.class.getName()
+            + " WHERE groupId == selectedGroupId && artifactId == selectedArtifactId"
+            + " PARAMETERS String selectedGroupId, String selectedArtifactId"
+            + " GROUP BY version ORDER BY version ASCENDING";
+
+        super.params = new Object[] { groupId, artifactId };
+    }
+
+    public Class getResultClass()
+    {
+        return String.class;
+    }
+
+    public String getSelectSql()
+    {
+        return sql;
+    }
+}
index 73c262cecd76ec5783503c844faab84ebe52f7a9..75e89536083e333b88e668e406734b1036017119 100644 (file)
@@ -22,13 +22,17 @@ package org.apache.maven.archiva.database.jdo;
 import org.apache.commons.lang.StringUtils;
 import org.apache.maven.archiva.database.ArchivaDatabaseException;
 import org.apache.maven.archiva.database.Constraint;
+import org.apache.maven.archiva.database.DeclarativeConstraint;
 import org.apache.maven.archiva.database.ObjectNotFoundException;
+import org.apache.maven.archiva.database.SimpleConstraint;
+import org.apache.maven.archiva.database.constraints.AbstractSimpleConstraint;
 import org.apache.maven.archiva.model.CompoundKey;
 import org.codehaus.plexus.jdo.JdoFactory;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
 
 import java.io.PrintStream;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.jdo.Extent;
@@ -167,10 +171,10 @@ public class JdoAccess
 
     public List getAllObjects( Class clazz )
     {
-        return getAllObjects( clazz, null );
+        return queryObjects( clazz, null );
     }
 
-    public List getAllObjects( Class clazz, Constraint constraint )
+    public List queryObjects( Class clazz, Constraint constraint )
     {
         PersistenceManager pm = getPersistenceManager();
         Transaction tx = pm.currentTransaction();
@@ -179,93 +183,26 @@ public class JdoAccess
         {
             tx.begin();
 
-            Extent extent = pm.getExtent( clazz, true );
-
-            Query query = pm.newQuery( extent );
-
             List result = null;
 
             if ( constraint != null )
             {
-                if ( constraint.getSortColumn() != null )
-                {
-                    String ordering = constraint.getSortColumn();
-
-                    if ( constraint.getSortDirection() != null )
-                    {
-                        ordering += " " + constraint.getSortDirection();
-                    }
-
-                    query.setOrdering( ordering );
-                }
-
-                if ( constraint.getFetchLimits() != null )
-                {
-                    pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
-                }
-
-                if ( constraint.getWhereCondition() != null )
-                {
-                    query.setFilter( constraint.getWhereCondition() );
-                }
-
-                if ( constraint.getDeclaredImports() != null )
+                if ( constraint instanceof DeclarativeConstraint )
                 {
-                    for ( int i = 0; i < constraint.getDeclaredImports().length; i++ )
-                    {
-                        String qimport = constraint.getDeclaredImports()[i];
-                        query.declareImports( qimport );
-                    }
+                    result = processConstraint( pm, clazz, (DeclarativeConstraint) constraint );
                 }
-
-                if ( constraint.getDeclaredParameters() != null )
+                else if ( constraint instanceof AbstractSimpleConstraint )
                 {
-                    if ( constraint.getParameters() == null )
-                    {
-                        throw new JDOException( "Unable to use query, there are declared parameters, "
-                            + "but no parameter objects to use." );
-                    }
-
-                    if ( constraint.getParameters().length != constraint.getDeclaredParameters().length )
-                    {
-                        throw new JDOException( "Unable to use query, there are <"
-                            + constraint.getDeclaredParameters().length + "> declared parameters, yet there are <"
-                            + constraint.getParameters().length + "> parameter objects to use.  This should be equal." );
-                    }
-
-                    for ( int i = 0; i < constraint.getDeclaredParameters().length; i++ )
-                    {
-                        String declaredParam = constraint.getDeclaredParameters()[i];
-                        query.declareParameters( declaredParam );
-                    }
-
-                    switch ( constraint.getParameters().length )
-                    {
-                        case 1:
-                            result = (List) query.execute( constraint.getParameters()[0] );
-                            break;
-                        case 2:
-                            result = (List) query
-                                .execute( constraint.getParameters()[0], constraint.getParameters()[1] );
-                            break;
-                        case 3:
-                            result = (List) query
-                                .execute( constraint.getParameters()[0], constraint.getParameters()[1], constraint
-                                    .getParameters()[2] );
-                            break;
-                        default:
-                            throw new JDOException( "Unable to use more than 3 parameters." );
-                    }
+                    result = processConstraint( pm, (SimpleConstraint) constraint );
                 }
                 else
                 {
-                    // Process unparameterized query.
-                    result = (List) query.execute();
+                    result = processUnconstrained( pm, clazz );
                 }
             }
             else
             {
-                result = (List) query.execute();
+                result = processUnconstrained( pm, clazz );
             }
 
             result = (List) pm.detachCopyAll( result );
@@ -280,6 +217,150 @@ public class JdoAccess
         }
     }
 
+    public List queryObjects( SimpleConstraint constraint )
+    {
+        PersistenceManager pm = getPersistenceManager();
+        Transaction tx = pm.currentTransaction();
+
+        try
+        {
+            tx.begin();
+
+            List result = processConstraint( pm, constraint );
+
+            // Only detach if results are known to be persistable.
+            if ( constraint.isResultsPersistable() )
+            {
+                result = (List) pm.detachCopyAll( result );
+            }
+            else
+            {
+                List copiedResults = new ArrayList();
+                copiedResults.addAll( result );
+                result = copiedResults;
+            }
+
+            tx.commit();
+
+            return result;
+        }
+        finally
+        {
+            rollbackIfActive( tx );
+        }
+    }
+
+    private List processUnconstrained( PersistenceManager pm, Class clazz )
+    {
+        Extent extent = pm.getExtent( clazz, true );
+        Query query = pm.newQuery( extent );
+        return (List) query.execute();
+    }
+
+    private List processConstraint( PersistenceManager pm, SimpleConstraint constraint )
+    {
+        Query query = pm.newQuery( constraint.getSelectSql() );
+
+        if ( constraint.getResultClass() == null )
+        {
+            throw new IllegalStateException( "Unable to use a SimpleConstraint with a null result class." );
+        }
+
+        query.setResultClass( constraint.getResultClass() );
+
+        if ( constraint.getFetchLimits() != null )
+        {
+            pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
+        }
+
+        if ( constraint.getParameters() != null )
+        {
+            return processParameterizedQuery( query, constraint.getParameters() );
+        }
+
+        return (List) query.execute();
+    }
+
+    private List processConstraint( PersistenceManager pm, Class clazz, DeclarativeConstraint constraint )
+    {
+        Extent extent = pm.getExtent( clazz, true );
+        Query query = pm.newQuery( extent );
+
+        if ( constraint.getSortColumn() != null )
+        {
+            String ordering = constraint.getSortColumn();
+
+            if ( constraint.getSortDirection() != null )
+            {
+                ordering += " " + constraint.getSortDirection();
+            }
+
+            query.setOrdering( ordering );
+        }
+
+        if ( constraint.getFetchLimits() != null )
+        {
+            pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
+        }
+
+        if ( constraint.getWhereCondition() != null )
+        {
+            query.setFilter( constraint.getWhereCondition() );
+        }
+
+        if ( constraint.getDeclaredImports() != null )
+        {
+            for ( int i = 0; i < constraint.getDeclaredImports().length; i++ )
+            {
+                String qimport = constraint.getDeclaredImports()[i];
+                query.declareImports( qimport );
+            }
+        }
+
+        if ( constraint.getDeclaredParameters() != null )
+        {
+            if ( constraint.getParameters() == null )
+            {
+                throw new JDOException( "Unable to use query, there are declared parameters, "
+                    + "but no parameter objects to use." );
+            }
+
+            if ( constraint.getParameters().length != constraint.getDeclaredParameters().length )
+            {
+                throw new JDOException( "Unable to use query, there are <" + constraint.getDeclaredParameters().length
+                    + "> declared parameters, yet there are <" + constraint.getParameters().length
+                    + "> parameter objects to use.  This should be equal." );
+            }
+
+            for ( int i = 0; i < constraint.getDeclaredParameters().length; i++ )
+            {
+                String declaredParam = constraint.getDeclaredParameters()[i];
+                query.declareParameters( declaredParam );
+            }
+
+            return processParameterizedQuery( query, constraint.getParameters() );
+        }
+        else
+        {
+            return (List) query.execute();
+        }
+    }
+
+    private List processParameterizedQuery( Query query, Object parameters[] )
+    {
+        switch ( parameters.length )
+        {
+            case 1:
+                return (List) query.execute( parameters[0] );
+            case 2:
+                return (List) query.execute( parameters[0], parameters[1] );
+            case 3:
+                return (List) query.execute( parameters[0], parameters[1], parameters[2] );
+            default:
+                throw new JDOException( "Unable to use more than 3 parameters." );
+        }
+    }
+
     public Object getObjectById( Class clazz, Object id, String fetchGroup )
         throws ObjectNotFoundException, ArchivaDatabaseException
     {
index 5c87e91dd0a58bad24b9fb5069b99af9eecc793a..b1544de1d42e3f6a3445e115bf54a355b537a776 100644 (file)
@@ -24,8 +24,11 @@ import org.apache.maven.archiva.database.ArtifactDAO;
 import org.apache.maven.archiva.database.ProjectModelDAO;
 import org.apache.maven.archiva.database.RepositoryDAO;
 import org.apache.maven.archiva.database.RepositoryProblemDAO;
+import org.apache.maven.archiva.database.SimpleConstraint;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 
+import java.util.List;
+
 /**
  * JdoArchivaDAO 
  *
@@ -38,6 +41,11 @@ public class JdoArchivaDAO
     extends AbstractLogEnabled
     implements ArchivaDAO
 {
+    /**
+     * @plexus.requirement role-hint="archiva"
+     */
+    private JdoAccess jdo;
+    
     /**
      * @plexus.requirement role-hint="jdo"
      */
@@ -57,6 +65,11 @@ public class JdoArchivaDAO
      * @plexus.requirement role-hint="jdo"
      */
     private RepositoryProblemDAO repositoryProblemDAO;
+    
+    public List query( SimpleConstraint constraint )
+    {
+        return jdo.queryObjects( constraint );
+    }
 
     public ArtifactDAO getArtifactDAO()
     {
index 8ef9f39a3d0d96b4de8e44bb283665327f5e7eb6..33bdbe2fc0bb8c0b80e1adf3d8f3fe21359ec64a 100644 (file)
@@ -87,7 +87,7 @@ public class JdoArtifactDAO
     public List queryArtifacts( Constraint constraint )
         throws ObjectNotFoundException, ArchivaDatabaseException
     {
-        List results = jdo.getAllObjects( ArchivaArtifactModel.class, constraint );
+        List results = jdo.queryObjects( ArchivaArtifactModel.class, constraint );
         if ( ( results == null ) || results.isEmpty() )
         {
             return results;
index f5d8cbe4fd955426faa26403d778ccc74f5d24f5..873f1b44a3f3c11eff3cdbe10bea9a92a8b0526d 100644 (file)
@@ -77,7 +77,7 @@ public class JdoProjectModelDAO
     public List queryProjectModels( Constraint constraint )
         throws ObjectNotFoundException, ArchivaDatabaseException
     {
-        return jdo.getAllObjects( ArchivaProjectModel.class, constraint );
+        return jdo.queryObjects( ArchivaProjectModel.class, constraint );
     }
 
     public ArchivaProjectModel saveProjectModel( ArchivaProjectModel model )
index efa001b32c34e338be7afb20a83df7182527c39d..0774c1c1d94519d2599e0e3714c8cae8d3cd1258 100644 (file)
@@ -81,7 +81,7 @@ public class JdoRepositoryDAO
     public List queryRepositories( Constraint constraint )
         throws ObjectNotFoundException, ArchivaDatabaseException
     {
-        List results = jdo.getAllObjects( ArchivaRepositoryModel.class, constraint );
+        List results = jdo.queryObjects( ArchivaRepositoryModel.class, constraint );
 
         if ( ( results == null ) || results.isEmpty() )
         {
index ead2bfda37fc7d12f54f89ad6f748d510a5ddce0..ee3ed6291c342320781302ad47fb2166e81caeda 100644 (file)
@@ -46,7 +46,7 @@ public class JdoRepositoryProblemDAO
     public List queryRepositoryProblems( Constraint constraint )
         throws ObjectNotFoundException, ArchivaDatabaseException
     {
-        return jdo.getAllObjects( RepositoryProblem.class, constraint );
+        return jdo.queryObjects( RepositoryProblem.class, constraint );
     }
 
     public RepositoryProblem saveRepositoryProblem( RepositoryProblem problem )
diff --git a/archiva-database/src/test/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsingTest.java b/archiva-database/src/test/java/org/apache/maven/archiva/database/browsing/RepositoryBrowsingTest.java
new file mode 100644 (file)
index 0000000..11d62cd
--- /dev/null
@@ -0,0 +1,115 @@
+package org.apache.maven.archiva.database.browsing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.archiva.database.AbstractArchivaDatabaseTestCase;
+import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.ArtifactDAO;
+import org.apache.maven.archiva.model.ArchivaArtifact;
+
+import java.util.Date;
+
+/**
+ * RepositoryBrowsingTest 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class RepositoryBrowsingTest
+    extends AbstractArchivaDatabaseTestCase
+{
+    private ArtifactDAO artifactDao;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        ArchivaDAO dao = (ArchivaDAO) lookup( ArchivaDAO.ROLE, "jdo" );
+        artifactDao = dao.getArtifactDAO();
+    }
+
+    public ArchivaArtifact createArtifact( String groupId, String artifactId, String version )
+    {
+        ArchivaArtifact artifact = artifactDao.createArtifact( groupId, artifactId, version, "", "jar" );
+        artifact.getModel().setLastModified( new Date() ); // mandatory field.
+        artifact.getModel().setRepositoryId( "testable_repo" );
+        return artifact;
+    }
+
+    public void saveTestData()
+        throws Exception
+    {
+        ArchivaArtifact artifact;
+
+        // Setup artifacts in fresh DB.
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test", "test-one", "1.2" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test.foo", "test-two", "1.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1-SNAPSHOT" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1-alpha-1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-bar", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.codehaus.modello", "modellong", "3.0" );
+        artifactDao.saveArtifact( artifact );
+    }
+
+    public RepositoryBrowsing lookupBrowser()
+        throws Exception
+    {
+        RepositoryBrowsing browser = (RepositoryBrowsing) lookup( RepositoryBrowsing.class.getName(), "default" );
+        assertNotNull( "RepositoryBrowsing should not be null.", browser );
+        return browser;
+    }
+
+    public void testSimpleBrowse()
+        throws Exception
+    {
+        saveTestData();
+
+        RepositoryBrowsing browser = lookupBrowser();
+        BrowsingResults results = browser.getRoot();
+        assertNotNull( "Browsing Results should not be null.", results );
+
+        String expectedRootGroupIds[] = new String[] { "commons-lang", "org" };
+
+        assertEquals( "Browsing Results: groupIds on root.", expectedRootGroupIds.length, results.getGroupIds().size() );
+    }
+}
diff --git a/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/AllTests.java b/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/AllTests.java
new file mode 100644 (file)
index 0000000..c7fc265
--- /dev/null
@@ -0,0 +1,48 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * IDE Provided Utility Class for all tests. 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class AllTests
+{
+
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite( "Test for org.apache.maven.archiva.database.constraints" );
+        //$JUnit-BEGIN$
+        suite.addTestSuite( ArtifactsProcessedConstraintTest.class );
+        suite.addTestSuite( ArtifactsBySha1ChecksumConstraintTest.class );
+        suite.addTestSuite( OlderArtifactsByAgeConstraintTest.class );
+        suite.addTestSuite( UniqueGroupIdConstraintTest.class );
+        suite.addTestSuite( OlderSnapshotArtifactsByAgeConstraintTest.class );
+        suite.addTestSuite( RecentArtifactsByAgeConstraintTest.class );
+        //$JUnit-END$
+        return suite;
+    }
+
+}
diff --git a/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraintTest.java b/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueArtifactIdConstraintTest.java
new file mode 100644 (file)
index 0000000..bd8a9a2
--- /dev/null
@@ -0,0 +1,119 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.maven.archiva.database.AbstractArchivaDatabaseTestCase;
+import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.ArtifactDAO;
+import org.apache.maven.archiva.database.SimpleConstraint;
+import org.apache.maven.archiva.model.ArchivaArtifact;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * UniqueArtifactIdConstraintTest 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueArtifactIdConstraintTest
+    extends AbstractArchivaDatabaseTestCase
+{
+    private ArtifactDAO artifactDao;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        ArchivaDAO dao = (ArchivaDAO) lookup( ArchivaDAO.ROLE, "jdo" );
+        artifactDao = dao.getArtifactDAO();
+    }
+
+    public ArchivaArtifact createArtifact( String groupId, String artifactId, String version )
+    {
+        ArchivaArtifact artifact = artifactDao.createArtifact( groupId, artifactId, version, "", "jar" );
+        artifact.getModel().setLastModified( new Date() ); // mandatory field.
+        artifact.getModel().setRepositoryId( "testable_repo" );
+        return artifact;
+    }
+
+    public void testConstraint()
+        throws Exception
+    {
+        ArchivaArtifact artifact;
+
+        // Setup artifacts in fresh DB.
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test", "test-one", "1.2" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test.foo", "test-two", "1.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-bar", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.codehaus.modello", "modellong", "3.0" );
+        artifactDao.saveArtifact( artifact );
+
+        assertConstraint( new String[] {}, new UniqueArtifactIdConstraint( "org.apache" ) );
+        assertConstraint( new String[] { "commons-lang" }, new UniqueArtifactIdConstraint( "commons-lang" ) );
+        assertConstraint( new String[] { "test-one" }, new UniqueArtifactIdConstraint( "org.apache.maven.test" ) );
+        assertConstraint( new String[] { "test-two", "test-bar" },
+                          new UniqueArtifactIdConstraint( "org.apache.maven.shared" ) );
+        assertConstraint( new String[] { "modellong" }, new UniqueArtifactIdConstraint( "org.codehaus.modello" ) );
+    }
+
+    private void assertConstraint( String[] artifactIds, SimpleConstraint constraint )
+    {
+        String prefix = "Unique Artifact IDs: ";
+
+        List results = dao.query( constraint );
+        assertNotNull( prefix + "Not Null", results );
+        assertEquals( prefix + "Results.size", artifactIds.length, results.size() );
+
+        List expectedArtifactIds = Arrays.asList( artifactIds );
+
+        Iterator it = results.iterator();
+        while ( it.hasNext() )
+        {
+            String actualArtifactId = (String) it.next();
+            assertTrue( prefix + "artifactId result should not be blank.", StringUtils.isNotBlank( actualArtifactId ) );
+            assertTrue( prefix + " artifactId result <" + actualArtifactId + "> exists in expected artifactIds.",
+                        expectedArtifactIds.contains( actualArtifactId ) );
+        }
+    }
+}
diff --git a/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraintTest.java b/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueGroupIdConstraintTest.java
new file mode 100644 (file)
index 0000000..e032d23
--- /dev/null
@@ -0,0 +1,132 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.maven.archiva.database.AbstractArchivaDatabaseTestCase;
+import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.ArtifactDAO;
+import org.apache.maven.archiva.database.SimpleConstraint;
+import org.apache.maven.archiva.model.ArchivaArtifact;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * UniqueGroupIdConstraintTest 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueGroupIdConstraintTest
+    extends AbstractArchivaDatabaseTestCase
+{
+    private ArtifactDAO artifactDao;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        ArchivaDAO dao = (ArchivaDAO) lookup( ArchivaDAO.ROLE, "jdo" );
+        artifactDao = dao.getArtifactDAO();
+    }
+
+    public ArchivaArtifact createArtifact( String groupId, String artifactId, String version )
+    {
+        ArchivaArtifact artifact = artifactDao.createArtifact( groupId, artifactId, version, "", "jar" );
+        artifact.getModel().setLastModified( new Date() ); // mandatory field.
+        artifact.getModel().setRepositoryId( "testable_repo" );
+        return artifact;
+    }
+
+    public void testConstraint()
+        throws Exception
+    {
+        ArchivaArtifact artifact;
+
+        // Setup artifacts in fresh DB.
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test", "test-one", "1.2" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test.foo", "test-two", "1.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.codehaus.modello", "test-two", "3.0" );
+        artifactDao.saveArtifact( artifact );
+
+        assertConstraint( new String[] {
+            "commons-lang",
+            "org.apache.maven.test",
+            "org.apache.maven.test.foo",
+            "org.apache.maven.shared",
+            "org.codehaus.modello" }, new UniqueGroupIdConstraint() );
+        assertConstraint( new String[] { "commons-lang" }, new UniqueGroupIdConstraint( "commons-lang" ) );
+        assertConstraint( new String[] {
+            "org.apache.maven.test",
+            "org.apache.maven.test.foo",
+            "org.apache.maven.shared" }, new UniqueGroupIdConstraint( "org.apache.maven" ) );
+        assertConstraint( new String[] {
+            "org.apache.maven.test",
+            "org.apache.maven.test.foo",
+            "org.apache.maven.shared" }, new UniqueGroupIdConstraint( "org.apache" ) );
+        assertConstraint( new String[] {
+            "org.apache.maven.test",
+            "org.apache.maven.test.foo",
+            "org.apache.maven.shared",
+            "org.codehaus.modello" }, new UniqueGroupIdConstraint( "org" ) );
+    }
+
+    private void assertConstraint( String[] expectedGroupIds, SimpleConstraint constraint )
+        throws Exception
+    {
+        String prefix = "Unique Group IDs: ";
+        
+        List results = dao.query( constraint );
+        assertNotNull( prefix + "Not Null", results );
+        assertEquals( prefix + "Results.size", expectedGroupIds.length, results.size() );
+
+        List groupIdList = Arrays.asList( expectedGroupIds );
+
+        Iterator it = results.iterator();
+        while ( it.hasNext() )
+        {
+            String actualGroupId = (String) it.next();
+            assertTrue( prefix + "groupId result should not be blank.", StringUtils.isNotBlank( actualGroupId ) );
+            assertTrue( prefix + " groupId result <" + actualGroupId + "> exists in expected GroupIds.",
+                        groupIdList.contains( actualGroupId ) );
+        }
+    }
+
+}
diff --git a/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraintTest.java b/archiva-database/src/test/java/org/apache/maven/archiva/database/constraints/UniqueVersionConstraintTest.java
new file mode 100644 (file)
index 0000000..d5d47aa
--- /dev/null
@@ -0,0 +1,128 @@
+package org.apache.maven.archiva.database.constraints;
+
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.maven.archiva.database.AbstractArchivaDatabaseTestCase;
+import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.ArtifactDAO;
+import org.apache.maven.archiva.database.SimpleConstraint;
+import org.apache.maven.archiva.model.ArchivaArtifact;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * UniqueVersionConstraintTest 
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class UniqueVersionConstraintTest
+    extends AbstractArchivaDatabaseTestCase
+{
+    private ArtifactDAO artifactDao;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        ArchivaDAO dao = (ArchivaDAO) lookup( ArchivaDAO.ROLE, "jdo" );
+        artifactDao = dao.getArtifactDAO();
+    }
+
+    public ArchivaArtifact createArtifact( String groupId, String artifactId, String version )
+    {
+        ArchivaArtifact artifact = artifactDao.createArtifact( groupId, artifactId, version, "", "jar" );
+        artifact.getModel().setLastModified( new Date() ); // mandatory field.
+        artifact.getModel().setRepositoryId( "testable_repo" );
+        return artifact;
+    }
+
+    public void testConstraint()
+        throws Exception
+    {
+        ArchivaArtifact artifact;
+
+        // Setup artifacts in fresh DB.
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "commons-lang", "commons-lang", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test", "test-one", "1.2" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.test.foo", "test-two", "1.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.0" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1-SNAPSHOT" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-two", "2.1-alpha-1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.apache.maven.shared", "test-bar", "2.1" );
+        artifactDao.saveArtifact( artifact );
+
+        artifact = createArtifact( "org.codehaus.modello", "modellong", "3.0" );
+        artifactDao.saveArtifact( artifact );
+
+        assertConstraint( new String[] {}, new UniqueVersionConstraint( "org.apache", "invalid" ) );
+        assertConstraint( new String[] {}, new UniqueVersionConstraint( "org.apache.test", "invalid" ) );
+        assertConstraint( new String[] {}, new UniqueVersionConstraint( "invalid", "test-two" ) );
+
+        assertConstraint( new String[] { "2.0", "2.1" }, new UniqueVersionConstraint( "commons-lang", "commons-lang" ) );
+        assertConstraint( new String[] { "1.2" }, new UniqueVersionConstraint( "org.apache.maven.test", "test-one" ) );
+        assertConstraint( new String[] { "2.0", "2.1-SNAPSHOT", "2.1.1", "2.1-alpha-1" },
+                          new UniqueVersionConstraint( "org.apache.maven.shared", "test-two" ) );
+        assertConstraint( new String[] { "3.0" }, new UniqueVersionConstraint( "org.codehaus.modello", "modellong" ) );
+    }
+
+    private void assertConstraint( String[] versions, SimpleConstraint constraint )
+    {
+        String prefix = "Unique Versions: ";
+
+        List results = dao.query( constraint );
+        assertNotNull( prefix + "Not Null", results );
+        assertEquals( prefix + "Results.size", versions.length, results.size() );
+
+        List expectedVersions = Arrays.asList( versions );
+
+        Iterator it = results.iterator();
+        while ( it.hasNext() )
+        {
+            String actualVersion = (String) it.next();
+            assertTrue( prefix + "version result should not be blank.", StringUtils.isNotBlank( actualVersion ) );
+            assertTrue( prefix + "version result <" + actualVersion + "> exists in expected versions.",
+                        expectedVersions.contains( actualVersion ) );
+        }
+    }
+}
index fa6e88dfaea90b2b6fb0061eddc769aafbef75ee..e76b40cad8bfbb8066c618cea3320324172174a1 100644 (file)
@@ -20,87 +20,40 @@ package org.apache.maven.archiva.web.action;
  */
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.maven.archiva.configuration.ArchivaConfiguration;
-import org.apache.maven.archiva.configuration.Configuration;
-import org.apache.maven.archiva.database.ArchivaDAO;
+import org.apache.maven.archiva.database.browsing.BrowsingResults;
+import org.apache.maven.archiva.database.browsing.RepositoryBrowsing;
 import org.codehaus.plexus.xwork.action.PlexusActionSupport;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-
 /**
  * Browse the repository.
  *
- * @todo cache should be a proper cache class that is a singleton requirement rather than static variables
+ * @todo cache browsing results.
+ * @todo implement repository selectors (all or specific repository)
+ * @todo implement security around browse (based on repository id at first)
  * @plexus.component role="com.opensymphony.xwork.Action" role-hint="browseAction"
  */
 public class BrowseAction
     extends PlexusActionSupport
 {
     /**
-     * @plexus.requirement
-     */
-    private ArchivaDAO dao;
-
-    /**
-     * @plexus.requirement
+     * @plexus.requirement role-hint="default"
      */
-    private ArchivaConfiguration archivaConfiguration;
+    private RepositoryBrowsing repoBrowsing;
 
-    private List groups;
+    private BrowsingResults results;
 
     private String groupId;
 
-    private static final String GROUP_SEPARATOR = ".";
-
-    private List artifactIds;
-
     private String artifactId;
 
-    private List versions;
-
-    private static GroupTreeNode rootNode;
-
-    private static long groupCacheTime;
-
     public String browse()
-        throws RepositoryIndexException, IOException
     {
-        RepositoryArtifactIndex index = getIndex();
-
-        if ( !index.exists() )
-        {
-            addActionError( "The repository is not yet indexed. Please wait, and then try again." );
-            return ERROR;
-        }
-
-        GroupTreeNode rootNode = buildGroupTree( index );
-
-        this.groups = collateGroups( rootNode );
-
+        this.results = repoBrowsing.getRoot();
         return SUCCESS;
     }
 
     public String browseGroup()
-        throws RepositoryIndexException, IOException, RepositoryIndexSearchException
     {
-        RepositoryArtifactIndex index = getIndex();
-
-        if ( !index.exists() )
-        {
-            addActionError( "The repository is not yet indexed. Please wait, and then try again." );
-            return ERROR;
-        }
-
-        GroupTreeNode rootNode = buildGroupTree( index );
-
         if ( StringUtils.isEmpty( groupId ) )
         {
             // TODO: i18n
@@ -108,38 +61,12 @@ public class BrowseAction
             return ERROR;
         }
 
-        StringTokenizer tok = new StringTokenizer( groupId, GROUP_SEPARATOR );
-        while ( tok.hasMoreTokens() )
-        {
-            String part = tok.nextToken();
-
-            if ( !rootNode.getChildren().containsKey( part ) )
-            {
-                // TODO: i18n
-                getLogger().debug(
-                    "Can't find part: " + part + " for groupId " + groupId + " in children " + rootNode.getChildren() );
-                addActionError( "The group specified was not found" );
-                return ERROR;
-            }
-            else
-            {
-                rootNode = (GroupTreeNode) rootNode.getChildren().get( part );
-            }
-        }
-
-        this.groups = collateGroups( rootNode );
-
-        this.artifactIds = index.getArtifactIds( groupId );
-        Collections.sort( this.artifactIds );
-
+        this.results = repoBrowsing.selectGroupId( groupId );
         return SUCCESS;
     }
 
     public String browseArtifact()
-        throws RepositoryIndexException, IOException, RepositoryIndexSearchException
     {
-        RepositoryArtifactIndex index = getIndex();
-
         if ( StringUtils.isEmpty( groupId ) )
         {
             // TODO: i18n
@@ -154,96 +81,10 @@ public class BrowseAction
             return ERROR;
         }
 
-        this.versions = index.getVersions( groupId, artifactId );
-        Collections.sort( this.versions );
-
-        if ( versions.isEmpty() )
-        {
-            // TODO: i18n
-            addActionError( "Could not find any artifacts with the given group and artifact ID" );
-            return ERROR;
-        }
-
+        this.results = repoBrowsing.selectArtifactId( groupId, artifactId );
         return SUCCESS;
     }
 
-    private GroupTreeNode buildGroupTree( RepositoryArtifactIndex index )
-        throws IOException, RepositoryIndexException
-    {
-        // TODO: give action message if indexing is in progress
-
-        long lastUpdate = index.getLastUpdatedTime();
-
-        if ( rootNode == null || lastUpdate > groupCacheTime )
-        {
-            List groups = index.getAllGroupIds();
-
-            getLogger().info( "Loaded " + groups.size() + " groups from index" );
-
-            rootNode = new GroupTreeNode();
-
-            // build a tree structure
-            for ( Iterator i = groups.iterator(); i.hasNext(); )
-            {
-                String groupId = (String) i.next();
-
-                StringTokenizer tok = new StringTokenizer( groupId, GROUP_SEPARATOR );
-
-                GroupTreeNode node = rootNode;
-
-                while ( tok.hasMoreTokens() )
-                {
-                    String part = tok.nextToken();
-
-                    if ( !node.getChildren().containsKey( part ) )
-                    {
-                        GroupTreeNode newNode = new GroupTreeNode( part, node );
-                        node.addChild( newNode );
-                        node = newNode;
-                    }
-                    else
-                    {
-                        node = (GroupTreeNode) node.getChildren().get( part );
-                    }
-                }
-            }
-            groupCacheTime = lastUpdate;
-        }
-        else
-        {
-            getLogger().debug( "Loaded groups from cache" );
-        }
-
-        return rootNode;
-    }
-
-    private List collateGroups( GroupTreeNode rootNode )
-    {
-        List groups = new ArrayList();
-        for ( Iterator i = rootNode.getChildren().values().iterator(); i.hasNext(); )
-        {
-            GroupTreeNode node = (GroupTreeNode) i.next();
-
-            while ( node.getChildren().size() == 1 )
-            {
-                node = (GroupTreeNode) node.getChildren().values().iterator().next();
-            }
-
-            groups.add( node.getFullName() );
-        }
-        return groups;
-    }
-
-    public List getGroups()
-    {
-        return groups;
-    }
-
-    public List getArtifactIds()
-    {
-        return artifactIds;
-    }
-
     public String getGroupId()
     {
         return groupId;
@@ -264,49 +105,8 @@ public class BrowseAction
         this.artifactId = artifactId;
     }
 
-    public List getVersions()
-    {
-        return versions;
-    }
-
-    private static class GroupTreeNode
+    public BrowsingResults getResults()
     {
-        private final String name;
-
-        private final String fullName;
-
-        private final Map children = new TreeMap();
-
-        GroupTreeNode()
-        {
-            name = null;
-            fullName = null;
-        }
-
-        GroupTreeNode( String name, GroupTreeNode parent )
-        {
-            this.name = name;
-            this.fullName = parent.fullName != null ? parent.fullName + GROUP_SEPARATOR + name : name;
-        }
-
-        public String getName()
-        {
-            return name;
-        }
-
-        public String getFullName()
-        {
-            return fullName;
-        }
-
-        public Map getChildren()
-        {
-            return children;
-        }
-
-        public void addChild( GroupTreeNode newNode )
-        {
-            children.put( newNode.name, newNode );
-        }
+        return results;
     }
 }