mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 08:25:44 +01:00
Support reading object by other identifiers than id
Therefore split adapter class for single entity and collection handling.
This commit is contained in:
@@ -26,43 +26,14 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
||||
* @param <EXCEPTION> The exception type for the model object, eg. {@link sonia.scm.user.UserException}.
|
||||
*/
|
||||
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||
class ResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||
class CollectionResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||
DTO extends HalRepresentation,
|
||||
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
|
||||
|
||||
ResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager) {
|
||||
CollectionResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the model object for the given id, transforms it to a dto and returns a corresponding http response.
|
||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||
*/
|
||||
Response get(String id, Function<MODEL_OBJECT, DTO> mapToDto) {
|
||||
MODEL_OBJECT modelObject = manager.get(id);
|
||||
if (modelObject == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
DTO dto = mapToDto.apply(modelObject);
|
||||
return Response.ok(dto).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the model object for the given id according to the given function and returns a corresponding http response.
|
||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||
*/
|
||||
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
|
||||
MODEL_OBJECT existingModelObject = manager.get(id);
|
||||
if (existingModelObject == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject);
|
||||
if (!id.equals(changedModelObject.getId())) {
|
||||
return Response.status(BAD_REQUEST).entity("illegal change of id").build();
|
||||
}
|
||||
return update(id, changedModelObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all model objects in a paged way, maps them using the given function and returns a corresponding http response.
|
||||
* This handles all corner cases, eg. missing privileges.
|
||||
@@ -1,13 +1,23 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.*;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupException;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -19,14 +29,14 @@ public class GroupCollectionResource {
|
||||
private final GroupCollectionToDtoMapper groupCollectionToDtoMapper;
|
||||
private final ResourceLinks resourceLinks;
|
||||
|
||||
private final ResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||
|
||||
@Inject
|
||||
public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupCollectionToDtoMapper groupCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
||||
this.dtoToGroupMapper = dtoToGroupMapper;
|
||||
this.groupCollectionToDtoMapper = groupCollectionToDtoMapper;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
||||
this.adapter = new IdResourceManagerAdapter<>(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,14 +22,14 @@ public class GroupResource {
|
||||
|
||||
private final GroupToGroupDtoMapper groupToGroupDtoMapper;
|
||||
private final GroupDtoToGroupMapper dtoToGroupMapper;
|
||||
private final ResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||
|
||||
@Inject
|
||||
public GroupResource(GroupManager manager, GroupToGroupDtoMapper groupToGroupDtoMapper,
|
||||
GroupDtoToGroupMapper groupDtoToGroupMapper) {
|
||||
this.groupToGroupDtoMapper = groupToGroupDtoMapper;
|
||||
this.dtoToGroupMapper = groupDtoToGroupMapper;
|
||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
||||
this.adapter = new IdResourceManagerAdapter<>(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import sonia.scm.Manager;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.PageResult;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Facade for {@link SingleResourceManagerAdapter} and {@link CollectionResourceManagerAdapter}.
|
||||
*/
|
||||
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||
class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||
DTO extends HalRepresentation,
|
||||
EXCEPTION extends Exception> {
|
||||
|
||||
private final Manager<MODEL_OBJECT, EXCEPTION> manager;
|
||||
|
||||
private final SingleResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> singleAdapter;
|
||||
private final CollectionResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> collectionAdapter;
|
||||
|
||||
IdResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager) {
|
||||
this.manager = manager;
|
||||
singleAdapter = new SingleResourceManagerAdapter<>(manager);
|
||||
collectionAdapter = new CollectionResourceManagerAdapter<>(manager);
|
||||
}
|
||||
|
||||
Response get(String id, Function<MODEL_OBJECT, DTO> mapToDto) {
|
||||
return singleAdapter.get(() -> manager.get(id), mapToDto);
|
||||
}
|
||||
|
||||
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
|
||||
return singleAdapter.update(() -> manager.get(id), applyChanges);
|
||||
}
|
||||
|
||||
public Response getAll(int page, int pageSize, String sortBy, boolean desc, Function<PageResult<MODEL_OBJECT>, CollectionDto> mapToDto) {
|
||||
return collectionAdapter.getAll(page, pageSize, sortBy, desc, mapToDto);
|
||||
}
|
||||
|
||||
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws IOException, EXCEPTION {
|
||||
return collectionAdapter.create(dto, modelObjectSupplier, uriCreator);
|
||||
}
|
||||
|
||||
public Response delete(String id) {
|
||||
return singleAdapter.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,14 @@ public class RepositoryResource {
|
||||
|
||||
private final RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
|
||||
|
||||
private final ResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
|
||||
private final RepositoryManager manager;
|
||||
private final SingleResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
|
||||
|
||||
@Inject
|
||||
public RepositoryResource(RepositoryToRepositoryDtoMapper repositoryToDtoMapper, RepositoryManager manager) {
|
||||
this.manager = manager;
|
||||
this.repositoryToDtoMapper = repositoryToDtoMapper;
|
||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
||||
this.adapter = new SingleResourceManagerAdapter<>(manager);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -39,6 +41,6 @@ public class RepositoryResource {
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||
return adapter.get("31QwjAKOK2", repositoryToDtoMapper::map);
|
||||
return adapter.get(() -> manager.getByNamespace(namespace, name), repositoryToDtoMapper::map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import sonia.scm.Manager;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.api.rest.resources.AbstractManagerResource;
|
||||
|
||||
import javax.ws.rs.core.GenericEntity;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* Adapter from resource http endpoints to managers.
|
||||
*
|
||||
* Provides common CRUD operations and DTO to Model Object mapping to keep Resources more DRY.
|
||||
*
|
||||
* @param <MODEL_OBJECT> The type of the model object, eg. {@link sonia.scm.user.User}.
|
||||
* @param <DTO> The corresponding transport object, eg. {@link UserDto}.
|
||||
* @param <EXCEPTION> The exception type for the model object, eg. {@link sonia.scm.user.UserException}.
|
||||
*/
|
||||
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||
class SingleResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||
DTO extends HalRepresentation,
|
||||
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
|
||||
|
||||
SingleResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the model object for the given id, transforms it to a dto and returns a corresponding http response.
|
||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||
*/
|
||||
Response get(Supplier<MODEL_OBJECT> reader, Function<MODEL_OBJECT, DTO> mapToDto) {
|
||||
MODEL_OBJECT modelObject = reader.get();
|
||||
if (modelObject == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
DTO dto = mapToDto.apply(modelObject);
|
||||
return Response.ok(dto).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the model object for the given id according to the given function and returns a corresponding http response.
|
||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||
*/
|
||||
public Response update(Supplier<MODEL_OBJECT> reader, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
|
||||
MODEL_OBJECT existingModelObject = reader.get();
|
||||
if (existingModelObject == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND).build();
|
||||
}
|
||||
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject);
|
||||
if (!getId(existingModelObject).equals(getId(changedModelObject))) {
|
||||
return Response.status(BAD_REQUEST).entity("illegal change of id").build();
|
||||
}
|
||||
return update(getId(existingModelObject), changedModelObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GenericEntity<Collection<MODEL_OBJECT>> createGenericEntity(Collection<MODEL_OBJECT> modelObjects) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getId(MODEL_OBJECT item) {
|
||||
return item.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPathPart() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,23 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.*;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserException;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -18,14 +28,14 @@ public class UserCollectionResource {
|
||||
private final UserCollectionToDtoMapper userCollectionToDtoMapper;
|
||||
private final ResourceLinks resourceLinks;
|
||||
|
||||
private final ResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||
|
||||
@Inject
|
||||
public UserCollectionResource(UserManager manager, UserDtoToUserMapper dtoToUserMapper,
|
||||
UserCollectionToDtoMapper userCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
||||
this.dtoToUserMapper = dtoToUserMapper;
|
||||
this.userCollectionToDtoMapper = userCollectionToDtoMapper;
|
||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
||||
this.adapter = new IdResourceManagerAdapter<>(manager);
|
||||
this.resourceLinks = resourceLinks;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,13 @@ public class UserResource {
|
||||
private final UserDtoToUserMapper dtoToUserMapper;
|
||||
private final UserToUserDtoMapper userToDtoMapper;
|
||||
|
||||
private final ResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||
|
||||
@Inject
|
||||
public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager) {
|
||||
this.dtoToUserMapper = dtoToUserMapper;
|
||||
this.userToDtoMapper = userToDtoMapper;
|
||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
||||
this.adapter = new IdResourceManagerAdapter<>(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user