Author: oching
Date: Tue Sep 16 19:51:40 2008
New Revision: 696137

URL: http://svn.apache.org/viewvc?rev=696137&view=rev
Log:
[MRM-90]
submitted by Gwen Harold Autencio
-filtered/advanced search

additional changes to patch:
-applied formatting
-removed unused methods and imports

Added:
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/SearchAction-filteredSearch-validation.xml
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/advancedSearch.jsp
Modified:
    
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java
    
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java
    
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/xwork.xml
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
    
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp

Modified: 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/CrossRepositorySearch.java
 Tue Sep 16 19:51:40 2008
@@ -69,4 +69,21 @@
      * @return the results.
      */
     public SearchResults searchForChecksum( String principal, List<String> 
selectedRepos, String checksum, SearchResultLimits limits );
+    
+    /**
+     * Search for a specific artifact matching the given field values. The 
search is performed on the bytecode
+     * index/indices.
+     * 
+     * @param principal
+     * @param selectedRepos repository to be searched
+     * @param groupId groupId to be matched
+     * @param artifactId artifactId to be matched
+     * @param version version to be matched
+     * @param className Java class or package name to be matched
+     * @param limits the limits to apply to the search results
+     * @return
+     */
+    public SearchResults executeFilteredSearch( String principal, List<String> 
selectedRepos, String groupId,
+                                                String artifactId, String 
version, String className,
+                                                SearchResultLimits limits );
 }

Modified: 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearch.java
 Tue Sep 16 19:51:40 2008
@@ -24,6 +24,7 @@
 import java.util.List;
 
 import org.apache.lucene.document.Document;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.queryParser.MultiFieldQueryParser;
 import org.apache.lucene.queryParser.ParseException;
 import org.apache.lucene.queryParser.QueryParser;
@@ -32,16 +33,20 @@
 import org.apache.lucene.search.Filter;
 import org.apache.lucene.search.Hits;
 import org.apache.lucene.search.MultiSearcher;
+import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryWrapperFilter;
 import org.apache.lucene.search.Searchable;
+import org.apache.lucene.search.TermQuery;
 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
 import org.apache.maven.archiva.configuration.ConfigurationNames;
 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
+import org.apache.maven.archiva.indexer.ArtifactKeys;
 import org.apache.maven.archiva.indexer.RepositoryContentIndex;
 import org.apache.maven.archiva.indexer.RepositoryContentIndexFactory;
 import org.apache.maven.archiva.indexer.RepositoryIndexException;
 import org.apache.maven.archiva.indexer.RepositoryIndexSearchException;
 import org.apache.maven.archiva.indexer.bytecode.BytecodeHandlers;
+import org.apache.maven.archiva.indexer.bytecode.BytecodeKeys;
 import org.apache.maven.archiva.indexer.filecontent.FileContentHandlers;
 import org.apache.maven.archiva.indexer.hashcodes.HashcodesHandlers;
 import org.apache.maven.archiva.indexer.hashcodes.HashcodesKeys;
@@ -57,7 +62,7 @@
 
 /**
  * DefaultCrossRepositorySearch
- *
+ * 
  * @author <a href="mailto:[EMAIL PROTECTED]">Joakim Erdfelt</a>
  * @version $Id$
  * @plexus.component 
role="org.apache.maven.archiva.indexer.search.CrossRepositorySearch" 
role-hint="default"
@@ -66,12 +71,12 @@
     implements CrossRepositorySearch, RegistryListener, Initializable
 {
     private Logger log = LoggerFactory.getLogger( 
DefaultCrossRepositorySearch.class );
-    
+
     /**
      * @plexus.requirement role-hint="lucene"
      */
     private RepositoryContentIndexFactory indexFactory;
-    
+
     /**
      * @plexus.requirement
      */
@@ -79,14 +84,61 @@
 
     private List<ManagedRepositoryConfiguration> localIndexedRepositories = 
new ArrayList<ManagedRepositoryConfiguration>();
 
