[MRM-1490] expose services tru rest

add some managed repo admin support

git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1159688 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Olivier Lamy 2011-08-19 17:14:32 +00:00
parent 0eec07ab1c
commit 23cceb8c62
6 changed files with 453 additions and 16 deletions

View File

@ -251,6 +251,22 @@ public class RepositoryArchivaTaskScheduler
}
}
public boolean unQueueTask( RepositoryTask task )
throws TaskQueueException
{
synchronized ( repositoryScanningQueue )
{
if ( isProcessingRepositoryTask( task ) )
{
log.info( "cannot unuqueue Repository task '{}' not already queued.", task );
return false;
}
else
{
return repositoryScanningQueue.remove( task );
}
}
}
public void configurationEvent( ConfigurationEvent event )
{
if ( event.getType() == ConfigurationEvent.SAVED )

View File

@ -41,12 +41,19 @@ public class ManagedRepository
private boolean releases = false;
private boolean blockRedeployments;
private boolean stageRepoNeeded;
private String cronExpression;
public ManagedRepository()
{
// no op
}
public ManagedRepository( String id, String name, String url, String layout, boolean snapshots, boolean releases )
public ManagedRepository( String id, String name, String url, String layout, boolean snapshots, boolean releases,
boolean blockRedeployments, boolean stageRepoNeeded, String cronExpression )
{
this.id = id;
this.name = name;
@ -54,9 +61,11 @@ public class ManagedRepository
this.layout = layout;
this.snapshots = snapshots;
this.releases = releases;
this.blockRedeployments = blockRedeployments;
this.stageRepoNeeded = stageRepoNeeded;
this.cronExpression = cronExpression;
}
public String getId()
{
return this.id;
@ -121,6 +130,36 @@ public class ManagedRepository
this.url = url;
}
public boolean isBlockRedeployments()
{
return blockRedeployments;
}
public void setBlockRedeployments( boolean blockRedeployments )
{
this.blockRedeployments = blockRedeployments;
}
public String getCronExpression()
{
return cronExpression;
}
public void setCronExpression( String cronExpression )
{
this.cronExpression = cronExpression;
}
public boolean isStageRepoNeeded()
{
return stageRepoNeeded;
}
public void setStageRepoNeeded( boolean stageRepoNeeded )
{
this.stageRepoNeeded = stageRepoNeeded;
}
public int hashCode()
{
@ -151,6 +190,8 @@ public class ManagedRepository
public String toString()
{
return "ManagedRepository{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", url='" + url + '\''
+ ", layout='" + layout + '\'' + ", snapshots=" + snapshots + ", releases=" + releases + '}';
+ ", layout='" + layout + '\'' + ", snapshots=" + snapshots + ", releases=" + releases
+ ", blockRedeployments=" + blockRedeployments + ", cronExpression='" + cronExpression + '\''
+ ", stageRepoNeeded=" + stageRepoNeeded + '}';
}
}

View File

@ -24,7 +24,9 @@ import org.apache.archiva.rest.api.model.RemoteRepository;
import org.apache.maven.archiva.security.ArchivaRoleConstants;
import org.codehaus.plexus.redback.authorization.RedbackAuthorization;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@ -45,6 +47,29 @@ public interface RepositoriesService
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
List<ManagedRepository> getManagedRepositories();
@Path( "getManagedRepository/{repositoryId}" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
ManagedRepository getManagedRepository( @PathParam( "repositoryId" ) String repositoryId );
@Path( "deleteManagedRepository/{repositoryId}" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
Boolean deleteManagedRepository( @PathParam( "repositoryId" ) String repositoryId )
throws Exception;
@Path( "addManagedRepository" )
@POST
@Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } )
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
Boolean addManagedRepository( ManagedRepository managedRepository )
throws Exception;
@Path( "getRemoteRepositories" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@ -64,4 +89,11 @@ public interface RepositoriesService
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_RUN_INDEXER )
Boolean alreadyScanning( @PathParam( "repositoryId" ) String repositoryId );
@Path( "removeScanningTaskFromQueue/{repositoryId}" )
@GET
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN } )
@RedbackAuthorization( permission = ArchivaRoleConstants.OPERATION_RUN_INDEXER )
Boolean removeScanningTaskFromQueue( @PathParam( "repositoryId" ) String repositoryId );
}

View File

@ -83,10 +83,22 @@
<groupId>org.codehaus.redback</groupId>
<artifactId>redback-rest-api</artifactId>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
</dependency>
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
<!-- normally not needed but here for wadl feature currently in cxf -->
<dependency>
<groupId>org.apache.cxf</groupId>

View File

