--- /dev/null
+package org.apache.archiva.admin.model;/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/**
+ * This exception is thrown, if a entity that should be created, exists already.
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+public class EntityExistsException extends RepositoryAdminException
+{
+ private static final String KEY = "entity.exists";
+
+ public static EntityExistsException of(String... parameters) {
+ String message = getMessage( KEY, parameters );
+ return new EntityExistsException( message, parameters );
+ }
+
+ public EntityExistsException( String s, String... parameters )
+ {
+ super( s );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityExistsException( String s, String fieldName, String... parameters )
+ {
+ super( s, fieldName );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityExistsException( String message, Throwable cause, String... parameters )
+ {
+ super( message, cause );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityExistsException( String message, Throwable cause, String fieldName, String... parameters )
+ {
+ super( message, cause, fieldName );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+}
--- /dev/null
+package org.apache.archiva.admin.model;/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/**
+ * This exception is thrown, if a requested entity does not exist.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+public class EntityNotFoundException extends RepositoryAdminException
+{
+ public static final String KEY = "entity.not_found";
+
+ public static EntityNotFoundException of(String... parameters) {
+ String message = getMessage( KEY, parameters );
+ return new EntityNotFoundException( message, parameters );
+ }
+
+ public EntityNotFoundException( String s, String... parameters )
+ {
+ super( s );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityNotFoundException( String s, String fieldName, String... parameters )
+ {
+ super( s, fieldName );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityNotFoundException( String message, Throwable cause, String... parameters )
+ {
+ super( message, cause );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+
+ public EntityNotFoundException( String message, Throwable cause, String fieldName, String... parameters )
+ {
+ super( message, cause, fieldName );
+ setKey( KEY );
+ setParameters( parameters );
+ }
+}
*/
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
/**
* @author Olivier Lamy
* @since 1.4-M1
extends Exception
{
+ private static final ResourceBundle bundle = ResourceBundle.getBundle( "org.apache.archiva.admin.model.error.AdminErrors", Locale.ROOT );
+
/**
* can return the field name of bean with issue
* can be <code>null</code>
*/
private String fieldName;
+ /**
+ * A unique identifier of this error
+ * @since 3.0
+ */
+ private String key;
+ private boolean keyExists = false;
+
+ /**
+ * Message parameters
+ */
+ String[] parameters = new String[0];
+
+
+ public static RepositoryAdminException ofKey(String key, String... params) {
+ String message = getMessage( key, params );
+ RepositoryAdminException ex = new RepositoryAdminException( message );
+ ex.setKey( key );
+ ex.setParameters( params );
+ return ex;
+ }
+
+ protected static String getMessage( String key, String[] params )
+ {
+ return MessageFormat.format( bundle.getString( key ), params );
+ }
+
+ public static RepositoryAdminException ofKey(String key, Throwable cause, String... params) {
+ String message = getMessage( key, params );
+ RepositoryAdminException ex = new RepositoryAdminException( message, cause );
+ ex.setKey( key );
+ ex.setParameters( params );
+ return ex;
+ }
+
+
+ public static RepositoryAdminException ofKeyAndField(String key, String fieldName, String... params) {
+ String message = getMessage( key, params );
+ RepositoryAdminException ex = new RepositoryAdminException( message, fieldName );
+ ex.setKey( key );
+ ex.setParameters( params );
+ return ex;
+ }
+
+ public static RepositoryAdminException ofKeyAndField(String key, Throwable cause, String fieldName, String... params) {
+ String message = getMessage( key, params );
+ RepositoryAdminException ex = new RepositoryAdminException( message, cause, fieldName );
+ ex.setKey( key );
+ ex.setFieldName( fieldName );
+ ex.setParameters( params );
+ return ex;
+ }
+
public RepositoryAdminException( String s )
{
super( s );
{
this.fieldName = fieldName;
}
+
+ public String getKey( )
+ {
+ return key;
+ }
+
+ public void setKey( String key )
+ {
+ this.keyExists=!StringUtils.isEmpty( key );
+ this.key = key;
+ }
+
+ public boolean keyExists() {
+ return this.keyExists;
+ }
+
+ public String[] getParameters( )
+ {
+ return parameters;
+ }
+
+ public void setParameters( String[] parameters )
+ {
+ if (parameters==null) {
+ this.parameters = new String[0];
+ }
+ this.parameters = parameters;
+ }
}
*/
private String cronExpression;
+ private String location;
+
public RepositoryGroup()
{
// no op
return this;
}
+ public String getLocation( )
+ {
+ return location;
+ }
+
+ public void setLocation( String location )
+ {
+ this.location = location;
+ }
+
@Override
public boolean equals( Object other )
{
*/
import org.apache.archiva.admin.model.AuditInformation;
+import org.apache.archiva.admin.model.EntityNotFoundException;
import org.apache.archiva.admin.model.RepositoryAdminException;
import org.apache.archiva.admin.model.beans.RepositoryGroup;
import org.apache.archiva.repository.storage.StorageAsset;
List<RepositoryGroup> getRepositoriesGroups()
throws RepositoryAdminException;
+ /**
+ * Returns the repository group. If it is not found a {@link org.apache.archiva.admin.model.EntityNotFoundException}
+ * will be thrown.
+ *
+ * @param repositoryGroupId the identifier of the repository group
+ * @return the repository group object
+ * @throws RepositoryAdminException
+ * @throws EntityNotFoundException
+ */
RepositoryGroup getRepositoryGroup( String repositoryGroupId )
- throws RepositoryAdminException;
+ throws RepositoryAdminException, EntityNotFoundException;
Boolean addRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
throws RepositoryAdminException;
--- /dev/null
+#
+# 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.
+#
+
+entity.exists=The entity {0} exists already
+entity.not_found=The entity {0} was not found
+repository_group.id.empty=The repository group id was empty
+repository_group.id.max_length=The id "{0}" of the repository group exceeds {1} characters
+repository_group.id.invalid_chars=The repository group id "{0}" contains invalid characters. Only the following are allowed: {1}.
+repository_group.merged_index_ttl.min=Merged Index TTL must be greater than {0}.
+repository_group.repository.not_found=The member repository with id "{0}" does not exist. Cannot be used in a repository group.
+repository_group.registry.add_error=The registry could not add the repository "{0}": {1}
+repository_group.registry.update_error=The registry could not update the repository "{0}": {1}
*/
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.beans.ManagedRepository;
import org.apache.archiva.admin.model.beans.RepositoryGroup;
}
@Override
- public RepositoryGroup getRepositoryGroup( String repositoryGroupId ) {
- return convertRepositoryGroupObject( repositoryRegistry.getRepositoryGroup( repositoryGroupId ) );
+ public RepositoryGroup getRepositoryGroup( String repositoryGroupId ) throws EntityNotFoundException
+ {
+ org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
+ if (group==null) {
+ throw new EntityNotFoundException( "Repository group does not exist" );
+ } else {
+ return convertRepositoryGroupObject( group );
+ }
}
@Override
try {
repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
} catch (RepositoryException e) {
- e.printStackTrace();
+ log.error( "Could not add the repository group to the registry: {}", e.getMessage( ), e );
+ throw RepositoryAdminException.ofKey( "repository_group.registry.add_error", e, repositoryGroup.getId(), e.getMessage() );
}
triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_GROUP, auditInformation );
try {
repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
} catch (RepositoryException e) {
- e.printStackTrace();
+ log.error( "Could not update the repository group in the registry: {}", e.getMessage( ), e );
+ throw RepositoryAdminException.ofKey( "repository_group.registry.update_error", e, repositoryGroup.getId(), e.getMessage() );
}
org.apache.archiva.repository.RepositoryGroup rg = repositoryRegistry.getRepositoryGroup( repositoryGroup.getId( ) );
String repoGroupId = repositoryGroup.getId();
if ( StringUtils.isBlank( repoGroupId ) )
{
- throw new RepositoryAdminException( "repositoryGroup id cannot be empty" );
+ throw RepositoryAdminException.ofKey("repository_group.id.empty" );
}
if ( repoGroupId.length() > 100 )
{
- throw new RepositoryAdminException(
- "Identifier [" + repoGroupId + "] is over the maximum limit of 100 characters" );
+ throw RepositoryAdminException.ofKey("repository_group.id.max_length",repoGroupId, Integer.toString( 100 ));
}
Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
if ( !matcher.matches() )
{
- throw new RepositoryAdminException(
- "Invalid character(s) found in identifier. Only the following characters are allowed: alphanumeric, '.', '-' and '_'" );
+ throw RepositoryAdminException.ofKey("repository_group.id.invalid_chars","alphanumeric, '.', '-','_'" );
}
if ( repositoryGroup.getMergedIndexTtl() <= 0 )
{
- throw new RepositoryAdminException( "Merged Index TTL must be greater than 0." );
+ throw RepositoryAdminException.ofKey("repository_group.merged_index_ttl.min","0" );
}
Configuration configuration = getArchivaConfiguration().getConfiguration();
{
if ( !updateMode )
{
- throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
+ throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
+ "], that id already exists as a repository group." );
}
}
else if ( configuration.getManagedRepositoriesAsMap().containsKey( repoGroupId ) )
{
- throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
+ throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
+ "], that id already exists as a managed repository." );
}
else if ( configuration.getRemoteRepositoriesAsMap().containsKey( repoGroupId ) )
{
- throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
+ throw new EntityExistsException( "Unable to add new repository group with id [" + repoGroupId
+ "], that id already exists as a remote repository." );
}
{
if ( getManagedRepositoryAdmin().getManagedRepository( id ) == null )
{
- throw new RepositoryAdminException(
- "managedRepository with id " + id + " not exists so cannot be used in a repositoryGroup" );
+ throw RepositoryAdminException.ofKey("repository_group.repository.not_found",id );
}
}
}
}
rg.setCronExpression( group.getSchedulingDefinition() );
rg.setMergedIndexTtl( group.getMergedIndexTTL() );
+ rg.setLocation( group.getLocation().toString() );
return rg;
}
}
--- /dev/null
+package org.apache.archiva.rest.api.model.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.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Objects;
+
+import static org.apache.archiva.indexer.ArchivaIndexManager.DEFAULT_INDEX_PATH;
+
+/**
+ * Index merge configuration.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+@XmlRootElement(name="mergeConfiguration")
+@Schema(name="MergeConfiguration", description = "Configuration settings for index merge of remote repositories.")
+public class MergeConfiguration implements Serializable
+{
+ private static final long serialVersionUID = -3629274059574459133L;
+
+ private String mergedIndexPath = DEFAULT_INDEX_PATH;
+ private int mergedIndexTtlMinutes = 30;
+ private String indexMergeSchedule = "";
+
+ @Schema(name="merged_index_path", description = "The path where the merged index is stored. The path is relative to the repository directory of the group.")
+ public String getMergedIndexPath( )
+ {
+ return mergedIndexPath;
+ }
+
+ public void setMergedIndexPath( String mergedIndexPath )
+ {
+ this.mergedIndexPath = mergedIndexPath;
+ }
+
+ @Schema(name="merged_index_ttl_minutes", description = "The Time to Life of the merged index in minutes.")
+ public int getMergedIndexTtlMinutes( )
+ {
+ return mergedIndexTtlMinutes;
+ }
+
+ public void setMergedIndexTtlMinutes( int mergedIndexTtlMinutes )
+ {
+ this.mergedIndexTtlMinutes = mergedIndexTtlMinutes;
+ }
+
+ @Schema(name="index_merge_schedule", description = "Cron expression that defines the times/intervals for index merging.")
+ public String getIndexMergeSchedule( )
+ {
+ return indexMergeSchedule;
+ }
+
+ public void setIndexMergeSchedule( String indexMergeSchedule )
+ {
+ this.indexMergeSchedule = indexMergeSchedule;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ MergeConfiguration that = (MergeConfiguration) o;
+
+ if ( mergedIndexTtlMinutes != that.mergedIndexTtlMinutes ) return false;
+ if ( !Objects.equals( mergedIndexPath, that.mergedIndexPath ) )
+ return false;
+ return Objects.equals( indexMergeSchedule, that.indexMergeSchedule );
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = mergedIndexPath != null ? mergedIndexPath.hashCode( ) : 0;
+ result = 31 * result + mergedIndexTtlMinutes;
+ result = 31 * result + ( indexMergeSchedule != null ? indexMergeSchedule.hashCode( ) : 0 );
+ return result;
+ }
+
+ @SuppressWarnings( "StringBufferReplaceableByString" )
+ @Override
+ public String toString( )
+ {
+ final StringBuilder sb = new StringBuilder( "MergeConfiguration{" );
+ sb.append( "mergedIndexPath='" ).append( mergedIndexPath ).append( '\'' );
+ sb.append( ", mergedIndexTtlMinutes=" ).append( mergedIndexTtlMinutes );
+ sb.append( ", indexMergeSchedule='" ).append( indexMergeSchedule ).append( '\'' );
+ sb.append( '}' );
+ return sb.toString( );
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.model.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.swagger.v3.oas.annotations.media.Schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+@XmlRootElement(name="repositoryGroup")
+@Schema(name="RepositoryGroup", description = "Information about a repository group, which combines multiple repositories as one virtual repository.")
+public class RepositoryGroup implements Serializable
+{
+ private static final long serialVersionUID = -7319687481737616081L;
+ private String id;
+ private final List<String> repositories = new ArrayList<>( );
+ private String location;
+ MergeConfiguration mergeConfiguration;
+
+ public RepositoryGroup( )
+ {
+ }
+
+ public RepositoryGroup(String id) {
+ this.id = id;
+ }
+
+ public static RepositoryGroup of( org.apache.archiva.admin.model.beans.RepositoryGroup modelObj ) {
+ RepositoryGroup result = new RepositoryGroup( );
+ MergeConfiguration mergeConfig = new MergeConfiguration( );
+ result.setMergeConfiguration( mergeConfig );
+ result.setId( modelObj.getId() );
+ result.setLocation( modelObj.getLocation() );
+ result.setRepositories( modelObj.getRepositories() );
+ mergeConfig.setMergedIndexPath( modelObj.getMergedIndexPath() );
+ mergeConfig.setMergedIndexTtlMinutes( modelObj.getMergedIndexTtl( ) );
+ mergeConfig.setIndexMergeSchedule( modelObj.getCronExpression( ) );
+ return result;
+ }
+
+ @Schema(description = "The unique id of the repository group.")
+ public String getId( )
+ {
+ return id;
+ }
+
+ public void setId( String id )
+ {
+ this.id = id;
+ }
+
+ @Schema(description = "The list of ids of repositories which are member of the repository group.")
+ public List<String> getRepositories( )
+ {
+ return repositories;
+ }
+
+ public void setRepositories( List<String> repositories )
+ {
+ this.repositories.clear();
+ this.repositories.addAll( repositories );
+ }
+
+ public void addRepository(String repositoryId) {
+ if (!this.repositories.contains( repositoryId )) {
+ this.repositories.add( repositoryId );
+ }
+ }
+
+ @Schema(name="merge_configuration",description = "The configuration for index merge.")
+ public MergeConfiguration getMergeConfiguration( )
+ {
+ return mergeConfiguration;
+ }
+
+ public void setMergeConfiguration( MergeConfiguration mergeConfiguration )
+ {
+ this.mergeConfiguration = mergeConfiguration;
+ }
+
+ @Schema(description = "The storage location of the repository. The merged index is stored relative to this location.")
+ public String getLocation( )
+ {
+ return location;
+ }
+
+ public void setLocation( String location )
+ {
+ this.location = location;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ RepositoryGroup that = (RepositoryGroup) o;
+
+ if ( !Objects.equals( id, that.id ) ) return false;
+ if ( !repositories.equals( that.repositories ) )
+ return false;
+ if ( !Objects.equals( location, that.location ) ) return false;
+ return Objects.equals( mergeConfiguration, that.mergeConfiguration );
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = id != null ? id.hashCode( ) : 0;
+ result = 31 * result + repositories.hashCode( );
+ result = 31 * result + ( location != null ? location.hashCode( ) : 0 );
+ result = 31 * result + ( mergeConfiguration != null ? mergeConfiguration.hashCode( ) : 0 );
+ return result;
+ }
+
+ @SuppressWarnings( "StringBufferReplaceableByString" )
+ @Override
+ public String toString( )
+ {
+ final StringBuilder sb = new StringBuilder( "RepositoryGroup{" );
+ sb.append( "id='" ).append( id ).append( '\'' );
+ sb.append( ", repositories=" ).append( repositories );
+ sb.append( ", location='" ).append( location ).append( '\'' );
+ sb.append( ", mergeConfiguration=" ).append( mergeConfiguration );
+ sb.append( '}' );
+ return sb.toString( );
+ }
+}
--- /dev/null
+package org.apache.archiva.rest.api.services.v2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * 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.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import org.apache.archiva.components.rest.model.PagedResult;
+import org.apache.archiva.redback.authorization.RedbackAuthorization;
+import org.apache.archiva.rest.api.model.v2.RepositoryGroup;
+import org.apache.archiva.security.common.ArchivaRoleConstants;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.apache.archiva.rest.api.services.v2.Configuration.DEFAULT_PAGE_LIMIT;
+
+/**
+ * Endpoint for repository groups that combine multiple repositories into a single virtual repository.
+ *
+ * @author Olivier Lamy
+ * @author Martin Stockhammer
+ * @since 3.0
+ */
+@Path( "/repository_groups" )
+@Schema( name="RepositoryGroups", description = "Managing of repository groups or virtual repositories")
+public interface RepositoryGroupService
+{
+ @Path( "" )
+ @GET
+ @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)")
+ },
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the list could be returned",
+ 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 )) )
+ }
+ )
+ 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( "key" ) List<String> orderBy,
+ @QueryParam("order") @DefaultValue( "asc" ) String order)
+ throws ArchivaRestServiceException;
+
+ @Path( "{repositoryGroupId}" )
+ @GET
+ @Produces( { APPLICATION_JSON } )
+ @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+ @Operation( summary = "Returns a single repository group configuration.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the configuration is returned",
+ 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 )) ),
+ @ApiResponse( responseCode = "404", description = "The repository group with the given id does not exist",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) )
+ }
+ )
+ RepositoryGroup getRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
+ throws ArchivaRestServiceException;
+
+ @Path( "" )
+ @POST
+ @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))
+ )
+ ,
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "201",
+ description = "If the list could be returned",
+ 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"))
+ }
+ ),
+ @ApiResponse( responseCode = "403", description = "Authenticated user is not permitted to gather the information",
+ 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 )) )
+ }
+ )
+ RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup )
+ throws ArchivaRestServiceException;
+
+ @Path( "{repositoryGroupId}" )
+ @PUT
+ @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))
+ )
+ ,
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ description = "If the group is returned",
+ 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 )) ),
+ @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
+ 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 )) )
+ }
+ )
+ RepositoryGroup updateRepositoryGroup( @PathParam( "repositoryGroupId" ) String groupId, RepositoryGroup repositoryGroup )
+ throws ArchivaRestServiceException;
+
+ @Path( "{repositoryGroupId}" )
+ @DELETE
+ @Produces( { APPLICATION_JSON } )
+ @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+ @Operation( summary = "Deletes the repository group entry with the given id.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ 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 )) ),
+ @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+ }
+ )
+ Response deleteRepositoryGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId )
+ throws ArchivaRestServiceException;
+
+ @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
+ @PUT
+ @Produces( { APPLICATION_JSON } )
+ @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+ @Operation( summary = "Adds the repository with the given id to the repository group.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ 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 )) ),
+ @ApiResponse( responseCode = "404", description = "The group with the given id does not exist",
+ content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = ArchivaRestError.class )) ),
+ }
+ )
+ RepositoryGroup addRepositoryToGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
+ @PathParam( "repositoryId" ) String repositoryId )
+ throws ArchivaRestServiceException;
+
+ @Path( "{repositoryGroupId}/repositories/{repositoryId}" )
+ @DELETE
+ @Produces( { APPLICATION_JSON } )
+ @RedbackAuthorization( permissions = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION )
+ @Operation( summary = "Removes the repository with the given id from the repository group.",
+ security = {
+ @SecurityRequirement(
+ name = ArchivaRoleConstants.OPERATION_MANAGE_CONFIGURATION
+ )
+ },
+ responses = {
+ @ApiResponse( responseCode = "200",
+ 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 )) ),
+ @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 )) ),
+ }
+ )
+ RepositoryGroup deleteRepositoryFromGroup( @PathParam( "repositoryGroupId" ) String repositoryGroupId,
+ @PathParam( "repositoryId" ) String repositoryId )
+ throws ArchivaRestServiceException;
+
+
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * <p>This is the V2 REST API of Archiva. It uses JAX-RS annotations for defining the endpoints.
+ * The API is documented with OpenApi annotations.</p>
+ *
+ * <h3>Some design principles of the API and classes:</h3>
+ * <ul>
+ * <li>All services use V2 model classes. Internal models are always converted to V2 classes.</li>
+ * <li>Schema attributes use the snake case syntax (lower case with '_' as divider)</li>
+ * <li>Return code <code>200</code> and <code>201</code> (POST) is used for successful execution.</li>
+ * <li>Return code <code>403</code> is used, if the user has not the permission for the action.</li>
+ * <li>Return code <code>422</code> is used for input that has invalid data.</li>
+ * </ul>
+ *
+ * <h4>Querying entity lists</h4>
+ * <p>The main entities of a given path are retrieved on the base path.
+ * Further sub entities or entries may be retrieved via subpaths.
+ * A single entity is returned by the "{id}" path. Be careful with technical paths that are parallel to the
+ * id path. Avoid naming conflicts with the id and technical paths.
+ * Entity attributes may be retrieved by "{id}/{attribute}" path or if there are lists or collections by
+ * "{id}/mycollection/{subentryid}"</p>
+ *
+ * <ul>
+ * <li><code>GET</code> method is used for retrieving entities on the base path ""</li>
+ * <li>The query for base entities should always return a paged result and be filterable and sortable</li>
+ * <li>Query parameters for filtering, ordering and limits should be optional and proper defaults must be set</li>
+ * <li>Return code <code>200</code> is used for successful retrieval</li>
+ * <li>This action is idempotent</li>
+ * </ul>
+ *
+ * <h4>Querying single entities</h4>
+ * <p>Single entities are retrieved on the path "{id}"</p>
+ * <ul>
+ * <li><code>GET</code> method is used for retrieving a single entity. The id is always a path parameter.</li>
+ * <li>Return code <code>200</code> is used for successful retrieval</li>
+ * <li>Return code <code>404</code> is used if the entity with the given id does not exist</li>
+ * <li>This action is idempotent</li>
+ * </ul>
+ *
+ * <h4>Creating entities</h4>
+ * <p>The main entities are created on the base path "".</p>
+ * <ul>
+ * <li><code>POST</code> is used for creating new entities</li>
+ * <li>The <code>POST</code> body must always have a complete definition of the entity.</li>
+ * <li>A unique <code>id</code> or <code>name</code> attribute is required for entities. If the id is generated during POST,
+ * it must be returned by response body.</li>
+ * <li>A successful <code>POST</code> request should always return the entity definition as it would be returned by the GET request.</li>
+ * <li>Return code <code>201</code> is used for successful creation of the new entity.</li>
+ * <li>A successful response has a <code>Location</code> header with the URL for retrieving the single created entity.</li>
+ * <li>Return code <code>303</code> is used, if the entity exists already</li>
+ * <li>This action is not idempotent</li>
+ * </ul>
+ *
+ * <h4>Updating entities</h4>
+ * <p>The path for entity update must contain the '{id}' of the entity. The path should be the same as for the GET operation.</p>
+ * <ul>
+ * <li><code>PUT</code> is used for updating existing entities</li>
+ * <li>The body contains a JSON object. Only existing attributes are updated.</li>
+ * <li>A successful PUT request should return the complete entity definition as it would be returned by the GET request.</li>
+ * <li>Return code <code>200</code> is used for successful update of the new entity. Even if nothing changed.</li>
+ * <li>This action is idempotent</li>
+ * </ul>
+ *
+ * <h4>Deleting entities</h4>
+ * <p>The path for entity deletion must contain the '{id}' of the entity. The path should be the same as
+ * for the GET operation.</p>
+ * <ul>
+ * <li><code>DELETE</code> is used for deleting existing entities</li>
+ * <li>The successful operation has no request and no response body</li>
+ * <li>Return code <code>200</code> is used for successful deletion of the new entity.</li>
+ * <li>This action is not idempotent</li>
+ * </ul>
+ *
+ * <h4>Errors</h4>
+ * <ul>
+ * <li>A error uses a return code <code>>=400</code> </li>
+ * <li>All errors use the same result object ({@link org.apache.archiva.rest.api.services.v2.ArchivaRestError}</li>
+ * <li>Error messages are returned as keys. Translation is part of the client application.</li>
+ * </ul>
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ */
+package org.apache.archiva.rest.api.services.v2;
\ No newline at end of file
--- /dev/null
+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 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.PagingHelper;
+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.ErrorMessage;
+import org.apache.archiva.rest.api.services.v2.RepositoryGroupService;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * REST V2 Implementation for repository groups.
+ *
+ * @author Martin Stockhammer <martin_s@apache.org>
+ * @since 3.0
+ * @see RepositoryGroupService
+ */
+public class DefaultRepositoryGroupService implements RepositoryGroupService
+{
+ @Context
+ HttpServletResponse httpServletResponse;
+
+ @Context
+ UriInfo uriInfo;
+
+ 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"} );
+ private static final PagingHelper PROP_PAGING_HELPER = new PagingHelper( );
+
+ @Inject
+ private RepositoryGroupAdmin repositoryGroupAdmin;
+
+
+ static
+ {
+ QUERY_HELPER.addStringFilter( "id", org.apache.archiva.admin.model.beans.RepositoryGroup::getId );
+ QUERY_HELPER.addNullsafeFieldComparator( "id", org.apache.archiva.admin.model.beans.RepositoryGroup::getId );
+ }
+
+
+ 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 );
+ }
+
+ @Override
+ public PagedResult<RepositoryGroup> getRepositoriesGroups( String searchTerm, Integer offset, Integer limit, List<String> orderBy, String order ) throws ArchivaRestServiceException
+ {
+ try
+ {
+ Predicate<org.apache.archiva.admin.model.beans.RepositoryGroup> filter = QUERY_HELPER.getQueryFilter( searchTerm );
+ Comparator<org.apache.archiva.admin.model.beans.RepositoryGroup> ordering = QUERY_HELPER.getComparator( orderBy, QUERY_HELPER.isAscending( order ) );
+ int totalCount = Math.toIntExact( repositoryGroupAdmin.getRepositoriesGroups( ).stream( ).filter( filter ).count( ) );
+ List<RepositoryGroup> result = repositoryGroupAdmin.getRepositoriesGroups( ).stream( ).filter( filter ).sorted( ordering ).skip( offset ).limit( limit ).map(
+ RepositoryGroup::of
+ ).collect( Collectors.toList( ) );
+ return new PagedResult<>( totalCount, offset, limit, result );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ log.error( "Repository admin error: {}", e.getMessage( ), e );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage() ) );
+ } catch ( ArithmeticException e ) {
+ log.error( "Could not convert total count: {}", e.getMessage( ) );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.INVALID_RESULT_SET_ERROR ) );
+ }
+
+ }
+
+ @Override
+ public RepositoryGroup getRepositoryGroup( String repositoryGroupId ) throws ArchivaRestServiceException
+ {
+ try
+ {
+ org.apache.archiva.admin.model.beans.RepositoryGroup group = repositoryGroupAdmin.getRepositoryGroup( repositoryGroupId );
+ return RepositoryGroup.of( group );
+ }
+ catch ( EntityNotFoundException e ) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_NOT_EXIST, repositoryGroupId ), 404 );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage() ));
+ }
+ }
+
+ private org.apache.archiva.admin.model.beans.RepositoryGroup toModel( RepositoryGroup group) {
+ org.apache.archiva.admin.model.beans.RepositoryGroup result = new org.apache.archiva.admin.model.beans.RepositoryGroup( );
+ result.setId( group.getId( ) );
+ result.setLocation( group.getLocation( ) );
+ result.setRepositories( new ArrayList<>( group.getRepositories( ) ) );
+ result.setMergedIndexPath( group.getMergeConfiguration().getMergedIndexPath() );
+ result.setMergedIndexTtl( group.getMergeConfiguration().getMergedIndexTtlMinutes() );
+ result.setCronExpression( group.getMergeConfiguration().getIndexMergeSchedule() );
+ return result;
+ }
+
+ @Override
+ public RepositoryGroup addRepositoryGroup( RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
+ {
+ try
+ {
+ Boolean result = repositoryGroupAdmin.addRepositoryGroup( toModel( repositoryGroup ), getAuditInformation( ) );
+ if (result) {
+ org.apache.archiva.admin.model.beans.RepositoryGroup newGroup = repositoryGroupAdmin.getRepositoryGroup( repositoryGroup.getId( ) );
+ if (newGroup!=null) {
+ return RepositoryGroup.of( newGroup );
+ } else {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
+ }
+ } else {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_ADD_FAILED ) );
+ }
+ } catch ( EntityExistsException e ) {
+ httpServletResponse.setHeader( "Location", uriInfo.getAbsolutePathBuilder( ).path( repositoryGroup.getId() ).build( ).toString( ) );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_GROUP_EXIST, repositoryGroup.getId( )), 303 );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ if (e.keyExists()) {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.PREFIX+e.getKey(), e.getParameters() ) );
+ } else
+ {
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
+ }
+ }
+ }
+
+ @Override
+ public RepositoryGroup updateRepositoryGroup( String groupId, RepositoryGroup repositoryGroup ) throws ArchivaRestServiceException
+ {
+ org.apache.archiva.admin.model.beans.RepositoryGroup updateGroup = toModel( repositoryGroup );
+ try
+ {
+ org.apache.archiva.admin.model.beans.RepositoryGroup originGroup = repositoryGroupAdmin.getRepositoryGroup( groupId );
+ if ( StringUtils.isEmpty( updateGroup.getId())) {
+ updateGroup.setId( groupId );
+ }
+ if (StringUtils.isEmpty( updateGroup.getLocation() )) {
+ updateGroup.setLocation( originGroup.getLocation() );
+ }
+ if (StringUtils.isEmpty( updateGroup.getMergedIndexPath() )) {
+ updateGroup.setMergedIndexPath( originGroup.getMergedIndexPath() );
+ }
+ repositoryGroupAdmin.updateRepositoryGroup( updateGroup, getAuditInformation( ) );
+ return RepositoryGroup.of( repositoryGroupAdmin.getRepositoryGroup( groupId ) );
+ }
+ catch ( RepositoryAdminException e )
+ {
+ log.error( "Repository admin error: {}", e.getMessage( ), e );
+ throw new ArchivaRestServiceException( ErrorMessage.of( ErrorKeys.REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
+ }
+ }
+
+ @Override
+ public Response deleteRepositoryGroup( String repositoryGroupId ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public RepositoryGroup addRepositoryToGroup( String repositoryGroupId, String repositoryId ) throws ArchivaRestServiceException
+ {
+ return null;
+ }
+
+ @Override
+ public RepositoryGroup deleteRepositoryFromGroup( String repositoryGroupId, String repositoryId ) throws org.apache.archiva.rest.api.services.v2.ArchivaRestServiceException
+ {
+ return null;
+ }
+}
* under the License.
*/
+import org.apache.archiva.rest.api.services.v2.ErrorMessage;
+
+import java.util.List;
+
/**
* @author Martin Stockhammer <martin_s@apache.org>
*/
public interface ErrorKeys
{
+ String PREFIX = "archiva.";
+ String REPOSITORY_GROUP_PREFIX = PREFIX + "repository_group.";
+
String INVALID_RESULT_SET_ERROR = "archiva.result_set.invalid";
String REPOSITORY_ADMIN_ERROR = "archiva.repositoryadmin.error";
String LDAP_CF_INIT_FAILED = "archiva.ldap.cf.init.failed";
String MISSING_DATA = "archiva.missing.data";
+ String REPOSITORY_GROUP_NOT_EXIST = REPOSITORY_GROUP_PREFIX+"notexist";
+ String REPOSITORY_GROUP_ADD_FAILED = REPOSITORY_GROUP_PREFIX+"add.failed" ;
+ String REPOSITORY_GROUP_EXIST = REPOSITORY_GROUP_PREFIX+"exists";
+
}