You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by og...@apache.org on 2009/04/23 00:57:04 UTC

svn commit: r767705 [12/31] - in /maven/mercury/trunk/mercury-core: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/maven/ src/main/java/org/apache/maven/mercury/ src/main/java/org/apache/maven/mer...

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,39 @@
+/*
+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.
+*/
+
+package org.apache.maven.mercury.repository.remote.m2;
+
+import org.apache.maven.mercury.repository.api.RepositoryException;
+
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class RepositoryNonQualifiedArtifactException
+    extends RepositoryException
+{
+    public RepositoryNonQualifiedArtifactException( String msg )
+    {
+        super( msg );
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryNonQualifiedArtifactException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,180 @@
+/**
+ *  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.
+ */
+package org.apache.maven.mercury.repository.remote.m2;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.maven.mercury.artifact.ArtifactCoordinates;
+import org.apache.maven.mercury.logging.IMercuryLogger;
+import org.apache.maven.mercury.logging.MercuryLoggerManager;
+import org.apache.maven.mercury.repository.local.m2.LocalRepositoryM2;
+import org.apache.maven.mercury.repository.metadata.AddVersionOperation;
+import org.apache.maven.mercury.repository.metadata.Metadata;
+import org.apache.maven.mercury.repository.metadata.MetadataBuilder;
+import org.apache.maven.mercury.repository.metadata.MetadataException;
+import org.apache.maven.mercury.repository.metadata.MetadataOperation;
+import org.apache.maven.mercury.repository.metadata.StringOperand;
+import org.apache.maven.mercury.util.FileUtil;
+import org.codehaus.plexus.lang.DefaultLanguage;
+import org.codehaus.plexus.lang.Language;
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class RepositoryUtilM2
+{
+  private static final IMercuryLogger LOG = MercuryLoggerManager.getLogger( RepositoryUtilM2.class ); 
+  private static final Language LANG = new DefaultLanguage( RepositoryUtilM2.class );
+  //----------------------------------------------------------------------------------
+  public static void flip( LocalRepositoryM2 repo, File dest )
+  {
+    if( repo == null )
+      throw new IllegalArgumentException( LANG.getMessage( "lrepo.null" ) );
+
+    File lDir = repo.getDirectory();
+    
+    if( lDir == null )
+      throw new IllegalArgumentException( LANG.getMessage( "lrepo.no.dir" ) );
+    
+    if( !lDir.exists() || !lDir.isDirectory() )
+      throw new IllegalArgumentException( LANG.getMessage( "lrepo.dir.not.exists", lDir.toString() ) );
+    
+    if( dest.exists() && !dest.isFile() )
+      throw new IllegalArgumentException( LANG.getMessage( "dest.is.file", dest.toString() ) );
+    
+    
+  }
+
+  public static void flipLocalFolderToRemoteRepository( File repoDir )
+  {
+    
+    if( !repoDir.exists() || !repoDir.isDirectory() )
+      throw new IllegalArgumentException( LANG.getMessage( "lrepo.dir.not.exists", repoDir.toString() ) );
+
+    // temporary solution: just rename metadata, hoping it is correct
+    // ideally - will use metadata correction utility
+    FileUtil.renameFile( repoDir, LocalRepositoryM2.METADATA_FILE_NAME, RemoteRepositoryM2.METADATA_FILE_NAME );
+  }
+  
+  private static final void findGA( File dir )
+  throws MetadataException, IOException
+  {
+    if( dir.isFile() )
+      return;
+    
+    File [] files = dir.listFiles();
+    
+    if( files == null || files.length < 1 )
+      return;
+    
+    int dep = FileUtil.depth( dir );
+    
+    List<MetadataOperation> vo = null;
+    
+    if( dep <= 1 )
+      vo = new ArrayList<MetadataOperation>();
+    
+    for( File f : files )
+    {
+      if( f.isFile() )
+        return;
+      
+      if( dep == 1 )
+      {
+        vo.add( new AddVersionOperation( new StringOperand(f.getName()) ) );
+      }
+      else 
+        findGA( f );
+    }
+    
+    if( dep == 1 )
+    {
+      Metadata md = new Metadata();
+      
+      byte [] mdBytes = MetadataBuilder.changeMetadata( md, vo );
+      
+      FileUtil.writeRawData( new File( dir, RemoteRepositoryM2.METADATA_FILE_NAME ), mdBytes );
+    }
+    else if( dep == 0 )
+    {
+      
+    }
+  }
+  //----------------------------------------------------------------------------------
+  //----------------------------------------------------------------------------------
+}
+//=====================================================================================
+class copyGa
+implements Runnable
+{
+  ConcurrentLinkedQueue<ArtifactCoordinates> _q;
+  File _root;
+  File _dest;
+  
+  public copyGa( ConcurrentLinkedQueue<ArtifactCoordinates> q, File from, File to )
+  {
+    this._q = q;
+    this._root = from;
+    this._dest = to;
+  }
+
+  // copy GAV to it's final dest
+  public void run()
+  {
+    try
+    {
+      for(;;)
+      {
+        ArtifactCoordinates ga = _q.remove();
+        
+//        File gaDir = new File( _root );
+//        File gaDest = new File( _dest );
+//        
+//        gaDest.mkdirs();
+//        
+//        Metadata gaMd = new Metadata();
+//        gaMd.setGroupId( groupId )
+//        
+//        File [] versions = gaDir.listFiles(); 
+//        
+//        for( File v : versions )
+//        {
+//          if( v.isFile() )
+//            continue;
+//        }
+        
+      }
+    }
+    catch( NoSuchElementException e )
+    {
+    }
+  }
+  //-------------------------------------
+}
+//=====================================================================================
+

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/remote/m2/RepositoryUtilM2.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties Wed Apr 22 22:56:48 2009
@@ -0,0 +1,22 @@
+#
+#  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.
+#
+error.reading.existing.artifact=Error {0} reading existing artifacts from repository {1}
+internal.error.sorting.query=internal error while sorting query {0} - buckets cannot be null 
+no.snapshots=cannot find snapshots for {0}, classifier {1}, type {2}
+query.element.bad.version=query element {0} has a bad version {1}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/Messages.properties
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,1417 @@
+/**
+ *  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.
+ */
+package org.apache.maven.mercury.repository.virtual;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+
+import org.apache.maven.mercury.artifact.Artifact;
+import org.apache.maven.mercury.artifact.ArtifactMetadata;
+import org.apache.maven.mercury.artifact.Quality;
+import org.apache.maven.mercury.artifact.api.ArtifactListProcessor;
+import org.apache.maven.mercury.artifact.api.ArtifactListProcessorException;
+import org.apache.maven.mercury.artifact.version.DefaultArtifactVersion;
+import org.apache.maven.mercury.artifact.version.MetadataVersionComparator;
+import org.apache.maven.mercury.builder.api.DependencyProcessor;
+import org.apache.maven.mercury.builder.api.MetadataReader;
+import org.apache.maven.mercury.builder.api.MetadataReaderException;
+import org.apache.maven.mercury.event.EventGenerator;
+import org.apache.maven.mercury.event.EventManager;
+import org.apache.maven.mercury.event.EventTypeEnum;
+import org.apache.maven.mercury.event.GenericEvent;
+import org.apache.maven.mercury.event.MercuryEventListener;
+import org.apache.maven.mercury.logging.IMercuryLogger;
+import org.apache.maven.mercury.logging.MercuryLoggerManager;
+import org.apache.maven.mercury.repository.api.MetadataResults;
+import org.apache.maven.mercury.repository.api.ArtifactResults;
+import org.apache.maven.mercury.repository.api.LocalRepository;
+import org.apache.maven.mercury.repository.api.RemoteRepository;
+import org.apache.maven.mercury.repository.api.Repository;
+import org.apache.maven.mercury.repository.api.RepositoryException;
+import org.apache.maven.mercury.repository.api.RepositoryMetadataCache;
+import org.apache.maven.mercury.repository.api.RepositoryReader;
+import org.apache.maven.mercury.repository.api.RepositoryWriter;
+import org.apache.maven.mercury.repository.cache.fs.MetadataCacheFs;
+import org.apache.maven.mercury.repository.metadata.MetadataException;
+import org.apache.maven.mercury.repository.remote.m2.RemoteRepositoryM2;
+import org.apache.maven.mercury.repository.remote.m2.RemoteRepositoryReaderM2;
+import org.apache.maven.mercury.transport.api.Server;
+import org.apache.maven.mercury.util.Util;
+import org.codehaus.plexus.lang.DefaultLanguage;
+import org.codehaus.plexus.lang.Language;
+
+/**
+ * this helper class hides the necessity to talk to localRepo and a bunch of remoteRepos. It also adds discrete
+ * convenience methods, hiding batch nature of RepositoryReader
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ */
+public class VirtualRepositoryReader
+    implements MetadataReader, EventGenerator
+{
+    public static final String EVENT_READ_ARTIFACTS = "read.artifacts";
+
+    public static final String EVENT_READ_ARTIFACTS_FROM_REPO = "read.artifacts.from.repo";
+
+    public static final String EVENT_READ_ARTIFACTS_FROM_REPO_QUALIFIED = "read.artifacts.from.repo.qualified";
+
+    public static final String EVENT_READ_ARTIFACTS_FROM_REPO_UNQUALIFIED = "read.artifacts.from.repo.unqualified";
+
+    public static final String EVENT_READ_VERSIONS = "read.versions";
+
+    public static final String EVENT_READ_VERSIONS_FROM_REPO = "read.versions.from.repo";
+
+    public static final String EVENT_READ_DEPENDENCIES = "read.dependencies";
+
+    public static final String EVENT_READ_DEPENDENCIES_FROM_REPO = "read.dependencies.from.repo";
+
+    public static final String EVENT_READ_RAW = "vr.read.raw";
+
+    public static final String EVENT_READ_RAW_FROM_REPO = "read.raw.from.repo";
+
+    /** file system cache subfolder */
+    public static final String METADATA_CACHE_DIR = ".cache";
+
+    /** minimum # of queue elements to consider parallelization */
+    private static int MIN_PARALLEL = 5;
+
+    private static final Language LANG = new DefaultLanguage( VirtualRepositoryReader.class );
+
+    private static final IMercuryLogger LOG = MercuryLoggerManager.getLogger( VirtualRepositoryReader.class );
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    private List<Repository> _repositories = new ArrayList<Repository>( 8 );
+
+    private RepositoryReader[] _repositoryReaders;
+
+    private LocalRepository _localRepository;
+
+    private RepositoryWriter _localRepositoryWriter;
+    
+    private RemoteRepositoryReaderM2 _idleReader;
+
+    private RepositoryMetadataCache _mdCache;
+
+    private Map<String, ArtifactListProcessor> _processors;
+
+    private boolean _initialized = false;
+
+    private EventManager _eventManager;
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public VirtualRepositoryReader( Collection<Repository> repositories )
+        throws RepositoryException
+    {
+        if ( !Util.isEmpty( repositories ) )
+        {
+            this._repositories.addAll( repositories );
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public VirtualRepositoryReader( LocalRepository localRepository, Collection<RemoteRepository> remoteRepositories )
+        throws RepositoryException
+    {
+        if ( _localRepository == null )
+        {
+            throw new RepositoryException( "null local repo" );
+        }
+
+        this._localRepository = localRepository;
+
+        this._repositories.add( localRepository );
+
+        if ( remoteRepositories != null && remoteRepositories.size() > 0 )
+        {
+            this._repositories.addAll( remoteRepositories );
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public VirtualRepositoryReader( Repository... repositories )
+        throws RepositoryException
+    {
+        if ( repositories != null && repositories.length > 0 )
+        {
+            for ( Repository r : repositories )
+            {
+                this._repositories.add( r );
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public static final RepositoryMetadataCache getCache( File localRepositoryRoot )
+        throws IOException
+    {
+        // TODO: 2008-10-13 og: man - I miss plexus! Badly want an IOC container. This
+        // should be configured, not hardcoded
+        return MetadataCacheFs.getCache( new File( localRepositoryRoot, METADATA_CACHE_DIR ) );
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public void addRepository( Repository repo )
+        throws RepositoryException
+    {
+        if ( _initialized )
+        {
+            throw new RepositoryException( "cannot add repositories after VirtualReader has been initialized" );
+        }
+
+        _repositories.add( repo );
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public void setProcessors( Map<String, ArtifactListProcessor> processors )
+    {
+        _processors = processors;
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    /**
+     * very important call - makes VRR sort out all the information it collected so far
+     */
+    public void init()
+        throws RepositoryException
+    {
+        if ( _initialized )
+        {
+            return;
+        }
+
+        _repositoryReaders = new RepositoryReader[_repositories.size()];
+
+        // move local repo's upfront - they are faster!
+        int i = 0;
+        for ( Repository r : _repositories )
+        {
+            if ( !r.isLocal() || !r.isReadable() )
+            {
+                continue;
+            }
+
+            RepositoryReader rr = r.getReader();
+
+            rr.setMetadataReader( this );
+
+            _repositoryReaders[i++] = rr;
+
+            if ( r.isWriteable() )
+            {
+                // we select the first writable repo in the list
+                if ( _localRepository != null )
+                {
+                    continue;
+                }
+
+                _localRepository = (LocalRepository) r.getReader().getRepository();
+                _localRepositoryWriter = _localRepository.getWriter();
+
+                if ( _mdCache == null )
+                {
+                    try
+                    {
+                        _mdCache = getCache( _localRepository.getDirectory() );
+
+                        if ( _eventManager != null )
+                        {
+                            _mdCache.setEventManager( _eventManager );
+                        }
+                    }
+                    catch ( IOException e )
+                    {
+                        throw new RepositoryException( e.getMessage() );
+                    }
+                }
+            }
+        }
+
+        // remote ones
+        for ( Repository r : _repositories )
+        {
+            if ( r.isLocal() || !r.isReadable() )
+            {
+                continue;
+            }
+
+            RepositoryReader rr = r.getReader();
+
+            if ( _mdCache != null )
+            {
+                rr.setMetadataCache( _mdCache );
+            }
+
+            rr.setMetadataReader( this );
+
+            _repositoryReaders[i++] = rr;
+        }
+        
+        try
+        {
+            _idleReader = (RemoteRepositoryReaderM2) new RemoteRepositoryM2( "http://localhost", DependencyProcessor.NULL_PROCESSOR ).getReader();
+        }
+        catch ( MalformedURLException e )
+        {
+            throw new RepositoryException( e );
+        }
+        
+        _initialized = true;
+    }
+    
+    /**
+     * close all readers is they are started
+     */
+    public void close()
+    {
+        if( ! _initialized )
+            return;
+        
+        try
+        {
+            for( RepositoryReader rr : _repositoryReaders )
+                rr.close();
+        }
+        finally
+        {
+            _initialized = false;
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public MetadataResults readVersions( Collection<ArtifactMetadata> query )
+        throws IllegalArgumentException, RepositoryException
+    {
+        if ( query == null )
+        {
+            throw new IllegalArgumentException( "null bmd supplied" );
+        }
+
+        init();
+
+        GenericEvent event = null;
+
+        try
+        {
+            if ( _eventManager != null )
+            {
+                event = new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_VERSIONS );
+            }
+
+            MetadataResults res = null;
+            ArtifactListProcessor tp = _processors == null ? null : _processors.get( ArtifactListProcessor.FUNCTION_TP );
+
+            GenericEvent eventRead = null;
+
+            List<ArtifactMetadata> qList = new ArrayList<ArtifactMetadata>( query.size() );
+            qList.addAll( query );
+
+            for ( RepositoryReader rr : _repositoryReaders )
+            {
+                try
+                {
+                    // all found
+                    if ( qList.isEmpty() )
+                    {
+                        break;
+                    }
+
+                    if ( _eventManager != null )
+                    {
+                        eventRead =
+                            new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_VERSIONS_FROM_REPO,
+                                              rr.getRepository().getId() );
+                    }
+
+                    MetadataResults repoRes = rr.readVersions( qList );
+
+                    if ( repoRes != null && repoRes.hasExceptions() )
+                    {
+                        if ( LOG.isWarnEnabled() )
+                        {
+                            LOG.warn( repoRes.getExceptions().toString() );
+                        }
+                    }
+
+                    if ( repoRes != null && repoRes.hasResults() )
+                    {
+                        for ( ArtifactMetadata key : repoRes.getResults().keySet() )
+                        {
+                            List<ArtifactMetadata> rorRes = repoRes.getResult( key );
+
+                            if ( tp != null )
+                            {
+                                try
+                                {
+                                    tp.configure( key );
+                                    rorRes = tp.process( rorRes );
+                                }
+                                catch ( ArtifactListProcessorException e )
+                                {
+                                    throw new RepositoryException( e );
+                                }
+                            }
+
+                            if ( Util.isEmpty( rorRes ) )
+                            {
+                                eventRead.setResult( "none found" );
+                                continue;
+                            }
+
+                            for ( ArtifactMetadata bmd : rorRes )
+                            {
+                                bmd.setTracker( rr );
+                            }
+
+                            if ( res == null )
+                            {
+                                res = new MetadataResults( key, rorRes );
+                            }
+                            else
+                            {
+                                res.add( key, rorRes );
+                            }
+/*
+                            String keyVersion = key.getVersion();
+                            VersionRange keyVersionRange = null;
+                            try
+                            {
+                                keyVersionRange = VersionRangeFactory.create( key.getVersion() );
+                            }
+                            catch ( VersionException e )
+                            {
+                                throw new RepositoryException( LANG.getMessage( "query.element.bad.version",
+                                                                                 key.toString(), e.getMessage() ) );
+                            }
+
+                            if ( keyVersionRange.isSingleton() )
+                            {
+                                Quality keyQuality = new Quality( keyVersion );
+                                if ( keyQuality.compareTo( Quality.RELEASE_QUALITY ) == 0 )
+                                {
+                                    // fixed release is found - no more scanning
+                                    qList.remove( key );
+                                }
+                            }
+*/
+                            if ( !key.isVirtual() && key.isSingleton() )
+                            {
+                                // fixed release is found - no more scanning
+                                qList.remove( key );
+                            }
+                        }
+                    }
+
+                    if ( _eventManager != null )
+                    {
+                        eventRead.setResult( "repo done" );
+                    }
+                }
+                finally
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead.stop();
+                        _eventManager.fireEvent( eventRead );
+                    }
+                }
+            }
+
+            if ( res != null && res.hasResults() )
+            {
+                processSingletons( res );
+            }
+
+            return res;
+        }
+        finally
+        {
+            if ( _eventManager != null )
+            {
+                event.stop();
+                _eventManager.fireEvent( event );
+            }
+        }
+    }
+
+    private void processSingletons( MetadataResults res )
+    {
+        if ( !res.hasResults() )
+        {
+            return;
+        }
+
+        Map<ArtifactMetadata, List<ArtifactMetadata> > m = res.getResults();
+
+        for ( ArtifactMetadata key : m.keySet() )
+        {
+            processSingletons( key, res.getResult( key ) );
+        }
+    }
+
+    /** order all found versions per query, then leave only the last one hanging */
+    private void processSingletons( ArtifactMetadata key, List<ArtifactMetadata> res )
+    {
+        if ( Util.isEmpty( res ) || !DefaultArtifactVersion.isVirtual( key.getVersion() ) )
+        {
+            return;
+        }
+
+        TreeSet<ArtifactMetadata> ts = new TreeSet<ArtifactMetadata>(
+                        new Comparator<ArtifactMetadata>()
+                        {
+                            public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
+                            {
+                                String v1 = o1.getVersion();
+                                String v2 = o2.getVersion();
+                                
+                                if( o1.isVirtualSnapshot() && o1.getTimeStamp() != null )
+                                    v1 = v1.replace( Artifact.SNAPSHOT_VERSION, o1.getTimeStamp()+"-00" );
+                                
+                                if( o2.isVirtualSnapshot() && o2.getTimeStamp() != null )
+                                    v2 = v2.replace( Artifact.SNAPSHOT_VERSION, o2.getTimeStamp()+"-00" );
+                                
+                                  DefaultArtifactVersion av1 = new DefaultArtifactVersion( v1 );
+                                  DefaultArtifactVersion av2 = new DefaultArtifactVersion( v2 );
+
+                                  return av1.compareTo( av2 );
+                            }
+
+                        }
+                                                                      );
+        ts.addAll( res );
+
+        ArtifactMetadata single = ts.last();
+        
+        // Oleg: -SNAPSHOT should always win        
+//        if( key.isVirtualSnapshot() )
+//        {
+//            ArtifactMetadata first = ts.first();
+//            
+//            if( first.isVirtualSnapshot() )
+//                single = first;
+//        }
+            
+
+        res.clear();
+
+        res.add( single );
+    }
+
+    //----------------------------------------------------------------------------------------------------------------------------
+    public ArtifactMetadata readDependencies( ArtifactMetadata bmd )
+        throws IllegalArgumentException, RepositoryException
+    {
+        if ( bmd == null )
+        {
+            throw new IllegalArgumentException( "null bmd supplied" );
+        }
+
+        GenericEvent event = null;
+
+        try
+        {
+            if ( _eventManager != null )
+            {
+                event =
+                    new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_DEPENDENCIES, bmd.toString() );
+            }
+
+            init();
+
+            List<ArtifactMetadata> query = new ArrayList<ArtifactMetadata>( 1 );
+            query.add( bmd );
+
+            ArtifactMetadata md = new ArtifactMetadata( bmd );
+
+            RepositoryReader[] repos = _repositoryReaders;
+
+            Object tracker = bmd.getTracker();
+
+            // do we know where this metadata came from ?
+            if ( tracker != null && RepositoryReader.class.isAssignableFrom( tracker.getClass() ) )
+            {
+                repos = new RepositoryReader[] { (RepositoryReader) tracker };
+            }
+
+            GenericEvent eventRead = null;
+
+            for ( RepositoryReader rr : repos )
+            {
+                try
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead =
+                            new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_DEPENDENCIES_FROM_REPO,
+                                              rr.getRepository().getId() );
+                    }
+
+                    MetadataResults res = rr.readDependencies( query );
+
+                    if ( res != null )
+                    {
+                        if( res.hasExceptions() )
+                        {
+                            if ( LOG.isWarnEnabled() )
+                            {
+                                LOG.warn( bmd + " dependecies: error : " + res.getExceptions().toString() );
+                            }
+                        }
+                        
+                        if( res.hasResults( bmd ) )
+                        {
+                            md.setDependencies( res.getResult( bmd ) );
+                            md.setTracker( rr );
+    
+                            if ( _eventManager != null )
+                            {
+                                eventRead.setInfo( eventRead.getInfo() + ", found: " + md.getDependencies() );
+                            }
+    
+                            if ( LOG.isDebugEnabled() )
+                            {
+                                LOG.debug( bmd + " dependecies found : " + md.getDependencies() );
+                            }
+    
+                            return md;
+                        }
+                    }
+                }
+                finally
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead.stop();
+                        _eventManager.fireEvent( eventRead );
+                    }
+                }
+            }
+
+            if ( _eventManager != null )
+            {
+                event.setResult( "not found" );
+            }
+
+            return md;
+        }
+        finally
+        {
+            if ( _eventManager != null )
+            {
+                event.stop();
+                _eventManager.fireEvent( event );
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    /**
+     * split query into repository buckets
+     */
+    private Map<RepositoryReader, List<ArtifactMetadata>> sortByRepo( Collection<? extends ArtifactMetadata> query )
+    {
+        HashMap<RepositoryReader, List<ArtifactMetadata>> res = null;
+
+        List<ArtifactMetadata> rejects = null;
+
+        for ( ArtifactMetadata bmd : query )
+        {
+            Object tracker = bmd.getTracker();
+
+            // do we know where this metadata came from ?
+            if ( tracker != null && RepositoryReader.class.isAssignableFrom( tracker.getClass() ) )
+            {
+                RepositoryReader rr = (RepositoryReader) tracker;
+
+                if ( res == null )
+                {
+                    res = new HashMap<RepositoryReader, List<ArtifactMetadata>>();
+                }
+
+                List<ArtifactMetadata> rl = res.get( rr );
+
+                if ( rl == null )
+                {
+                    rl = new ArrayList<ArtifactMetadata>();
+                    res.put( rr, rl );
+                }
+
+                rl.add( bmd );
+
+            }
+            else
+            {
+                if ( rejects == null )
+                {
+                    rejects = new ArrayList<ArtifactMetadata>();
+                }
+
+                rejects.add( bmd );
+            }
+        }
+
+        if ( rejects != null )
+        {
+            if ( res == null )
+            {
+                res = new HashMap<RepositoryReader, List<ArtifactMetadata>>();
+            }
+
+            res.put( RepositoryReader.NULL_READER, rejects );
+        }
+
+        return res;
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public ArtifactResults readArtifactsNoBatch( Collection<? extends ArtifactMetadata> query )
+        throws RepositoryException
+    {
+        GenericEvent event = null;
+
+        try
+        {
+            ArtifactResults res = null;
+
+            if ( _eventManager != null )
+            {
+                event = new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_ARTIFACTS, "" );
+            }
+
+            if ( Util.isEmpty( query ) )
+            {
+                return res;
+            }
+
+            Map<RepositoryReader, List<ArtifactMetadata>> buckets = sortByRepo( query );
+
+            List<ArtifactMetadata> leftovers = buckets == null ? null : buckets.get( RepositoryReader.NULL_READER );
+
+            if ( buckets == null )
+            {
+                throw new RepositoryException( LANG.getMessage( "internal.error.sorting.query", query.toString() ) );
+            }
+
+            init();
+
+            res = new ArtifactResults();
+
+            // first read repository-qualified Artifacts
+            for ( RepositoryReader rr : buckets.keySet() )
+            {
+                if ( RepositoryReader.NULL_READER.equals( rr ) )
+                {
+                    continue;
+                }
+
+                String repoId = rr.getRepository().getId();
+
+                GenericEvent eventRead = null;
+
+                try
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead =
+                            new GenericEvent( EventTypeEnum.virtualRepositoryReader,
+                                              EVENT_READ_ARTIFACTS_FROM_REPO_QUALIFIED, repoId );
+                    }
+
+                    List<ArtifactMetadata> rrQuery = buckets.get( rr );
+
+                    ArtifactResults rrRes = rr.readArtifacts( rrQuery );
+
+                    if ( rrRes.hasExceptions() )
+                    {
+                        throw new RepositoryException( LANG.getMessage( "error.reading.existing.artifact",
+                                                                         rrRes.getExceptions().toString(),
+                                                                         rr.getRepository().getId() ) );
+                    }
+
+                    if ( rrRes.hasResults() )
+                    {
+                        for ( ArtifactMetadata bm : rrRes.getResults().keySet() )
+                        {
+                            List<Artifact> al = rrRes.getResults( bm );
+
+                            res.addAll( bm, al );
+
+                            // don't write local artifacts back to the same repo
+                            if ( _localRepository != null && repoId.equals( _localRepository.getId() ) )
+                            {
+                                continue;
+                            }
+
+                            if ( _localRepositoryWriter != null )
+                            {
+                                _localRepositoryWriter.writeArtifacts( al );
+                            }
+                        }
+                    }
+                }
+                finally
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead.stop();
+                        _eventManager.fireEvent( eventRead );
+                    }
+                }
+            }
+
+            // then process unqualified virtuals
+            if ( !Util.isEmpty( leftovers ) )
+            {
+                List<ArtifactMetadata> virtuals = null;
+
+                for ( ArtifactMetadata md : leftovers )
+                {
+                    if ( DefaultArtifactVersion.isVirtual( md.getVersion() ) )
+                    {
+                        if ( virtuals == null )
+                        {
+                            virtuals = new ArrayList<ArtifactMetadata>();
+                        }
+
+                        virtuals.add( md );
+                    }
+                }
+
+
+                if ( virtuals != null )
+                {
+                    MetadataResults virtRes = readVersions( virtuals );
+
+                    leftovers.removeAll( virtuals );
+
+                    virtuals.clear();
+
+                    if ( virtRes != null )
+                    {
+                        if ( virtRes.hasResults() )
+                        {
+                            Map<ArtifactMetadata, ArtifactMetadata> sMap = new HashMap<ArtifactMetadata, ArtifactMetadata>();
+
+                            for ( ArtifactMetadata md : virtRes.getResults().keySet() )
+                            {
+                                ArtifactMetadata v = virtRes.getResult( md ).get( 0 );
+                                virtuals.add( v );
+                                sMap.put( v, md );
+                            }
+
+                            ArtifactResults ares = readArtifacts( virtuals );
+
+                            if ( ares != null )
+                            {
+                                if ( ares.hasResults() )
+                                {
+                                    Map<ArtifactMetadata, List<Artifact>> aresMap = ares.getResults();
+
+                                    // remap
+                                    for ( ArtifactMetadata md : aresMap.keySet() )
+                                    {
+                                        res.add( sMap.get( md ), aresMap.get( md ).get( 0 ) );
+                                    }
+                                }
+
+                                if ( ares.hasExceptions() )
+                                {
+                                    res.getExceptions().putAll( ares.getExceptions() );
+                                }
+                            }
+
+                            if ( virtRes.hasExceptions() )
+                            {
+                                res.addError( virtRes.getExceptions() );
+                            }
+                        }
+
+                        if ( virtRes.hasExceptions() )
+                        {
+                            res.addError( virtRes.getExceptions() );
+                        }
+                    }
+                }
+
+            }
+
+            // then search all repos for unqualified Artifacts
+            if ( !Util.isEmpty( leftovers ) )
+            {
+                for ( RepositoryReader rr : _repositoryReaders )
+                {
+                    if ( leftovers.isEmpty() )
+                    {
+                        break;
+                    }
+
+                    String repoId = rr.getRepository().getId();
+
+                    GenericEvent eventRead = null;
+
+                    try
+                    {
+                        if ( _eventManager != null )
+                        {
+                            eventRead =
+                                new GenericEvent( EventTypeEnum.virtualRepositoryReader,
+                                                  EVENT_READ_ARTIFACTS_FROM_REPO_UNQUALIFIED, repoId );
+                        }
+
+                        ArtifactResults rrRes = rr.readArtifacts( leftovers );
+
+                        if ( rrRes.hasExceptions() )
+                        {
+                            res.addError( rrRes );
+                        }
+                        else if ( rrRes.hasResults() )
+                        {
+                            for ( ArtifactMetadata bm : rrRes.getResults().keySet() )
+                            {
+                                List<Artifact> al = rrRes.getResults( bm );
+
+                                res.addAll( bm, al );
+
+                                leftovers.remove( bm );
+
+                                // don't write local artifacts back to the same repo
+                                if ( _localRepository != null && repoId.equals( _localRepository.getId() ) )
+                                {
+                                    continue;
+                                }
+
+                                if ( _localRepositoryWriter != null )
+                                {
+                                    _localRepositoryWriter.writeArtifacts( al );
+                                }
+
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        if ( _eventManager != null )
+                        {
+                            eventRead.stop();
+                            _eventManager.fireEvent( eventRead );
+                        }
+                    }
+                }
+            }
+
+            return res;
+        }
+        finally
+        {
+            if ( _eventManager != null )
+            {
+                event.stop();
+                _eventManager.fireEvent( event );
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public ArtifactResults readArtifacts( Collection<? extends ArtifactMetadata> query )
+        throws RepositoryException
+    {
+        GenericEvent event = null;
+
+        try
+        {
+            ArtifactResults res = null;
+
+            if ( _eventManager != null )
+            {
+                event = new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_ARTIFACTS, "" );
+            }
+
+            if ( Util.isEmpty( query ) )
+            {
+                return res;
+            }
+            
+            int qSize = query.size();
+            
+            List<ArtifactMetadata> qualified = new ArrayList<ArtifactMetadata>( qSize );
+            
+            List<ArtifactMetadata> leftovers = new ArrayList<ArtifactMetadata>( qSize );
+            
+            for( ArtifactMetadata md : query )
+            {
+                Object tracker = md.getTracker();
+    
+                // do we know where this metadata came from ?
+                if ( tracker != null 
+                     && RemoteRepositoryReaderM2.class.isAssignableFrom( tracker.getClass() )
+                     && !md.isVirtual()
+                     && md.isSingleton()
+                )
+                    qualified.add( md );
+                else
+                    leftovers.add( md );
+            }
+
+            if ( qualified.isEmpty()  && leftovers.isEmpty() )
+            {
+                throw new RepositoryException( LANG.getMessage( "internal.error.sorting.query", query.toString() ) );
+            }
+
+            init();
+
+            res = new ArtifactResults();
+
+            // first read repository-qualified Artifacts
+            GenericEvent eventRead = null;
+
+            if( qualified.size() > 0 )
+            try
+            {
+                if ( _eventManager != null )
+                    eventRead = new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_ARTIFACTS, ""+qualified );
+                
+                ArtifactResults rrRes = new ArtifactResults();
+                
+                _idleReader.readQualifiedArtifacts( qualified, rrRes );
+
+                if ( rrRes.hasExceptions() )
+                {
+                    throw new RepositoryException( LANG.getMessage( "error.reading.existing.artifact",
+                                                                     rrRes.getExceptions().toString(),
+                                                                     "multiple.server.internal.repo" ) );
+                }
+
+                if ( rrRes.hasResults() )
+                {
+                    for ( ArtifactMetadata bm : rrRes.getResults().keySet() )
+                    {
+                        List<Artifact> al = rrRes.getResults( bm );
+
+                        res.addAll( bm, al );
+
+                        if ( _localRepositoryWriter != null )
+                        {
+                            _localRepositoryWriter.writeArtifacts( al );
+                        }
+                    }
+                }
+            }
+            catch ( Exception e )
+            {
+                throw new RepositoryException( e );
+            }
+            finally
+            {
+                if ( _eventManager != null )
+                {
+                    eventRead.stop();
+                    _eventManager.fireEvent( eventRead );
+                }
+            }
+
+            // then process unqualified virtuals
+            if ( !Util.isEmpty( leftovers ) )
+            {
+                List<ArtifactMetadata> virtuals = null;
+
+                for ( ArtifactMetadata md : leftovers )
+                {
+                    if ( DefaultArtifactVersion.isVirtual( md.getVersion() ) )
+                    {
+                        if ( virtuals == null )
+                        {
+                            virtuals = new ArrayList<ArtifactMetadata>();
+                        }
+
+                        virtuals.add( md );
+                    }
+                }
+
+
+                if ( virtuals != null )
+                {
+                    MetadataResults virtRes = readVersions( virtuals );
+
+                    leftovers.removeAll( virtuals );
+
+                    virtuals.clear();
+
+                    if ( virtRes != null )
+                    {
+                        if ( virtRes.hasResults() )
+                        {
+                            Map<ArtifactMetadata, ArtifactMetadata> sMap = new HashMap<ArtifactMetadata, ArtifactMetadata>();
+
+                            for ( ArtifactMetadata md : virtRes.getResults().keySet() )
+                            {
+                                ArtifactMetadata v = virtRes.getResult( md ).get( 0 );
+                                virtuals.add( v );
+                                sMap.put( v, md );
+                            }
+
+                            ArtifactResults ares = readArtifactsNoBatch( virtuals );
+
+                            if ( ares != null )
+                            {
+                                if ( ares.hasResults() )
+                                {
+                                    Map<ArtifactMetadata, List<Artifact>> aresMap = ares.getResults();
+
+                                    // remap
+                                    for ( ArtifactMetadata md : aresMap.keySet() )
+                                    {
+                                        res.add( sMap.get( md ), aresMap.get( md ).get( 0 ) );
+                                    }
+                                }
+
+                                if ( ares.hasExceptions() )
+                                {
+                                    res.getExceptions().putAll( ares.getExceptions() );
+                                }
+                            }
+
+                            if ( virtRes.hasExceptions() )
+                            {
+                                res.addError( virtRes.getExceptions() );
+                            }
+                        }
+
+                        if ( virtRes.hasExceptions() )
+                        {
+                            res.addError( virtRes.getExceptions() );
+                        }
+                    }
+                }
+
+            }
+
+            // then search all repos for unqualified Artifacts
+            if ( !Util.isEmpty( leftovers ) )
+            {
+                for ( RepositoryReader rr : _repositoryReaders )
+                {
+                    if ( leftovers.isEmpty() )
+                    {
+                        break;
+                    }
+
+                    String repoId = rr.getRepository().getId();
+
+                    try
+                    {
+                        if ( _eventManager != null )
+                        {
+                            eventRead =
+                                new GenericEvent( EventTypeEnum.virtualRepositoryReader,
+                                                  EVENT_READ_ARTIFACTS_FROM_REPO_UNQUALIFIED, repoId );
+                        }
+
+                        ArtifactResults rrRes = rr.readArtifacts( leftovers );
+
+                        if ( rrRes.hasExceptions() )
+                        {
+                            res.addError( rrRes );
+                        }
+                        else if ( rrRes.hasResults() )
+                        {
+                            for ( ArtifactMetadata bm : rrRes.getResults().keySet() )
+                            {
+                                List<Artifact> al = rrRes.getResults( bm );
+
+                                res.addAll( bm, al );
+
+                                leftovers.remove( bm );
+
+                                // don't write local artifacts back to the same repo
+                                if ( _localRepository != null && repoId.equals( _localRepository.getId() ) )
+                                {
+                                    continue;
+                                }
+
+                                if ( _localRepositoryWriter != null )
+                                {
+                                    _localRepositoryWriter.writeArtifacts( al );
+                                }
+
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        if ( _eventManager != null )
+                        {
+                            eventRead.stop();
+                            _eventManager.fireEvent( eventRead );
+                        }
+                    }
+                }
+            }
+
+            return res;
+        }
+        finally
+        {
+            if ( _eventManager != null )
+            {
+                event.stop();
+                _eventManager.fireEvent( event );
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    // MetadataReader implementation
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public byte[] readMetadata( ArtifactMetadata bmd )
+        throws MetadataReaderException
+    {
+        return readMetadata( bmd, false );
+    }
+
+    public byte[] readMetadata( ArtifactMetadata bmd, boolean exempt  )
+        throws MetadataReaderException
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( "Asking for pom: " + bmd );
+        }
+        
+        byte [] res = readRawData( bmd, "", "pom", exempt ); 
+
+        return res; 
+    }
+
+    // ----------------------------------------------------------------------------------------------------------------------------
+    // MetadataReader implementation
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public byte[] readRawData( ArtifactMetadata bmd, String classifier, String type )
+        throws MetadataReaderException
+    {
+        return readRawData( bmd, classifier, type, false );
+    }
+
+    public byte[] readRawData( ArtifactMetadata bmd, String classifier, String type, boolean exempt )
+        throws MetadataReaderException
+    {
+
+        GenericEvent event = null;
+        String eventTag = null;
+
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( "request for " + bmd + ", classifier=" + classifier + ", type=" + type );
+        }
+
+        if ( bmd == null )
+        {
+            throw new IllegalArgumentException( "null bmd supplied" );
+        }
+
+        try
+        {
+            if ( _eventManager != null )
+            {
+                eventTag =
+                    bmd.toString() + ( Util.isEmpty( classifier ) ? "" : ", classifier=" + classifier )
+                        + ( Util.isEmpty( type ) ? "" : ", type=" + type );
+                event = new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_RAW, eventTag );
+            }
+
+            ArtifactMetadata bmdQuery = new ArtifactMetadata(bmd);
+            
+            if( !Util.isEmpty( type ))
+                bmdQuery.setType( type );
+            
+            // pom cannot have classifiers
+            if( "pom".equals( bmdQuery.getType() ) )
+                bmdQuery.setClassifier( null );
+
+            try
+            {
+                init();
+            }
+            catch ( RepositoryException e )
+            {
+                throw new MetadataReaderException( e );
+            }
+
+            byte[] res = null;
+            Quality vq = new Quality( bmd.getVersion() );
+
+            if ( LOG.isDebugEnabled() )
+            {
+                LOG.debug( "quality calculated as " + (vq.getQuality() == null ? "null" : vq.getQuality().name()) );
+            }
+
+            if ( Quality.SNAPSHOT_QUALITY.equals( vq ) )
+            {
+                List<ArtifactMetadata> query = new ArrayList<ArtifactMetadata>( 1 );
+                
+                ArtifactMetadata nBmd = new ArtifactMetadata( bmdQuery );
+                
+                if( !Util.isEmpty( type ))
+                    nBmd.setType( type );
+                
+                query.add( nBmd );
+
+                try
+                {
+                    MetadataResults vRes = readVersions( query );
+                    if ( Util.isEmpty( vRes ) )
+                    {
+                        if ( LOG.isDebugEnabled() )
+                        {
+                            LOG.debug( "no snapshots found - throw exception" );
+                        }
+
+                        throw new MetadataReaderException( LANG.getMessage( "no.snapshots", bmd.toString(),
+                                                                             classifier, type ) );
+                    }
+
+                    if ( vRes.hasResults( nBmd ) )
+                    {
+                        List<ArtifactMetadata> versions = vRes.getResult( nBmd );
+                        
+                        processSingletons( nBmd, versions );
+
+//                        TreeSet<ArtifactMetadata> snapshots =
+//                            new TreeSet<ArtifactMetadata>( new MetadataVersionComparator() );
+//                        snapshots.addAll( versions );
+//
+//                        bmdQuery = snapshots.last();
+                        
+                        bmdQuery = versions.get( 0 );
+                    }
+                    else
+                    {
+                        if ( LOG.isDebugEnabled() )
+                        {
+                            LOG.debug( "no snapshots found - throw exception" );
+                        }
+
+                        throw new MetadataReaderException( LANG.getMessage( "no.snapshots", bmd.toString(),
+                                                                             classifier, type ) );
+                    }
+                }
+                catch ( Exception e )
+                {
+                    throw new MetadataReaderException( e );
+                }
+            }
+
+            for ( RepositoryReader rr : _repositoryReaders )
+            {
+                GenericEvent eventRead = null;
+
+                try
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead =
+                            new GenericEvent( EventTypeEnum.virtualRepositoryReader, EVENT_READ_RAW_FROM_REPO,
+                                              rr.getRepository().getId() + ": " + eventTag );
+                    }
+
+                    res = rr.readRawData( bmdQuery, classifier, type, false );
+                    if ( res != null )
+                    {
+                        if ( LOG.isDebugEnabled() )
+                        {
+                            LOG.debug( bmdQuery + " found in " + rr.getRepository().getServer() );
+                        }
+
+                        if ( _eventManager != null )
+                        {
+                            eventRead.setInfo( eventRead.getInfo() );
+                        }
+
+                        return res;
+                    }
+
+                    if ( _eventManager != null )
+                    {
+                        eventRead.setResult( "not found" );
+                    }
+                }
+                finally
+                {
+                    if ( _eventManager != null )
+                    {
+                        eventRead.stop();
+                        _eventManager.fireEvent( eventRead );
+                    }
+                }
+            }
+
+            if ( LOG.isDebugEnabled() )
+            {
+                LOG.debug( "no data found, returning null" );
+            }
+
+            return null;
+        }
+        finally
+        {
+            if ( _eventManager != null )
+            {
+                event.stop();
+                _eventManager.fireEvent( event );
+            }
+        }
+    }
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public RepositoryMetadataCache getCache()
+    {
+        return _mdCache;
+    }
+    // ----------------------------------------------------------------------------------------------------------------------------
+    public void register( MercuryEventListener listener )
+    {
+        if ( _eventManager == null )
+        {
+            _eventManager = new EventManager();
+        }
+
+        _eventManager.register( listener );
+    }
+
+    public void setEventManager( EventManager eventManager )
+    {
+        _eventManager = eventManager;
+    }
+
+    public void unRegister( MercuryEventListener listener )
+    {
+        if ( _eventManager != null )
+        {
+            _eventManager.unRegister( listener );
+        }
+    }
+    // ----------------------------------------------------------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------------------------------------------------------
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/repository/virtual/VirtualRepositoryReader.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,132 @@
+/**
+ * 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.
+ */
+package org.apache.maven.mercury.spi.http.client;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.maven.mercury.logging.IMercuryLogger;
+import org.apache.maven.mercury.logging.MercuryLoggerManager;
+import org.apache.maven.mercury.transport.api.Server;
+import org.mortbay.jetty.client.Address;
+import org.mortbay.jetty.client.HttpDestination;
+import org.mortbay.jetty.client.security.Realm;
+import org.mortbay.jetty.client.security.RealmResolver;
+
+/**
+ * DestinationRealmResolver
+ *
+ * Resolve a security realm based on the Server instance
+ * which matches an async Destination.
+ */
+public class DestinationRealmResolver implements RealmResolver
+{
+    private static final IMercuryLogger LOG = MercuryLoggerManager.getLogger(DestinationRealmResolver.class);
+    
+    protected Set<Server> _servers = new HashSet<Server>();
+    
+    
+    
+    public DestinationRealmResolver (Set<Server> servers)
+    {
+        _servers.addAll(servers);
+    }
+
+    public Realm getRealm(String name, HttpDestination dest, String pathSpec)
+            throws IOException
+    {
+       Address address = dest.getAddress();
+       boolean secure = dest.isSecure();
+
+       if( LOG.isDebugEnabled() )
+       {
+         LOG.debug("Dest "+address.getHost()+":"+address.getPort()+"(secure="+secure+")" );
+         LOG.debug("Server list: "+_servers );
+         
+       }
+
+       //get a username and password appropriate for the destination. Usernames and passwords are
+       //associated with Server Credential objects.
+       Server server = null;
+       Iterator<Server> itor = _servers.iterator();
+       while (server==null && itor.hasNext())
+       {
+           Server s = itor.next();
+           if (s.getURL() != null)
+           {
+               String protocol = s.getURL().getProtocol();
+               String host = s.getURL().getHost();
+               int port = s.getURL().getPort();
+               if( port == -1 )
+               {
+                 port = "https".equalsIgnoreCase( protocol ) ? 443 : 80;
+               }
+
+               if( LOG.isDebugEnabled() )
+                 LOG.debug("Trying dest "+address.getHost()+":"+address.getPort()+"(secure="+dest.isSecure()
+                     +") against server "+protocol+"://"+host+":"+port );
+
+               if (((secure && "https".equalsIgnoreCase(protocol)) || (!secure && "http".equalsIgnoreCase(protocol)))
+                   &&
+                   (address.getPort() == port))
+               {
+                   if (address.getHost().equalsIgnoreCase(host) || address.getHost().equalsIgnoreCase(host))
+                   {
+                       server = s;
+                       if (LOG.isDebugEnabled())
+                           LOG.debug("Matched server "+address.getHost()+":"+address.getPort());
+                   }
+               }
+           }
+       }
+
+       if (server == null || server.getServerCredentials() == null)
+       {
+           if (LOG.isDebugEnabled())
+               LOG.debug("No server matching "+address.getHost()+":"+address.getPort()+" or no credentials");
+           return null;
+       }
+       
+       if (server.getServerCredentials().isCertificate())
+           throw new UnsupportedOperationException("Certificate not supported");
+       
+       final Server realmServer = server;
+       return new Realm ()
+       {
+           public String getCredentials()
+           {
+               return realmServer.getServerCredentials().getPass();
+           }
+
+           public String getId()
+           {
+               return realmServer.getId();
+           }
+
+           public String getPrincipal()
+           {
+               return realmServer.getServerCredentials().getUser();
+           }
+
+       };
+    }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DestinationRealmResolver.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,107 @@
+/**
+ * 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.
+ */
+
+package org.apache.maven.mercury.spi.http.client;
+
+import java.io.File;
+import java.net.URL;
+
+import org.apache.maven.mercury.transport.api.Binding;
+import org.apache.maven.mercury.transport.api.Server;
+import org.mortbay.io.Buffer;
+import org.mortbay.jetty.client.HttpClient;
+import org.mortbay.jetty.client.HttpExchange;
+
+/**
+ * FileExchange
+ * <p/>
+ * Base class for asynchronously PUTting or GETting a file.
+ */
+public abstract class FileExchange extends HttpExchange
+{
+
+   
+
+    public static final String __BATCH_HEADER = "Jetty-Batch-Id";
+    public static final String __BATCH_SUPPORTED_HEADER = "Jetty-Batch-Supported";
+    public static final String __BATCH_COMMIT_HEADER = "Jetty-Batch-Commit";
+    public static final String __BATCH_DISCARD_HEADER = "Jetty-Batch-Discard";
+
+
+    protected HttpClient _httpClient;
+    protected int _status;
+    protected String _url;
+    protected File _localFile;
+    protected Binding _binding;
+    protected Server _server;
+
+    public abstract void onFileComplete( String url, File localFile );
+
+    public abstract void onFileError( String url, Exception e );
+
+
+    public FileExchange( Server server, Binding binding, File localFile, HttpClient client )
+    {
+        _server = server;
+        _binding = binding;
+        if (_binding != null)
+        {
+            URL url = binding.getRemoteResource();
+            if (url != null)
+                _url = url.toString();
+        }
+
+        _localFile = localFile;
+        _httpClient = client;
+        setURL( _url );
+    }
+
+    public void send()
+    {
+        try
+        {
+            SecureSender.send(_server, _httpClient, this);
+        }
+        catch ( Exception e )
+        {
+            onFileError( _url, e );
+        }
+    }
+
+    protected void onResponseStatus( Buffer version, int status, Buffer reason )
+    {
+        _status = status;
+    }
+
+    protected void onException( Throwable ex )
+    {
+        onFileError( _url, new Exception( ex ) );
+    }
+
+    protected void onExpire()
+    {
+        onFileError( _url, new Exception( "Timeout occurred" ) );
+    }
+    
+    protected void onConnectionFailed(Throwable ex)
+    {
+        onFileError(_url, new Exception(ex));
+    }
+    
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,109 @@
+/**
+ * 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.
+ */
+
+package org.apache.maven.mercury.spi.http.client;
+
+import java.util.Map;
+
+import org.mortbay.io.Buffer;
+import org.mortbay.jetty.client.HttpClient;
+import org.mortbay.jetty.client.HttpExchange;
+
+/**
+ * HandshakeExchange
+ * <p/>
+ * Asychronous http message sending. Used to generate a commit or discard
+ * message to the remote server after the mercury upload is finished.
+ */
+public abstract class HandshakeExchange extends HttpExchange
+{
+    private HttpClient _httpClient;
+    private String _method;
+    private String _url;
+    private Map<String, String> _headers;
+    private int _status;
+
+    public abstract void onHandshakeComplete( String url );
+
+    public abstract void onHandshakeError( String url, Exception e );
+
+    /**
+     * @param httpClient
+     * @param method
+     * @param url
+     * @param headers
+     */
+    public HandshakeExchange( HttpClient httpClient, String method, String url, Map<String, String> headers )
+    {
+        _httpClient = httpClient;
+        _method = method;
+        _url = url;
+        _headers = headers;
+    }
+
+    public void send()
+    {
+        try
+        {
+            setMethod( _method );
+            setURL( _url );
+            if ( _headers != null )
+            {
+                for ( Map.Entry<String, String> e : _headers.entrySet() )
+                {
+                    setRequestHeader( e.getKey(), e.getValue() );
+                }
+            }
+            _httpClient.send( this );
+        }
+        catch ( Exception e )
+        {
+            onHandshakeError( _url, new Exception( null, e ) );
+        }
+    }
+
+
+    protected void onResponseStatus( Buffer version, int status, Buffer reason )
+    {
+        _status = status;
+    }
+
+    protected void onException( Throwable ex )
+    {
+        onHandshakeError( _url, new Exception( ex ) );
+    }
+
+    protected void onExpire()
+    {
+        onHandshakeError( _url, new Exception( "Timeout occurred" ) );
+    }
+
+    protected void onResponseComplete()
+    {
+        if ( _status != HttpServletResponse.SC_OK )
+        {
+            onHandshakeError( _url, new Exception( "Http Error Code:" + _status ) );
+        }
+        else
+        {
+            onHandshakeComplete( _url );
+        }
+    }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java (added)
+++ maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+
+//========================================================================
+//Copyright 2008 Sonatype Inc.
+//------------------------------------------------------------------------
+//Licensed 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.
+//========================================================================
+
+package org.apache.maven.mercury.spi.http.client;
+import org.apache.maven.mercury.transport.api.Binding;
+
+/**
+ * BatchException
+ * <p/>
+ * Exception that occurs whilst deploying or retrieving files
+ * asynchronously.
+ */
+public class HttpClientException
+    extends Exception
+{
+    private Binding binding;
+
+    public HttpClientException( Binding b, String s )
+    {
+        super( s );
+        binding = b;
+    }
+
+    public HttpClientException( Binding b, String s, Throwable throwable )
+    {
+        super( s, throwable );
+        binding = b;
+    }
+
+    public HttpClientException( Binding b, Throwable throwable )
+    {
+        super( throwable );
+        binding = b;
+    }
+
+    public Binding getBinding()
+    {
+        return binding;
+    }
+
+
+    public String getMessage()
+    {
+        return super.getMessage() + " for " + binding;
+    }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision