diff options
author | Martin Stockhammer <martin_s@apache.org> | 2021-01-27 20:16:26 +0100 |
---|---|---|
committer | Martin Stockhammer <martin_s@apache.org> | 2021-01-27 20:16:26 +0100 |
commit | b32d75a85b4f5805d6d251ea2237f838087aa2bf (patch) | |
tree | 162037148959d4bddb68ef7a7aa22ea89a69759f /archiva-modules | |
parent | 7eef53d7c5145de75ecb6734169bacb53b02f5a0 (diff) | |
download | archiva-b32d75a85b4f5805d6d251ea2237f838087aa2bf.tar.gz archiva-b32d75a85b4f5805d6d251ea2237f838087aa2bf.zip |
Adding task admin implementation
Diffstat (limited to 'archiva-modules')
26 files changed, 1420 insertions, 108 deletions
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/AbstractArtifactConsumerTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/AbstractArtifactConsumerTest.java index d6b116e3a..0ff779ffe 100644 --- a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/AbstractArtifactConsumerTest.java +++ b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/AbstractArtifactConsumerTest.java @@ -25,8 +25,10 @@ import org.apache.archiva.configuration.FileType; import org.apache.archiva.configuration.FileTypes; import org.apache.archiva.consumers.KnownRepositoryContentConsumer; import org.apache.archiva.consumers.functors.ConsumerWantsFilePredicate; +import org.apache.archiva.repository.base.ArchivaRepositoryRegistry; import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner; import org.apache.commons.lang3.StringUtils; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,8 +39,7 @@ import javax.inject.Inject; import java.nio.file.Path; import java.nio.file.Paths; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.*; @RunWith( ArchivaSpringJUnit4ClassRunner.class ) @ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath:/spring-context.xml" } ) @@ -54,6 +55,8 @@ public abstract class AbstractArtifactConsumerTest @Inject ArchivaConfiguration archivaConfiguration; + ArchivaRepositoryRegistry repositoryRegistry; + @Before public void setUp() @@ -68,6 +71,14 @@ public abstract class AbstractArtifactConsumerTest archivaConfiguration.getConfiguration().getArchivaRuntimeConfiguration().addChecksumType("SHA256"); repoLocation = Paths.get( "target/test-" + getName() + "/test-repo" ); + + repositoryRegistry = applicationContext.getBean( "repositoryRegistry", ArchivaRepositoryRegistry.class ); + assertNotNull( repositoryRegistry ); + } + + @After + public void destroy() { + repositoryRegistry.destroy(); } diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java index cfcd19efe..2f906a586 100644 --- a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java +++ b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/java/org/apache/archiva/consumers/core/repository/AbstractRepositoryPurgeTest.java @@ -24,6 +24,8 @@ import org.apache.archiva.metadata.repository.MetadataRepository; import org.apache.archiva.metadata.repository.RepositorySession; import org.apache.archiva.metadata.repository.RepositorySessionFactory; import org.apache.archiva.repository.ManagedRepositoryContent; +import org.apache.archiva.repository.RepositoryRegistry; +import org.apache.archiva.repository.base.ArchivaRepositoryRegistry; import org.apache.archiva.repository.maven.metadata.storage.Maven2RepositoryPathTranslator; import org.apache.archiva.repository.base.BasicManagedRepository; import org.apache.archiva.repository.ReleaseScheme; @@ -53,8 +55,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; /** @@ -108,6 +109,8 @@ public abstract class AbstractRepositoryPurgeTest protected MetadataRepository metadataRepository; + protected ArchivaRepositoryRegistry repositoryRegistry; + @Inject protected ApplicationContext applicationContext; @@ -127,6 +130,8 @@ public abstract class AbstractRepositoryPurgeTest repositorySession = sessionControl.createMock( RepositorySession.class ); metadataRepository = mock( MetadataRepository.class ); sessionFactory = sessionFactoryControl.createMock( RepositorySessionFactory.class ); + repositoryRegistry = applicationContext.getBean( "repositoryRegistry", ArchivaRepositoryRegistry.class ); + assertNotNull( repositoryRegistry ); EasyMock.expect( repositorySession.getRepository() ).andStubReturn( metadataRepository ); EasyMock.expect( sessionFactory.createSession( ) ).andStubReturn( repositorySession ); @@ -138,6 +143,7 @@ public abstract class AbstractRepositoryPurgeTest { config = null; repo = null; + repositoryRegistry.destroy(); } diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/resources/spring-context-cleanup-released-snapshots.xml b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/resources/spring-context-cleanup-released-snapshots.xml index 2f646583c..ee3d8e022 100644 --- a/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/resources/spring-context-cleanup-released-snapshots.xml +++ b/archiva-modules/archiva-base/archiva-consumers/archiva-core-consumers/src/test/resources/spring-context-cleanup-released-snapshots.xml @@ -32,7 +32,7 @@ </bean> <alias name="archivaConfiguration#cleanup-released-snapshots" alias="archivaConfiguration"/> <alias name="archivaConfiguration#cleanup-released-snapshots" alias="archivaConfiguration#default"/> - <context:component-scan base-package="org.apache.archiva.configuration,org.apache.archiva.repository.content.maven2,org.apache.archiva.indexer.maven"/> + <context:component-scan base-package="org.apache.archiva.configuration,org.apache.archiva.repository.content.base,org.apache.archiva.indexer.maven"/> <alias name="repositoryContentFactory#cleanup-released-snapshots" alias="repositoryContentFactory#default" /> diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/ArchivaAdministration.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/ArchivaAdministration.java index 7037f4957..beda0b97a 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/ArchivaAdministration.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/ArchivaAdministration.java @@ -29,6 +29,7 @@ import org.apache.archiva.admin.model.beans.UiConfiguration; import java.util.List; /** + * Base administration interface for Archiva. Provides methods for managing archiva base tasks. * @author Olivier Lamy * @since 1.4-M1 */ diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/RepositoryTaskAdministration.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/RepositoryTaskAdministration.java new file mode 100644 index 000000000..0375f2e73 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/admin/RepositoryTaskAdministration.java @@ -0,0 +1,115 @@ +package org.apache.archiva.admin.model.admin; +/* + * 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.RepositoryTaskInfo; +import org.apache.archiva.admin.model.beans.ScanStatus; +import org.springframework.util.StopWatch; + +import java.util.List; + +/** + * Interface for managing repository scan tasks. + * + * @author Martin Stockhammer <martin_s@apache.org> + * @since 3.0 + */ +public interface RepositoryTaskAdministration +{ + /** + * Schedules a full repository scan for the given repository. Metadata and Index are updated. + * All files are scanned, even if they were not modified since the last scan. + * + * @param repositoryId the repository identifier + * @throws RepositoryAdminException if it was not possible to schedule the scan + */ + void scheduleFullScan( String repositoryId ) throws RepositoryAdminException; + + /** + * Schedules a scan that rebuilds the fulltext index of the repository. + * + * @param repositoryId the repository identifier + * @throws RepositoryAdminException if it was not possible to schedule the index scan + */ + void scheduleIndexFullScan( String repositoryId ) throws RepositoryAdminException; + + /** + * Schedules a scan that rebuilds the fulltext index of the repository. + * + * @param repositoryId the repository identifier + * @param relativePath the path to the file to add to the index + * @throws RepositoryAdminException if it was not possible to schedule the index scan + */ + void scheduleIndexScan( String repositoryId, String relativePath ) throws RepositoryAdminException; + + /** + * Schedules a scan that rebuilds metadata of the repository + * + * @param repositoryId the repository identifier + * @throws RepositoryAdminException if it was not possible to schedule the index scan + */ + void scheduleMetadataFullScan( String repositoryId ) throws RepositoryAdminException; + + /** + * Schedules a scan that rebuilds metadata of the repository but only for updated files. + * + * @param repositoryId the repository identifier + * @throws RepositoryAdminException if it was not possible to schedule the index scan + */ + void scheduleMetadataUpdateScan( String repositoryId ) throws RepositoryAdminException; + + /** + * Returns information about currently running scans for the given repository. + * + * @return the status information + * @param repositoryId the repository identifier + * @throws RepositoryAdminException if there was an error retrieving the scan status + */ + ScanStatus getCurrentScanStatus(String repositoryId) throws RepositoryAdminException; + + + /** + * Returns information about currently running scans for all repositories. + * + * @return the status information + * @throws RepositoryAdminException if there was an error retrieving the scan status + */ + ScanStatus getCurrentScanStatus() throws RepositoryAdminException; + + /** + * Cancels the tasks either running or queued for the given repository. + * @param repositoryId the repository identifier + * @return a list of canceled tasks. + */ + List<RepositoryTaskInfo> cancelTasks(String repositoryId) throws RepositoryAdminException; + + /** + * Cancels the metadata scan tasks either running or queued for the given repository. + * @param repositoryId the repository identifier + * @return a list of canceled tasks. + */ + List<RepositoryTaskInfo> cancelScanTasks(String repositoryId) throws RepositoryAdminException; + + /** + * Cancels the indexing tasks either running or queued for the given repository. + * @param repositoryId the repository identifier + * @return a list of canceled tasks. + */ + List<RepositoryTaskInfo> cancelIndexTasks(String repositoryId) throws RepositoryAdminException; +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/IndexingTask.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/IndexingTask.java new file mode 100644 index 000000000..8b39c201c --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/IndexingTask.java @@ -0,0 +1,87 @@ +package org.apache.archiva.admin.model.beans; +/* + * 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.io.Serializable; + +/** + * Information about index update tasks running on a repository. + * + * @author Martin Stockhammer <martin_s@apache.org> + */ +public class IndexingTask extends RepositoryTaskInfo implements Serializable +{ + private static final long serialVersionUID = -1947200162602613310L; + /** + * <code>true</code>, if this task is just updating the existing index. + */ + private boolean updateOnly; + + public boolean isUpdateOnly( ) + { + return updateOnly; + } + + public void setUpdateOnly( boolean updateOnly ) + { + this.updateOnly = updateOnly; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) return true; + if ( o == null || getClass( ) != o.getClass( ) ) return false; + + IndexingTask that = (IndexingTask) o; + + if ( isFullScan( ) != that.fullScan ) return false; + if ( updateOnly != that.updateOnly ) return false; + if ( isRunning( ) != that.isRunning( ) ) return false; + if ( getMaxExecutionTimeMs( ) != that.getMaxExecutionTimeMs( ) ) return false; + if ( !getRepositoryId( ).equals( that.getRepositoryId( ) ) ) return false; + return getResource( ).equals( that.getResource( ) ); + } + + @Override + public int hashCode( ) + { + int result = getRepositoryId( ).hashCode( ); + result = 31 * result + ( isFullScan( ) ? 1 : 0 ); + result = 31 * result + ( updateOnly ? 1 : 0 ); + result = 31 * result + getResource( ).hashCode( ); + result = 31 * result + ( isRunning( ) ? 1 : 0 ); + result = 31 * result + (int) ( getMaxExecutionTimeMs( ) ^ ( getMaxExecutionTimeMs( ) >>> 32 ) ); + return result; + } + + @Override + public String toString( ) + { + final StringBuilder sb = new StringBuilder( "IndexingTask{" ); + sb.append( "repositoryId='" ).append( getRepositoryId( ) ).append( '\'' ); + sb.append( ", fullRepository=" ).append( isFullScan( ) ); + sb.append( ", updateOnly=" ).append( updateOnly ); + sb.append( ", resource='" ).append( getResource( ) ).append( '\'' ); + sb.append( ", running=" ).append( isRunning( ) ); + sb.append( ", maxExecutionTimeMs=" ).append( getMaxExecutionTimeMs( ) ); + sb.append( '}' ); + return sb.toString( ); + } + +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/MetadataScanTask.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/MetadataScanTask.java new file mode 100644 index 000000000..02ab7ee8c --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/MetadataScanTask.java @@ -0,0 +1,84 @@ +package org.apache.archiva.admin.model.beans; +/* + * 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.io.Serializable; + +/** + * @author Martin Stockhammer <martin_s@apache.org> + */ +public class MetadataScanTask extends RepositoryTaskInfo implements Serializable +{ + private static final long serialVersionUID = -681163357370848098L; + /** + * <code>true</code> if related artifacts are updated too. + */ + private boolean updateRelatedArtifacts; + + public boolean isUpdateRelatedArtifacts( ) + { + return updateRelatedArtifacts; + } + + public void setUpdateRelatedArtifacts( boolean updateRelatedArtifacts ) + { + this.updateRelatedArtifacts = updateRelatedArtifacts; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) return true; + if ( o == null || getClass( ) != o.getClass( ) ) return false; + + MetadataScanTask scanTask = (MetadataScanTask) o; + + if ( updateRelatedArtifacts != scanTask.updateRelatedArtifacts ) return false; + if ( fullScan != scanTask.fullScan ) return false; + if ( running != scanTask.running ) return false; + if ( maxExecutionTimeMs != scanTask.maxExecutionTimeMs ) return false; + if ( !repositoryId.equals( scanTask.repositoryId ) ) return false; + return resource.equals( scanTask.resource ); + } + + @Override + public int hashCode( ) + { + int result = repositoryId.hashCode( ); + result = 31 * result + ( updateRelatedArtifacts ? 1 : 0 ); + result = 31 * result + ( fullScan ? 1 : 0 ); + result = 31 * result + ( running ? 1 : 0 ); + result = 31 * result + resource.hashCode( ); + result = 31 * result + (int) ( maxExecutionTimeMs ^ ( maxExecutionTimeMs >>> 32 ) ); + return result; + } + + @Override + public String toString( ) + { + final StringBuilder sb = new StringBuilder( "ScanTask{" ); + sb.append( "repositoryId='" ).append( repositoryId ).append( '\'' ); + sb.append( ", updateRelatedArtifacts=" ).append( updateRelatedArtifacts ); + sb.append( ", fullRepository=" ).append( fullScan ); + sb.append( ", running=" ).append( running ); + sb.append( ", resource='" ).append( resource ).append( '\'' ); + sb.append( ", maxExecutionTimeMs=" ).append( maxExecutionTimeMs ); + sb.append( '}' ); + return sb.toString( ); + } +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/RepositoryTaskInfo.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/RepositoryTaskInfo.java new file mode 100644 index 000000000..9a0a838bd --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/RepositoryTaskInfo.java @@ -0,0 +1,121 @@ +package org.apache.archiva.admin.model.beans; +/* + * 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.OffsetDateTime; + +/** + * @author Martin Stockhammer <martin_s@apache.org> + */ +public class RepositoryTaskInfo +{ + /** + * The repository identifier + */ + protected String repositoryId = ""; + /** + * <code>true</code>, if all files are scanned. <code>false</code>, if only updated files are scanned + */ + protected boolean fullScan; + /** + * The scanned resource, if this is not a full repository scan + */ + protected String resource = ""; + /** + * Running status of the task. + */ + protected boolean running = false; + /** + * The maximum execution time set for this task. + */ + protected long maxExecutionTimeMs = 0; + /** + * The time when the status check was built + */ + OffsetDateTime checkTime; + + public RepositoryTaskInfo( ) + { + this.checkTime = OffsetDateTime.now( ); + } + + public RepositoryTaskInfo( OffsetDateTime checkTime ) + { + this.checkTime = checkTime; + } + + public String getRepositoryId( ) + { + return repositoryId; + } + + public void setRepositoryId( String repositoryId ) + { + this.repositoryId = repositoryId==null?"":repositoryId; + } + + public boolean isFullScan( ) + { + return fullScan; + } + + public void setFullScan( boolean fullScan ) + { + this.fullScan = fullScan; + } + + public String getResource( ) + { + return resource; + } + + public void setResource( String resource ) + { + this.resource = resource == null ? "" : resource; + } + + public boolean isRunning( ) + { + return running; + } + + public void setRunning( boolean running ) + { + this.running = running; + } + + public long getMaxExecutionTimeMs( ) + { + return maxExecutionTimeMs; + } + + public void setMaxExecutionTimeMs( long maxExecutionTimeMs ) + { + this.maxExecutionTimeMs = maxExecutionTimeMs; + } + + public OffsetDateTime getCheckTime( ) + { + return checkTime; + } + + public void setCheckTime( OffsetDateTime checkTime ) + { + this.checkTime = checkTime; + } +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/ScanStatus.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/ScanStatus.java new file mode 100644 index 000000000..50dc46e57 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/java/org/apache/archiva/admin/model/beans/ScanStatus.java @@ -0,0 +1,85 @@ +package org.apache.archiva.admin.model.beans; +/* + * 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.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Information about running and queued repository scans. + * + * @author Martin Stockhammer <martin_s@apache.org> + */ +public class ScanStatus implements Serializable +{ + private List<IndexingTask> indexingQueue = new ArrayList<>( ); + private List<MetadataScanTask> scanQueue = new ArrayList<>( ); + + public ScanStatus( ) + { + } + + public boolean isMetadataScanRunning( ) + { + return scanQueue.size( ) > 0 && scanQueue.get(0).isRunning(); + } + + public int getMetadataScanQueueSize() { + int size= scanQueue.size( ); + if (size>0) { + return size-1; + } else { + return 0; + } + } + + public boolean isIndexScanRunning( ) + { + return indexingQueue.size()>0 && indexingQueue.get(0).isRunning(); + } + + public int getIndexScanQueueSize() { + int size = indexingQueue.size(); + if (size>0) { + return size-1; + } else { + return 0; + } + } + + public List<IndexingTask> getIndexingQueue( ) + { + return indexingQueue; + } + + public void setIndexingQueue( List<IndexingTask> indexingQueue ) + { + this.indexingQueue = new ArrayList<>( indexingQueue ); + } + + public List<MetadataScanTask> getScanQueue( ) + { + return scanQueue; + } + + public void setScanQueue( List<MetadataScanTask> scanQueue ) + { + this.scanQueue = new ArrayList<>( scanQueue ); + } +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/resources/org/apache/archiva/admin/model/error/AdminErrors.properties b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/resources/org/apache/archiva/admin/model/error/AdminErrors.properties index 4addc0aef..82056a09f 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/resources/org/apache/archiva/admin/model/error/AdminErrors.properties +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-api/src/main/resources/org/apache/archiva/admin/model/error/AdminErrors.properties @@ -26,3 +26,7 @@ repository_group.repository.not_found=The member repository with id "{0}" does n repository_group.registry.add_error=The registry could not add the repository "{0}": {1} repository_group.registry.update_error=The registry could not update the repository "{0}": {1} repository_group.not_editable=The repository group "{0}" is not editable +repository.id.invalid=The given repository id {0} is not valid. +repository.not_found=The repository with the given id "{0}" was not found +repository.file.not_found=No file "{1}" found in the repository "{0}" +repository.scan.task_retrieval_failed=Could not get scan task information: {0}
\ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/pom.xml b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/pom.xml index 80e462062..2f5f27703 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/pom.xml +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/pom.xml @@ -117,6 +117,18 @@ <groupId>org.apache.archiva.components</groupId> <artifactId>archiva-components-spring-taskqueue</artifactId> </dependency> + <dependency> + <groupId>org.apache.archiva</groupId> + <artifactId>archiva-scheduler-indexing</artifactId> + </dependency> + <dependency> + <groupId>org.apache.archiva</groupId> + <artifactId>archiva-scheduler-repository</artifactId> + </dependency> + <dependency> + <groupId>org.apache.archiva.maven</groupId> + <artifactId>archiva-maven-scheduler</artifactId> + </dependency> <dependency> @@ -167,6 +179,11 @@ <!-- Test scope --> <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.apache.archiva</groupId> <artifactId>archiva-proxy</artifactId> <scope>test</scope> diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/admin/DefaultRepositoryTaskAdministration.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/admin/DefaultRepositoryTaskAdministration.java new file mode 100644 index 000000000..5dc9bb1dd --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/admin/DefaultRepositoryTaskAdministration.java @@ -0,0 +1,360 @@ +package org.apache.archiva.admin.repository.admin; +/* + * 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.admin.RepositoryTaskAdministration; +import org.apache.archiva.admin.model.beans.IndexingTask; +import org.apache.archiva.admin.model.beans.MetadataScanTask; +import org.apache.archiva.admin.model.beans.RepositoryTaskInfo; +import org.apache.archiva.admin.model.beans.ScanStatus; +import org.apache.archiva.components.taskqueue.TaskQueueException; +import org.apache.archiva.components.taskqueue.execution.TaskQueueExecutor; +import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager; +import org.apache.archiva.repository.RepositoryRegistry; +import org.apache.archiva.repository.storage.StorageAsset; +import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask; +import org.apache.archiva.scheduler.indexing.IndexingArchivaTaskScheduler; +import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler; +import org.apache.archiva.scheduler.repository.model.RepositoryTask; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.inject.Named; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Martin Stockhammer <martin_s@apache.org> + */ +@Service( "repositoryTaskAdministration#default" ) +public class DefaultRepositoryTaskAdministration implements RepositoryTaskAdministration +{ + private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryTaskAdministration.class ); + + + final RepositoryRegistry repositoryRegistry; + + final + TaskQueueExecutor<ArtifactIndexingTask> indexingTaskExecutor; + + final + TaskQueueExecutor<RepositoryTask> scanningTaskExecutor; + + private final RepositoryArchivaTaskScheduler repositoryArchivaTaskScheduler; + + private final IndexingArchivaTaskScheduler indexingArchivaTaskScheduler; + + public DefaultRepositoryTaskAdministration( RepositoryRegistry repositoryRegistry, + @Named( value = "taskQueueExecutor#indexing" ) TaskQueueExecutor<ArtifactIndexingTask> indexingTaskExecutor, + @Named( value = "taskQueueExecutor#repository-scanning" ) TaskQueueExecutor<RepositoryTask> scanningTaskExecutor, + @Named( value = "archivaTaskScheduler#repository" ) RepositoryArchivaTaskScheduler repositoryArchivaTaskScheduler, + @Named( value = "archivaTaskScheduler#indexing" ) IndexingArchivaTaskScheduler indexingArchivaTaskScheduler) + { + this.repositoryRegistry = repositoryRegistry; + this.indexingTaskExecutor = indexingTaskExecutor; + this.scanningTaskExecutor = scanningTaskExecutor; + this.repositoryArchivaTaskScheduler = repositoryArchivaTaskScheduler; + this.indexingArchivaTaskScheduler = indexingArchivaTaskScheduler; + } + + @Override + public void scheduleFullScan( String repositoryId ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + try + { + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + ArtifactIndexingTask task = + new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext( ) ); + task.setExecuteOnEntireRepo( true ); + task.setOnlyUpdate( false ); + indexingArchivaTaskScheduler.queueTask( task ); + repositoryArchivaTaskScheduler.queueTask( new RepositoryTask( repositoryId, true ) ); + } + catch ( TaskQueueException e ) + { + log.error( "Could not queue the task: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_queue_error", e, e.getMessage( ) ); + } + } + + @Override + public void scheduleIndexFullScan( String repositoryId ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + try + { + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + ArtifactIndexingTask task = + new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext( ) ); + task.setExecuteOnEntireRepo( true ); + task.setOnlyUpdate( false ); + indexingArchivaTaskScheduler.queueTask( task ); + } + catch ( TaskQueueException e ) + { + log.error( "Could not queue the task: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_queue_error", e, e.getMessage( ) ); + } + } + + @Override + public void scheduleIndexScan( String repositoryId, String relativePath ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + try + { + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + StorageAsset asset = repository.getAsset( relativePath ); + if (!asset.exists()) { + throw RepositoryAdminException.ofKey( "repository.file.not_found", repositoryId, relativePath ); + } + ArtifactIndexingTask task = + new ArtifactIndexingTask( repository, asset.getFilePath( ), ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext( ) ); + task.setExecuteOnEntireRepo( false ); + task.setOnlyUpdate( true ); + indexingArchivaTaskScheduler.queueTask( task ); + } + catch ( TaskQueueException e ) + { + log.error( "Could not queue the task: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_queue_error", e, e.getMessage( ) ); + } + + } + + @Override + public void scheduleMetadataFullScan( String repositoryId ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + try + { + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + repositoryArchivaTaskScheduler.queueTask( new RepositoryTask( repositoryId, true ) ); + } + catch ( TaskQueueException e ) + { + log.error( "Could not queue the task: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_queue_error", e, e.getMessage( ) ); + } + + } + + @Override + public void scheduleMetadataUpdateScan( String repositoryId ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + try + { + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + repositoryArchivaTaskScheduler.queueTask( new RepositoryTask( repositoryId, false ) ); + } + catch ( TaskQueueException e ) + { + log.error( "Could not queue the task: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_queue_error", e, e.getMessage( ) ); + } + + } + + public static MetadataScanTask getMetadataScanTaskInfo(RepositoryTask repositoryTask) { + MetadataScanTask scanTask = new MetadataScanTask( ); + scanTask.setFullScan( repositoryTask.isScanAll()); + scanTask.setUpdateRelatedArtifacts( repositoryTask.isUpdateRelatedArtifacts() ); + StorageAsset file = repositoryTask.getResourceFile( ); + scanTask.setResource( repositoryTask.getResourceFile( )==null?"":repositoryTask.getResourceFile().toString( ) ); + scanTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTime() ); + scanTask.setRepositoryId( repositoryTask.getRepositoryId( ) ); + return scanTask; + } + + public static IndexingTask getIndexingTaskInfo(ArtifactIndexingTask repositoryTask) { + IndexingTask indexingTask = new IndexingTask( ); + indexingTask.setFullScan( repositoryTask.isExecuteOnEntireRepo()); + indexingTask.setUpdateOnly( repositoryTask.isOnlyUpdate() ); + indexingTask.setResource( repositoryTask.getResourceFile( )==null?"":repositoryTask.getResourceFile().toString( ) ); + indexingTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTime() ); + indexingTask.setRepositoryId( repositoryTask.getRepository().getId() ); + return indexingTask; + + } + + public void updateScanInfo( ScanStatus scanStatus, RepositoryTask runningRepositoryTask, List<RepositoryTask> taskQueue) { + List<MetadataScanTask> newScanQueue = new ArrayList<>( ); + if (runningRepositoryTask!=null) { + MetadataScanTask taskInfo = getMetadataScanTaskInfo( runningRepositoryTask ); + taskInfo.setRunning( true ); + newScanQueue.add( 0, taskInfo); + } + newScanQueue.addAll( taskQueue.stream( ).map( task -> getMetadataScanTaskInfo( task ) ).collect( Collectors.toList( ) ) ); + scanStatus.setScanQueue( newScanQueue ); + } + + public void updateIndexInfo( ScanStatus scanStatus, ArtifactIndexingTask runningIndexingTask, List<ArtifactIndexingTask> taskQueue) { + List<IndexingTask> newIndexQueue = new ArrayList<>( ); + if (runningIndexingTask!=null) { + IndexingTask taskInfo = getIndexingTaskInfo( runningIndexingTask ); + taskInfo.setRunning( true ); + newIndexQueue.add(taskInfo ); + } + newIndexQueue.addAll( taskQueue.stream( ).map( task -> getIndexingTaskInfo( task ) ).collect( Collectors.toList( ) ) ); + scanStatus.setIndexingQueue( newIndexQueue ); + } + + + @Override + public ScanStatus getCurrentScanStatus( String repositoryId ) throws RepositoryAdminException + { + if ( StringUtils.isEmpty( repositoryId ) ) { + throw RepositoryAdminException.ofKey( "repository.id.invalid", "" ); + } + org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); + if (repository==null) { + throw RepositoryAdminException.ofKey( "repository.not_found", repositoryId ); + } + ScanStatus status = new ScanStatus( ); + try + { + RepositoryTask scanTask = scanningTaskExecutor.getCurrentTask( ); + if ( scanTask!=null && !repositoryId.equals( scanTask.getRepositoryId( ) ) ) + { + scanTask = null; + } + ArtifactIndexingTask indexTask = indexingTaskExecutor.getCurrentTask( ); + if ( indexTask!=null && !repositoryId.equals( indexTask.getRepository( ).getId( ) ) ) + { + indexTask = null; + } + updateScanInfo( status, scanTask, scanningTaskExecutor.getQueue( ).getQueueSnapshot( ).stream( ).filter( task -> repositoryId.equals( task.getRepositoryId( ) ) ).collect( Collectors.toList( ) ) ); + updateIndexInfo( status, indexTask, indexingTaskExecutor.getQueue( ).getQueueSnapshot( ).stream( ).filter( task -> repositoryId.equals( task.getRepository( ).getId( ) ) ).collect( Collectors.toList( ) ) ); + return status; + } + catch ( TaskQueueException e ) + { + log.error( "Could not get task information: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_retrieval_failed", e.getMessage( ) ); + } + + } + + @Override + public ScanStatus getCurrentScanStatus( ) throws RepositoryAdminException + { + ScanStatus status = new ScanStatus( ); + try + { + RepositoryTask scanTask = scanningTaskExecutor.getCurrentTask( ); + ArtifactIndexingTask indexTask = indexingTaskExecutor.getCurrentTask( ); + updateScanInfo( status, scanTask, scanningTaskExecutor.getQueue( ).getQueueSnapshot() ); + updateIndexInfo( status, indexTask, indexingTaskExecutor.getQueue( ).getQueueSnapshot( ) ); + return status; + } + catch ( TaskQueueException e ) + { + log.error( "Could not get task information: {}", e.getMessage( ), e ); + throw RepositoryAdminException.ofKey( "repository.scan.task_retrieval_failed", e.getMessage( ) ); + } + + } + + @Override + public List<RepositoryTaskInfo> cancelTasks( String repositoryId ) throws RepositoryAdminException + { + ArrayList<RepositoryTaskInfo> resultList = new ArrayList<>( ); + resultList.addAll( cancelScanTasks( repositoryId ) ); + resultList.addAll( cancelIndexTasks( repositoryId ) ); + return resultList; + } + + @Override + public List<RepositoryTaskInfo> cancelScanTasks( String repositoryId ) throws RepositoryAdminException + { + try + { + ArrayList<RepositoryTaskInfo> resultList = new ArrayList<>( ); + List<RepositoryTask> removeTasks = scanningTaskExecutor.getQueue( ).getQueueSnapshot( ).stream( ).filter( task -> repositoryId.equals( task.getRepositoryId() ) ).collect( Collectors.toList( ) ); + scanningTaskExecutor.getQueue( ).removeAll( removeTasks ); + RepositoryTask currentTask = scanningTaskExecutor.getCurrentTask( ); + if ( currentTask != null && repositoryId.equals( currentTask.getRepositoryId()) ) + { + scanningTaskExecutor.cancelTask( currentTask ); + resultList.add( getMetadataScanTaskInfo( currentTask ) ); + } + resultList.addAll( removeTasks.stream( ).map( task -> getMetadataScanTaskInfo( task ) ).collect( Collectors.toList( ) ) ); + return resultList; + } + catch ( TaskQueueException e ) + { + throw RepositoryAdminException.ofKey( "repository.task.dequeue_failed", repositoryId ); + } + } + + @Override + public List<RepositoryTaskInfo> cancelIndexTasks( String repositoryId ) throws RepositoryAdminException + { + try + { + ArrayList<RepositoryTaskInfo> resultList = new ArrayList<>( ); + List<ArtifactIndexingTask> removeTasks = indexingTaskExecutor.getQueue( ).getQueueSnapshot( ).stream( ).filter( task -> repositoryId.equals( task.getRepository( ).getId( ) ) ).collect( Collectors.toList( ) ); + indexingTaskExecutor.getQueue( ).removeAll( removeTasks ); + ArtifactIndexingTask currentTask = indexingTaskExecutor.getCurrentTask( ); + if ( currentTask != null && repositoryId.equals( currentTask.getRepository( ).getId( ) ) ) + { + indexingTaskExecutor.cancelTask( currentTask ); + resultList.add( getIndexingTaskInfo( currentTask ) ); + } + resultList.addAll( removeTasks.stream( ).map( task -> getIndexingTaskInfo( task ) ).collect( Collectors.toList( ) ) ); + return resultList; + } + catch ( TaskQueueException e ) + { + throw RepositoryAdminException.ofKey( "repository.task.dequeue_failed", repositoryId ); + } + } + + +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MockRepositoryArchivaTaskScheduler.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MockRepositoryArchivaTaskScheduler.java index 8c3cfe264..1540b4670 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MockRepositoryArchivaTaskScheduler.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/mock/MockRepositoryArchivaTaskScheduler.java @@ -26,7 +26,7 @@ import org.springframework.stereotype.Service; /** * @author Olivier Lamy */ -@Service("archivaTaskScheduler#repository") +@Service("archivaTaskScheduler#mock") public class MockRepositoryArchivaTaskScheduler implements RepositoryArchivaTaskScheduler { diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/admin/RepositoryTaskAdministrationTest.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/admin/RepositoryTaskAdministrationTest.java new file mode 100644 index 000000000..6cdf31a6b --- /dev/null +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/java/org/apache/archiva/admin/repository/admin/RepositoryTaskAdministrationTest.java @@ -0,0 +1,267 @@ +package org.apache.archiva.admin.repository.admin; +/* + * 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.admin.RepositoryTaskAdministration; +import org.apache.archiva.admin.model.beans.ScanStatus; +import org.apache.archiva.components.taskqueue.TaskQueue; +import org.apache.archiva.components.taskqueue.TaskQueueException; +import org.apache.archiva.components.taskqueue.execution.TaskQueueExecutor; +import org.apache.archiva.repository.ManagedRepository; +import org.apache.archiva.repository.RepositoryRegistry; +import org.apache.archiva.repository.storage.StorageAsset; +import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask; +import org.apache.archiva.scheduler.indexing.IndexingArchivaTaskScheduler; +import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler; +import org.apache.archiva.scheduler.repository.model.RepositoryTask; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * @author Martin Stockhammer <martin_s@apache.org> + */ +@Tag( "archiva-admin" ) +@DisplayName( "Unit Tests for RepositoryTaskAdministration" ) +public class RepositoryTaskAdministrationTest +{ + + private RepositoryTaskAdministration taskAdministration; + private TaskQueueExecutor<ArtifactIndexingTask> indexingTaskExecutor; + private TaskQueueExecutor<RepositoryTask> scanningTaskExecutor; + private RepositoryArchivaTaskScheduler repositoryArchivaTaskScheduler; + private IndexingArchivaTaskScheduler indexingArchivaTaskScheduler; + private RepositoryRegistry registry; + + @BeforeEach + public void init() { + registry = mock( RepositoryRegistry.class ); + indexingTaskExecutor = mock( TaskQueueExecutor.class ); + scanningTaskExecutor = mock( TaskQueueExecutor.class ); + repositoryArchivaTaskScheduler = mock( RepositoryArchivaTaskScheduler.class ); + indexingArchivaTaskScheduler = mock( IndexingArchivaTaskScheduler.class ); + this.taskAdministration = new DefaultRepositoryTaskAdministration( registry, indexingTaskExecutor, + scanningTaskExecutor, repositoryArchivaTaskScheduler, indexingArchivaTaskScheduler ); + } + + @Test + public void testScanStatus() throws RepositoryAdminException, TaskQueueException + { + TaskQueue queue = mock( TaskQueue.class ); + TaskQueue indexQueue = mock( TaskQueue.class ); + + List<RepositoryTask> scanList = new ArrayList<>( ); + RepositoryTask scanTask1 = new RepositoryTask( ); + scanTask1.setRepositoryId( "abcde" ); + scanTask1.setScanAll( true ); + scanTask1.setResourceFile( null ); + scanList.add( scanTask1 ); + RepositoryTask scanTask2 = new RepositoryTask( ); + scanTask2.setRepositoryId( "testrepo2" ); + scanTask2.setScanAll( true ); + scanTask2.setResourceFile( null ); + scanList.add( scanTask1 ); + + List<ArtifactIndexingTask> indexList = new ArrayList<>( ); + ArtifactIndexingTask indexTask1 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask1.getRepository( ).getId( ) ).thenReturn( "indexrepo1" ); + when( indexTask1.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask1.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask1 ); + ArtifactIndexingTask indexTask2 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask2.getRepository( ).getId( ) ).thenReturn( "indexrepo2" ); + when( indexTask2.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask2.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask2 ); + + when( scanningTaskExecutor.getQueue( ) ).thenReturn( queue ); + when( indexingTaskExecutor.getQueue( ) ).thenReturn( indexQueue ); + when( queue.getQueueSnapshot( ) ).thenReturn( scanList ); + when( indexQueue.getQueueSnapshot( ) ).thenReturn( indexList ); + ScanStatus currentScanStatus = taskAdministration.getCurrentScanStatus( ); + assertNotNull( currentScanStatus ); + assertNotNull( currentScanStatus.getIndexingQueue( ) ); + assertNotNull( currentScanStatus.getScanQueue( ) ); + assertEquals( 2, currentScanStatus.getScanQueue( ).size( ) ); + assertEquals( 2, currentScanStatus.getIndexingQueue( ).size( ) ); + } + + @Test + public void testScanStatusWithId() throws RepositoryAdminException, TaskQueueException + { + TaskQueue queue = mock( TaskQueue.class ); + TaskQueue indexQueue = mock( TaskQueue.class ); + + List<RepositoryTask> scanList = new ArrayList<>( ); + RepositoryTask scanTask1 = new RepositoryTask( ); + scanTask1.setRepositoryId( "abcde" ); + scanTask1.setScanAll( true ); + scanTask1.setResourceFile( null ); + scanList.add( scanTask1 ); + RepositoryTask scanTask2 = new RepositoryTask( ); + scanTask2.setRepositoryId( "testrepo2" ); + scanTask2.setScanAll( true ); + scanTask2.setResourceFile( null ); + scanList.add( scanTask1 ); + + List<ArtifactIndexingTask> indexList = new ArrayList<>( ); + ArtifactIndexingTask indexTask1 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask1.getRepository( ).getId( ) ).thenReturn( "indexrepo1" ); + when( indexTask1.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask1.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask1 ); + ArtifactIndexingTask indexTask2 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask2.getRepository( ).getId( ) ).thenReturn( "indexrepo2" ); + when( indexTask2.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask2.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask2 ); + + when( scanningTaskExecutor.getQueue( ) ).thenReturn( queue ); + when( indexingTaskExecutor.getQueue( ) ).thenReturn( indexQueue ); + when( queue.getQueueSnapshot( ) ).thenReturn( scanList ); + when( indexQueue.getQueueSnapshot( ) ).thenReturn( indexList ); + when( registry.getManagedRepository( "indexrepo2" ) ).thenReturn( mock( ManagedRepository.class ) ); + ScanStatus currentScanStatus = taskAdministration.getCurrentScanStatus( "indexrepo2"); + assertNotNull( currentScanStatus ); + assertNotNull( currentScanStatus.getIndexingQueue( ) ); + assertNotNull( currentScanStatus.getScanQueue( ) ); + assertEquals( 0, currentScanStatus.getScanQueue( ).size( ) ); + assertEquals( 1, currentScanStatus.getIndexingQueue( ).size( ) ); + } + + @Test + public void testScheduleFullScan() throws RepositoryAdminException, TaskQueueException + { + when( registry.getManagedRepository( "internal" ) ).thenReturn( mock( ManagedRepository.class ) ); + taskAdministration.scheduleFullScan( "internal" ); + verify( repositoryArchivaTaskScheduler, times(1) ).queueTask( any() ); + verify( indexingArchivaTaskScheduler, times(1) ).queueTask( any() ); + } + + @Test + public void testScheduleIndexScan() throws RepositoryAdminException, TaskQueueException + { + when( registry.getManagedRepository( "internal" ) ).thenReturn( mock( ManagedRepository.class ) ); + taskAdministration.scheduleIndexFullScan( "internal" ); + ArgumentCaptor<ArtifactIndexingTask> captor = ArgumentCaptor.forClass( ArtifactIndexingTask.class ); + verify( repositoryArchivaTaskScheduler, times(0) ).queueTask( any() ); + verify( indexingArchivaTaskScheduler, times(1) ).queueTask( captor.capture() ); + assertTrue(captor.getValue().isExecuteOnEntireRepo()); + } + + @Test + public void testScheduleIndexScanWithFile() throws RepositoryAdminException, TaskQueueException + { + ManagedRepository managedRepo = mock( ManagedRepository.class, RETURNS_DEEP_STUBS ); + when( registry.getManagedRepository( "internal" ) ).thenReturn( managedRepo ); + StorageAsset asset = mock( StorageAsset.class ); + when( asset.getFilePath( ) ).thenReturn( Paths.get( "abc/def/ghij.pom" ) ); + when( asset.exists( ) ).thenReturn( true ); + when( registry.getManagedRepository( "internal" ).getAsset( "abc/def/ghij.pom" ) ).thenReturn( asset ); + taskAdministration.scheduleIndexScan( "internal", "abc/def/ghij.pom" ); + ArgumentCaptor<ArtifactIndexingTask> captor = ArgumentCaptor.forClass( ArtifactIndexingTask.class ); + verify( repositoryArchivaTaskScheduler, times(0) ).queueTask( any() ); + verify( indexingArchivaTaskScheduler, times(1) ).queueTask( captor.capture() ); + ArtifactIndexingTask caption = captor.getValue( ); + assertFalse(caption.isExecuteOnEntireRepo()); + assertEquals( "abc/def/ghij.pom", caption.getResourceFile( ).toString() ); + } + + @Test + public void testScheduleMetadataScan() throws RepositoryAdminException, TaskQueueException + { + when( registry.getManagedRepository( "internal" ) ).thenReturn( mock( ManagedRepository.class ) ); + taskAdministration.scheduleMetadataFullScan( "internal" ); + ArgumentCaptor<RepositoryTask> captor = ArgumentCaptor.forClass( RepositoryTask.class ); + verify( repositoryArchivaTaskScheduler, times(1) ).queueTask( captor.capture( ) ); + verify( indexingArchivaTaskScheduler, times(0) ).queueTask( any() ); + assertTrue(captor.getValue().isScanAll()); + } + + @Test + public void testScheduleMetadataUpdateScan() throws RepositoryAdminException, TaskQueueException + { + when( registry.getManagedRepository( "internal" ) ).thenReturn( mock( ManagedRepository.class ) ); + taskAdministration.scheduleMetadataUpdateScan( "internal" ); + ArgumentCaptor<RepositoryTask> captor = ArgumentCaptor.forClass( RepositoryTask.class ); + verify( repositoryArchivaTaskScheduler, times(1) ).queueTask( captor.capture( ) ); + verify( indexingArchivaTaskScheduler, times(0) ).queueTask( any() ); + assertFalse(captor.getValue().isScanAll()); + } + + + @Test + void cancelAllTasks() throws TaskQueueException, RepositoryAdminException + { + TaskQueue queue = mock( TaskQueue.class ); + TaskQueue indexQueue = mock( TaskQueue.class ); + + List<RepositoryTask> scanList = new ArrayList<>( ); + RepositoryTask scanTask1 = new RepositoryTask( ); + scanTask1.setRepositoryId( "abcde" ); + scanTask1.setScanAll( true ); + scanTask1.setResourceFile( null ); + scanList.add( scanTask1 ); + RepositoryTask scanTask2 = new RepositoryTask( ); + scanTask2.setRepositoryId( "testrepo2" ); + scanTask2.setScanAll( true ); + scanTask2.setResourceFile( null ); + scanList.add( scanTask1 ); + + List<ArtifactIndexingTask> indexList = new ArrayList<>( ); + ArtifactIndexingTask indexTask1 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask1.getRepository( ).getId( ) ).thenReturn( "indexrepo1" ); + when( indexTask1.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask1.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask1 ); + ArtifactIndexingTask indexTask2 = mock( ArtifactIndexingTask.class, RETURNS_DEEP_STUBS ); + when( indexTask2.getRepository( ).getId( ) ).thenReturn( "indexrepo2" ); + when( indexTask2.isExecuteOnEntireRepo( ) ).thenReturn( true ); + when( indexTask2.getResourceFile( ) ).thenReturn( null ); + indexList.add( indexTask2 ); + + when( scanningTaskExecutor.getQueue( ) ).thenReturn( queue ); + when( indexingTaskExecutor.getQueue( ) ).thenReturn( indexQueue ); + when( queue.getQueueSnapshot( ) ).thenReturn( scanList ); + when( indexQueue.getQueueSnapshot( ) ).thenReturn( indexList ); + taskAdministration.cancelTasks( "indexrepo1" ); + ArgumentCaptor<List> scanCaptor = ArgumentCaptor.forClass( List.class ); + ArgumentCaptor<List> indexCaptor = ArgumentCaptor.forClass( List.class ); + + verify( queue ).removeAll( scanCaptor.capture() ); + verify( indexQueue ).removeAll( indexCaptor.capture() ); + + List scanCancelList = scanCaptor.getValue( ); + List indexCancelList = indexCaptor.getValue( ); + assertEquals( 0, scanCancelList.size( ) ); + assertEquals( 1, indexCancelList.size( ) ); + assertEquals( "indexrepo1", ( (ArtifactIndexingTask) indexCancelList.get( 0 ) ).getRepository( ).getId( ) ); + + + } +} diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/spring-context.xml b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/spring-context.xml index 5c201e56f..203c32674 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/spring-context.xml +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/test/resources/spring-context.xml @@ -31,8 +31,9 @@ default-lazy-init="true"> <context:annotation-config/> - <context:component-scan base-package="org.apache.archiva.admin.mock,org.apache.archiva.repository.content.maven2"/> + <context:component-scan base-package="org.apache.archiva.admin.mock,org.apache.archiva.repository.content.base"/> + <alias name="archivaTaskScheduler#mock" alias="archivaTaskScheduler#default" /> <bean name="scheduler" class="org.apache.archiva.components.scheduler.DefaultScheduler"> <property name="properties"> <props> diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/IndexingTask.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/IndexingTask.java index e4d668486..b3bc50930 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/IndexingTask.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/IndexingTask.java @@ -37,13 +37,13 @@ public class IndexingTask implements Serializable private boolean running = false; private long maxExecutionTimeMs = 0; - public static IndexingTask of( ArtifactIndexingTask repositoryTask ) { + public static IndexingTask of( org.apache.archiva.admin.model.beans.IndexingTask repositoryTask ) { IndexingTask indexingTask = new IndexingTask( ); - indexingTask.setFullRepository( repositoryTask.isExecuteOnEntireRepo()); - indexingTask.setUpdateOnly( repositoryTask.isOnlyUpdate() ); - indexingTask.setResource( repositoryTask.getResourceFile( ).toString( ) ); - indexingTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTime() ); - indexingTask.setRepositoryId( repositoryTask.getRepository().getId() ); + indexingTask.setFullRepository( repositoryTask.isFullScan()); + indexingTask.setUpdateOnly( repositoryTask.isUpdateOnly() ); + indexingTask.setResource( repositoryTask.getResource() ); + indexingTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTimeMs() ); + indexingTask.setRepositoryId( repositoryTask.getRepositoryId() ); return indexingTask; } diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/Repository.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/Repository.java index ea4993d98..04f77b9db 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/Repository.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/Repository.java @@ -97,10 +97,18 @@ public class Repository implements Serializable } else { myLocale = locale; } + String repoName = repository.getName( myLocale ); + if (repoName==null) { + repoName = repository.getName( ); + } + String description = repository.getDescription( myLocale ); + if (description==null) { + description = repository.getDescription( ); + } Repository newRepo = new Repository( ); newRepo.setId( repository.getId() ); - newRepo.setName( repository.getName( myLocale ) ); - newRepo.setDescription( repository.getDescription( myLocale ) ); + newRepo.setName( repoName ); + newRepo.setDescription( description ); newRepo.setLocation( repository.getLocation().toASCIIString() ); newRepo.setIndex( repository.hasIndex() ); newRepo.setLayout( repository.getLayout() ); diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanStatus.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanStatus.java index 9800bbbf2..27c6b02b5 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanStatus.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanStatus.java @@ -18,6 +18,7 @@ package org.apache.archiva.rest.api.model.v2; */ import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.archiva.admin.model.beans.MetadataScanTask; import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask; import org.apache.archiva.scheduler.repository.model.RepositoryTask; @@ -43,30 +44,18 @@ public class ScanStatus implements Serializable { } - public void updateScanInfo( RepositoryTask runningRepositoryTask, List<RepositoryTask> taskQueue) { - List<ScanTask> newScanQueue = new ArrayList<>( ); - if (runningRepositoryTask==null) { - this.scanRunning=false; - } else { - this.scanRunning=true; - newScanQueue.add( 0, ScanTask.of( runningRepositoryTask ) ); - } - newScanQueue.addAll( taskQueue.stream( ).map( task -> ScanTask.of( task ) ).collect( Collectors.toList( ) ) ); - this.scanQueued = taskQueue.size( ); - this.scanQueue = newScanQueue; - } + public static ScanStatus of( org.apache.archiva.admin.model.beans.ScanStatus modelStatus ) { + ScanStatus status = new ScanStatus( ); + status.setIndexRunning( modelStatus.isIndexScanRunning() ); + status.setScanRunning( modelStatus.isMetadataScanRunning() ); + List<org.apache.archiva.admin.model.beans.IndexingTask> indexQueue = modelStatus.getIndexingQueue( ); + status.setIndexingQueue( indexQueue.stream().map(IndexingTask::of).collect( Collectors.toList()) ); + status.setIndexQueued( indexQueue.size( ) > 0 ? indexQueue.size( ) - 1 : 0 ); + List<MetadataScanTask> scanQueue = modelStatus.getScanQueue( ); + status.setScanQueue( scanQueue.stream().map( ScanTask::of ).collect( Collectors.toList()) ); + status.setScanQueued( scanQueue.size( ) > 0 ? scanQueue.size( ) - 1 : 0 ); + return status; - public void updateIndexInfo( ArtifactIndexingTask runningIndexingTask, List<ArtifactIndexingTask> taskQueue) { - List<IndexingTask> newIndexQueue = new ArrayList<>( ); - if (runningIndexingTask==null) { - this.indexRunning=false; - } else { - this.indexRunning=true; - newIndexQueue.add(IndexingTask.of( runningIndexingTask ) ); - } - newIndexQueue.addAll( taskQueue.stream( ).map( task -> IndexingTask.of( task ) ).collect( Collectors.toList( ) ) ); - this.indexQueued = taskQueue.size( ); - this.indexingQueue = newIndexQueue; } @Schema( name = "scan_running", description = "True, if a scan is currently running" ) diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanTask.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanTask.java index 96aa96f2f..1dc1530e6 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanTask.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/ScanTask.java @@ -18,6 +18,7 @@ package org.apache.archiva.rest.api.model.v2; */ import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.archiva.admin.model.beans.MetadataScanTask; import org.apache.archiva.scheduler.repository.model.RepositoryTask; import java.io.Serializable; @@ -36,12 +37,12 @@ public class ScanTask implements Serializable private String resource = ""; private long maxExecutionTimeMs = 0; - public static ScanTask of( RepositoryTask repositoryTask ) { + public static ScanTask of( MetadataScanTask repositoryTask ) { ScanTask scanTask = new ScanTask( ); - scanTask.setFullRepository( repositoryTask.isScanAll()); + scanTask.setFullRepository( repositoryTask.isFullScan()); scanTask.setUpdateRelatedArtifacts( repositoryTask.isUpdateRelatedArtifacts() ); - scanTask.setResource( repositoryTask.getResourceFile( ).toString( ) ); - scanTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTime() ); + scanTask.setResource( repositoryTask.getResource() ); + scanTask.setMaxExecutionTimeMs( repositoryTask.getMaxExecutionTimeMs() ); scanTask.setRepositoryId( repositoryTask.getRepositoryId( ) ); return scanTask; } diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java index 5544ff315..c328a485d 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/ErrorKeys.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/ErrorKeys.java @@ -1,4 +1,4 @@ -package org.apache.archiva.rest.services.v2;/* +package org.apache.archiva.rest.api.services.v2;/* * 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 diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryService.java index 8092ac72f..4063977ab 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/RepositoryService.java @@ -144,10 +144,6 @@ public interface RepositoryService throws ArchivaRestServiceException; - /** - * scan directories - * @since 1.4-M3 - */ @Path ("managed/{id}/scan/now") @POST @Produces ({ APPLICATION_JSON }) diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultMavenManagedRepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultMavenManagedRepositoryService.java index 3c9c3a654..e380a24d9 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultMavenManagedRepositoryService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultMavenManagedRepositoryService.java @@ -24,6 +24,7 @@ import org.apache.archiva.components.rest.util.QueryHelper; import org.apache.archiva.rest.api.model.v2.FileInfo; import org.apache.archiva.rest.api.model.v2.MavenManagedRepository; import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException; +import org.apache.archiva.rest.api.services.v2.ErrorKeys; import org.apache.archiva.rest.api.services.v2.ErrorMessage; import org.apache.archiva.rest.api.services.v2.MavenManagedRepositoryService; import org.slf4j.Logger; diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java index 42b719306..9290873d6 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryGroupService.java @@ -46,6 +46,7 @@ import org.apache.archiva.redback.rest.services.RedbackRequestInformation; import org.apache.archiva.redback.users.User; import org.apache.archiva.rest.api.model.v2.RepositoryGroup; import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException; +import org.apache.archiva.rest.api.services.v2.ErrorKeys; import org.apache.archiva.rest.api.services.v2.ErrorMessage; import org.apache.archiva.rest.api.services.v2.RepositoryGroupService; import org.apache.commons.lang3.StringUtils; diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryService.java index 4f34cd135..7e41b093b 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultRepositoryService.java @@ -17,11 +17,10 @@ package org.apache.archiva.rest.services.v2; * under the License. */ +import org.apache.archiva.admin.model.RepositoryAdminException; +import org.apache.archiva.admin.model.admin.RepositoryTaskAdministration; import org.apache.archiva.components.rest.model.PagedResult; import org.apache.archiva.components.rest.util.QueryHelper; -import org.apache.archiva.components.taskqueue.Task; -import org.apache.archiva.components.taskqueue.TaskQueueException; -import org.apache.archiva.components.taskqueue.execution.TaskQueueExecutor; import org.apache.archiva.metadata.repository.MetadataRepositoryException; import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager; import org.apache.archiva.repository.RepositoryRegistry; @@ -33,19 +32,14 @@ import org.apache.archiva.rest.api.model.v2.Repository; import org.apache.archiva.rest.api.model.v2.RepositoryStatistics; import org.apache.archiva.rest.api.model.v2.ScanStatus; import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException; +import org.apache.archiva.rest.api.services.v2.ErrorKeys; import org.apache.archiva.rest.api.services.v2.ErrorMessage; import org.apache.archiva.rest.api.services.v2.RepositoryService; -import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask; -import org.apache.archiva.scheduler.indexing.IndexingArchivaTaskScheduler; -import org.apache.archiva.scheduler.indexing.maven.ArchivaIndexingTaskExecutor; -import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler; -import org.apache.archiva.scheduler.repository.model.RepositoryTask; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import javax.inject.Inject; import javax.inject.Named; import javax.ws.rs.core.Response; import java.util.Comparator; @@ -58,49 +52,64 @@ import java.util.stream.Collectors; * @author Martin Stockhammer <martin_s@apache.org> * @since 3.0 */ -@Service("v2.repositoryService#rest") +@Service( "v2.repositoryService#rest" ) public class DefaultRepositoryService implements RepositoryService { - @Inject + final RepositoryRegistry repositoryRegistry; - @Inject + final RepositoryStatisticsManager repositoryStatisticsManager; - @Inject - @Named(value="taskQueueExecutor#indexing") - TaskQueueExecutor<ArtifactIndexingTask> indexingTaskExecutor; + private final RepositoryTaskAdministration repositoryTaskAdministration; - @Inject - @Named(value="taskQueueExecutor#repository-scanning") - TaskQueueExecutor<RepositoryTask> scanningTaskExecutor; - - @Inject - @Named(value = "archivaTaskScheduler#repository") - private RepositoryArchivaTaskScheduler repositoryArchivaTaskScheduler; - - @Inject - @Named( value = "archivaTaskScheduler#indexing" ) - private IndexingArchivaTaskScheduler indexingArchivaTaskScheduler; - - @Inject - private RepositoryScanner repoScanner; + private final RepositoryScanner repoScanner; private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryService.class ); private static final QueryHelper<org.apache.archiva.repository.Repository> QUERY_HELPER = new QueryHelper<>( new String[]{"id", "name"} ); + static { QUERY_HELPER.addStringFilter( "id", org.apache.archiva.repository.Repository::getId ); QUERY_HELPER.addStringFilter( "name", org.apache.archiva.repository.Repository::getName ); + QUERY_HELPER.addStringFilter( "description", org.apache.archiva.repository.Repository::getDescription ); + QUERY_HELPER.addStringFilter( "type", repo -> repo.getType( ).name( ) ); + QUERY_HELPER.addBooleanFilter( "scanned", org.apache.archiva.repository.Repository::isScanned ); QUERY_HELPER.addNullsafeFieldComparator( "id", org.apache.archiva.repository.Repository::getId ); QUERY_HELPER.addNullsafeFieldComparator( "name", org.apache.archiva.repository.Repository::getName ); + QUERY_HELPER.addNullsafeFieldComparator( "type", repo -> repo.getType( ).name( ) ); + QUERY_HELPER.addNullsafeFieldComparator( "boolean", org.apache.archiva.repository.Repository::isScanned ); + } + + public DefaultRepositoryService( RepositoryRegistry repositoryRegistry, RepositoryStatisticsManager repositoryStatisticsManager, + @Named( value = "repositoryTaskAdministration#default") RepositoryTaskAdministration repositoryTaskAdministration, + RepositoryScanner repoScanner ) + { + this.repositoryRegistry = repositoryRegistry; + this.repositoryStatisticsManager = repositoryStatisticsManager; + this.repoScanner = repoScanner; + this.repositoryTaskAdministration = repositoryTaskAdministration; + } + + private void handleAdminException( RepositoryAdminException e ) throws ArchivaRestServiceException + { + log.error( "Repository admin error: {}", e.getMessage( ), e ); + if ( e.keyExists( ) ) + { + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PREFIX + e.getKey( ), e.getParameters( ) ) ); + } + else + { + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) ); + } } + @Override public PagedResult<Repository> getRepositories( String searchTerm, Integer offset, Integer limit, List<String> orderBy, String order, - String localeString) throws ArchivaRestServiceException + String localeString ) throws ArchivaRestServiceException { final Locale locale = StringUtils.isNotEmpty( localeString ) ? Locale.forLanguageTag( localeString ) : Locale.getDefault( ); boolean isAscending = QUERY_HELPER.isAscending( order ); @@ -123,7 +132,8 @@ public class DefaultRepositoryService implements RepositoryService @Override public RepositoryStatistics getManagedRepositoryStatistics( String repositoryId ) throws ArchivaRestServiceException { - if (repositoryRegistry.getManagedRepository( repositoryId )==null) { + if ( repositoryRegistry.getManagedRepository( repositoryId ) == null ) + { throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_MANAGED_NOT_FOUND, repositoryId ), 404 ); } try @@ -142,17 +152,13 @@ public class DefaultRepositoryService implements RepositoryService { try { - org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId ); - ArtifactIndexingTask task = - new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext() ); - task.setExecuteOnEntireRepo( true ); - task.setOnlyUpdate( !fullScan ); - indexingArchivaTaskScheduler.queueTask( task ); - repositoryArchivaTaskScheduler.queueTask( new RepositoryTask( repositoryId, fullScan ) ); + repositoryTaskAdministration.scheduleFullScan( repositoryId ); return Response.ok( ).build( ); - } catch ( TaskQueueException e ) { - log.error( "Could not queue the task: {}", e.getMessage( ), e ); - throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.TASK_QUEUE_FAILED, e.getMessage( ) ) ); + } + catch ( RepositoryAdminException e ) + { + handleAdminException( e ); + return Response.serverError( ).build( ); } } @@ -166,34 +172,22 @@ public class DefaultRepositoryService implements RepositoryService } catch ( RepositoryScannerException e ) { - log.error( e.getMessage(), e ); - throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_SCAN_FAILED, e.getMessage() )); + log.error( e.getMessage( ), e ); + throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_SCAN_FAILED, e.getMessage( ) ) ); } } @Override public ScanStatus getScanStatus( String repositoryId ) throws ArchivaRestServiceException { - ScanStatus status = new ScanStatus( ); try { - RepositoryTask scanTask = scanningTaskExecutor.getCurrentTask( ); - if ( !repositoryId.equals( scanTask.getRepositoryId( ) ) ) - { - scanTask=null; - } - ArtifactIndexingTask indexTask = indexingTaskExecutor.getCurrentTask( ); - if (!repositoryId.equals(indexTask.getRepository().getId())) { - indexTask = null; - } - status.updateScanInfo( scanTask, scanningTaskExecutor.getQueue( ).getQueueSnapshot( ).stream( ).filter( task -> repositoryId.equals(task.getRepositoryId()) ).collect( Collectors.toList() ) ); - status.updateIndexInfo( indexTask, indexingTaskExecutor.getQueue( ).getQueueSnapshot( ).stream().filter( task -> repositoryId.equals(task.getRepository().getId())).collect( Collectors.toList()) ); - return status; + return ScanStatus.of( repositoryTaskAdministration.getCurrentScanStatus( ) ); } - catch ( TaskQueueException e ) + catch ( RepositoryAdminException e ) { - log.error( "Could not get task information: {}", e.getMessage( ), e ); - throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.TASK_QUEUE_FAILED, e.getMessage( ) ) ); + handleAdminException( e ); + return null; } } diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java index 990207486..360d03ebc 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java @@ -56,6 +56,7 @@ import org.apache.archiva.rest.api.model.v2.CacheConfiguration; import org.apache.archiva.rest.api.model.v2.LdapConfiguration; import org.apache.archiva.rest.api.model.v2.SecurityConfiguration; import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException; +import org.apache.archiva.rest.api.services.v2.ErrorKeys; import org.apache.archiva.rest.api.services.v2.ErrorMessage; import org.apache.archiva.rest.api.services.v2.SecurityConfigurationService; import org.apache.commons.collections4.CollectionUtils; @@ -87,8 +88,8 @@ import java.util.ResourceBundle; import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.apache.archiva.rest.services.v2.ErrorKeys.INVALID_RESULT_SET_ERROR; -import static org.apache.archiva.rest.services.v2.ErrorKeys.REPOSITORY_ADMIN_ERROR; +import static org.apache.archiva.rest.api.services.v2.ErrorKeys.INVALID_RESULT_SET_ERROR; +import static org.apache.archiva.rest.api.services.v2.ErrorKeys.REPOSITORY_ADMIN_ERROR; /** * @author Martin Stockhammer <martin_s@apache.org> diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryServiceTest.java new file mode 100644 index 000000000..0c74d3a8c --- /dev/null +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/services/v2/NativeRepositoryServiceTest.java @@ -0,0 +1,162 @@ +package org.apache.archiva.rest.services.v2; + +/* + * 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 io.restassured.response.Response; +import org.apache.archiva.components.rest.model.PagedResult; +import org.apache.archiva.rest.api.model.v2.Repository; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; + +import java.util.List; + +import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Martin Stockhammer <martin_s@apache.org> + */ +@TestInstance( TestInstance.Lifecycle.PER_CLASS ) +@Tag( "rest-native" ) +@TestMethodOrder( MethodOrderer.Random.class ) +@DisplayName( "Native REST tests for V2 RepositoryService" ) +public class NativeRepositoryServiceTest extends AbstractNativeRestServices +{ + @Override + protected String getServicePath( ) + { + return "/repositories"; + } + + @BeforeAll + void setup( ) throws Exception + { + super.setupNative( ); + } + + @AfterAll + void destroy( ) throws Exception + { + super.shutdownNative( ); + } + + @Test + void testGetRepositories() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .get( "" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + PagedResult<Repository> repositoryPagedResult = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class ); + assertEquals( 3, repositoryPagedResult.getPagination( ).getTotalCount( ) ); + List<Repository> data = response.getBody( ).jsonPath( ).getList( "data", Repository.class ); + assertTrue( data.stream( ).anyMatch( p -> "central".equals( p.getId( ) ) ) ); + assertTrue( data.stream( ).anyMatch( p -> "internal".equals( p.getId( ) ) ) ); + assertTrue( data.stream( ).anyMatch( p -> "snapshots".equals( p.getId( ) ) ) ); + Repository snapshotRepo = data.stream( ).filter( p -> "snapshots".equals( p.getId( ) ) ).findFirst( ).get( ); + assertEquals( "Archiva Managed Snapshot Repository", snapshotRepo.getName( ) ); + assertEquals( "MAVEN", snapshotRepo.getType() ); + assertEquals( "managed", snapshotRepo.getCharacteristic() ); + assertEquals( "default", snapshotRepo.getLayout() ); + assertTrue( snapshotRepo.isScanned( ) ); + assertTrue( snapshotRepo.isIndex( ) ); + + Repository centralRepo = data.stream( ).filter( p -> "central".equals( p.getId( ) ) ).findFirst( ).get( ); + assertEquals( "Central Repository", centralRepo.getName( ) ); + assertEquals( "MAVEN", centralRepo.getType() ); + assertEquals( "remote", centralRepo.getCharacteristic() ); + assertEquals( "default", centralRepo.getLayout() ); + + + } + + @Test + void testGetFilteredRepositories() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .queryParam( "q", "central" ) + .get( "" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + PagedResult<Repository> repositoryPagedResult = response.getBody( ).jsonPath( ).getObject( "", PagedResult.class ); + assertEquals( 1, repositoryPagedResult.getPagination( ).getTotalCount( ) ); + List<Repository> data = response.getBody( ).jsonPath( ).getList( "data", Repository.class ); + assertTrue( data.stream( ).anyMatch( p -> "central".equals( p.getId( ) ) ) ); + } + + + @Test + void getStatistics() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .get( "managed/internal/statistics" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + + } + + @Test + void scheduleScan() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .post( "managed/internal/scan/schedule" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + + } + + @Test + void immediateScan() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .post( "managed/internal/scan/now" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + + } + + @Test + void scanStatus() { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .get( "managed/internal/scan/status" ) + .prettyPeek() + .then( ).statusCode( 200 ).extract( ).response( ); + assertNotNull( response ); + + } +} |