-    public SearchResults searchForChecksum( String principal, List<String> 
selectedRepos, String checksum, SearchResultLimits limits )
+    public SearchResults executeFilteredSearch( String principal, List<String> 
selectedRepos, String groupId,
+                                                String artifactId, String 
version, String className,
+                                                SearchResultLimits limits )
+    {
+        List<RepositoryContentIndex> indexes = getBytecodeIndexes( principal, 
selectedRepos );
+        SearchResults results = new SearchResults();
+        BooleanQuery booleanQuery = new BooleanQuery();
+
+        if ( groupId != null && groupId.length() > 0 )
+        {
+            parseAndAdd( booleanQuery, ArtifactKeys.GROUPID, groupId, "\\.|-" 
);
+        }
+
+        if ( artifactId != null && artifactId.length() > 0 )
+        {
+            parseAndAdd( booleanQuery, ArtifactKeys.ARTIFACTID, artifactId, 
"\\.|-" );
+        }
+
+        if ( version != null && version.length() > 0 )
+        {
+            parseAndAdd( booleanQuery, ArtifactKeys.VERSION, version, "\\.|-" 
);
+        }
+
+        if ( className != null && className.length() > 0 )
+        {
+
+            try
+            {
+                QueryParser parser =
+                    new MultiFieldQueryParser( new String[] { 
BytecodeKeys.CLASSES, BytecodeKeys.FILES,
+                        BytecodeKeys.METHODS }, new 
BytecodeHandlers().getAnalyzer() );
+                booleanQuery.add( parser.parse( className ), 
BooleanClause.Occur.MUST );
+            }
+            catch ( ParseException e )
+            {
+
+            }
+        }
+
+        LuceneQuery query = new LuceneQuery( booleanQuery );
+        results = searchAll( query, limits, indexes, null );
+        results.getRepositories().add( this.localIndexedRepositories );
+
+        return results;
+    }
+
+    public SearchResults searchForChecksum( String principal, List<String> 
selectedRepos, String checksum,
+                                            SearchResultLimits limits )
     {
         List<RepositoryContentIndex> indexes = getHashcodeIndexes( principal, 
selectedRepos );
 
         try
         {
             QueryParser parser = new MultiFieldQueryParser( new 
String[]{HashcodesKeys.MD5, HashcodesKeys.SHA1},
-                                                            new 
HashcodesHandlers().getAnalyzer() );
+                                           new 
HashcodesHandlers().getAnalyzer() );
             LuceneQuery query = new LuceneQuery( parser.parse( checksum ) );
             SearchResults results = searchAll( query, limits, indexes, null );
             results.getRepositories().addAll( this.localIndexedRepositories );
@@ -124,23 +176,22 @@
         return new SearchResults();
     }
 
-    
     public SearchResults searchForTerm( String principal, List<String> 
selectedRepos, String term, SearchResultLimits limits )
     {
         return searchForTerm( principal, selectedRepos, term, limits, null );  
      
     }
-    
+
     public SearchResults searchForTerm( String principal, List<String> 
selectedRepos, String term,
                                         SearchResultLimits limits, 
List<String> previousSearchTerms )
     {
         List<RepositoryContentIndex> indexes = getFileContentIndexes( 
principal, selectedRepos );
-        
+
         try
         {
             QueryParser parser = new FileContentHandlers().getQueryParser();
             LuceneQuery query = null;
             SearchResults results = null;
-            if( previousSearchTerms == null || previousSearchTerms.isEmpty() )
+            if ( previousSearchTerms == null || previousSearchTerms.isEmpty() )
             {
                 query = new LuceneQuery( parser.parse( term ) );
                 results = searchAll( query, limits, indexes, null );
@@ -149,17 +200,17 @@
             {
                 // AND the previous search terms
                 BooleanQuery booleanQuery = new BooleanQuery();
-                for( String previousSearchTerm : previousSearchTerms )
+                for ( String previousSearchTerm : previousSearchTerms )
                 {
                     booleanQuery.add( parser.parse( previousSearchTerm ), 
BooleanClause.Occur.MUST );
                 }
-                
-                query = new LuceneQuery( booleanQuery );                
+
+                query = new LuceneQuery( booleanQuery );
                 Filter filter = new QueryWrapperFilter( parser.parse( term ) );
                 results = searchAll( query, limits, indexes, filter );
-            }            
+            }
             results.getRepositories().addAll( this.localIndexedRepositories );
-            
+
             return results;
         }
         catch ( ParseException e )
@@ -168,9 +219,9 @@
         }
 
         // empty results.
-        return new SearchResults(); 
+        return new SearchResults();
     }
-    
+
     private SearchResults searchAll( LuceneQuery luceneQuery, 
SearchResultLimits limits, List<RepositoryContentIndex> indexes, Filter filter )
     {
         org.apache.lucene.search.Query specificQuery = 
luceneQuery.getLuceneQuery();
@@ -203,7 +254,7 @@
 
             // Perform the search.
             Hits hits = null;
-            if( filter != null )
+            if ( filter != null )
             {
                 hits = searcher.search( specificQuery, filter );
             }
@@ -355,7 +406,7 @@
 
         return ret;
     }
-    
+
     private boolean indexExists( RepositoryContentIndex index )
     {
         try
@@ -402,6 +453,26 @@
         }
     }
 
+    private void parseAndAdd( BooleanQuery query, String key, String value, 
String delimiter )
+    {
+        if ( value != null && value.length() > 0 )
+        {
+            String[] terms = value.split( delimiter );
+            for ( int i = 0; i < terms.length; i++ )
+            {
+                Term valueTerm = new Term( key, terms[i] );
+                Query valueQuery = new TermQuery( valueTerm );
+                query.add( valueQuery, BooleanClause.Occur.MUST );
+            }
+        }
+        else
+        {
+            Term valueTerm = new Term( key, value );
+            Query valueQuery = new TermQuery( valueTerm );
+            query.add( valueQuery, BooleanClause.Occur.MUST );
+        }
+    }
+
     public void initialize()
         throws InitializationException
     {

Modified: 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/maven/archiva/indexer/search/DefaultCrossRepositorySearchTest.java
 Tue Sep 16 19:51:40 2008
@@ -242,6 +242,51 @@
                              
"org.apache.maven.continuum.web.action.BuildDefinitionAction.isBuildFresh", 
null, true );        
     }
     