@ -1,15 +1,28 @@
package org.apache.archiva.rest.services;
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.metadata.repository.stats.RepositoryStatisticsManager;
import org.apache.archiva.rest.api.model.ManagedRepository;
import org.apache.archiva.rest.api.model.RemoteRepository;
import org.apache.archiva.rest.api.services.RepositoriesService;
import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
import org.apache.archiva.scheduler.repository.RepositoryTask;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.validator.GenericValidator;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.Configuration;
import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
import org.codehaus.plexus.registry.Registry;
import org.codehaus.plexus.registry.RegistryException;
import org.codehaus.plexus.taskqueue.TaskQueueException;
import org.codehaus.redback.components.scheduler.CronExpressionValidator;
import org.codehaus.redback.components.scheduler.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -17,8 +30,11 @@ import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.PathParam;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Olivier Lamy
@ -28,9 +44,17 @@ import java.util.List;
public class DefaultRepositoriesService
implements RepositoriesService
{
private Logger log = LoggerFactory.getLogger( getClass() );
// FIXME duplicate from xmlrpc
// olamy move this to a common remote services api
private static final String REPOSITORY_ID_VALID_EXPRESSION = "^[a-zA-Z0-9._-]+$";
private static final String REPOSITORY_NAME_VALID_EXPRESSION = "^([a-zA-Z0-9.)/_(-]|\\s)+$";
private static final String REPOSITORY_LOCATION_VALID_EXPRESSION = "^[-a-zA-Z0-9._/~:?!&amp;=\\\\]+$";
@Inject
protected ArchivaConfiguration archivaConfiguration;
@ -38,6 +62,16 @@ public class DefaultRepositoriesService
@Named( value = "archivaTaskScheduler#repository" )
private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
@Inject
@Named( value = "commons-configuration" )
private Registry registry;
@Inject
private RepositoryStatisticsManager repositoryStatisticsManager;
@Inject
private RepositorySessionFactory repositorySessionFactory;
public List<ManagedRepository> getManagedRepositories()
{
List<ManagedRepositoryConfiguration> managedRepoConfigs =
@ -48,15 +82,100 @@ public class DefaultRepositoriesService
for ( ManagedRepositoryConfiguration repoConfig : managedRepoConfigs )
{
// TODO fix resolution of repo url!
// TODO staging repo too
ManagedRepository repo =
new ManagedRepository( repoConfig.getId(), repoConfig.getName(), "URL", repoConfig.getLayout(),
repoConfig.isSnapshots(), repoConfig.isReleases() );
repoConfig.isSnapshots(), repoConfig.isReleases(),
repoConfig.isBlockRedeployments(), false,
repoConfig.getRefreshCronExpression() );
managedRepos.add( repo );
}
return managedRepos;
}
public ManagedRepository getManagedRepository( String repositoryId )
{
List<ManagedRepository> repos = getManagedRepositories();
for ( ManagedRepository repo : repos )
{
if ( StringUtils.equals( repo.getId(), repositoryId ) )
{
return repo;
}
}
return null;
}
// FIXME duplicate of xml rpc
// move this in a common place archiva commons remote service
public Boolean deleteManagedRepository( String repoId )
throws Exception
{
Configuration config = archivaConfiguration.getConfiguration();
ManagedRepositoryConfiguration repository = config.findManagedRepositoryById( repoId );
if ( repository == null )
{
throw new Exception( "A repository with that id does not exist" );
}
RepositorySession repositorySession = repositorySessionFactory.createSession();
try
{
MetadataRepository metadataRepository = repositorySession.getRepository();
metadataRepository.removeRepository( repository.getId() );
repositoryStatisticsManager.deleteStatistics( metadataRepository, repository.getId() );
repositorySession.save();
}
finally
{
repositorySession.close();
}
config.removeManagedRepository( repository );
try
{
saveConfiguration( config );
}
catch ( Exception e )
{
throw new Exception( "Error saving configuration for delete action" + e.getMessage() );
}
File dir = new File( repository.getLocation() );
if ( !FileUtils.deleteQuietly( dir ) )
{
throw new IOException( "Cannot delete repository " + dir );
}
List<ProxyConnectorConfiguration> proxyConnectors = config.getProxyConnectors();
for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
{
if ( StringUtils.equals( proxyConnector.getSourceRepoId(), repository.getId() ) )
{
archivaConfiguration.getConfiguration().removeProxyConnector( proxyConnector );
}
}
Map<String, List<String>> repoToGroupMap = archivaConfiguration.getConfiguration().getRepositoryToGroupMap();
if ( repoToGroupMap != null )
{
if ( repoToGroupMap.containsKey( repository.getId() ) )
{
List<String> repoGroups = repoToGroupMap.get( repository.getId() );
for ( String repoGroup : repoGroups )
{
archivaConfiguration.getConfiguration().findRepositoryGroupById( repoGroup ).removeRepository(
repository.getId() );
}
}
}
return Boolean.TRUE;
}
public List<RemoteRepository> getRemoteRepositories()
{
Configuration config = archivaConfiguration.getConfiguration();
@ -90,6 +209,7 @@ public class DefaultRepositoriesService
catch ( TaskQueueException e )
{
log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
return false;
}
return true;
}
@ -98,4 +218,205 @@ public class DefaultRepositoriesService
{
return repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId );
}
public Boolean removeScanningTaskFromQueue( @PathParam( "repositoryId" ) String repositoryId )
{
RepositoryTask task = new RepositoryTask();
task.setRepositoryId( repositoryId );
try
{
return repositoryTaskScheduler.unQueueTask( task );
}
catch ( TaskQueueException e )
{
log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
return false;
}
}
public Boolean addManagedRepository( ManagedRepository managedRepository )
throws Exception
{
return addManagedRepository( managedRepository.getId(), managedRepository.getLayout(),
managedRepository.getName(), managedRepository.getUrl(),
managedRepository.isBlockRedeployments(), managedRepository.isReleases(),
managedRepository.isSnapshots(), managedRepository.isStageRepoNeeded(),
managedRepository.getCronExpression() );
}
private Boolean addManagedRepository( String repoId, String layout, String name, String location,
boolean blockRedeployments, boolean releasesIncluded,
boolean snapshotsIncluded, boolean stageRepoNeeded, String cronExpression )
throws Exception
{
Configuration config = archivaConfiguration.getConfiguration();
CronExpressionValidator validator = new CronExpressionValidator();
if ( config.getManagedRepositoriesAsMap().containsKey( repoId ) )
{
throw new Exception( "Unable to add new repository with id [" + repoId
+ "], that id already exists as a managed repository." );
}
else if ( config.getRemoteRepositoriesAsMap().containsKey( repoId ) )
{
throw new Exception( "Unable to add new repository with id [" + repoId
+ "], that id already exists as a remote repository." );
}
else if ( config.getRepositoryGroupsAsMap().containsKey( repoId ) )
{
throw new Exception( "Unable to add new repository with id [" + repoId
+ "], that id already exists as a repository group." );
}
if ( !validator.validate( cronExpression ) )
{
throw new Exception( "Invalid cron expression." );
}
if ( !GenericValidator.matchRegexp( repoId, REPOSITORY_ID_VALID_EXPRESSION ) )
{
throw new Exception(
"Invalid repository ID. Identifier must only contain alphanumeric characters, underscores(_), dots(.), and dashes(-)." );
}
if ( !GenericValidator.matchRegexp( name, REPOSITORY_NAME_VALID_EXPRESSION ) )
{
throw new Exception(
"Invalid repository name. Repository Name must only contain alphanumeric characters, white-spaces(' '), "
+ "forward-slashes(/), open-parenthesis('('), close-parenthesis(')'), underscores(_), dots(.), and dashes(-)." );
}
String repoLocation = removeExpressions( location );
if ( !GenericValidator.matchRegexp( repoLocation, REPOSITORY_LOCATION_VALID_EXPRESSION ) )
{
throw new Exception(
"Invalid repository location. Directory must only contain alphanumeric characters, equals(=), question-marks(?), "
+ "exclamation-points(!), ampersands(&amp;), forward-slashes(/), back-slashes(\\), underscores(_), dots(.), colons(:), tildes(~), and dashes(-)." );
}
ManagedRepositoryConfiguration repository = new ManagedRepositoryConfiguration();
repository.setId( repoId );
repository.setBlockRedeployments( blockRedeployments );
repository.setReleases( releasesIncluded );
repository.setSnapshots( snapshotsIncluded );
repository.setName( name );
repository.setLocation( repoLocation );
repository.setLayout( layout );
repository.setRefreshCronExpression( cronExpression );
addRepository( repository, config );
if ( stageRepoNeeded )
{
ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
addRepository( stagingRepository, config );
}
saveConfiguration( config );
//MRM-1342 Repository statistics report doesn't appear to be working correctly
//scan repository when adding of repository is successful
try
{
executeRepositoryScanner( repoId );
if ( stageRepoNeeded )
{
ManagedRepositoryConfiguration stagingRepository = getStageRepoConfig( repository );
executeRepositoryScanner( stagingRepository.getId() );
}
}
catch ( Exception e )
{
log.warn( new StringBuilder( "Unable to scan repository [" ).append( repoId ).append( "]: " ).append(
e.getMessage() ).toString(), e );
}
return Boolean.TRUE;
}
//-----------------------------------------------
// util methods
// FIXME most are copied from xmlrpc
// olamt move those in common utility classes
//-----------------------------------------------
public Boolean executeRepositoryScanner( String repoId )
throws Exception
{
return scanRepository( repoId, true );
}
private void saveConfiguration( Configuration config )
throws Exception
{
try
{
archivaConfiguration.save( config );
}
catch ( RegistryException e )
{
throw new Exception( "Error occurred in the registry." );
}
catch ( IndeterminateConfigurationException e )
{
throw new Exception( "Error occurred while saving the configuration." );
}
}
protected void addRepository( ManagedRepositoryConfiguration repository, Configuration configuration )
throws IOException
{
// Normalize the path
File file = new File( repository.getLocation() );
repository.setLocation( file.getCanonicalPath() );
if ( !file.exists() )
{
file.mkdirs();
}
if ( !file.exists() || !file.isDirectory() )
{
throw new IOException(
"Unable to add repository - no write access, can not create the root directory: " + file );
}
configuration.addManagedRepository( repository );
}
private ManagedRepositoryConfiguration getStageRepoConfig( ManagedRepositoryConfiguration repository )
{
ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
stagingRepository.setId( repository.getId() + "-stage" );
stagingRepository.setLayout( repository.getLayout() );
stagingRepository.setName( repository.getName() + "-stage" );
stagingRepository.setBlockRedeployments( repository.isBlockRedeployments() );
stagingRepository.setDaysOlder( repository.getDaysOlder() );
stagingRepository.setDeleteReleasedSnapshots( repository.isDeleteReleasedSnapshots() );
stagingRepository.setIndexDir( repository.getIndexDir() );
String path = repository.getLocation();
int lastIndex = path.lastIndexOf( '/' );
stagingRepository.setLocation( path.substring( 0, lastIndex ) + "/" + stagingRepository.getId() );
stagingRepository.setRefreshCronExpression( repository.getRefreshCronExpression() );
stagingRepository.setReleases( repository.isReleases() );
stagingRepository.setRetentionCount( repository.getRetentionCount() );
stagingRepository.setScanned( repository.isScanned() );
stagingRepository.setSnapshots( repository.isSnapshots() );
return stagingRepository;
}
private String removeExpressions( String directory )
{
String value = StringUtils.replace( directory, "${appserver.base}",
registry.getString( "appserver.base", "${appserver.base}" ) );
value = StringUtils.replace( value, "${appserver.home}",
registry.getString( "appserver.home", "${appserver.home}" ) );
return value;
}
}

