http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java index ae7cd62..469d122 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java @@ -28,6 +28,10 @@ import org.apache.archiva.configuration.IndeterminateConfigurationException; import org.apache.archiva.configuration.ManagedRepositoryConfiguration; import org.apache.archiva.configuration.ProxyConnectorConfiguration; import org.apache.archiva.configuration.RepositoryGroupConfiguration; +import org.apache.archiva.indexer.ArchivaIndexManager; +import org.apache.archiva.indexer.ArchivaIndexingContext; +import org.apache.archiva.indexer.IndexManagerFactory; +import org.apache.archiva.indexer.IndexUpdateFailedException; import org.apache.archiva.metadata.model.facets.AuditEvent; import org.apache.archiva.metadata.repository.MetadataRepository; import org.apache.archiva.metadata.repository.MetadataRepositoryException; @@ -40,6 +44,7 @@ import org.apache.archiva.redback.components.taskqueue.TaskQueueException; import org.apache.archiva.redback.role.RoleManager; import org.apache.archiva.redback.role.RoleManagerException; import org.apache.archiva.repository.ReleaseScheme; +import org.apache.archiva.repository.Repository; import org.apache.archiva.repository.RepositoryException; import org.apache.archiva.repository.RepositoryRegistry; import org.apache.archiva.repository.features.ArtifactCleanupFeature; @@ -50,10 +55,8 @@ import org.apache.archiva.scheduler.repository.model.RepositoryTask; import org.apache.archiva.security.common.ArchivaRoleConstants; import org.apache.commons.lang.StringUtils; import org.apache.maven.index.NexusIndexer; -import org.apache.maven.index.context.IndexCreator; + import org.apache.maven.index.context.IndexingContext; -import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException; -import org.apache.maven.index_shaded.lucene.index.IndexFormatTooOldException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -112,12 +115,11 @@ public class DefaultManagedRepositoryAdmin @Named(value = "cache#namespaces") private Cache<String, Collection<String>> namespacesCache; - // fields @Inject - private List<? extends IndexCreator> indexCreators; + private IndexManagerFactory indexManagerFactory; + + - @Inject - private NexusIndexer indexer; @PostConstruct public void initialize() @@ -127,7 +129,6 @@ public class DefaultManagedRepositoryAdmin for ( ManagedRepository managedRepository : getManagedRepositories() ) { log.debug("Initializating {}", managedRepository.getId()); - createIndexContext( managedRepository ); addRepositoryRoles( managedRepository.getId() ); } @@ -137,22 +138,6 @@ public class DefaultManagedRepositoryAdmin public void shutdown() throws RepositoryAdminException { - try - { - // close index on shutdown - for ( ManagedRepository managedRepository : getManagedRepositories() ) - { - IndexingContext context = indexer.getIndexingContexts().get( managedRepository.getId() ); - if ( context != null ) - { - indexer.removeIndexingContext( context, false ); - } - } - } - catch ( IOException e ) - { - throw new RepositoryAdminException( e.getMessage(), e ); - } } /* @@ -290,7 +275,6 @@ public class DefaultManagedRepositoryAdmin log.error("Could not add repository roles for repository [{}]: {}", managedRepository.getId(), e.getMessage(), e); throw new RepositoryAdminException( "Could not add roles to repository "+e.getMessage() ); } - createIndexContext( managedRepository ); return Boolean.TRUE; } @@ -304,64 +288,56 @@ public class DefaultManagedRepositoryAdmin { Configuration config = getArchivaConfiguration().getConfiguration(); ManagedRepositoryConfiguration repoConfig=config.findManagedRepositoryById( repositoryId ); - - log.debug("Repo location "+repoConfig.getLocation()); - - org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId ); - org.apache.archiva.repository.ManagedRepository stagingRepository = null; - if (repo!=null) { - try - { - if (repo.supportsFeature( StagingRepositoryFeature.class )) { - stagingRepository = repo.getFeature( StagingRepositoryFeature.class ).get().getStagingRepository(); + if (repoConfig!=null) { + + log.debug("Repo location " + repoConfig.getLocation()); + + org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository(repositoryId); + org.apache.archiva.repository.ManagedRepository stagingRepository = null; + if (repo != null) { + try { + if (repo.supportsFeature(StagingRepositoryFeature.class)) { + stagingRepository = repo.getFeature(StagingRepositoryFeature.class).get().getStagingRepository(); + } + repositoryRegistry.removeRepository(repo, config); + } catch (RepositoryException e) { + log.error("Removal of repository {} failed: {}", repositoryId, e.getMessage(), e); + throw new RepositoryAdminException("Removal of repository " + repositoryId + " failed."); } - repositoryRegistry.removeRepository( repo, config ); - } - catch ( RepositoryException e ) - { - log.error("Removal of repository {} failed: {}", repositoryId, e.getMessage(), e); - throw new RepositoryAdminException( "Removal of repository "+repositoryId+" failed." ); + } else { + throw new RepositoryAdminException("A repository with that id does not exist"); } - } else { - throw new RepositoryAdminException( "A repository with that id does not exist" ); - } - triggerAuditEvent( repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation ); - if (repoConfig!=null) - { - deleteManagedRepository( repoConfig, deleteContent, config, false ); - } + triggerAuditEvent(repositoryId, null, AuditEvent.DELETE_MANAGED_REPO, auditInformation); + if (repoConfig != null) { + deleteManagedRepository(repoConfig, deleteContent, config, false); + } - // stage repo exists ? - if ( stagingRepository != null ) - { - // do not trigger event when deleting the staged one - ManagedRepositoryConfiguration stagingRepositoryConfig = config.findManagedRepositoryById( stagingRepository.getId( ) ); - try - { - repositoryRegistry.removeRepository( stagingRepository ); - if (stagingRepositoryConfig!=null) - { - deleteManagedRepository( stagingRepositoryConfig, deleteContent, config, true ); + // stage repo exists ? + if (stagingRepository != null) { + // do not trigger event when deleting the staged one + ManagedRepositoryConfiguration stagingRepositoryConfig = config.findManagedRepositoryById(stagingRepository.getId()); + try { + repositoryRegistry.removeRepository(stagingRepository); + if (stagingRepositoryConfig != null) { + deleteManagedRepository(stagingRepositoryConfig, deleteContent, config, true); + } + } catch (RepositoryException e) { + log.error("Removal of staging repository {} failed: {}", stagingRepository.getId(), e.getMessage(), e); } } - catch ( RepositoryException e ) - { - log.error("Removal of staging repository {} failed: {}", stagingRepository.getId(), e.getMessage(), e); + + try { + saveConfiguration(config); + } catch (Exception e) { + throw new RepositoryAdminException("Error saving configuration for delete action" + e.getMessage(), e); } - } - try - { - saveConfiguration( config ); - } - catch ( Exception e ) - { - throw new RepositoryAdminException( "Error saving configuration for delete action" + e.getMessage(), e ); + return Boolean.TRUE; + } else { + return Boolean.FALSE; } - - return Boolean.TRUE; } private Boolean deleteManagedRepository( ManagedRepositoryConfiguration repository, boolean deleteContent, @@ -369,20 +345,6 @@ public class DefaultManagedRepositoryAdmin throws RepositoryAdminException { - try - { - IndexingContext context = indexer.getIndexingContexts().get( repository.getId() ); - if ( context != null ) - { - // delete content only if directory exists - indexer.removeIndexingContext( context, - deleteContent && context.getIndexDirectoryFile().exists() ); - } - } - catch ( IOException e ) - { - throw new RepositoryAdminException( e.getMessage(), e ); - } if ( !stagedOne ) { RepositorySession repositorySession = getRepositorySessionFactory().createSession(); @@ -454,11 +416,24 @@ public class DefaultManagedRepositoryAdmin "fail to remove repository roles for repository " + repository.getId() + " : " + e.getMessage(), e ); } + try { + final RepositoryRegistry reg = getRepositoryRegistry(); + if (reg.getManagedRepository(repository.getId())!=null) { + reg.removeRepository(reg.getManagedRepository(repository.getId())); + } + } catch (RepositoryException e) { + throw new RepositoryAdminException("Removal of repository "+repository.getId()+ " failed: "+e.getMessage()); + } + saveConfiguration( config ); return Boolean.TRUE; } + ArchivaIndexManager getIndexManager(ManagedRepository managedRepository) { + org.apache.archiva.repository.ManagedRepository repo = getRepositoryRegistry().getManagedRepository(managedRepository.getId()); + return indexManagerFactory.getIndexManager(repo.getType()); + } @Override public Boolean updateManagedRepository( ManagedRepository managedRepository, boolean needStageRepo, @@ -486,11 +461,11 @@ public class DefaultManagedRepositoryAdmin stagingExists = oldRepo.getFeature( StagingRepositoryFeature.class ).get().getStagingRepository() != null; } boolean updateIndexContext = !StringUtils.equals( updatedRepoConfig.getIndexDir(), managedRepository.getIndexDirectory() ); - + org.apache.archiva.repository.ManagedRepository newRepo; // TODO remove content from old if path has changed !!!!! try { - org.apache.archiva.repository.ManagedRepository newRepo = repositoryRegistry.putRepository( updatedRepoConfig, configuration ); + newRepo = repositoryRegistry.putRepository( updatedRepoConfig, configuration ); if (newRepo.supportsFeature( StagingRepositoryFeature.class )) { org.apache.archiva.repository.ManagedRepository stagingRepo = newRepo.getFeature( StagingRepositoryFeature.class ).get( ).getStagingRepository( ); if (stagingRepo!=null && !stagingExists) @@ -551,21 +526,10 @@ public class DefaultManagedRepositoryAdmin { try { - IndexingContext indexingContext = indexer.getIndexingContexts().get( managedRepository.getId() ); - if ( indexingContext != null ) - { - indexer.removeIndexingContext( indexingContext, true ); - } - - // delete directory too as only content is deleted - Path indexDirectory = indexingContext.getIndexDirectoryFile().toPath(); - org.apache.archiva.common.utils.FileUtils.deleteDirectory( indexDirectory ); - createIndexContext( managedRepository ); - } - catch ( IOException e ) - { - throw new RepositoryAdminException( e.getMessage(), e ); + repositoryRegistry.resetIndexingContext(newRepo); + } catch (IndexUpdateFailedException e) { + e.printStackTrace(); } } @@ -591,110 +555,6 @@ public class DefaultManagedRepositoryAdmin } - public IndexingContext createIndexContext( org.apache.archiva.repository.ManagedRepository repository) throws RepositoryAdminException - { - return createIndexContext( convertRepo( repository ) ); - } - - @Override - public IndexingContext createIndexContext( ManagedRepository repository ) - throws RepositoryAdminException - { - - IndexingContext context = indexer.getIndexingContexts().get( repository.getId() ); - - if ( context != null ) - { - log.debug( "skip creating repository indexingContent with id {} as already exists", repository.getId() ); - return context; - } - - // take care first about repository location as can be relative - Path repositoryDirectory = Paths.get( repository.getLocation() ); - - if ( !repositoryDirectory.isAbsolute() ) - { - repositoryDirectory = - Paths.get( getRegistry().getString( "appserver.base" ), "repositories", - repository.getLocation() ); - } - - if ( !Files.exists(repositoryDirectory) ) - { - try { - Files.createDirectories(repositoryDirectory); - } catch (IOException e) { - log.error("Could not create directory {}", repositoryDirectory); - } - } - - try - { - - String indexDir = repository.getIndexDirectory(); - //File managedRepository = new File( repository.getLocation() ); - - Path indexDirectory = null; - if ( StringUtils.isNotBlank( indexDir ) ) - { - indexDirectory = Paths.get( repository.getIndexDirectory() ); - // not absolute so create it in repository directory - if ( !indexDirectory.isAbsolute() ) - { - indexDirectory = repositoryDirectory.resolve(repository.getIndexDirectory() ); - } - repository.setIndexDirectory( indexDirectory.toAbsolutePath().toString() ); - } - else - { - indexDirectory = repositoryDirectory.resolve(".indexer" ); - if ( !repositoryDirectory.isAbsolute() ) - { - indexDirectory = repositoryDirectory.resolve( ".indexer" ); - } - repository.setIndexDirectory( indexDirectory.toAbsolutePath().toString() ); - } - - if ( !Files.exists(indexDirectory) ) - { - Files.createDirectories(indexDirectory); - } - - context = indexer.getIndexingContexts().get( repository.getId() ); - - if ( context == null ) - { - try - { - context = indexer.addIndexingContext( repository.getId(), repository.getId(), repositoryDirectory.toFile(), - indexDirectory.toFile(), - repositoryDirectory.toUri().toURL().toExternalForm(), - indexDirectory.toUri().toURL().toString(), indexCreators ); - - context.setSearchable( repository.isScanned() ); - } - catch ( IndexFormatTooOldException e ) - { - // existing index with an old lucene format so we need to delete it!!! - // delete it first then recreate it. - log.warn( "the index of repository {} is too old we have to delete and recreate it", // - repository.getId() ); - org.apache.archiva.common.utils.FileUtils.deleteDirectory( indexDirectory ); - context = indexer.addIndexingContext( repository.getId(), repository.getId(), repositoryDirectory.toFile(), - indexDirectory.toFile(), - repositoryDirectory.toUri().toURL().toExternalForm(), - indexDirectory.toUri().toURL().toString(), indexCreators ); - - context.setSearchable( repository.isScanned() ); - } - } - return context; - } - catch ( IOException| UnsupportedExistingLuceneIndexException e ) - { - throw new RepositoryAdminException( e.getMessage(), e ); - } - } public Boolean scanRepository( String repositoryId, boolean fullScan ) { @@ -799,25 +659,6 @@ public class DefaultManagedRepositoryAdmin this.repositoryTaskScheduler = repositoryTaskScheduler; } - public NexusIndexer getIndexer() - { - return indexer; - } - - public void setIndexer( NexusIndexer indexer ) - { - this.indexer = indexer; - } - - public List<? extends IndexCreator> getIndexCreators() - { - return indexCreators; - } - - public void setIndexCreators( List<? extends IndexCreator> indexCreators ) - { - this.indexCreators = indexCreators; - } public RepositoryRegistry getRepositoryRegistry( ) {
http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/proxyconnector/DefaultProxyConnectorAdmin.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/proxyconnector/DefaultProxyConnectorAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/proxyconnector/DefaultProxyConnectorAdmin.java index fbf2048..94ace55 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/proxyconnector/DefaultProxyConnectorAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/proxyconnector/DefaultProxyConnectorAdmin.java @@ -30,6 +30,7 @@ import org.apache.archiva.configuration.Configuration; import org.apache.archiva.configuration.ProxyConnectorConfiguration; import org.apache.archiva.configuration.functors.ProxyConnectorSelectionPredicate; import org.apache.archiva.metadata.model.facets.AuditEvent; +import org.apache.archiva.repository.RepositoryRegistry; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Service; @@ -53,10 +54,7 @@ public class DefaultProxyConnectorAdmin { @Inject - private ManagedRepositoryAdmin managedRepositoryAdmin; - - @Inject - private RemoteRepositoryAdmin remoteRepositoryAdmin; + RepositoryRegistry repositoryRegistry; @Override public List<ProxyConnector> getProxyConnectors() @@ -230,13 +228,13 @@ public class DefaultProxyConnectorAdmin throws RepositoryAdminException { // validate source a Managed target a Remote - if ( managedRepositoryAdmin.getManagedRepository( proxyConnector.getSourceRepoId() ) == null ) + if ( repositoryRegistry.getManagedRepository( proxyConnector.getSourceRepoId() ) == null ) { throw new RepositoryAdminException( "non valid ProxyConnector sourceRepo with id " + proxyConnector.getSourceRepoId() + " is not a ManagedRepository" ); } - if ( remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() ) == null ) + if ( repositoryRegistry.getRemoteRepository( proxyConnector.getTargetRepoId() ) == null ) { throw new RepositoryAdminException( "non valid ProxyConnector sourceRepo with id " + proxyConnector.getTargetRepoId() http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/remote/DefaultRemoteRepositoryAdmin.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/remote/DefaultRemoteRepositoryAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/remote/DefaultRemoteRepositoryAdmin.java index 19b540a..3f8c58b 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/remote/DefaultRemoteRepositoryAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/remote/DefaultRemoteRepositoryAdmin.java @@ -26,6 +26,7 @@ import org.apache.archiva.configuration.Configuration; import org.apache.archiva.configuration.ProxyConnectorConfiguration; import org.apache.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.archiva.configuration.RepositoryCheckPath; +import org.apache.archiva.indexer.UnsupportedBaseContextException; import org.apache.archiva.metadata.model.facets.AuditEvent; import org.apache.archiva.repository.RemoteRepository; import org.apache.archiva.repository.PasswordCredentials; @@ -307,7 +308,9 @@ public class DefaultRemoteRepositoryAdmin { try { - String appServerBase = getRegistry().getString( "appserver.base" ); + RemoteRepository repo = repositoryRegistry.getRemoteRepository(remoteRepository.getId()); + return repo.getIndexingContext().getBaseContext(IndexingContext.class); + /*String appServerBase = getRegistry().getString( "appserver.base" ); String contextKey = "remote-" + remoteRepository.getId(); IndexingContext indexingContext = indexer.getIndexingContexts().get( contextKey ); @@ -359,11 +362,9 @@ public class DefaultRemoteRepositoryAdmin remoteRepository.getUrl(), calculateIndexRemoteUrl( remoteRepository ), indexCreators ); - } - } - catch ( IOException | UnsupportedExistingLuceneIndexException e ) - { - throw new RepositoryAdminException( e.getMessage(), e ); + }*/ + } catch (UnsupportedBaseContextException e) { + throw new RepositoryAdminException( e.getMessage(), e); } } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/ArchivaIndexManagerMock.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/ArchivaIndexManagerMock.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/ArchivaIndexManagerMock.java new file mode 100644 index 0000000..049f4a7 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/ArchivaIndexManagerMock.java @@ -0,0 +1,777 @@ +package org.apache.archiva.admin.mock; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.archiva.admin.model.RepositoryAdminException; +import org.apache.archiva.admin.model.beans.NetworkProxy; +import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin; +import org.apache.archiva.common.utils.FileUtils; +import org.apache.archiva.common.utils.PathUtil; +import org.apache.archiva.configuration.ArchivaConfiguration; +import org.apache.archiva.indexer.*; +import org.apache.archiva.proxy.common.WagonFactory; +import org.apache.archiva.proxy.common.WagonFactoryException; +import org.apache.archiva.proxy.common.WagonFactoryRequest; +import org.apache.archiva.repository.*; +import org.apache.archiva.repository.features.IndexCreationFeature; +import org.apache.archiva.repository.features.RemoteIndexFeature; +import org.apache.commons.lang.StringUtils; +import org.apache.maven.index.*; +import org.apache.maven.index.context.IndexCreator; +import org.apache.maven.index.context.IndexingContext; +import org.apache.maven.index.packer.IndexPacker; +import org.apache.maven.index.packer.IndexPackingRequest; +import org.apache.maven.index.updater.IndexUpdateRequest; +import org.apache.maven.index.updater.ResourceFetcher; +import org.apache.maven.index_shaded.lucene.index.IndexFormatTooOldException; +import org.apache.maven.wagon.*; +import org.apache.maven.wagon.authentication.AuthenticationException; +import org.apache.maven.wagon.authentication.AuthenticationInfo; +import org.apache.maven.wagon.authorization.AuthorizationException; +import org.apache.maven.wagon.events.TransferEvent; +import org.apache.maven.wagon.events.TransferListener; +import org.apache.maven.wagon.proxy.ProxyInfo; +import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon; +import org.apache.maven.wagon.shared.http.HttpConfiguration; +import org.apache.maven.wagon.shared.http.HttpMethodConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.inject.Inject; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.stream.Collectors; + +@Service("archivaIndexManager#maven") +public class ArchivaIndexManagerMock implements ArchivaIndexManager { + + private static final Logger log = LoggerFactory.getLogger( ArchivaIndexManagerMock.class ); + + @Inject + private Indexer indexer; + + @Inject + private IndexerEngine indexerEngine; + + @Inject + private List<? extends IndexCreator> indexCreators; + + @Inject + private IndexPacker indexPacker; + + @Inject + private Scanner scanner; + + @Inject + private ArchivaConfiguration archivaConfiguration; + + @Inject + private WagonFactory wagonFactory; + + @Inject + private NetworkProxyAdmin networkProxyAdmin; + + + @Inject + private ArtifactContextProducer artifactContextProducer; + + private ConcurrentSkipListSet<Path> activeContexts = new ConcurrentSkipListSet<>( ); + + private static final int WAIT_TIME = 100; + private static final int MAX_WAIT = 10; + + + public static IndexingContext getMvnContext(ArchivaIndexingContext context ) throws UnsupportedBaseContextException + { + if ( !context.supports( IndexingContext.class ) ) + { + log.error( "The provided archiva index context does not support the maven IndexingContext" ); + throw new UnsupportedBaseContextException( "The context does not support the Maven IndexingContext" ); + } + return context.getBaseContext( IndexingContext.class ); + } + + private Path getIndexPath( ArchivaIndexingContext ctx ) + { + return PathUtil.getPathFromUri( ctx.getPath( ) ); + } + + @FunctionalInterface + interface IndexUpdateConsumer + { + + void accept( IndexingContext indexingContext ) throws IndexUpdateFailedException; + } + + /* + * This method is used to do some actions around the update execution code. And to make sure, that no other + * method is running on the same index. + */ + private void executeUpdateFunction( ArchivaIndexingContext context, IndexUpdateConsumer function ) throws IndexUpdateFailedException + { + IndexingContext indexingContext = null; + try + { + indexingContext = getMvnContext( context ); + } + catch ( UnsupportedBaseContextException e ) + { + throw new IndexUpdateFailedException( "Maven index is not supported by this context", e ); + } + final Path ctxPath = getIndexPath( context ); + int loop = MAX_WAIT; + boolean active = false; + while ( loop-- > 0 && !active ) + { + active = activeContexts.add( ctxPath ); + try + { + Thread.currentThread( ).sleep( WAIT_TIME ); + } + catch ( InterruptedException e ) + { + // Ignore this + } + } + if ( active ) + { + try + { + function.accept( indexingContext ); + } + finally + { + activeContexts.remove( ctxPath ); + } + } + else + { + throw new IndexUpdateFailedException( "Timeout while waiting for index release on context " + context.getId( ) ); + } + } + + @Override + public void pack( final ArchivaIndexingContext context ) throws IndexUpdateFailedException + { + executeUpdateFunction( context, indexingContext -> { + try + { + IndexPackingRequest request = new IndexPackingRequest( indexingContext, + indexingContext.acquireIndexSearcher( ).getIndexReader( ), + indexingContext.getIndexDirectoryFile( ) ); + indexPacker.packIndex( request ); + indexingContext.updateTimestamp( true ); + } + catch ( IOException e ) + { + log.error( "IOException while packing index of context " + context.getId( ) + ( StringUtils.isNotEmpty( e.getMessage( ) ) ? ": " + e.getMessage( ) : "" ) ); + throw new IndexUpdateFailedException( "IOException during update of " + context.getId( ), e ); + } + } + ); + + } + + @Override + public void scan(final ArchivaIndexingContext context) throws IndexUpdateFailedException + { + executeUpdateFunction( context, indexingContext -> { + DefaultScannerListener listener = new DefaultScannerListener( indexingContext, indexerEngine, true, null ); + ScanningRequest request = new ScanningRequest( indexingContext, listener ); + ScanningResult result = scanner.scan( request ); + if ( result.hasExceptions( ) ) + { + log.error( "Exceptions occured during index scan of " + context.getId( ) ); + result.getExceptions( ).stream( ).map( e -> e.getMessage( ) ).distinct( ).limit( 5 ).forEach( + s -> log.error( "Message: " + s ) + ); + } + + } ); + } + + @Override + public void update(final ArchivaIndexingContext context, final boolean fullUpdate) throws IndexUpdateFailedException + { + log.info( "start download remote index for remote repository {}", context.getRepository( ).getId( ) ); + URI remoteUpdateUri; + if ( !( context.getRepository( ) instanceof RemoteRepository) || !(context.getRepository().supportsFeature(RemoteIndexFeature.class)) ) + { + throw new IndexUpdateFailedException( "The context is not associated to a remote repository with remote index " + context.getId( ) ); + } else { + RemoteIndexFeature rif = context.getRepository().getFeature(RemoteIndexFeature.class).get(); + remoteUpdateUri = context.getRepository().getLocation().resolve(rif.getIndexUri()); + } + final RemoteRepository remoteRepository = (RemoteRepository) context.getRepository( ); + + executeUpdateFunction( context, + indexingContext -> { + try + { + // create a temp directory to download files + Path tempIndexDirectory = Paths.get( indexingContext.getIndexDirectoryFile( ).getParent( ), ".tmpIndex" ); + Path indexCacheDirectory = Paths.get( indexingContext.getIndexDirectoryFile( ).getParent( ), ".indexCache" ); + Files.createDirectories( indexCacheDirectory ); + if ( Files.exists( tempIndexDirectory ) ) + { + org.apache.archiva.common.utils.FileUtils.deleteDirectory( tempIndexDirectory ); + } + Files.createDirectories( tempIndexDirectory ); + tempIndexDirectory.toFile( ).deleteOnExit( ); + String baseIndexUrl = indexingContext.getIndexUpdateUrl( ); + + String wagonProtocol = remoteUpdateUri.toURL( ).getProtocol( ); + + NetworkProxy networkProxy = null; + if ( remoteRepository.supportsFeature( RemoteIndexFeature.class ) ) + { + RemoteIndexFeature rif = remoteRepository.getFeature( RemoteIndexFeature.class ).get( ); + if ( StringUtils.isNotBlank( rif.getProxyId( ) ) ) + { + try + { + networkProxy = networkProxyAdmin.getNetworkProxy( rif.getProxyId( ) ); + } + catch ( RepositoryAdminException e ) + { + log.error( "Error occured while retrieving proxy {}", e.getMessage( ) ); + } + if ( networkProxy == null ) + { + log.warn( + "your remote repository is configured to download remote index trought a proxy we cannot find id:{}", + rif.getProxyId( ) ); + } + } + + final StreamWagon wagon = (StreamWagon) wagonFactory.getWagon( + new WagonFactoryRequest( wagonProtocol, remoteRepository.getExtraHeaders( ) ).networkProxy( + networkProxy ) + ); + int readTimeout = (int) rif.getDownloadTimeout( ).toMillis( ) * 1000; + wagon.setReadTimeout( readTimeout ); + wagon.setTimeout( (int) remoteRepository.getTimeout( ).toMillis( ) * 1000 ); + + if ( wagon instanceof AbstractHttpClientWagon) + { + HttpConfiguration httpConfiguration = new HttpConfiguration( ); + HttpMethodConfiguration httpMethodConfiguration = new HttpMethodConfiguration( ); + httpMethodConfiguration.setUsePreemptive( true ); + httpMethodConfiguration.setReadTimeout( readTimeout ); + httpConfiguration.setGet( httpMethodConfiguration ); + AbstractHttpClientWagon.class.cast( wagon ).setHttpConfiguration( httpConfiguration ); + } + + wagon.addTransferListener( new DownloadListener( ) ); + ProxyInfo proxyInfo = null; + if ( networkProxy != null ) + { + proxyInfo = new ProxyInfo( ); + proxyInfo.setType( networkProxy.getProtocol( ) ); + proxyInfo.setHost( networkProxy.getHost( ) ); + proxyInfo.setPort( networkProxy.getPort( ) ); + proxyInfo.setUserName( networkProxy.getUsername( ) ); + proxyInfo.setPassword( networkProxy.getPassword( ) ); + } + AuthenticationInfo authenticationInfo = null; + if ( remoteRepository.getLoginCredentials( ) != null && ( remoteRepository.getLoginCredentials( ) instanceof PasswordCredentials) ) + { + PasswordCredentials creds = (PasswordCredentials) remoteRepository.getLoginCredentials( ); + authenticationInfo = new AuthenticationInfo( ); + authenticationInfo.setUserName( creds.getUsername( ) ); + authenticationInfo.setPassword( new String( creds.getPassword( ) ) ); + } + wagon.connect( new org.apache.maven.wagon.repository.Repository( remoteRepository.getId( ), baseIndexUrl ), authenticationInfo, + proxyInfo ); + + Path indexDirectory = indexingContext.getIndexDirectoryFile( ).toPath( ); + if ( !Files.exists( indexDirectory ) ) + { + Files.createDirectories( indexDirectory ); + } + + ResourceFetcher resourceFetcher = + new WagonResourceFetcher( log, tempIndexDirectory, wagon, remoteRepository ); + IndexUpdateRequest request = new IndexUpdateRequest( indexingContext, resourceFetcher ); + request.setForceFullUpdate( fullUpdate ); + request.setLocalIndexCacheDir( indexCacheDirectory.toFile( ) ); + + // indexUpdater.fetchAndUpdateIndex( request ); + + indexingContext.updateTimestamp( true ); + } + + } + catch ( AuthenticationException e ) + { + log.error( "Could not login to the remote proxy for updating index of {}", remoteRepository.getId( ), e ); + throw new IndexUpdateFailedException( "Login in to proxy failed while updating remote repository " + remoteRepository.getId( ), e ); + } + catch ( ConnectionException e ) + { + log.error( "Connection error during index update for remote repository {}", remoteRepository.getId( ), e ); + throw new IndexUpdateFailedException( "Connection error during index update for remote repository " + remoteRepository.getId( ), e ); + } + catch ( MalformedURLException e ) + { + log.error( "URL for remote index update of remote repository {} is not correct {}", remoteRepository.getId( ), remoteUpdateUri, e ); + throw new IndexUpdateFailedException( "URL for remote index update of repository is not correct " + remoteUpdateUri, e ); + } + catch ( IOException e ) + { + log.error( "IOException during index update of remote repository {}: {}", remoteRepository.getId( ), e.getMessage( ), e ); + throw new IndexUpdateFailedException( "IOException during index update of remote repository " + remoteRepository.getId( ) + + ( StringUtils.isNotEmpty( e.getMessage( ) ) ? ": " + e.getMessage( ) : "" ), e ); + } + catch ( WagonFactoryException e ) + { + log.error( "Wagon for remote index download of {} could not be created: {}", remoteRepository.getId( ), e.getMessage( ), e ); + throw new IndexUpdateFailedException( "Error while updating the remote index of " + remoteRepository.getId( ), e ); + } + } ); + + } + + @Override + public void addArtifactsToIndex( final ArchivaIndexingContext context, final Collection<URI> artifactReference ) throws IndexUpdateFailedException + { + final URI ctxUri = context.getPath(); + executeUpdateFunction(context, indexingContext -> { + Collection<ArtifactContext> artifacts = artifactReference.stream().map(r -> artifactContextProducer.getArtifactContext(indexingContext, Paths.get(ctxUri.resolve(r)).toFile())).collect(Collectors.toList()); + try { + indexer.addArtifactsToIndex(artifacts, indexingContext); + } catch (IOException e) { + log.error("IOException while adding artifact {}", e.getMessage(), e); + throw new IndexUpdateFailedException("Error occured while adding artifact to index of "+context.getId() + + (StringUtils.isNotEmpty(e.getMessage()) ? ": "+e.getMessage() : "")); + } + }); + } + + @Override + public void removeArtifactsFromIndex( ArchivaIndexingContext context, Collection<URI> artifactReference ) throws IndexUpdateFailedException + { + final URI ctxUri = context.getPath(); + executeUpdateFunction(context, indexingContext -> { + Collection<ArtifactContext> artifacts = artifactReference.stream().map(r -> artifactContextProducer.getArtifactContext(indexingContext, Paths.get(ctxUri.resolve(r)).toFile())).collect(Collectors.toList()); + try { + indexer.deleteArtifactsFromIndex(artifacts, indexingContext); + } catch (IOException e) { + log.error("IOException while removing artifact {}", e.getMessage(), e); + throw new IndexUpdateFailedException("Error occured while removing artifact from index of "+context.getId() + + (StringUtils.isNotEmpty(e.getMessage()) ? ": "+e.getMessage() : "")); + } + }); + + } + + @Override + public boolean supportsRepository( RepositoryType type ) + { + return type == RepositoryType.MAVEN; + } + + @Override + public ArchivaIndexingContext createContext( Repository repository ) throws IndexCreationFailedException + { + log.debug("Creating context for repo {}, type: {}", repository.getId(), repository.getType()); + if ( repository.getType( ) != RepositoryType.MAVEN ) + { + throw new UnsupportedRepositoryTypeException( repository.getType( ) ); + } + IndexingContext mvnCtx = null; + try + { + if ( repository instanceof RemoteRepository ) + { + mvnCtx = createRemoteContext( (RemoteRepository) repository ); + } + else if ( repository instanceof ManagedRepository ) + { + mvnCtx = createManagedContext( (ManagedRepository) repository ); + } + } + catch ( IOException e ) + { + log.error( "IOException during context creation " + e.getMessage( ), e ); + throw new IndexCreationFailedException( "Could not create index context for repository " + repository.getId( ) + + ( StringUtils.isNotEmpty( e.getMessage( ) ) ? ": " + e.getMessage( ) : "" ), e ); + } + MavenIndexContextMock context = new MavenIndexContextMock( repository, mvnCtx ); + + return context; + } + + @Override + public ArchivaIndexingContext reset(ArchivaIndexingContext context) throws IndexUpdateFailedException { + ArchivaIndexingContext ctx; + executeUpdateFunction(context, indexingContext -> { + try { + indexingContext.close(true); + } catch (IOException e) { + log.warn("Index close failed"); + } + try { + FileUtils.deleteDirectory(Paths.get(context.getPath())); + } catch (IOException e) { + throw new IndexUpdateFailedException("Could not delete index files"); + } + }); + try { + Repository repo = context.getRepository(); + ctx = createContext(context.getRepository()); + if (repo instanceof EditableRepository) { + ((EditableRepository)repo).setIndexingContext(ctx); + } + } catch (IndexCreationFailedException e) { + throw new IndexUpdateFailedException("Could not create index"); + } + return ctx; + } + + @Override + public ArchivaIndexingContext move(ArchivaIndexingContext context, Repository repo) throws IndexCreationFailedException { + if (context==null) { + return null; + } + if (context.supports(IndexingContext.class)) { + try { + Path newPath = getIndexPath(repo); + IndexingContext ctx = context.getBaseContext(IndexingContext.class); + Path oldPath = ctx.getIndexDirectoryFile().toPath(); + if (oldPath.equals(newPath)) { + // Nothing to do, if path does not change + return context; + } + if (!Files.exists(oldPath)) { + return createContext(repo); + } else if (context.isEmpty()) { + context.close(); + return createContext(repo); + } else { + context.close(false); + Files.move(oldPath, newPath); + return createContext(repo); + } + } catch (IOException e) { + log.error("IOException while moving index directory {}", e.getMessage(), e); + throw new IndexCreationFailedException("Could not recreated the index.", e); + } catch (UnsupportedBaseContextException e) { + throw new IndexCreationFailedException("The given context, is not a maven context."); + } + } else { + throw new IndexCreationFailedException("Bad context type. This is not a maven context."); + } + } + + private Path getIndexPath(Repository repo) throws IOException { + IndexCreationFeature icf = repo.getFeature(IndexCreationFeature.class).get(); + Path repoDir = repo.getLocalPath(); + URI indexDir = icf.getIndexPath(); + Path indexDirectory = null; + if ( ! StringUtils.isEmpty(indexDir.toString( ) ) ) + { + + indexDirectory = PathUtil.getPathFromUri( indexDir ); + // not absolute so create it in repository directory + if ( !indexDirectory.isAbsolute( ) ) + { + indexDirectory = repoDir.resolve( indexDirectory ); + } + } + else + { + indexDirectory = repoDir.resolve( ".index" ); + } + + if ( !Files.exists( indexDirectory ) ) + { + Files.createDirectories( indexDirectory ); + } + return indexDirectory; + } + + private IndexingContext createRemoteContext(RemoteRepository remoteRepository ) throws IOException + { + Path appServerBase = archivaConfiguration.getAppServerBaseDir( ); + + String contextKey = "remote-" + remoteRepository.getId( ); + + + // create remote repository path + Path repoDir = remoteRepository.getLocalPath(); + if ( !Files.exists( repoDir ) ) + { + Files.createDirectories( repoDir ); + } + + Path indexDirectory = null; + + // is there configured indexDirectory ? + if ( remoteRepository.supportsFeature( RemoteIndexFeature.class ) ) + { + RemoteIndexFeature rif = remoteRepository.getFeature( RemoteIndexFeature.class ).get( ); + indexDirectory = getIndexPath(remoteRepository); + String remoteIndexUrl = calculateIndexRemoteUrl( remoteRepository.getLocation( ), rif ); + try + { + + return getIndexingContext( remoteRepository, contextKey, repoDir, indexDirectory, remoteIndexUrl ); + } + catch ( IndexFormatTooOldException e ) + { + // existing index with an old lucene format so we need to delete it!!! + // delete it first then recreate it. + log.warn( "the index of repository {} is too old we have to delete and recreate it", // + remoteRepository.getId( ) ); + org.apache.archiva.common.utils.FileUtils.deleteDirectory( indexDirectory ); + return getIndexingContext( remoteRepository, contextKey, repoDir, indexDirectory, remoteIndexUrl ); + + } + } + else + { + throw new IOException( "No remote index defined" ); + } + } + + private IndexingContext getIndexingContext( Repository repository, String contextKey, Path repoDir, Path indexDirectory, String indexUrl ) throws IOException + { + return indexer.createIndexingContext( contextKey, repository.getId( ), repoDir.toFile( ), indexDirectory.toFile( ), + repository.getLocation( ) == null ? null : repository.getLocation( ).toString( ), + indexUrl, + true, false, + indexCreators ); + } + + private IndexingContext createManagedContext( ManagedRepository repository ) throws IOException + { + + IndexingContext context; + // take care first about repository location as can be relative + Path repositoryDirectory = repository.getLocalPath(); + + if ( !Files.exists( repositoryDirectory ) ) + { + try + { + Files.createDirectories( repositoryDirectory ); + } + catch ( IOException e ) + { + log.error( "Could not create directory {}", repositoryDirectory ); + } + } + + Path indexDirectory = null; + + if ( repository.supportsFeature( IndexCreationFeature.class ) ) + { + indexDirectory = getIndexPath(repository); + + String indexUrl = repositoryDirectory.toUri( ).toURL( ).toExternalForm( ); + try + { + context = getIndexingContext( repository, repository.getId( ), repositoryDirectory, indexDirectory, indexUrl ); + context.setSearchable( repository.isScanned( ) ); + } + catch ( IndexFormatTooOldException e ) + { + // existing index with an old lucene format so we need to delete it!!! + // delete it first then recreate it. + log.warn( "the index of repository {} is too old we have to delete and recreate it", // + repository.getId( ) ); + org.apache.archiva.common.utils.FileUtils.deleteDirectory( indexDirectory ); + context = getIndexingContext( repository, repository.getId( ), repositoryDirectory, indexDirectory, indexUrl ); + context.setSearchable( repository.isScanned( ) ); + } + return context; + } + else + { + throw new IOException( "No repository index defined" ); + } + } + + private String calculateIndexRemoteUrl( URI baseUri, RemoteIndexFeature rif ) + { + if ( rif.getIndexUri( ) == null ) + { + return baseUri.resolve( ".index" ).toString( ); + } + else + { + return baseUri.resolve( rif.getIndexUri( ) ).toString( ); + } + } + + private static final class DownloadListener + implements TransferListener + { + private Logger log = LoggerFactory.getLogger( getClass( ) ); + + private String resourceName; + + private long startTime; + + private int totalLength = 0; + + @Override + public void transferInitiated( TransferEvent transferEvent ) + { + startTime = System.currentTimeMillis( ); + resourceName = transferEvent.getResource( ).getName( ); + log.debug( "initiate transfer of {}", resourceName ); + } + + @Override + public void transferStarted( TransferEvent transferEvent ) + { + this.totalLength = 0; + resourceName = transferEvent.getResource( ).getName( ); + log.info( "start transfer of {}", transferEvent.getResource( ).getName( ) ); + } + + @Override + public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length ) + { + log.debug( "transfer of {} : {}/{}", transferEvent.getResource( ).getName( ), buffer.length, length ); + this.totalLength += length; + } + + @Override + public void transferCompleted( TransferEvent transferEvent ) + { + resourceName = transferEvent.getResource( ).getName( ); + long endTime = System.currentTimeMillis( ); + log.info( "end of transfer file {} {} kb: {}s", transferEvent.getResource( ).getName( ), + this.totalLength / 1024, ( endTime - startTime ) / 1000 ); + } + + @Override + public void transferError( TransferEvent transferEvent ) + { + log.info( "error of transfer file {}: {}", transferEvent.getResource( ).getName( ), + transferEvent.getException( ).getMessage( ), transferEvent.getException( ) ); + } + + @Override + public void debug( String message ) + { + log.debug( "transfer debug {}", message ); + } + } + + private static class WagonResourceFetcher + implements ResourceFetcher + { + + Logger log; + + Path tempIndexDirectory; + + Wagon wagon; + + RemoteRepository remoteRepository; + + private WagonResourceFetcher( Logger log, Path tempIndexDirectory, Wagon wagon, + RemoteRepository remoteRepository ) + { + this.log = log; + this.tempIndexDirectory = tempIndexDirectory; + this.wagon = wagon; + this.remoteRepository = remoteRepository; + } + + @Override + public void connect( String id, String url ) + throws IOException + { + //no op + } + + @Override + public void disconnect( ) + throws IOException + { + // no op + } + + @Override + public InputStream retrieve(String name ) + throws IOException, FileNotFoundException + { + try + { + log.info( "index update retrieve file, name:{}", name ); + Path file = tempIndexDirectory.resolve( name ); + Files.deleteIfExists( file ); + file.toFile( ).deleteOnExit( ); + wagon.get( addParameters( name, remoteRepository ), file.toFile( ) ); + return Files.newInputStream( file ); + } + catch ( AuthorizationException | TransferFailedException e ) + { + throw new IOException( e.getMessage( ), e ); + } + catch ( ResourceDoesNotExistException e ) + { + FileNotFoundException fnfe = new FileNotFoundException( e.getMessage( ) ); + fnfe.initCause( e ); + throw fnfe; + } + } + + // FIXME remove crappy copy/paste + protected String addParameters( String path, RemoteRepository remoteRepository ) + { + if ( remoteRepository.getExtraParameters( ).isEmpty( ) ) + { + return path; + } + + boolean question = false; + + StringBuilder res = new StringBuilder( path == null ? "" : path ); + + for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters( ).entrySet( ) ) + { + if ( !question ) + { + res.append( '?' ).append( entry.getKey( ) ).append( '=' ).append( entry.getValue( ) ); + } + } + + return res.toString( ); + } + + } +} http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MavenIndexContextMock.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MavenIndexContextMock.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MavenIndexContextMock.java new file mode 100644 index 0000000..1b6a54b --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MavenIndexContextMock.java @@ -0,0 +1,136 @@ +package org.apache.archiva.admin.mock; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.archiva.indexer.ArchivaIndexingContext; +import org.apache.archiva.repository.Repository; +import org.apache.maven.index.context.IndexingContext; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.sql.Date; +import java.time.ZonedDateTime; +import java.util.Set; + +/** + * Maven implementation of index context + */ +public class MavenIndexContextMock implements ArchivaIndexingContext { + + private IndexingContext delegate; + private Repository repository; + + MavenIndexContextMock(Repository repository, IndexingContext delegate) { + this.delegate = delegate; + this.repository = repository; + + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public Repository getRepository() { + return repository; + } + + @Override + public URI getPath() { + return delegate.getIndexDirectoryFile().toURI(); + } + + @Override + public boolean isEmpty() throws IOException { + return Files.list(delegate.getIndexDirectoryFile().toPath()).count()==0; + } + + @Override + public void commit() throws IOException { + delegate.commit(); + } + + @Override + public void rollback() throws IOException { + delegate.rollback(); + } + + @Override + public void optimize() throws IOException { + delegate.optimize(); + } + + @Override + public void close(boolean deleteFiles) throws IOException { + try { + delegate.close(deleteFiles); + } catch (NoSuchFileException e) { + // Ignore missing directory + } + } + + @Override + public void close() throws IOException { + try { + delegate.close(false); + } catch (NoSuchFileException e) { + // Ignore missing directory + } + } + + @Override + public void purge() throws IOException { + delegate.purge(); + } + + @Override + public boolean supports(Class<?> clazz) { + return IndexingContext.class.equals(clazz); + } + + @Override + public <T> T getBaseContext(Class<T> clazz) throws UnsupportedOperationException { + if (IndexingContext.class.equals(clazz)) { + return (T) delegate; + } else { + throw new UnsupportedOperationException("The class "+clazz+" is not supported by the maven indexer"); + } + } + + @Override + public Set<String> getGroups() throws IOException { + return delegate.getAllGroups(); + } + + @Override + public void updateTimestamp(boolean save) throws IOException { + delegate.updateTimestamp(save); + } + + @Override + public void updateTimestamp(boolean save, ZonedDateTime time) throws IOException { + delegate.updateTimestamp(save, Date.from(time.toInstant())); + } + + +} http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java index c586f23..ed6e286 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/group/RepositoryGroupAdminTest.java @@ -24,6 +24,8 @@ import org.apache.archiva.admin.model.beans.RepositoryGroup; import org.apache.archiva.admin.model.group.RepositoryGroupAdmin; import org.apache.archiva.admin.repository.AbstractRepositoryAdminTest; import org.apache.archiva.metadata.model.facets.AuditEvent; +import org.apache.archiva.repository.Repository; +import org.apache.archiva.repository.RepositoryRegistry; import org.junit.Test; import javax.inject.Inject; @@ -39,12 +41,23 @@ public class RepositoryGroupAdminTest @Inject RepositoryGroupAdmin repositoryGroupAdmin; + @Inject + RepositoryRegistry repositoryRegistry; + @Test public void addAndDeleteGroup() throws Exception { try { + Repository repo = repositoryRegistry.getRepository("test-new-one"); + if (repo!=null) { + repositoryRegistry.removeRepository(repo); + } + repo = repositoryRegistry.getRepository("test-new-two"); + if (repo!=null) { + repositoryRegistry.removeRepository(repo); + } ManagedRepository managedRepositoryOne = getTestManagedRepository( "test-new-one", Paths.get(APPSERVER_BASE_PATH,"test-new-one" ).toString()); @@ -55,8 +68,10 @@ public class RepositoryGroupAdminTest managedRepositoryAdmin.addManagedRepository( managedRepositoryTwo, false, getFakeAuditInformation() ); + RepositoryGroup repositoryGroup = new RepositoryGroup( "repo-group-one", Arrays.asList( "test-new-one", "test-new-two" ) ); + // repositoryGroupAdmin.deleteRepositoryGroup("repo-group-one", null); mockAuditListener.clearEvents(); @@ -84,8 +99,8 @@ public class RepositoryGroupAdminTest finally { mockAuditListener.clearEvents(); - managedRepositoryAdmin.deleteManagedRepository( "test-new-one", getFakeAuditInformation(), true ); - managedRepositoryAdmin.deleteManagedRepository( "test-new-two", getFakeAuditInformation(), true ); + repositoryRegistry.removeRepository(repositoryRegistry.getManagedRepository("test-new-one")); + repositoryRegistry.removeRepository(repositoryRegistry.getManagedRepository("test-new-two")); } } @@ -202,8 +217,7 @@ public class RepositoryGroupAdminTest finally { mockAuditListener.clearEvents(); - - managedRepositoryAdmin.deleteManagedRepository( "test-new-two", getFakeAuditInformation(), true ); + repositoryRegistry.removeRepository(repositoryRegistry.getRepository("test-new-two")); } } @@ -231,8 +245,8 @@ public class RepositoryGroupAdminTest finally { mockAuditListener.clearEvents(); - managedRepositoryAdmin.deleteManagedRepository( "test-new-one", getFakeAuditInformation(), true ); - managedRepositoryAdmin.deleteManagedRepository( "test-new-two", getFakeAuditInformation(), true ); + repositoryRegistry.removeRepository(repositoryRegistry.getRepository("test-new-one")); + repositoryRegistry.removeRepository(repositoryRegistry.getRepository("test-new-two")); } } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/default-archiva.xml ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/default-archiva.xml b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/default-archiva.xml index 7955798..36d467f 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/default-archiva.xml +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/default-archiva.xml @@ -53,6 +53,7 @@ <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> + <indexDir>.index</indexDir> </remoteRepository> </remoteRepositories> http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/ArchivaIndexManager.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/ArchivaIndexManager.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/ArchivaIndexManager.java index fb34eb2..63a8a92 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/ArchivaIndexManager.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/ArchivaIndexManager.java @@ -20,6 +20,7 @@ package org.apache.archiva.indexer; */ import org.apache.archiva.repository.Repository; +import org.apache.archiva.repository.RepositoryEventListener; import org.apache.archiva.repository.RepositoryType; import java.net.URI; @@ -75,4 +76,23 @@ public interface ArchivaIndexManager { * @return the index context */ ArchivaIndexingContext createContext(Repository repository) throws IndexCreationFailedException; + + /** + * Reinitializes the index. E.g. remove the files and create a new empty index. + * + * @param context + * @return the new created index + */ + ArchivaIndexingContext reset(ArchivaIndexingContext context) throws IndexUpdateFailedException; + + /** + * Moves the context to a new directory. It's up to the implementation, if a new context is created + * or the context is moved only. + * + * @param context The current context + * @param repo The repository + * @return The new context + * @throws IndexCreationFailedException + */ + ArchivaIndexingContext move(ArchivaIndexingContext context, Repository repo) throws IndexCreationFailedException; } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/GenericIndexManager.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/GenericIndexManager.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/GenericIndexManager.java index d0f8034..8d8072e 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/GenericIndexManager.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/indexer/GenericIndexManager.java @@ -20,6 +20,7 @@ package org.apache.archiva.indexer; */ import org.apache.archiva.repository.Repository; +import org.apache.archiva.repository.RepositoryEvent; import org.apache.archiva.repository.RepositoryType; import org.springframework.stereotype.Service; @@ -63,4 +64,15 @@ public class GenericIndexManager implements ArchivaIndexManager { public ArchivaIndexingContext createContext(Repository repository) { return null; } + + @Override + public ArchivaIndexingContext reset(ArchivaIndexingContext context) throws IndexUpdateFailedException { + return null; + } + + @Override + public ArchivaIndexingContext move(ArchivaIndexingContext context, Repository repo) throws IndexCreationFailedException { + return null; + } + } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/EditableRepository.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/EditableRepository.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/EditableRepository.java index b275492..7b7dd8f 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/EditableRepository.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/EditableRepository.java @@ -19,6 +19,8 @@ package org.apache.archiva.repository; * under the License. */ +import org.apache.archiva.indexer.ArchivaIndexingContext; + import java.net.URI; import java.util.Locale; @@ -120,5 +122,11 @@ public interface EditableRepository extends Repository */ void setLayout(String layout); + /** + * Sets the indexing context reference. + * @param context + */ + void setIndexingContext(ArchivaIndexingContext context); + } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java index fae5745..78a330a 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/Repository.java @@ -22,6 +22,7 @@ package org.apache.archiva.repository; import org.apache.archiva.indexer.ArchivaIndexingContext; import org.apache.archiva.repository.features.RepositoryFeature; +import java.io.IOException; import java.net.URI; import java.nio.file.Path; import java.util.List; @@ -34,7 +35,7 @@ import java.util.Set; * * Created by Martin Stockhammer on 21.09.17. */ -public interface Repository { +public interface Repository extends RepositoryEventHandler { /** * Return the identifier of the repository. Repository identifier should be unique at least @@ -175,4 +176,10 @@ public interface Repository { * @throws UnsupportedOperationException */ ArchivaIndexingContext getIndexingContext(); + + /** + * Closes all resources that are opened by this repository. + */ + void close(); + } http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java new file mode 100644 index 0000000..d8bdf95 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEvent.java @@ -0,0 +1,69 @@ +package org.apache.archiva.repository; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.time.LocalDateTime; + +/** + * Repository event. Repository events are used for providing information about repository changes. + * + * @param <T> + */ +public class RepositoryEvent<T> { + + final EventType type; + final String repo; + final T value; + final T oldValue; + final LocalDateTime instant; + + public RepositoryEvent(EventType type, String repo, T oldValue, T value) { + this.type = type; + this.repo = repo; + this.value = value; + this.oldValue = oldValue; + this.instant = LocalDateTime.now(); + } + + public interface EventType { + String name(); + } + + + EventType getType() { + return type; + }; + + String getRepositoryId() { + return repo; + }; + + T getValue() { + return value; + } + + T getOldValue() { + return oldValue; + } + + public LocalDateTime getInstant() { + return instant; + } +} http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java new file mode 100644 index 0000000..7432627 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventHandler.java @@ -0,0 +1,32 @@ +package org.apache.archiva.repository; + +/* + * 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. + */ + +/** + * Implementations of this interface are able to handle repository event listeners + */ +public interface RepositoryEventHandler { + + void addListener(RepositoryEventListener listener); + + void removeListener(RepositoryEventListener listener); + + void clearListeners(); +} http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java new file mode 100644 index 0000000..0234f34 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryEventListener.java @@ -0,0 +1,28 @@ +package org.apache.archiva.repository; + +/* + * 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. + */ + +/** + * Listener that accepts repository events. + */ +public interface RepositoryEventListener { + + <T> void raise(RepositoryEvent<T> event); +} http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java index a501514..4492b01 100644 --- a/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java +++ b/archiva-modules/archiva-base/archiva-repository-api/src/main/java/org/apache/archiva/repository/RepositoryProvider.java @@ -37,7 +37,7 @@ import java.util.Set; * * */ -public interface RepositoryProvider +public interface RepositoryProvider extends RepositoryEventListener { /** http://git-wip-us.apache.org/repos/asf/archiva/blob/c544376a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java ---------------------------------------------------------------------- diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java index c90c5bf..d63007a 100644 --- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java +++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/AbstractRepository.java @@ -26,26 +26,28 @@ import com.cronutils.parser.CronParser; import org.apache.archiva.common.utils.PathUtil; import org.apache.archiva.indexer.ArchivaIndexingContext; import org.apache.archiva.repository.features.RepositoryFeature; +import org.apache.archiva.repository.features.StagingRepositoryFeature; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Implementation of a repository with the necessary fields for a bare repository. * No features are provided. Capabilities and features must be implemented by concrete classes. * */ -public abstract class AbstractRepository implements EditableRepository +public abstract class AbstractRepository implements EditableRepository, RepositoryEventListener { + + Logger log = LoggerFactory.getLogger(AbstractRepository.class); + private final RepositoryType type; private final String id; private Map<Locale, String> names = new HashMap<>( ); @@ -60,10 +62,13 @@ public abstract class AbstractRepository implements EditableRepository String schedulingDefinition = "0 0 02 * * ?"; private String layout = "default"; public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ); + private List<RepositoryEventListener> listeners = new ArrayList<>(); + Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( ); protected Path repositoryBase; + private ArchivaIndexingContext indexingContext; public AbstractRepository(RepositoryType type, String id, String name, Path repositoryBase) { this.id = id; @@ -129,7 +134,7 @@ public abstract class AbstractRepository implements EditableRepository @Override public Path getLocalPath() { Path localPath; - if (getLocation().getScheme()=="file" || StringUtils.isEmpty(getLocation().getScheme())) { + if (StringUtils.isEmpty(getLocation().getScheme()) || "file".equals(getLocation().getScheme()) ) { localPath = PathUtil.getPathFromUri(getLocation()); if (localPath.isAbsolute()) { return localPath; @@ -259,8 +264,53 @@ public abstract class AbstractRepository implements EditableRepository } @Override + public void setIndexingContext(ArchivaIndexingContext context) { + this.indexingContext = context; + } + + @Override public ArchivaIndexingContext getIndexingContext() { - // TODO: Implement - return null; + return indexingContext; + } + + @Override + public void close() { + ArchivaIndexingContext ctx = getIndexingContext(); + if (ctx!=null) { + try { + ctx.close(); + } catch (IOException e) { + log.warn("Error during index context close.",e); + } + } + if (supportsFeature(StagingRepositoryFeature.class)) { + StagingRepositoryFeature sf = getFeature(StagingRepositoryFeature.class).get(); + if (sf.getStagingRepository()!=null) { + sf.getStagingRepository().close(); + } + } + clearListeners(); } + + @Override + public <T> void raise(RepositoryEvent<T> event) { + for(RepositoryEventListener listener : listeners) { + listener.raise(event); + } + } + + public void addListener(RepositoryEventListener listener) { + if (!this.listeners.contains(listener)) { + this.listeners.add(listener); + } + } + + public void removeListener(RepositoryEventListener listener) { + this.removeListener(listener); + } + + public void clearListeners() { + this.listeners.clear(); + } + }