+    public void testExecuteFilteredSearch()
+        throws Exception
+    {
+        CrossRepositorySearch search = lookupCrossRepositorySearch();
+
+        String expectedRepos[] = new String[] { TEST_DEFAULT_REPO_ID };
+
+        String expectedResults[] = new String[] { "org1", "org2", "org3", 
"org4", "org5", "org6", "org7", "org8" };
+
+        String secondExpectedResults[] = new String[] { "continuum-webapp" };
+
+        String thirdExpectedResults[] = new String[] { "archiva-common" };
+
+        // search for groupId
+        assertFilteredSearchResults( expectedRepos, expectedResults, search, 
"org", null, null, null, 30 );
+
+        // search for groupId and artifactId
+        assertFilteredSearchResults( expectedRepos, secondExpectedResults, 
search, "org.apache.maven",
+                                     "continuum-webapp", null, null, 30 );
+
+        // search for groupId , artifactId and version
+        assertFilteredSearchResults( expectedRepos, thirdExpectedResults, 
search, "org.apache.maven.archiva",
+                                     "archiva-common", "1.0", null, 30 );
+    }
+    
+    private void assertFilteredSearchResults ( String expectedRepos[], String 
expectedResults[], CrossRepositorySearch search, 
+                                               String groupId, String 
artifactId, String version, String className , int rowCount )
+    {
+        SearchResultLimits limits = new SearchResultLimits( 0 );
+        limits.setPageSize(  rowCount );
+        
+        List<String> selectedRepos = new ArrayList<String>();
+        selectedRepos.addAll( Arrays.asList( expectedRepos ) );
+        
+        SearchResults results = null;
+        
+        results = search.executeFilteredSearch( "guest" , selectedRepos, 
groupId, artifactId, version, className, limits );
+        
+        assertNotNull( "Search Results should not be null.", results );
+        assertEquals( "Repository Hits", expectedRepos.length, 
results.getRepositories().size() );
+        assertEquals( expectedRepos.length, 1);
+        assertEquals( TEST_DEFAULT_REPO_ID , selectedRepos.get( 0 ) );
+        assertEquals( "Search Result Hits", expectedResults.length, 
results.getHits().size() );
+    }
+    
     private void assertSearchResults( String expectedRepos[], String 
expectedResults[], CrossRepositorySearch search,
                                       String term, List<String> 
previousSearchTerms, boolean bytecode )
         throws Exception
@@ -251,11 +296,12 @@
         
         List<String> selectedRepos = new ArrayList<String>();
         selectedRepos.addAll( Arrays.asList( expectedRepos ) );
-        
+       
         SearchResults results = null;
+
         if( previousSearchTerms == null )