View File

@ -19,16 +19,14 @@ package org.apache.archiva.rest.services;
* under the License.
*/
import org.apache.archiva.rest.api.model.ManagedRepository;
import org.apache.archiva.rest.api.model.RemoteRepository;
import org.apache.archiva.rest.api.services.RepositoriesService;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.apache.cxf.jaxrs.client.ServerWebApplicationException;
import org.apache.cxf.jaxrs.client.WebClient;
import org.codehaus.plexus.taskqueue.TaskQueue;
import org.junit.Test;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.List;
/**
@ -37,8 +35,6 @@ import java.util.List;
public class RepositoriesServiceTest
extends AbstractArchivaRestTest
{
@Inject @Named("taskQueue#repository-scanning")
private TaskQueue repositoryScanningQueue;
RepositoriesService getRepositoriesService()
{
@ -101,12 +97,7 @@ public class RepositoriesServiceTest
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
String repoId = service.getManagedRepositories().get( 0 ).getId();
/*
while ( service.alreadyScanning( repoId ) )
{
Thread.sleep( 1 );
}
*/
assertTrue( service.scanRepository( repoId, true ) );
log.info( "sanRepo call ok " );
@ -114,4 +105,28 @@ public class RepositoriesServiceTest
assertTrue( service.alreadyScanning( repoId ) );
}
@Test
public void addManagedRepo()
throws Exception
{
RepositoriesService service = getRepositoriesService();
WebClient.client( service ).header( "Authorization", authorizationHeader );
WebClient.getConfig( service ).getHttpConduit().getClient().setReceiveTimeout( 300000 );
ManagedRepository repo = getTestManagedRepository();
if ( service.getManagedRepository( repo.getId() ) != null )
{
service.deleteManagedRepository( repo.getId() );
assertNull( service.getManagedRepository( repo.getId() ) );
}
service.addManagedRepository( repo );
assertNotNull( service.getManagedRepository( repo.getId() ) );
}
private ManagedRepository getTestManagedRepository()
{
return new ManagedRepository( "TEST", "test", "foo", "default", true, true, false, false, "2 * * * * ?" );
}
}