Centralizing repository group handling. First part.

This commit is contained in:
Martin Stockhammer 2021-06-01 22:46:51 +02:00
parent ca18ec34d7
commit 0ce53483a8
38 changed files with 897 additions and 330 deletions

View File

@ -55,6 +55,20 @@ public interface ArchivaConfiguration
void save( Configuration configuration )
throws RegistryException, IndeterminateConfigurationException;
/**
* Save any updated configuration. This method allows to add a tag to the thrown event.
* This allows to verify the origin if the caller is the same as the listener.
*
* @param configuration the configuration to save
* @param eventTag the tag to add to the thrown event
* @throws org.apache.archiva.components.registry.RegistryException
* if there is a problem saving the registry data
* @throws IndeterminateConfigurationException
* if the configuration cannot be saved because it was read from two sources
*/
void save( Configuration configuration, String eventTag )
throws RegistryException, IndeterminateConfigurationException;
/**
* Determines if the configuration in use was as a result of a defaulted configuration.
*

View File

@ -32,9 +32,17 @@ public class ConfigurationEvent
private int type;
private String tag;
public ConfigurationEvent( int type )
{
this.type = type;
tag = "";
}
public ConfigurationEvent(int type, String tag) {
this.type = type;
this.tag = tag;
}
public int getType()
@ -42,35 +50,33 @@ public class ConfigurationEvent
return type;
}
@Override
public int hashCode()
public String getTag( )
{
final int prime = 31;
int result = 1;
result = prime * result + type;
return result;
return tag;
}
public void setTag( String tag )
{
this.tag = tag;
}
@Override
public boolean equals( Object obj )
public boolean equals( Object o )
{
if ( this == obj )
{
return true;
}
if ( obj == null )
{
return false;
}
if ( getClass() != obj.getClass() )
{
return false;
}
final ConfigurationEvent other = (ConfigurationEvent) obj;
if ( type != other.type )
{
return false;
}
return true;
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;
ConfigurationEvent that = (ConfigurationEvent) o;
if ( type != that.type ) return false;
return tag.equals( that.tag );
}
@Override
public int hashCode( )
{
int result = type;
result = 31 * result + tag.hashCode( );
return result;
}
}

View File

@ -410,7 +410,20 @@ public class DefaultArchivaConfiguration
@SuppressWarnings("unchecked")
@Override
public synchronized void save(Configuration configuration)
public synchronized void save(Configuration configuration) throws IndeterminateConfigurationException, RegistryException
{
save( configuration, "" );
}
/**
* Saves the configuration and adds the given tag to the event.
* @param configuration the configuration to save
* @param eventTag the tag to add to the configuration saved event
* @throws IndeterminateConfigurationException if the
* @throws RegistryException
*/
@Override
public synchronized void save(Configuration configuration, String eventTag)
throws IndeterminateConfigurationException, RegistryException {
Registry section = registry.getSection(KEY + ".user");
Registry baseSection = registry.getSection(KEY + ".base");
@ -491,7 +504,7 @@ public class DefaultArchivaConfiguration
this.configuration = unescapeExpressions(configuration);
isConfigurationDefaulted = false;
triggerEvent(ConfigurationEvent.SAVED);
triggerEvent(ConfigurationEvent.SAVED, eventTag);
}
private void escapeCronExpressions(Configuration configuration) {
@ -530,7 +543,7 @@ public class DefaultArchivaConfiguration
addRegistryChangeListener(regListener);
}
triggerEvent(ConfigurationEvent.SAVED);
triggerEvent(ConfigurationEvent.SAVED, "default-file");
Registry section = registry.getSection(KEY + ".user");
if (section == null) {
@ -580,8 +593,8 @@ public class DefaultArchivaConfiguration
}
}
private void triggerEvent(int type) {
ConfigurationEvent evt = new ConfigurationEvent(type);
private void triggerEvent(int type, String eventTag) {
ConfigurationEvent evt = new ConfigurationEvent(type, eventTag);
for (ConfigurationListener listener : listeners) {
listener.configurationEvent(evt);
}

View File

@ -26,6 +26,7 @@ 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.base.RepositoryGroupHandler;
import org.apache.archiva.repository.maven.metadata.storage.Maven2RepositoryPathTranslator;
import org.apache.archiva.repository.base.BasicManagedRepository;
import org.apache.archiva.repository.ReleaseScheme;
@ -113,6 +114,10 @@ public abstract class AbstractRepositoryPurgeTest
@Inject
protected ApplicationContext applicationContext;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Before
public void setUp()

View File

@ -74,6 +74,8 @@ public class CleanupReleasedSnapshotsRepositoryPurgeTest
@Inject
MetadataTools metadataTools;
@Before
@Override
public void setUp()

View File

@ -27,6 +27,7 @@ import org.apache.archiva.components.taskqueue.TaskQueueException;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.BasicManagedRepository;
import org.apache.archiva.repository.ReleaseScheme;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.scheduler.ArchivaTaskScheduler;
import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
@ -96,6 +97,9 @@ public class NexusIndexerConsumerTest
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Override
@Before

View File

@ -29,11 +29,15 @@ import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.event.Event;
import org.apache.archiva.event.EventHandler;
import org.apache.archiva.event.EventType;
import org.apache.archiva.metadata.model.facets.AuditEvent;
import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.event.RepositoryRegistryEvent;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
@ -62,7 +66,7 @@ import java.util.stream.Collectors;
@Service("repositoryGroupAdmin#default")
public class DefaultRepositoryGroupAdmin
extends AbstractRepositoryAdmin
implements RepositoryGroupAdmin
implements RepositoryGroupAdmin, EventHandler<Event>
{
private Logger log = LoggerFactory.getLogger( getClass() );
@ -82,6 +86,10 @@ public class DefaultRepositoryGroupAdmin
private Path groupsDirectory;
@PostConstruct
public void baseInit() {
this.repositoryRegistry.registerEventHandler( EventType.ROOT, this );
}
public void initialize()
{
String appServerBase = getRegistry().getString( "appserver.base" );
@ -438,4 +446,14 @@ public class DefaultRepositoryGroupAdmin
rg.setLocation( group.getLocation().toString() );
return rg;
}
@Override
public void handle( Event event )
{
if ( EventType.isInstanceOf( event.getType( ), RepositoryRegistryEvent.INITIALIZED ) )
{
log.debug( "Initializing RepositoryGroupAdmin" );
initialize();
}
}
}

View File

@ -31,6 +31,7 @@ import org.apache.archiva.configuration.ArchivaConfiguration;
import org.apache.archiva.redback.role.RoleManager;
import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.memory.SimpleUser;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
@ -84,6 +85,10 @@ public abstract class AbstractRepositoryAdminTest
@Inject
private ArchivaConfiguration archivaConfiguration;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Before
public void initialize() {
Path confFile = Paths.get(APPSERVER_BASE_PATH, "conf/archiva.xml");

View File

@ -26,6 +26,7 @@ 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.apache.archiva.repository.base.RepositoryGroupHandler;
import org.junit.Test;
import javax.inject.Inject;
@ -44,6 +45,9 @@ public class RepositoryGroupAdminTest
@Inject
RepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Test
public void addAndDeleteGroup()
throws Exception

View File

@ -47,6 +47,21 @@ public class RepositoryRegistryEvent extends Event
*/
public static EventType<RepositoryRegistryEvent> INITIALIZED = new EventType(ANY, "REGISTRY.INITIALIZED");
/**
* When the repository groups are initialized
*/
public static EventType<RepositoryRegistryEvent> GROUPS_INITIALIZED = new EventType(ANY, "REGISTRY.GROUPS_INITIALIZED");
/**
* When the managed repositories are initialized
*/
public static EventType<RepositoryRegistryEvent> MANAGED_REPOS_INITIALIZED = new EventType(ANY, "REGISTRY.MANAGED_REPOS_INITIALIZED");
/**
* When the remote repositories are initialized
*/
public static EventType<RepositoryRegistryEvent> REMOTE_REPOS_INITIALIZED = new EventType(ANY, "REGISTRY.REMOTE_REPOS_INITIALIZED");
public RepositoryRegistryEvent(EventType<? extends RepositoryRegistryEvent> type, Object origin) {
super(type, origin);
}

View File

@ -28,7 +28,6 @@ import org.apache.archiva.components.registry.RegistryException;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.EditableRemoteRepository;
import org.apache.archiva.repository.EditableRepository;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.Repository;
@ -55,12 +54,11 @@ import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
/**
* Registry for repositories. This is the central entry point for repositories. It provides methods for
* retrieving, adding and removing repositories.
@ -78,6 +76,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
{
private static final Logger log = LoggerFactory.getLogger(RepositoryRegistry.class);
private final ConfigurationHandler configurationHandler;
/**
* We inject all repository providers
@ -88,9 +87,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
@Inject
IndexManagerFactory indexManagerFactory;
@Inject
ArchivaConfiguration archivaConfiguration;
@Inject
List<MetadataReader> metadataReaderList;
@ -98,6 +94,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
@Named("repositoryContentFactory#default")
RepositoryContentFactory repositoryContentFactory;
private final EventManager eventManager;
@ -107,20 +105,23 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
private Map<String, RemoteRepository> remoteRepositories = new HashMap<>();
private Map<String, RemoteRepository> uRemoteRepositories = Collections.unmodifiableMap(remoteRepositories);
private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
private Map<String, RepositoryGroup> uRepositoryGroups = Collections.unmodifiableMap(repositoryGroups);
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private volatile boolean ignoreConfigEvents = false;
private RepositoryGroupHandler groupHandler;
public ArchivaRepositoryRegistry() {
private AtomicBoolean groups_initalized = new AtomicBoolean( false );
private AtomicBoolean managed_initialized = new AtomicBoolean( false );
private AtomicBoolean remote_initialized = new AtomicBoolean( false );
public ArchivaRepositoryRegistry(ConfigurationHandler configurationHandler) {
this.eventManager = new EventManager(this);
this.configurationHandler = configurationHandler;
}
@Override
public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration ) {
this.archivaConfiguration = archivaConfiguration;
this.configurationHandler.setArchivaConfiguration( archivaConfiguration );
}
@PostConstruct
@ -128,21 +129,41 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
rwLock.writeLock().lock();
try {
log.debug("Initializing repository registry");
updateManagedRepositoriesFromConfig();
updateRemoteRepositoriesFromConfig();
updateManagedRepositoriesFromConfig( );
pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.MANAGED_REPOS_INITIALIZED, this ) );
managed_initialized.set( true );
updateRemoteRepositoriesFromConfig( );
pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.REMOTE_REPOS_INITIALIZED, this ) );
remote_initialized.set( true );
repositoryGroups.clear();
Map<String, RepositoryGroup> repositoryGroups = getRepositorGroupsFromConfig();
this.repositoryGroups.putAll(repositoryGroups);
// archivaConfiguration.addChangeListener(this);
archivaConfiguration.addListener(this);
initializeRepositoryGroups();
this.configurationHandler.addListener(this);
} finally {
rwLock.writeLock().unlock();
}
pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.RELOADED, this));
if (managed_initialized.get() && remote_initialized.get() && groups_initalized.get( )) {
pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
}
}
private void initializeRepositoryGroups() {
if (this.groupHandler!=null) {
this.groupHandler.initializeFromConfig();
this.groups_initalized.set( true );
pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.GROUPS_INITIALIZED, this ) );
}
}
public void registerGroupHandler(RepositoryGroupHandler groupHandler) {
this.groupHandler = groupHandler;
initializeRepositoryGroups();
if (managed_initialized.get() && remote_initialized.get() && groups_initalized.get( )) {
pushEvent( new RepositoryRegistryEvent( RepositoryRegistryEvent.INITIALIZED, this ) );
}
}
@PreDestroy
public void destroy() {
for (ManagedRepository rep : managedRepositories.values()) {
@ -153,11 +174,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
repo.close();
}
remoteRepositories.clear();
groupHandler.close();
pushEvent(new RepositoryRegistryEvent(RepositoryRegistryEvent.DESTROYED, this));
}
private Map<RepositoryType, RepositoryProvider> createProviderMap() {
protected Map<RepositoryType, RepositoryProvider> getRepositoryProviderMap() {
Map<RepositoryType, RepositoryProvider> map = new HashMap<>();
if (repositoryProviders != null) {
for (RepositoryProvider provider : repositoryProviders) {
@ -169,7 +191,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
return map;
}
private RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
protected RepositoryProvider getProvider(RepositoryType type) throws RepositoryException
{
return repositoryProviders.stream().filter(repositoryProvider -> repositoryProvider.provides().contains(type)).findFirst().orElseThrow(() -> new RepositoryException("Repository type cannot be handled: " + type));
}
@ -182,7 +204,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
Set<String> configRepoIds = new HashSet<>();
List<ManagedRepositoryConfiguration> managedRepoConfigs =
getArchivaConfiguration().getConfiguration().getManagedRepositories();
configurationHandler.getBaseConfiguration().getManagedRepositories();
if (managedRepoConfigs == null) {
return;
@ -299,7 +321,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
private void updateRemoteRepositoriesFromConfig() {
try {
List<RemoteRepositoryConfiguration> remoteRepoConfigs =
getArchivaConfiguration().getConfiguration().getRemoteRepositories();
configurationHandler.getBaseConfiguration().getRemoteRepositories();
if (remoteRepoConfigs == null) {
return;
@ -341,53 +363,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
repo.registerEventHandler(RepositoryEvent.ANY, this);
}
private Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
try {
List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
getArchivaConfiguration().getConfiguration().getRepositoryGroups();
if (repositoryGroupConfigurations == null) {
return Collections.emptyMap();
}
Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
Map<RepositoryType, RepositoryProvider> providerMap = createProviderMap();
for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
if (providerMap.containsKey(repositoryType)) {
try {
RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
repositoryGroupMap.put(repo.getId(), repo);
} catch (Exception e) {
log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
}
}
}
return repositoryGroupMap;
} catch (Throwable e) {
log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
return Collections.emptyMap();
}
}
private RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException {
RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
repositoryGroup.registerEventHandler(RepositoryEvent.ANY, this);
updateRepositoryReferences(provider, repositoryGroup, config);
return repositoryGroup;
}
private void updateRepositoryReferences(RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
if (group instanceof EditableRepositoryGroup ) {
EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
eGroup.setRepositories(configuration.getRepositories().stream().map(r -> getManagedRepository(r)).collect(Collectors.toList()));
}
}
private ArchivaConfiguration getArchivaConfiguration() {
return this.archivaConfiguration;
}
/**
* Returns all repositories that are registered. There is no defined order of the returned repositories.
@ -438,7 +415,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public Collection<RepositoryGroup> getRepositoryGroups( ) {
rwLock.readLock().lock();
try {
return uRepositoryGroups.values();
return groupHandler.getRepositoryGroups( );
} finally {
rwLock.readLock().unlock();
}
@ -462,8 +439,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
} else if (remoteRepositories.containsKey(repoId)) {
log.debug("Remote repo");
return remoteRepositories.get(repoId);
} else if (repositoryGroups.containsKey(repoId)) {
return repositoryGroups.get(repoId);
} else if (groupHandler.hasRepositoryGroup(repoId)) {
return groupHandler.getRepositoryGroup(repoId);
} else {
return null;
}
@ -510,23 +487,14 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public RepositoryGroup getRepositoryGroup( String groupId ) {
rwLock.readLock().lock();
try {
return repositoryGroups.get(groupId);
return groupHandler.getRepositoryGroup(groupId);
} finally {
rwLock.readLock().unlock();
}
}
/*
* The <code>ignoreConfigEvents</code> works only for synchronized configuration events.
* If the configuration throws async events, we cannot know, if the event is caused by this instance or another thread.
*/
private void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
ignoreConfigEvents = true;
try {
getArchivaConfiguration().save(configuration);
} finally {
ignoreConfigEvents = false;
}
protected void saveConfiguration(Configuration configuration) throws IndeterminateConfigurationException, RegistryException {
configurationHandler.save(configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
}
/**
@ -552,7 +520,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
RepositoryProvider provider = getProvider(managedRepository.getType());
ManagedRepositoryConfiguration newCfg = provider.getManagedConfiguration(managedRepository);
Configuration configuration = getArchivaConfiguration().getConfiguration();
Configuration configuration = configurationHandler.getBaseConfiguration();
updateRepositoryReferences(provider, managedRepository, newCfg, configuration);
ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(id);
if (oldCfg != null) {
@ -595,7 +563,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
try {
final String id = managedRepositoryConfiguration.getId();
final RepositoryType repositoryType = RepositoryType.valueOf(managedRepositoryConfiguration.getType());
Configuration configuration = getArchivaConfiguration().getConfiguration();
Configuration configuration = configurationHandler.getBaseConfiguration();
ManagedRepository repo = managedRepositories.get(id);
ManagedRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getManagedConfiguration(repo) : null;
repo = putRepository(managedRepositoryConfiguration, configuration);
@ -670,33 +638,10 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
rwLock.writeLock().lock();
try {
final String id = repositoryGroup.getId();
RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
try {
if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
originRepoGroup.close();
}
RepositoryProvider provider = getProvider(repositoryGroup.getType());
RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
Configuration configuration = getArchivaConfiguration().getConfiguration();
updateRepositoryReferences(provider, repositoryGroup, newCfg);
RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
if (oldCfg != null) {
configuration.removeRepositoryGroup(oldCfg);
}
configuration.addRepositoryGroup(newCfg);
saveConfiguration(configuration);
return repositoryGroup;
} catch (Exception e) {
// Rollback
if (originRepoGroup != null) {
repositoryGroups.put(id, originRepoGroup);
} else {
repositoryGroups.remove(id);
}
log.error("Exception during configuration update {}", e.getMessage(), e);
throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
if (this.groupHandler==null) {
throw new RepositoryException( "Fatal error. RepositoryGroupHandler not registered!" );
}
return this.groupHandler.putRepositoryGroup( repositoryGroup );
} finally {
rwLock.writeLock().unlock();
}
@ -714,22 +659,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
rwLock.writeLock().lock();
try {
final String id = repositoryGroupConfiguration.getId();
final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
Configuration configuration = getArchivaConfiguration().getConfiguration();
RepositoryGroup repo = repositoryGroups.get(id);
RepositoryGroupConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
try {
saveConfiguration(configuration);
} catch (IndeterminateConfigurationException | RegistryException e) {
if (oldCfg != null) {
getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
}
log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
}
return repo;
return groupHandler.putRepositoryGroup( repositoryGroupConfiguration );
} finally {
rwLock.writeLock().unlock();
}
@ -749,41 +679,12 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
rwLock.writeLock().lock();
try {
final String id = repositoryGroupConfiguration.getId();
final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
RepositoryGroup repo;
setRepositoryGroupDefaults(repositoryGroupConfiguration);
if (repositoryGroups.containsKey(id)) {
repo = repositoryGroups.get(id);
if (repo instanceof EditableRepositoryGroup) {
getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
} else {
throw new RepositoryException("The repository is not editable " + id);
}
} else {
repo = getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
repositoryGroups.put(id, repo);
}
updateRepositoryReferences(getProvider(repoType), repo, repositoryGroupConfiguration);
replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
return repo;
return groupHandler.putRepositoryGroup( repositoryGroupConfiguration, configuration );
} finally {
rwLock.writeLock().unlock();
}
}
private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
if (StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
}
if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
repositoryGroupConfiguration.setMergedIndexTtl(300);
}
if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
}
}
private void replaceOrAddRepositoryConfig(ManagedRepositoryConfiguration managedRepositoryConfiguration, Configuration configuration) {
if (configuration != null) {
ManagedRepositoryConfiguration oldCfg = configuration.findManagedRepositoryById(managedRepositoryConfiguration.getId());
@ -874,7 +775,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
public RemoteRepository putRepository( RemoteRepository remoteRepository ) throws RepositoryException {
rwLock.writeLock().lock();
try {
Configuration configuration = getArchivaConfiguration().getConfiguration();
Configuration configuration = configurationHandler.getBaseConfiguration();
try {
RemoteRepository repo = putRepository(remoteRepository, configuration);
saveConfiguration(configuration);
@ -902,7 +803,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
try {
final String id = remoteRepositoryConfiguration.getId();
final RepositoryType repositoryType = RepositoryType.valueOf(remoteRepositoryConfiguration.getType());
Configuration configuration = getArchivaConfiguration().getConfiguration();
Configuration configuration = configurationHandler.getBaseConfiguration();
RemoteRepository repo = remoteRepositories.get(id);
RemoteRepositoryConfiguration oldCfg = repo != null ? getProvider(repositoryType).getRemoteConfiguration(repo) : null;
repo = putRepository(remoteRepositoryConfiguration, configuration);
@ -1012,8 +913,8 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
repo = managedRepositories.remove(id);
if (repo != null) {
repo.close();
removeRepositoryFromGroups(repo);
Configuration configuration = getArchivaConfiguration().getConfiguration();
this.groupHandler.removeRepositoryFromGroups(repo);
Configuration configuration = configurationHandler.getBaseConfiguration();
ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
if (cfg != null) {
configuration.removeManagedRepository(cfg);
@ -1032,12 +933,6 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
}
}
private void removeRepositoryFromGroups(ManagedRepository repo) {
if (repo != null) {
repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository).
map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
}
}
@Override
public void removeRepository( ManagedRepository managedRepository, Configuration configuration ) throws RepositoryException {
@ -1052,7 +947,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
repo = managedRepositories.remove(id);
if (repo != null) {
repo.close();
removeRepositoryFromGroups(repo);
this.groupHandler.removeRepositoryFromGroups(repo);
ManagedRepositoryConfiguration cfg = configuration.findManagedRepositoryById(id);
if (cfg != null) {
configuration.removeManagedRepository(cfg);
@ -1080,26 +975,10 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
return;
}
final String id = repositoryGroup.getId();
RepositoryGroup repo = getRepositoryGroup(id);
if (repo != null) {
if (groupHandler.hasRepositoryGroup( id )) {
rwLock.writeLock().lock();
try {
repo = repositoryGroups.remove(id);
if (repo != null) {
repo.close();
Configuration configuration = getArchivaConfiguration().getConfiguration();
RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
if (cfg != null) {
configuration.removeRepositoryGroup(cfg);
}
saveConfiguration(configuration);
}
} catch (RegistryException | IndeterminateConfigurationException e) {
// Rollback
log.error("Could not save config after repository removal: {}", e.getMessage(), e);
repositoryGroups.put(repo.getId(), repo);
throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
groupHandler.removeRepositoryGroup( id );
} finally {
rwLock.writeLock().unlock();
}
@ -1112,23 +991,14 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
return;
}
final String id = repositoryGroup.getId();
RepositoryGroup repo = getRepositoryGroup(id);
if (repo != null) {
if (groupHandler.hasRepositoryGroup( id )) {
rwLock.writeLock().lock();
try {
repo = repositoryGroups.remove(id);
if (repo != null) {
repo.close();
RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
if (cfg != null) {
configuration.removeRepositoryGroup(cfg);
}
}
groupHandler.removeRepositoryGroup( id, configuration );
} finally {
rwLock.writeLock().unlock();
}
}
}
private void doRemoveRepo(RemoteRepository repo, Configuration configuration) {
@ -1164,7 +1034,7 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
try {
repo = remoteRepositories.remove(id);
if (repo != null) {
Configuration configuration = getArchivaConfiguration().getConfiguration();
Configuration configuration = configurationHandler.getBaseConfiguration();
doRemoveRepo(repo, configuration);
saveConfiguration(configuration);
}
@ -1292,8 +1162,9 @@ public class ArchivaRepositoryRegistry implements ConfigurationListener, EventHa
@Override
public void configurationEvent(ConfigurationEvent event) {
// Note: the ignoreConfigEvents flag does not work, if the config events are asynchronous.
if (!ignoreConfigEvents) {
// We ignore the event, if the save was triggered by ourself
if ( !ConfigurationHandler.REGISTRY_EVENT_TAG.equals( event.getTag( ) ) )
{
reload();
}
}

View File

@ -0,0 +1,71 @@
package org.apache.archiva.repository.base;
/*
* 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.components.registry.RegistryException;
import org.apache.archiva.configuration.ArchivaConfiguration;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.ConfigurationListener;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.springframework.stereotype.Service;
/**
* This is just a simple wrapper to access the archiva configuration used by the registry and associated classes
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
@Service("configurationHandler#default")
public class ConfigurationHandler
{
public static final String REGISTRY_EVENT_TAG = "repositoryRegistry";
private ArchivaConfiguration archivaConfiguration;
public ConfigurationHandler( ArchivaConfiguration archivaConfiguration ) {
this.archivaConfiguration = archivaConfiguration;
}
public void addListener( ConfigurationListener listener ) {
this.archivaConfiguration.addListener( listener );
}
public ArchivaConfiguration getArchivaConfiguration( )
{
return archivaConfiguration;
}
public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
{
this.archivaConfiguration = archivaConfiguration;
}
public Configuration getBaseConfiguration() {
return archivaConfiguration.getConfiguration( );
}
public void save(Configuration configuration, String eventTag) throws IndeterminateConfigurationException, RegistryException
{
archivaConfiguration.save( configuration, eventTag);
}
public void save(Configuration configuration) throws IndeterminateConfigurationException, RegistryException
{
archivaConfiguration.save( configuration, "" );
}
}

View File

@ -0,0 +1,328 @@
package org.apache.archiva.repository.base;
/*
* 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.components.registry.RegistryException;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
import org.apache.archiva.repository.EditableRepository;
import org.apache.archiva.repository.EditableRepositoryGroup;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.RepositoryGroup;
import org.apache.archiva.repository.RepositoryProvider;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.event.RepositoryEvent;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Named;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
/**
* This class manages repository groups for the RepositoryRegistry.
* It is tightly coupled with the {@link ArchivaRepositoryRegistry}.
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
@Service("repositoryGroupHandler#default")
public class RepositoryGroupHandler
{
private static final Logger log = LoggerFactory.getLogger(RepositoryGroupHandler.class);
private final ArchivaRepositoryRegistry repositoryRegistry;
private final ConfigurationHandler configurationHandler;
private final MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler;
private Map<String, RepositoryGroup> repositoryGroups = new HashMap<>();
/**
* Creates a new instance. All dependencies are injected on the constructor.
* @param repositoryRegistry the registry. To avoid circular dependencies via DI, this class registers itself on the registry.
* @param configurationHandler the configuration handler is used to retrieve and save configuration.
* @param mergedRemoteIndexesScheduler the index scheduler is used for merging the indexes from all group members
*/
public RepositoryGroupHandler( ArchivaRepositoryRegistry repositoryRegistry,
ConfigurationHandler configurationHandler,
@Named("mergedRemoteIndexesScheduler#default") MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler) {
this.configurationHandler = configurationHandler;
this.mergedRemoteIndexesScheduler = mergedRemoteIndexesScheduler;
this.repositoryRegistry = repositoryRegistry;
}
@PostConstruct
private void init() {
log.debug( "Initializing repository group handler " + repositoryRegistry.toString( ) );
// We are registering this class on the registry. This is necessary to avoid circular dependencies via injection.
this.repositoryRegistry.registerGroupHandler( this );
}
public void initializeFromConfig() {
this.repositoryGroups.clear();
this.repositoryGroups.putAll( getRepositorGroupsFromConfig( ) );
}
public Map<String, RepositoryGroup> getRepositorGroupsFromConfig() {
try {
List<RepositoryGroupConfiguration> repositoryGroupConfigurations =
this.configurationHandler.getBaseConfiguration().getRepositoryGroups();
if (repositoryGroupConfigurations == null) {
return Collections.emptyMap();
}
Map<String, RepositoryGroup> repositoryGroupMap = new LinkedHashMap<>(repositoryGroupConfigurations.size());
Map<RepositoryType, RepositoryProvider> providerMap = repositoryRegistry.getRepositoryProviderMap();
for (RepositoryGroupConfiguration repoConfig : repositoryGroupConfigurations) {
RepositoryType repositoryType = RepositoryType.valueOf(repoConfig.getType());
if (providerMap.containsKey(repositoryType)) {
try {
RepositoryGroup repo = createNewRepositoryGroup(providerMap.get(repositoryType), repoConfig);
repositoryGroupMap.put(repo.getId(), repo);
} catch (Exception e) {
log.error("Could not create repository group {}: {}", repoConfig.getId(), e.getMessage(), e);
}
}
}
return repositoryGroupMap;
} catch (Throwable e) {
log.error("Could not initialize repositories from config: {}", e.getMessage(), e);
return Collections.emptyMap();
}
}
public RepositoryGroup createNewRepositoryGroup(RepositoryProvider provider, RepositoryGroupConfiguration config) throws RepositoryException
{
RepositoryGroup repositoryGroup = provider.createRepositoryGroup(config);
repositoryGroup.registerEventHandler( RepositoryEvent.ANY, repositoryRegistry);
updateRepositoryReferences(provider, repositoryGroup, config);
return repositoryGroup;
}
public void updateRepositoryReferences( RepositoryProvider provider, RepositoryGroup group, RepositoryGroupConfiguration configuration) {
if (group instanceof EditableRepositoryGroup ) {
EditableRepositoryGroup eGroup = (EditableRepositoryGroup) group;
eGroup.setRepositories(configuration.getRepositories().stream()
.map(r -> repositoryRegistry.getManagedRepository(r)).collect( Collectors.toList()));
}
}
/**
* Adds a new repository group to the current list, or replaces the repository group definition with
* the same id, if it exists already.
* The change is saved to the configuration immediately.
*
* @param repositoryGroup the new repository group.
* @throws RepositoryException if the new repository group could not be saved to the configuration.
*/
public RepositoryGroup putRepositoryGroup( RepositoryGroup repositoryGroup ) throws RepositoryException {
final String id = repositoryGroup.getId();
RepositoryGroup originRepoGroup = repositoryGroups.put(id, repositoryGroup);
try {
if (originRepoGroup != null && originRepoGroup != repositoryGroup) {
originRepoGroup.close();
}
RepositoryProvider provider = repositoryRegistry.getProvider( repositoryGroup.getType());
RepositoryGroupConfiguration newCfg = provider.getRepositoryGroupConfiguration(repositoryGroup);
Configuration configuration = this.configurationHandler.getBaseConfiguration();
updateRepositoryReferences(provider, repositoryGroup, newCfg);
RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(id);
if (oldCfg != null) {
configuration.removeRepositoryGroup(oldCfg);
}
configuration.addRepositoryGroup(newCfg);
repositoryRegistry.saveConfiguration(configuration);
return repositoryGroup;
} catch (Exception e) {
// Rollback
if (originRepoGroup != null) {
repositoryGroups.put(id, originRepoGroup);
} else {
repositoryGroups.remove(id);
}
log.error("Exception during configuration update {}", e.getMessage(), e);
throw new RepositoryException("Could not save the configuration" + (e.getMessage() == null ? "" : ": " + e.getMessage()));
}
}
/**
* Adds a new repository group or updates the repository with the same id, if it exists already.
* The configuration is saved immediately.
*
* @param repositoryGroupConfiguration the repository configuration
* @return the updated or created repository
* @throws RepositoryException if an error occurs, or the configuration is not valid.
*/
public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration ) throws RepositoryException {
final String id = repositoryGroupConfiguration.getId();
final RepositoryType repositoryType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
Configuration configuration = this.configurationHandler.getBaseConfiguration();
RepositoryGroup repo = repositoryGroups.get(id);
RepositoryGroupConfiguration oldCfg = repo != null ? repositoryRegistry.getProvider(repositoryType).getRepositoryGroupConfiguration(repo) : null;
repo = putRepositoryGroup(repositoryGroupConfiguration, configuration);
try {
repositoryRegistry.saveConfiguration(configuration);
} catch ( IndeterminateConfigurationException | RegistryException e) {
if (oldCfg != null) {
repositoryRegistry.getProvider(repositoryType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, oldCfg);
}
log.error("Could not save the configuration for repository group {}: {}", id, e.getMessage(), e);
throw new RepositoryException("Could not save the configuration for repository group " + id + ": " + e.getMessage());
}
return repo;
}
public RepositoryGroup putRepositoryGroup( RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration ) throws RepositoryException {
final String id = repositoryGroupConfiguration.getId();
final RepositoryType repoType = RepositoryType.valueOf(repositoryGroupConfiguration.getType());
RepositoryGroup repo;
setRepositoryGroupDefaults(repositoryGroupConfiguration);
if (repositoryGroups.containsKey(id)) {
repo = repositoryGroups.get(id);
if (repo instanceof EditableRepositoryGroup) {
repositoryRegistry.getProvider(repoType).updateRepositoryGroupInstance((EditableRepositoryGroup) repo, repositoryGroupConfiguration);
} else {
throw new RepositoryException("The repository is not editable " + id);
}
} else {
repo = repositoryRegistry.getProvider(repoType).createRepositoryGroup(repositoryGroupConfiguration);
repositoryGroups.put(id, repo);
}
updateRepositoryReferences(repositoryRegistry.getProvider(repoType), repo, repositoryGroupConfiguration);
replaceOrAddRepositoryConfig(repositoryGroupConfiguration, configuration);
return repo;
}
private void setRepositoryGroupDefaults(RepositoryGroupConfiguration repositoryGroupConfiguration) {
if ( StringUtils.isEmpty(repositoryGroupConfiguration.getMergedIndexPath())) {
repositoryGroupConfiguration.setMergedIndexPath(DEFAULT_INDEX_PATH);
}
if (repositoryGroupConfiguration.getMergedIndexTtl() <= 0) {
repositoryGroupConfiguration.setMergedIndexTtl(300);
}
if (StringUtils.isEmpty(repositoryGroupConfiguration.getCronExpression())) {
repositoryGroupConfiguration.setCronExpression("0 0 03 ? * MON");
}
}
private void replaceOrAddRepositoryConfig(RepositoryGroupConfiguration repositoryGroupConfiguration, Configuration configuration) {
RepositoryGroupConfiguration oldCfg = configuration.findRepositoryGroupById(repositoryGroupConfiguration.getId());
if (oldCfg != null) {
configuration.removeRepositoryGroup(oldCfg);
}
configuration.addRepositoryGroup(repositoryGroupConfiguration);
}
public void removeRepositoryFromGroups( ManagedRepository repo) {
if (repo != null) {
repositoryGroups.values().stream().filter(repoGroup -> repoGroup instanceof EditableRepository ).
map(repoGroup -> (EditableRepositoryGroup) repoGroup).forEach(repoGroup -> repoGroup.removeRepository(repo));
}
}
/**
* Removes a repository group from the registry and configuration, if it exists.
* The change is saved to the configuration immediately.
*
* @param id the id of the repository group to remove
* @throws RepositoryException if a error occurs during configuration save
*/
public void removeRepositoryGroup( final String id ) throws RepositoryException {
RepositoryGroup repo = getRepositoryGroup(id);
if (repo != null) {
try {
repo = repositoryGroups.remove(id);
if (repo != null) {
repo.close();
Configuration configuration = this.configurationHandler.getBaseConfiguration();
RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
if (cfg != null) {
configuration.removeRepositoryGroup(cfg);
}
this.configurationHandler.save(configuration, ConfigurationHandler.REGISTRY_EVENT_TAG );
}
} catch (RegistryException | IndeterminateConfigurationException e) {
// Rollback
log.error("Could not save config after repository removal: {}", e.getMessage(), e);
repositoryGroups.put(repo.getId(), repo);
throw new RepositoryException("Could not save configuration after repository removal: " + e.getMessage());
}
}
}
public void removeRepositoryGroup( String id, Configuration configuration ) throws RepositoryException {
RepositoryGroup repo = repositoryGroups.get(id);
if (repo != null) {
repo = repositoryGroups.remove(id);
if (repo != null) {
repo.close();
RepositoryGroupConfiguration cfg = configuration.findRepositoryGroupById(id);
if (cfg != null) {
configuration.removeRepositoryGroup(cfg);
}
}
}
}
public RepositoryGroup getRepositoryGroup( String groupId ) {
return repositoryGroups.get(groupId);
}
public Collection<RepositoryGroup> getRepositoryGroups() {
return repositoryGroups.values( );
}
public boolean hasRepositoryGroup(String id) {
return repositoryGroups.containsKey( id );
}
@PreDestroy
private void destroy() {
this.close( );
}
public void close() {
for (RepositoryGroup group : repositoryGroups.values()) {
try
{
group.close( );
} catch (Throwable e) {
log.error( "Could not close repository group {}: {}", group.getId( ), e.getMessage( ) );
}
}
this.repositoryGroups.clear();
}
}

View File

@ -66,6 +66,10 @@ public class ArchivaRepositoryRegistryTest
@Inject
ArchivaConfiguration archivaConfiguration;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
private static final Path userCfg = Paths.get(System.getProperty( "user.home" ), ".m2/archiva.xml");
private static Path cfgCopy;

View File

@ -24,6 +24,7 @@ import org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.indexer.IndexCreationFailedException;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.repository.features.RemoteIndexFeature;
import org.apache.archiva.repository.maven.MavenManagedRepository;
@ -61,6 +62,9 @@ public class MavenIndexManagerTest {
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler groupHandler;
private Path indexPath;
private MavenManagedRepository repository;

View File

@ -31,6 +31,8 @@ import org.apache.archiva.indexer.search.SearchResults;
import org.apache.archiva.proxy.ProxyRegistry;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.base.ConfigurationHandler;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
import org.apache.commons.lang3.SystemUtils;
@ -92,6 +94,9 @@ public abstract class AbstractMavenRepositorySearch
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Inject
ProxyRegistry proxyRegistry;
@ -143,7 +148,7 @@ public abstract class AbstractMavenRepositorySearch
archivaConfig.addListener( EasyMock.anyObject( ConfigurationListener.class ) );
EasyMock.expect( archivaConfig.getDefaultLocale() ).andReturn( Locale.getDefault( ) ).anyTimes();
EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
archivaConfig.save(EasyMock.anyObject(Configuration.class));
archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
EasyMock.expectLastCall().anyTimes();
archivaConfigControl.replay();
repositoryRegistry.reload();
@ -158,7 +163,7 @@ public abstract class AbstractMavenRepositorySearch
archivaConfigControl.reset();
EasyMock.expect( archivaConfig.getDefaultLocale() ).andReturn( Locale.getDefault( ) ).anyTimes();
EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
archivaConfig.save(EasyMock.anyObject(Configuration.class));
archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
EasyMock.expectLastCall().anyTimes();
archivaConfigControl.replay();
repositoryRegistry.removeRepository(TEST_REPO_1);
@ -259,7 +264,7 @@ public abstract class AbstractMavenRepositorySearch
archivaConfigControl.reset();
archivaConfig.addListener( EasyMock.anyObject( ConfigurationListener.class ) );
EasyMock.expect( archivaConfig.getConfiguration() ).andReturn(config).anyTimes();
archivaConfig.save(EasyMock.anyObject(Configuration.class));
archivaConfig.save(EasyMock.anyObject(Configuration.class), EasyMock.anyString());
EasyMock.expectLastCall().anyTimes();
archivaConfigControl.replay();
repositoryRegistry.reload();

View File

@ -23,6 +23,7 @@ import org.apache.archiva.indexer.search.SearchFields;
import org.apache.archiva.indexer.search.SearchResultHit;
import org.apache.archiva.indexer.search.SearchResults;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Test;
@ -43,6 +44,9 @@ public class MavenRepositorySearchOSGITest
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@After
@Override
public void tearDown() throws Exception {

View File

@ -24,6 +24,7 @@ import org.apache.archiva.indexer.search.SearchResultLimits;
import org.apache.archiva.indexer.search.SearchResults;
import org.apache.archiva.indexer.util.SearchUtil;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
import org.junit.After;
import org.junit.Test;
@ -31,6 +32,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import javax.inject.Inject;
import java.util.Arrays;
/**
@ -42,9 +44,12 @@ public class MavenRepositorySearchPaginateTest
extends TestCase
{
@Autowired
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@After
public void endTests() {
assert repositoryRegistry!=null;

View File

@ -111,6 +111,12 @@ public class MockConfiguration
/* do nothing */
}
@Override
public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
{
// do nothing
}
public void triggerChange( String name, String value )
{
for ( org.apache.archiva.components.registry.RegistryListener listener : registryListeners )

View File

@ -27,6 +27,7 @@ import org.apache.archiva.configuration.ArchivaRuntimeConfiguration;
import org.apache.archiva.configuration.Configuration;
import org.apache.archiva.configuration.ConfigurationListener;
import org.apache.archiva.configuration.FileType;
import org.apache.archiva.configuration.IndeterminateConfigurationException;
import org.apache.archiva.configuration.RepositoryScanningConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.easymock.IMocksControl;
@ -109,6 +110,12 @@ public class MockConfiguration
/* do nothing */
}
@Override
public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
{
// do nothing
}
public void triggerChange( String name, String value )
{
for(RegistryListener listener: registryListeners)

View File

@ -22,6 +22,7 @@ import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.Repository;
import org.apache.archiva.repository.RepositoryException;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.ConfigurationHandler;
import java.util.Map;
import java.util.TreeMap;
@ -31,6 +32,11 @@ public class RepositoryRegistryMock extends ArchivaRepositoryRegistry
private Map<String, ManagedRepository> managedRepositories = new TreeMap<>();
public RepositoryRegistryMock( ConfigurationHandler configurationHandler )
{
super( configurationHandler );
}
@Override
public ManagedRepository putRepository(ManagedRepository managedRepository) throws RepositoryException
{

View File

@ -56,6 +56,12 @@ public class StubConfiguration
this.configuration = configuration;
}
@Override
public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
{
this.configuration = configuration;
}
@Override
public boolean isDefaulted()
{

View File

@ -51,6 +51,12 @@ public class TestConfiguration
this.configuration = configuration;
}
@Override
public void save( Configuration configuration, String eventTag ) throws RegistryException, IndeterminateConfigurationException
{
this.configuration = configuration;
}
@Override
public boolean isDefaulted()
{

View File

@ -26,6 +26,7 @@ import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.base.BasicManagedRepository;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.ReleaseScheme;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
@ -73,6 +74,9 @@ public class ArchivaIndexingTaskExecutorTest
@Inject
ArchivaRepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Inject
private IndexUpdater indexUpdater;

View File

@ -29,6 +29,7 @@ import org.apache.archiva.mock.MockRepositorySessionFactory;
import org.apache.archiva.components.taskqueue.execution.TaskExecutor;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.scheduler.repository.model.RepositoryTask;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
import org.junit.After;
@ -65,6 +66,9 @@ public abstract class AbstractArchivaRepositoryScanningTaskExecutorTest
@Inject
RepositoryRegistry repositoryRegistry;
@Inject
RepositoryGroupHandler groupHandler;
@Inject
@Named( value = "taskExecutor#test-repository-scanning" )
protected TaskExecutor<RepositoryTask> taskExecutor;

View File

@ -55,20 +55,20 @@ import static org.apache.archiva.rest.api.services.v2.RestConfiguration.DEFAULT_
* @since 3.0
*/
@Path( "/repository_groups" )
@Schema( name="RepositoryGroups", description = "Managing of repository groups or virtual repositories")
@Schema( name = "RepositoryGroups", description = "Managing of repository groups or virtual repositories" )
public interface RepositoryGroupService
{
@Path( "" )
@GET
@Produces( { APPLICATION_JSON } )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Returns all repository group entries.",
parameters = {
@Parameter(name = "q", description = "Search term"),
@Parameter(name = "offset", description = "The offset of the first element returned"),
@Parameter(name = "limit", description = "Maximum number of items to return in the response"),
@Parameter(name = "orderBy", description = "List of attribute used for sorting (key, value)"),
@Parameter(name = "order", description = "The sort order. Either ascending (asc) or descending (desc)")
@Parameter( name = "q", description = "Search term" ),
@Parameter( name = "offset", description = "The offset of the first element returned" ),
@Parameter( name = "limit", description = "Maximum number of items to return in the response" ),
@Parameter( name = "orderBy", description = "List of attribute used for sorting (key, value)" ),
@Parameter( name = "order", description = "The sort order. Either ascending (asc) or descending (desc)" )
},
security = {
@SecurityRequirement(
@ -78,22 +78,22 @@ public interface RepositoryGroupService
responses = {
@ApiResponse( responseCode = "200",
description = "If the list could be returned",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class))
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = PagedResult.class ) )
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
PagedResult<RepositoryGroup> getRepositoriesGroups(@QueryParam("q") @DefaultValue( "" ) String searchTerm,
@QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
@QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
@QueryParam( "orderBy") @DefaultValue( "id" ) List<String> orderBy,
@QueryParam("order") @DefaultValue( "asc" ) String order)
PagedResult<RepositoryGroup> getRepositoriesGroups( @QueryParam( "q" ) @DefaultValue( "" ) String searchTerm,
@QueryParam( "offset" ) @DefaultValue( "0" ) Integer offset,
@QueryParam( "limit" ) @DefaultValue( value = DEFAULT_PAGE_LIMIT ) Integer limit,
@QueryParam( "orderBy" ) @DefaultValue( "id" ) List<String> orderBy,
@QueryParam( "order" ) @DefaultValue( "asc" ) String order )
throws ArchivaRestServiceException;
@Path( "{repositoryGroupId}" )
@GET
@Produces( { APPLICATION_JSON } )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Returns a single repository group configuration.",
security = {
@ -104,12 +104,12 @@ public interface RepositoryGroupService
responses = {
@ApiResponse( responseCode = "200",
description = "If the configuration is returned",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "404", description = "The repository group with the given id does not exist",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
RepositoryGroup getRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
@ -117,14 +117,14 @@ public interface RepositoryGroupService
@Path( "" )
@POST
@Consumes( { APPLICATION_JSON } )
@Produces( { APPLICATION_JSON } )
@Consumes( {APPLICATION_JSON} )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Creates a new group entry.",
requestBody =
@RequestBody(required = true, description = "The configuration of the repository group.",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
)
@RequestBody( required = true, description = "The configuration of the repository group.",
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
)
,
security = {
@SecurityRequirement(
@ -134,17 +134,17 @@ public interface RepositoryGroupService
responses = {
@ApiResponse( responseCode = "201",
description = "If the list could be returned",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
),
@ApiResponse( responseCode = "303", description = "The repository group exists already",
headers = {
@Header( name="Location", description = "The URL of existing group", schema = @Schema(type="string"))
@Header( name = "Location", description = "The URL of existing group", schema = @Schema( type = "string" ) )
}
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "422", description = "The body data is not valid",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup )
@ -152,13 +152,13 @@ public interface RepositoryGroupService
@Path( "{repositoryGroupId}" )
@PUT
@Consumes( { APPLICATION_JSON } )
@Produces( { APPLICATION_JSON } )
@Consumes( {APPLICATION_JSON} )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Returns all repository group entries.",
requestBody =
@RequestBody(required = true, description = "The configuration of the repository group.",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
@RequestBody( required = true, description = "The configuration of the repository group.",
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
)
,
security = {
@ -169,14 +169,14 @@ public interface RepositoryGroupService
responses = {
@ApiResponse( responseCode = "200",
description = "If the group is returned",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = RepositoryGroup.class))
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = RepositoryGroup.class ) )
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "422", description = "The body data is not valid",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) )
}
)
RepositoryGroup updateRepositoryGroup( @PathParam( "repositoryGroupId" ) String groupId, RepositoryGroup repositoryGroup )
@ -184,7 +184,7 @@ public interface RepositoryGroupService
@Path( "{repositoryGroupId}" )
@DELETE
@Produces( { APPLICATION_JSON } )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Deletes the repository group entry with the given id.",
security = {
@ -197,9 +197,9 @@ public interface RepositoryGroupService
description = "If the group was deleted"
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
Response deleteRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
@ -207,7 +207,7 @@ public interface RepositoryGroupService
@Path( "{repositoryGroupId}/repositories/{repositoryId}" )
@PUT
@Produces( { APPLICATION_JSON } )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Adds the repository with the given id to the repository group.",
security = {
@ -220,18 +220,18 @@ public interface RepositoryGroupService
description = "If the repository was added or if it was already part of the group"
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
RepositoryGroup addRepositoryToGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
@PathParam( "repositoryId" ) String repositoryId )
@PathParam( "repositoryId" ) String repositoryId )
throws ArchivaRestServiceException;
@Path( "{repositoryGroupId}/repositories/{repositoryId}" )
@DELETE
@Produces( { APPLICATION_JSON } )
@Produces( {APPLICATION_JSON} )
@RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
@Operation( summary = "Removes the repository with the given id from the repository group.",
security = {
@ -244,13 +244,13 @@ public interface RepositoryGroupService
description = "If the repository was removed."
),
@ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to delete the group",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
@ApiResponse( responseCode = "404", description = "The group with the given id does not exist, or the repository was not part of the group.",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
content = @Content( mediaType = APPLICATION_JSON, schema = @Schema( implementation = ArchivaRestError.class ) ) ),
}
)
RepositoryGroup deleteRepositoryFromGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
@PathParam( "repositoryId" ) String repositoryId )
@PathParam( "repositoryId" ) String repositoryId )
throws ArchivaRestServiceException;

View File

@ -1,4 +1,4 @@
package org.apache.archiva.rest.api.services.v2;
package org.apache.archiva.rest.api.services.v2.maven;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@ -31,6 +31,8 @@ import org.apache.archiva.redback.authorization.RedbackAuthorization;
import org.apache.archiva.rest.api.model.v2.FileInfo;
import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
import org.apache.archiva.rest.api.services.v2.ArchivaRestError;
import org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException;
import org.apache.archiva.security.common.ArchivaRoleConstants;
import javax.ws.rs.Consumes;
@ -51,6 +53,8 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.apache.archiva.rest.api.services.v2.RestConfiguration.DEFAULT_PAGE_LIMIT;
/**
* Service interface for managing managed maven repositories
*
* @author Martin Stockhammer <martin_s@apache.org>
* @since 3.0
*/

View File

@ -47,6 +47,7 @@ import org.apache.archiva.redback.system.SecuritySystem;
import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.UserManagerException;
import org.apache.archiva.redback.users.UserNotFoundException;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.repository.content.BaseRepositoryContentLayout;
import org.apache.archiva.repository.content.ContentNotFoundException;
import org.apache.archiva.repository.content.LayoutException;
@ -128,6 +129,10 @@ public class DefaultRepositoriesService
@Inject
private RepositoryRegistry repositoryRegistry;
@SuppressWarnings( "unused" )
@Inject
private RepositoryGroupHandler repositoryGroupHandler;
@Inject
private SecuritySystem securitySystem;

View File

@ -0,0 +1,40 @@
package org.apache.archiva.rest.services.utils;
/*
* 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.AuditInformation;
import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
import org.apache.archiva.redback.rest.services.RedbackRequestInformation;
import org.apache.archiva.redback.users.User;
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
public class AuditHelper
{
private static final AuditInformation NULL_RESULT = new AuditInformation( null, null );
public static AuditInformation getAuditData() {
RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
if (redbackRequestInformation==null) {
return NULL_RESULT;
} else
{
return new AuditInformation( redbackRequestInformation.getUser( ), redbackRequestInformation.getRemoteAddr( ) );
}
}
}

View File

@ -35,35 +35,28 @@ import org.apache.archiva.redback.users.UserNotFoundException;
import org.apache.archiva.repository.ManagedRepository;
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.RepositoryType;
import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.LayoutException;
import org.apache.archiva.repository.storage.fs.FilesystemStorage;
import org.apache.archiva.repository.storage.fs.FsStorageUtil;
import org.apache.archiva.repository.storage.util.StorageUtil;
import org.apache.archiva.rest.api.model.v2.Artifact;
import org.apache.archiva.rest.api.model.v2.FileInfo;
import org.apache.archiva.rest.api.model.v2.MavenManagedRepository;
import org.apache.archiva.rest.api.model.v2.MavenManagedRepositoryUpdate;
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.apache.archiva.rest.api.services.v2.maven.MavenManagedRepositoryService;
import org.apache.archiva.security.common.ArchivaRoleConstants;
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.servlet.http.HttpServletResponse;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Comparator;
@ -103,7 +96,9 @@ public class DefaultMavenManagedRepositoryService implements MavenManagedReposit
private RepositoryRegistry repositoryRegistry;
private SecuritySystem securitySystem;
public DefaultMavenManagedRepositoryService( SecuritySystem securitySystem, RepositoryRegistry repositoryRegistry, ManagedRepositoryAdmin managedRepositoryAdmin )
public DefaultMavenManagedRepositoryService( SecuritySystem securitySystem,
RepositoryRegistry repositoryRegistry,
ManagedRepositoryAdmin managedRepositoryAdmin )
{
this.securitySystem = securitySystem;
this.repositoryRegistry = repositoryRegistry;
@ -113,8 +108,16 @@ public class DefaultMavenManagedRepositoryService implements MavenManagedReposit
protected AuditInformation getAuditInformation( )
{
RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser( );
String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr( );
User user;
String remoteAddr;
if (redbackRequestInformation==null) {
user = null;
remoteAddr = null;
} else
{
user = redbackRequestInformation.getUser( );
remoteAddr = redbackRequestInformation.getRemoteAddr( );
}
return new AuditInformation( user, remoteAddr );
}

View File

@ -34,16 +34,12 @@ package org.apache.archiva.rest.services.v2;/*
* under the License.
*/
import org.apache.archiva.admin.model.AuditInformation;
import org.apache.archiva.admin.model.EntityExistsException;
import org.apache.archiva.admin.model.EntityNotFoundException;
import org.apache.archiva.admin.model.RepositoryAdminException;
import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
import org.apache.archiva.components.rest.model.PagedResult;
import org.apache.archiva.components.rest.util.QueryHelper;
import org.apache.archiva.redback.rest.services.RedbackAuthenticationThreadLocal;
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;
@ -54,7 +50,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
@ -65,6 +60,8 @@ import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static org.apache.archiva.rest.services.utils.AuditHelper.getAuditData;
/**
* REST V2 Implementation for repository groups.
*
@ -81,8 +78,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
@Context
UriInfo uriInfo;
@Inject
private RepositoryGroupAdmin repositoryGroupAdmin;
final private RepositoryGroupAdmin repositoryGroupAdmin;
private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryGroupService.class );
private static final QueryHelper<org.apache.archiva.admin.model.beans.RepositoryGroup> QUERY_HELPER = new QueryHelper<>( new String[]{"id"} );
@ -93,12 +89,8 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
protected AuditInformation getAuditInformation( )
{
RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get( );
User user = redbackRequestInformation == null ? null : redbackRequestInformation.getUser( );
String remoteAddr = redbackRequestInformation == null ? null : redbackRequestInformation.getRemoteAddr( );
return new AuditInformation( user, remoteAddr );
public DefaultRepositoryGroupService(RepositoryGroupAdmin repositoryGroupAdmin) {
this.repositoryGroupAdmin = repositoryGroupAdmin;
}
@Override
@ -166,7 +158,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
{
try
{
Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditInformation( ) );
Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditData() );
if ( result )
{
org.apache.archiva.admin.model.beans.RepositoryGroup newGroup = repositoryGroupAdmin.getRepositoryGroup( repositoryGroup.getId( ) );
@ -243,7 +235,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
{
updateGroup.setMergedIndexTtl( originGroup.getMergedIndexTtl( ) );
}
repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditInformation( ) );
repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditData( ) );
return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
}
catch ( EntityNotFoundException e )
@ -265,7 +257,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
Boolean deleted = repositoryGroupAdmin.deleteRepositoryGroup( repositoryGroupId, getAuditInformation( ) );
Boolean deleted = repositoryGroupAdmin.deleteRepositoryGroup( repositoryGroupId, getAuditData( ) );
if ( !deleted )
{
throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_DELETE_FAILED ) );
@ -297,7 +289,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
repositoryGroupAdmin.addRepositoryToGroup( repositoryGroupId, repositoryId, getAuditInformation( ) );
repositoryGroupAdmin.addRepositoryToGroup( repositoryGroupId, repositoryId, getAuditData( ) );
return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
}
catch ( EntityNotFoundException e )
@ -335,7 +327,7 @@ public class DefaultRepositoryGroupService implements RepositoryGroupService
}
try
{
repositoryGroupAdmin.deleteRepositoryFromGroup( repositoryGroupId, repositoryId, getAuditInformation( ) );
repositoryGroupAdmin.deleteRepositoryFromGroup( repositoryGroupId, repositoryId, getAuditData( ) );
return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId ) );
}
catch ( EntityNotFoundException e )

View File

@ -29,11 +29,8 @@
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd" default-lazy-init="true">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<!--
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>
-->
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<import resource="classpath*:META-INF/cxf/cxf.xml"/>
<import resource="classpath*:META-INF/cxf/cxf-servlet.xml"/>
<context:annotation-config/>
<context:component-scan
@ -119,6 +116,7 @@
<ref bean="v2.defaultSecurityConfigurationService" />
<ref bean="v2.repositoryGroupService#rest" />
<ref bean="v2.repositoryService#rest"/>
<ref bean="v2.managedMavenRepositoryService#rest"/>
</jaxrs:serviceBeans>
<jaxrs:features>

View File

@ -378,7 +378,7 @@ public abstract class AbstractNativeRestServices
}
else
{
log.error( "Serer is not in STARTED state!" );
log.error( "Server is not in STARTED state!" );
}
}
@ -410,15 +410,11 @@ public abstract class AbstractNativeRestServices
this.requestSpec = getRequestSpecBuilder( ).build( );
RestAssured.basePath = basePath;
RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
new Jackson2ObjectMapperFactory() {
@Override
public ObjectMapper create( Type cls, String charset) {
ObjectMapper om = new ObjectMapper().findAndRegisterModules();
om.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE );
return om;
}
( cls, charset ) -> {
ObjectMapper om = new ObjectMapper().findAndRegisterModules();
om.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE );
return om;
}
));
}

View File

@ -0,0 +1,97 @@
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.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import org.apache.archiva.components.rest.model.PagedResult;
import org.apache.archiva.components.rest.model.PropertyEntry;
import org.apache.archiva.rest.api.model.v2.BeanInformation;
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.MavenManagedRepository;
import org.apache.archiva.rest.api.services.v2.RestConfiguration;
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.Order;
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.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.OrderAnnotation.class )
@DisplayName( "Native REST tests for V2 ManagedRepositoryService" )
public class NativeMavenManagedRepositoryServiceTest extends AbstractNativeRestServices
{
@Override
protected String getServicePath( )
{
return "/repositories/maven/managed";
}
@BeforeAll
void setup( ) throws Exception
{
super.setupNative( );
}
@AfterAll
void destroy( ) throws Exception
{
super.shutdownNative( );
}
@Test
@Order( 1 )
void testGetRepositories( )
{
String token = getAdminToken( );
Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON )
.when( )
.get( "" )
.then( ).statusCode( 200 ).extract( ).response( );
JsonPath json = response.getBody( ).jsonPath( );
assertEquals( 2, json.getInt( "pagination.total_count" ) );
assertEquals( 0, json.getInt( "pagination.offset" ) );
assertEquals( Integer.valueOf( RestConfiguration.DEFAULT_PAGE_LIMIT ), json.getInt( "pagination.limit" ) );
List<MavenManagedRepository> repositories = json.getList( "data", MavenManagedRepository.class );
assertEquals( "internal", repositories.get( 0 ).getId( ) );
assertEquals( "snapshots", repositories.get( 1 ).getId( ) );
}
}

View File

@ -32,7 +32,7 @@
<context:annotation-config/>
<context:component-scan
base-package="org.apache.archiva.redback.keys,org.apache.archiva.rest.services.utils,org.apache.archiva.repository.content.maven2"/>
base-package="org.apache.archiva.redback.keys,org.apache.archiva.rest.services.utils,org.apache.archiva.repository.maven.content"/>
<bean name="scheduler" class="org.apache.archiva.components.scheduler.DefaultScheduler">
<property name="properties">

View File

@ -30,6 +30,7 @@ import org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.repository.base.ArchivaRepositoryRegistry;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
import org.apache.archiva.webdav.httpunit.MkColMethodWebRequest;
import org.apache.commons.io.FileUtils;
@ -99,6 +100,9 @@ public abstract class AbstractRepositoryServletTestCase
@Inject
protected ApplicationContext applicationContext;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
@Inject
ArchivaRepositoryRegistry repositoryRegistry;

View File

@ -34,6 +34,7 @@ import org.apache.archiva.configuration.FileTypes;
import org.apache.archiva.configuration.RepositoryGroupConfiguration;
import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.repository.maven.content.MavenContentHelper;
import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
import org.apache.archiva.proxy.ProxyRegistry;
@ -158,6 +159,10 @@ public class ArchivaDavResourceFactoryTest
@Inject
FileTypes fileTypes;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
public Path getProjectBase() {
if (this.projectBase.get()==null) {
String pathVal = System.getProperty("mvn.project.base.dir");
@ -194,8 +199,9 @@ public class ArchivaDavResourceFactoryTest
expect (archivaConfiguration.getDefaultLocale()).andReturn( Locale.getDefault() ).anyTimes();
archivaConfiguration.addListener( EasyMock.anyObject( ) );
expectLastCall().times(0, 4);
archivaConfiguration.save( config );
archivaConfiguration.save( eq(config));
expectLastCall().times( 0, 5 );
archivaConfiguration.save( eq(config), EasyMock.anyString());
expectLastCall().times( 0, 5 );
archivaConfigurationControl.replay();

View File

@ -35,6 +35,7 @@ import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.memory.SimpleUser;
import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.metadata.audit.TestAuditListener;
import org.apache.archiva.repository.base.RepositoryGroupHandler;
import org.apache.archiva.security.ServletAuthenticator;
import org.apache.archiva.security.common.ArchivaRoleConstants;
import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
@ -91,6 +92,10 @@ public class RepositoryServletSecurityTest
@Inject
protected RepositoryRegistry repositoryRegistry;
@SuppressWarnings( "unused" )
@Inject
RepositoryGroupHandler repositoryGroupHandler;
private DavSessionProvider davSessionProvider;
private IMocksControl servletAuthControl;