-        {
-            if( bytecode )
+            {
+                if( bytecode )
             {
                 results = search.searchForBytecode( "guest", selectedRepos, 
term, limits );
             }
@@ -268,16 +314,18 @@
         {
             results = search.searchForTerm( "guest", selectedRepos, term, 
limits, previousSearchTerms );
         }
+
         
         assertNotNull( "Search Results should not be null.", results );
         assertEquals( "Repository Hits", expectedRepos.length, 
results.getRepositories().size() );
+        
         // TODO: test the repository ids returned.
 
         assertEquals( "Search Result Hits", expectedResults.length, 
results.getHits().size() );
         // TODO: test the order of hits.
         // TODO: test the value of the hits.
     }
-
+    
     protected ManagedRepositoryConfiguration createRepository( String id, 
String name, File location )
     {
         ManagedRepositoryConfiguration repo = new 
ManagedRepositoryConfiguration();

Modified: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
 Tue Sep 16 19:51:40 2008
@@ -1,5 +1,5 @@
 package org.apache.maven.archiva.web.action;
-
+       
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -23,10 +23,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
-import com.opensymphony.xwork.ActionContext;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.maven.archiva.configuration.ArchivaConfiguration;
+import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
 import org.apache.maven.archiva.database.ArchivaDAO;
 import org.apache.maven.archiva.database.Constraint;
 import 
org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
@@ -42,6 +44,9 @@
 import org.apache.maven.archiva.security.UserRepositories;
 import org.codehaus.plexus.xwork.action.PlexusActionSupport;
 
+import com.opensymphony.xwork.ActionContext;
+import com.opensymphony.xwork.Preparable;
+
 /**
  * Search all indexed fields by the given criteria.
  *
@@ -49,10 +54,16 @@
  */
 public class SearchAction
     extends PlexusActionSupport
-{           
+    implements Preparable
+{
     /**
      * Query string.
      */
+
+    private ArchivaConfiguration archivaConfiguration;
+
+    private Map<String, ManagedRepositoryConfiguration> managedRepositories;
+
     private String q;
 
     /**
@@ -90,27 +101,132 @@
     
     private int totalPages;
     
-    private boolean searchResultsOnly; 
+    private boolean searchResultsOnly;
     
     private String completeQueryString;
     
     private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
-    
+
     private static final String BYTECODE_KEYWORD = "bytecode:";
 
+    private List<String> managedRepositoryList;
+
+    private String groupId;
+
+    private String artifactId;
+
+    private String version;
+
+    private String className;
+
+    private int rowCount = 30;
+
+    private String repositoryId;
+
+    private boolean fromFilterSearch;
+
+    private boolean filterSearch = false;
+
+    private boolean fromResultsPage;
+
+    private int num;
+
+    public boolean isFromResultsPage()
+    {
+        return fromResultsPage;
+    }
+
+    public void setFromResultsPage( boolean fromResultsPage )
+    {
+        this.fromResultsPage = fromResultsPage;
+    }
+
+    public boolean isFromFilterSearch()
+    {
+        return fromFilterSearch;
+    }
+
+    public void setFromFilterSearch( boolean fromFilterSearch )
+    {
+        this.fromFilterSearch = fromFilterSearch;
+    }
+
+    public void prepare()
+    {
+        managedRepositoryList = new ArrayList<String>();
+        managedRepositoryList = getObservableRepos();
+
+        if ( managedRepositoryList.size() > 0 )
+        {
+            managedRepositoryList.add( "all" );
+        }
+    }
+
+    // advanced search MRM-90 -- filtered search
+    public String filteredSearch()
+        throws MalformedURLException, RepositoryIndexException, 
RepositoryIndexSearchException
+    {
+        fromFilterSearch = true;
+
+        if ( CollectionUtils.isEmpty( managedRepositoryList ) )
+        {
+            return GlobalResults.ACCESS_TO_NO_REPOS;
+        }
+
+        SearchResultLimits limits = new SearchResultLimits( currentPage );
+
+        limits.setPageSize( rowCount );
+        List<String> selectedRepos = new ArrayList<String>();
+
+        if ( repositoryId.equals( "all" ) )
+        {
+            selectedRepos = getObservableRepos();
+        }
+        else
+        {
+            selectedRepos.add( repositoryId );
+        }
+
+        if ( CollectionUtils.isEmpty( selectedRepos ) )
+        {
+            return GlobalResults.ACCESS_TO_NO_REPOS;
+        }
+
+        results =
+            crossRepoSearch.executeFilteredSearch( getPrincipal(), 
selectedRepos, groupId, artifactId, version,
+                                                   className, limits );
+
+        if ( results.isEmpty() )
+        {
+            addActionError( "No results found" );
+            return INPUT;
+        }
+
+        totalPages = results.getTotalHits() / limits.getPageSize();
+
+        if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
+        {
+            totalPages = totalPages + 1;
+        }
+
+        return SUCCESS;
+    }
+
     public String quickSearch()
         throws MalformedURLException, RepositoryIndexException, 
RepositoryIndexSearchException
     {
         /* TODO: give action message if indexing is in progress.
          * This should be based off a count of 'unprocessed' artifacts.
-         * This (yet to be written) routine could tell the user that X 
(unprocessed) artifacts are not yet 
+         * This (yet to be written) routine could tell the user that X 
(unprocessed) artifacts are not yet
          * present in the full text search.
          */
 
         assert q != null && q.length() != 0;
-        
+
+        fromFilterSearch = false;
+
         SearchResultLimits limits = new SearchResultLimits( currentPage );
-        
+
         List<String> selectedRepos = getObservableRepos();
         if ( CollectionUtils.isEmpty( selectedRepos ) )
         {
@@ -118,13 +234,13 @@
         }
 
         if( isBytecodeSearch( q ) )
-        {   
+        {
             results = crossRepoSearch.searchForBytecode( getPrincipal(), 
selectedRepos, removeKeyword( q ), limits );
         }
         else
         {
             if( searchResultsOnly && !completeQueryString.equals( "" ) )
-            { 
+            {
                 results = crossRepoSearch.searchForTerm( getPrincipal(), 
selectedRepos, q, limits, parseCompleteQueryString() );
             }
             else
@@ -133,33 +249,33 @@
                 results = crossRepoSearch.searchForTerm( getPrincipal(), 
selectedRepos, q, limits );
             }
         }
-        
+
         if ( results.isEmpty() )
         {
             addActionError( "No results found" );
             return INPUT;
         }
-        
+
         totalPages = results.getTotalHits() / limits.getPageSize();
-        
+
         if( (results.getTotalHits() % limits.getPageSize()) != 0 )
         {
             totalPages = totalPages + 1;
         }
         // TODO: filter / combine the artifacts by version? (is that even 
possible with non-artifact hits?)
 
-        /* I don't think that we should, as I expect us to utilize the 'score' 
system in lucene in 
+        /* I don't think that we should, as I expect us to utilize the 'score' 
system in lucene in
          * the future to return relevant links better.
          * I expect the lucene scoring system to take multiple hits on 
different areas of a single document
-         * to result in a higher score. 
+         * to result in a higher score.
          *   - Joakim
          */
-        
+
         if( !isEqualToPreviousSearchTerm( q ) )
         {
             buildCompleteQueryString( q );
         }
-        
+
         return SUCCESS;
     }
 
@@ -185,10 +301,10 @@
 
         if ( databaseResults.size() == 1 )
         {
-            // 1 hit? return it's information directly!            
+            // 1 hit? return it's information directly!
             return ARTIFACT;
         }
-        
+
         return RESULTS;
     }
 
@@ -197,12 +313,12 @@
     {
         return INPUT;
     }
-    
+
     private String getPrincipal()
     {
         return archivaXworkUser.getActivePrincipal( 
ActionContext.getContext().getSession() );
     }
-    
+
     private List<String> getObservableRepos()
     {
         try
@@ -227,44 +343,44 @@
 
     private void buildCompleteQueryString( String searchTerm )
     {
-        if( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
+        if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
         {
             searchTerm = StringUtils.remove( searchTerm, 
COMPLETE_QUERY_STRING_SEPARATOR );
         }
-        
-        if( completeQueryString == null || "".equals( completeQueryString ) )
+
+        if ( completeQueryString == null || "".equals( completeQueryString ) )
         {
             completeQueryString = searchTerm;
         }
         else
-        {            
+        {
             completeQueryString = completeQueryString + 
COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
         }
     }
-    
+
     private List<String> parseCompleteQueryString()
     {
-        List<String> parsedCompleteQueryString = new ArrayList<String>();      
  
+        List<String> parsedCompleteQueryString = new ArrayList<String>();
         String[] parsed = StringUtils.split( completeQueryString, 
COMPLETE_QUERY_STRING_SEPARATOR );
         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
-        
+
         return parsedCompleteQueryString;
     }
-    
+
     private boolean isEqualToPreviousSearchTerm( String searchTerm )
     {
-        if( !"".equals( completeQueryString ) )
+        if ( !"".equals( completeQueryString ) )
         {
             String[] parsed = StringUtils.split( completeQueryString, 
COMPLETE_QUERY_STRING_SEPARATOR );
-            if( StringUtils.equalsIgnoreCase( searchTerm, parsed[ 
parsed.length - 1 ] ) )
+            if ( StringUtils.equalsIgnoreCase( searchTerm, 
parsed[parsed.length - 1] ) )
             {
                 return true;
             }
         }
-        
+
         return false;
     }
-    
+
     public String getQ()
     {
         return q;
@@ -284,12 +400,12 @@
     {
         return databaseResults;
     }
-    
+
     public void setCurrentPage( int page )
     {
         this.currentPage = page;
     }
-    
+
     public int getCurrentPage()
     {
         return currentPage;
@@ -323,23 +439,123 @@
     public void setCompleteQueryString( String completeQueryString )
     {
         this.completeQueryString = completeQueryString;
-    }    
-    
+    }
+
     private boolean isBytecodeSearch( String queryString )
     {
-        if( queryString.startsWith( BYTECODE_KEYWORD ) )
+        if ( queryString.startsWith( BYTECODE_KEYWORD ) )
         {
-            return true;            
+            return true;
         }
-        
+
         return false;
     }
-    
+
     private String removeKeyword( String queryString )
-    {  
+    {
         String qString = StringUtils.uncapitalize( queryString );
-        qString= StringUtils.remove( queryString, BYTECODE_KEYWORD );
-        
+        qString = StringUtils.remove( queryString, BYTECODE_KEYWORD );
+
         return qString;
     }
+
+    public ArchivaConfiguration getArchivaConfiguration()
+    {
+        return archivaConfiguration;
+    }
+
+    public void setArchivaConfiguration( ArchivaConfiguration 
archivaConfiguration )
+    {
+        this.archivaConfiguration = archivaConfiguration;
+    }
+
+    public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
+    {
+        return 
getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
+    }
+
+    public void setManagedRepositories( Map<String, 
ManagedRepositoryConfiguration> managedRepositories )
+    {
+        this.managedRepositories = managedRepositories;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    public void setGroupId( String groupId )
+    {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    public void setArtifactId( String artifactId )
+    {
+        this.artifactId = artifactId;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion( String version )
+    {
+        this.version = version;
+    }
+
+    public int getRowCount()
+    {
+        return rowCount;
+    }
+
+    public void setRowCount( int rowCount )
+    {
+        this.rowCount = rowCount;
+    }
+
+    public boolean isFilterSearch()
+    {
+        return filterSearch;
+    }
+
+    public void setFilterSearch( boolean filterSearch )
+    {
+        this.filterSearch = filterSearch;
+    }
+
+    public String getRepositoryId()
+    {
+        return repositoryId;
+    }
+
+    public void setRepositoryId( String repositoryId )
+    {
+        this.repositoryId = repositoryId;
+    }
+
+    public List<String> getManagedRepositoryList()
+    {
+        return managedRepositoryList;
+    }
+
+    public void setManagedRepositoryList( List<String> managedRepositoryList )
+    {
+        this.managedRepositoryList = managedRepositoryList;
+    }
+
+    public String getClassName()
+    {
+        return className;
+    }
+
+    public void setClassName( String className )
+    {
+        this.className = className;
+    }
 }

Added: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/SearchAction-filteredSearch-validation.xml
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/SearchAction-filteredSearch-validation.xml?rev=696137&view=auto
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/SearchAction-filteredSearch-validation.xml
 (added)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/org/apache/maven/archiva/web/action/SearchAction-filteredSearch-validation.xml
 Tue Sep 16 19:51:40 2008
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ 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.
+  -->
+
+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
+    "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd";>
+
+<validators>
+  <field name="rowCount">
+    <field-validator type="int">
+      <message>Invalid entry</message>
+    </field-validator>
+    <field-validator type="int">
+    <param name="min">1</param>
+      <message>Row count must be larger than ${min}.</message>
+    </field-validator>
+  </field>
+</validators>

Modified: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/xwork.xml
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/xwork.xml?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/xwork.xml
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/resources/xwork.xml
 Tue Sep 16 19:51:40 2008
@@ -143,6 +143,16 @@
     <action name="index" class="searchAction" method="input">
       <result name="input">/WEB-INF/jsp/quickSearch.jsp</result>
     </action>
+
+    <action name="advancedSearch" class="searchAction" method="input">
+      <result name="input">/WEB-INF/jsp/advancedSearch.jsp</result>
+    </action>
+
+    <action name="filteredSearch" class="searchAction" method="filteredSearch">
+      <result name="input">/WEB-INF/jsp/advancedSearch.jsp</result>
+      <result>/WEB-INF/jsp/results.jsp</result>
+      <result name="error">/WEB-INF/jsp/quickSearch.jsp</result>
+    </action>
        
     <action name="quickSearch" class="searchAction" method="quickSearch">
       <result name="input">/WEB-INF/jsp/quickSearch.jsp</result>

Added: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/advancedSearch.jsp
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/advancedSearch.jsp?rev=696137&view=auto
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/advancedSearch.jsp
 (added)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/advancedSearch.jsp
 Tue Sep 16 19:51:40 2008
@@ -0,0 +1,67 @@
+<%--
+  ~ 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.
+  --%>
+
+<%@ taglib prefix="ww" uri="/webwork" %>
+<html>
+<head>
+  <title>Advanced Search</title>
+  <ww:head/>
+</head>
+
+<ww:if test="%{infoMessage != null}">
+  <p>${infoMessage}</p>
+</ww:if>
+
+<body>
+
+<h1>Advanced Search</h1>
+
+
+<div id="contentArea">
+
+  <div id="searchBox">
+  
+    <ww:form method="get" action="filteredSearch" validate="true">
+      <ww:textfield label="Row Count" size="50" name="rowCount"/>
+      <ww:textfield label="Group Id" size="50" name="groupId"/>
+      <ww:textfield label="Artifact Id" size="50" name="artifactId"/>
+      <ww:textfield label="Version" size="50" name="version"/>
+      <ww:textfield label="Class / Package" size="50" name="className"/>
+      <ww:select name="repositoryId" label="Repository ID" 
list="managedRepositoryList"/>
+      <ww:hidden name="completeQueryString" value="${completeQueryString}"/>
+      <ww:hidden name="fromFilterSearch" value="${fromFilterSearch}"/>
+      <ww:submit label="Go!"/>
+    </ww:form>
+  
+    <ww:url id="indexUrl" action="index"/>
+      <ww:a href="%{indexUrl}">
+        Quick Search Page
+    </ww:a>
+
+  </div>
+
+  <script type="text/javascript">
+    document.getElementById("filteredSearch_groupId").focus();
+  </script>
+  <ww:actionerror/>
+
+</div> 
+
+</body>
+</html>

Modified: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/quickSearch.jsp
 Tue Sep 16 19:51:40 2008
@@ -44,6 +44,11 @@
     document.getElementById("quickSearch_q").focus();
   </script>
 
+  <ww:url id="filteredSearchUrl" action="advancedSearch"/>
+  <ww:a href="%{filteredSearchUrl}">
+    Advanced Search
+  </ww:a>
+
   <p>
     <ww:actionerror/>
   </p>

Modified: 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp
URL: 
http://svn.apache.org/viewvc/archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp?rev=696137&r1=696136&r2=696137&view=diff
==============================================================================
--- 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp
 (original)
+++ 
archiva/trunk/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/results.jsp
 Tue Sep 16 19:51:40 2008
@@ -30,7 +30,12 @@
 
 <body>
 
-<h1>Search</h1>
+<c:if test="${fromFilterSearch == true}">
+  <h1>Advanced Search</h1>
+</c:if>
+<c:if test="${fromFilterSearch == false}">
+  <h1>Search</h1>
+</c:if> 
 
 <c:url var="imgNextPageUrl" value="/images/icon_next_page.gif"/>
 <c:url var="imgPrevPageUrl" value="/images/icon_prev_page.gif"/>
@@ -39,20 +44,44 @@
 
 <div id="contentArea">
   <div id="searchBox">
-  <ww:form method="get" action="quickSearch" validate="true">
-    <ww:textfield label="Search for" size="50" name="q"/>
-    <ww:checkbox label="Search within results" name="searchResultsOnly"/>      
  
-    <ww:hidden name="completeQueryString" value="${completeQueryString}"/>     
   
-    <ww:submit label="Go!"/>
-  </ww:form>
-
-  <script type="text/javascript">
-    document.getElementById("quickSearch_q").focus();
-  </script>
+
+    <c:if test="${fromFilterSearch == true}">
+      <ww:form method="get" action="filteredSearch" validate="true">
+        <ww:textfield label="Row Count" size="50" name="rowCount"/>
+        <ww:textfield label="Group Id" size="50" name="groupId"/>
+        <ww:textfield label="Artifact Id" size="50" name="artifactId"/>
+        <ww:textfield label="Version" size="50" name="version"/>
+        <ww:textfield label="Class / Package" size="50" name="className"/>
+        <ww:select name="repositoryId" label="Repository ID" 
list="managedRepositoryList"/>
+        <ww:hidden name="completeQueryString" value="${completeQueryString}"/>
+        <ww:hidden name="fromFilterSearch" value="${fromFilterSearch}"/>
+        <ww:submit label="Go!"/>
+      </ww:form>
+  
+      <ww:url id="indexUrl" action="index"/>
+      <ww:a href="%{indexUrl}">
+        Quick Search Page
+      </ww:a>
+      <script type="text/javascript">
+        document.getElementById("filteredSearch_groupId").focus();
+      </script>
+      </c:if>
+    <c:if test="${fromFilterSearch == false}">
+      <ww:form method="get" action="quickSearch" validate="true">
+        <ww:textfield label="Search for" size="50" name="q"/>
+        <ww:checkbox label="Search within results" name="searchResultsOnly"/>  
      
+        <ww:hidden name="completeQueryString" value="${completeQueryString}"/> 
       
+        <ww:submit label="Go!"/>
+      </ww:form> 
+      <script type="text/javascript">
+        document.getElementById("quickSearch_q").focus();
+      </script>
+    </c:if>
 
   <p>
     <ww:actionerror/>
   </p>
+
   </div>
 
   <h1>Results</h1>
@@ -62,10 +91,10 @@
 
       <%-- search was made from the indices --%>
       <c:when test="${databaseResults == null}">
-        <c:set var="hitsNum">${fn:length(results.hits) + (currentPage * 
results.limits.pageSize)}</c:set>
+        <c:set var="hitsNum">${fn:length(results.hits) + (currentPage  * 
results.limits.pageSize)}</c:set>
         <c:choose>
           <c:when test="${results.totalHits > results.limits.pageSize}">
-            <p>Hits: ${(hitsNum - results.limits.pageSize) + 1} to ${hitsNum} 
of ${results.totalHits}</p>
+              <p>Hits: ${(hitsNum - results.limits.pageSize) + 1} to 
${hitsNum} of ${results.totalHits}</p>
           </c:when>
           <c:otherwise>
             <p>Hits: 1 to ${hitsNum} of ${results.totalHits}</p>
@@ -80,22 +109,55 @@
          <%-- Pagination start --%>
            <p>                       
             <%-- Prev & Next icons --%>
-            <c:set var="prevPageUrl">
-              <ww:url action="quickSearch" namespace="/">
-                <ww:param name="q" value="%{'${q}'}"/>
-                <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
-                <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>                
-                <ww:param name="currentPage" value="%{'${currentPage - 1}'}"/>
-              </ww:url>
-           </c:set>
-           <c:set var="nextPageUrl">
-              <ww:url action="quickSearch" namespace="/">
-                <ww:param name="q" value="%{'${q}'}"/>                
-                <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
-                <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>
-                <ww:param name="currentPage" value="%{'${currentPage + 1}'}"/>
-              </ww:url>
-           </c:set>    
+              <c:if test="${fromFilterSearch == false}">
+               <c:set var="prevPageUrl">
+                 <ww:url action="quickSearch" namespace="/">
+                   <ww:param name="q" value="%{'${q}'}"/>                
+                   <ww:param name="currentPage" value="%{'${currentPage - 
1}'}"/>
+                 </ww:url>
+                     </c:set>
+                     <c:set var="nextPageUrl">
+                 <ww:url action="quickSearch" namespace="/">
+                   <ww:param name="q" value="%{'${q}'}"/>                
+                   <ww:param name="currentPage" value="%{'${currentPage + 
1}'}"/>
+                 </ww:url>
+                     </c:set>    
+              </c:if>
+
+              <c:if test="${fromFilterSearch == true}">
+               <c:set var="prevPageUrl">
+                 <ww:url action="filteredSearch" namespace="/">
+ <%--            <ww:param name="q" value="%{'${q}'}"/>   --%>
+                   <ww:param name="rowCount" value="%{'${rowCount}'}"/>  
+                   <ww:param name="groupId" value="%{'${groupId}'}"/>
+                   <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+                   <ww:param name="version" value="%{'${version}'}"/>
+                   <ww:param name="className" value="%{'${className}'}"/>
+                   <ww:param name="repositoryId" value="%{'${repositoryId}'}"/>
+                   <ww:param name="filterSearch" value="%{'${filterSearch}'}"/>
+                  <ww:param name="fromResultsPage" value="true"/>
+                   <ww:param name="currentPage" value="%{'${currentPage - 
1}'}"/>
+                 <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
+                 <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>
+                 </ww:url>
+                     </c:set>
+                     <c:set var="nextPageUrl">
+                <ww:url action="filteredSearch" namespace="/">
+<%--            <ww:param name="q" value="%{'${q}'}"/> --%>
+                  <ww:param name="rowCount" value="%{'${rowCount}'}"/>  
+                  <ww:param name="groupId" value="%{'${groupId}'}"/>
+                  <ww:param name="artifactId" value="%{'${artifactId}'}"/>
+                  <ww:param name="version" value="%{'${version}'}"/>
+                  <ww:param name="className" value="%{'${className}'}"/>
+                  <ww:param name="repositoryId" value="%{'${repositoryId}'}"/>
+                  <ww:param name="filterSearch" value="%{'${filterSearch}'}"/>
+                 <ww:param name="fromResultsPage" value="true"/>
+                  <ww:param name="currentPage" value="%{'${currentPage + 
1}'}"/>
+                 <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
+                 <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>
+                </ww:url>
+             </c:set>    
+             </c:if>
             
             <c:choose>
               <c:when test="${currentPage == 0}">                              
 
@@ -133,25 +195,54 @@
                        </c:choose>
                                                
                        <c:forEach var="i" begin="${beginVal}" end="${endVal}">
-              <c:choose>                                           
-                               <c:when test="${i != currentPage}">
-                                  <c:set var="specificPageUrl">
-                             <ww:url action="quickSearch" namespace="/">
-                               <ww:param name="q" value="%{'${q}'}"/>
-                               <ww:param name="currentPage" value="%{'${i}'}"/>
-                               <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
-                               <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>
-                             </ww:url>
-                         </c:set>
-                                 <a href="${specificPageUrl}">${i + 1}</a>
-                               </c:when>
-                               <c:otherwise>           
-                                       <b>${i + 1}</b>   
-                               </c:otherwise>                                  
                    
-              </c:choose> 
+                          <c:if test="${fromFilterSearch == false}">
+                            <c:choose>                                         
    
+                             <c:when test="${i != currentPage}">
+                               <c:set var="specificPageUrl">
+                                 <ww:url action="quickSearch" namespace="/">
+                                   <ww:param name="q" value="%{'${q}'}"/>
+                                   <ww:param name="currentPage" 
value="%{'${i}'}"/>
+                                   <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
+                                   <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>  
+                                 </ww:url>
+                               </c:set>
+                                 <a href="${specificPageUrl}">${i + 1}</a>
+                             </c:when>
+                             <c:otherwise>             
+                               <b>${i + 1}</b>   
+                             </c:otherwise>                                    
                    
+                            </c:choose>
+                          </c:if>
+
+                          <c:if test="${fromFilterSearch == true}">
+                            <c:choose>                                         
    
+                             <c:when test="${i != currentPage}">
+                               <c:set var="specificPageUrl">
+                                 <ww:url action="filteredSearch" namespace="/">
+<%--                               <ww:param name="q" value="%{'${q}'}"/>   
--%>
+                                    <ww:param name="rowCount" 
value="%{'${rowCount}'}"/>  
+                                    <ww:param name="groupId" 
value="%{'${groupId}'}"/>
+                                    <ww:param name="artifactId" 
value="%{'${artifactId}'}"/>
+                                    <ww:param name="version" 
value="%{'${version}'}"/>
+                                    <ww:param name="className" 
value="%{'${className}'}"/>
+                                    <ww:param name="repositoryId" 
value="%{'${repositoryId}'}"/>
+                                    <ww:param name="filterSearch" 
value="%{'${filterSearch}'}"/>
+                                   <ww:param name="fromResultsPage" 
value="true"/>
+                                   <ww:param name="currentPage" 
value="%{'${i}'}"/>
+                                   <ww:param name="searchResultsOnly" 
value="%{'${searchResultsOnly}'}"/>
+                                   <ww:param name="completeQueryString" 
value="%{'${completeQueryString}'}"/>
+                                 </ww:url>
+                               </c:set>
+                               <a href="${specificPageUrl}">${i + 1}</a>
+                             </c:when>
+                             <c:otherwise>             
+                               <b>${i + 1}</b>   
+                             </c:otherwise>
+                            </c:choose>
+                          </c:if>
                        </c:forEach>
-                               
-                       <c:choose>
+                       
+                        <c:choose>
                          <c:when test="${currentPage == (totalPages - 1)}">
                            <img src="${imgNextPageDisabledUrl}"/>
               </c:when>


Reply via email to