Replace model object exception with generic ones and migrate guice

This commit is contained in:
René Pfeuffer
2018-08-21 07:53:33 +02:00
parent bb9a0657a5
commit a0f74e3329
227 changed files with 1380 additions and 3549 deletions

View File

@@ -5,7 +5,6 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.repository.Branches;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.api.CommandNotSupportedException;
import sonia.scm.repository.api.RepositoryService;
@@ -55,7 +54,7 @@ public class BranchRootResource {
@ResponseCode(code = 404, condition = "not found, no branch with the specified name for the repository available or repository not found"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("branch") String branchName) throws IOException, RepositoryException {
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("branch") String branchName) throws IOException {
try (RepositoryService repositoryService = servicefactory.create(new NamespaceAndName(namespace, name))) {
Branches branches = repositoryService.getBranchesCommand().getBranches();
return branches.getBranches()
@@ -100,7 +99,7 @@ public class BranchRootResource {
@ResponseCode(code = 404, condition = "not found, no repository found for the given namespace and name"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws IOException, RepositoryException {
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws IOException {
try (RepositoryService repositoryService = servicefactory.create(new NamespaceAndName(namespace, name))) {
Branches branches = repositoryService.getBranchesCommand().getBranches();
return Response.ok(branchCollectionToDtoMapper.map(namespace, name, branches.getBranches())).build();

View File

@@ -1,6 +1,7 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import sonia.scm.AlreadyExistsException;
import sonia.scm.Manager;
import sonia.scm.ModelObject;
import sonia.scm.PageResult;
@@ -22,16 +23,14 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
*
* @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}.
*
* @see SingleResourceManagerAdapter
*/
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
class CollectionResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
DTO extends HalRepresentation,
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
DTO extends HalRepresentation> extends AbstractManagerResource<MODEL_OBJECT> {
CollectionResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
CollectionResourceManagerAdapter(Manager<MODEL_OBJECT> manager, Class<MODEL_OBJECT> type) {
super(manager, type);
}
@@ -48,7 +47,7 @@ class CollectionResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
* Creates a model object for the given dto and returns a corresponding http response.
* This handles all corner cases, eg. no conflicts or missing privileges.
*/
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws EXCEPTION {
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws AlreadyExistsException {
if (dto == null) {
return Response.status(BAD_REQUEST).build();
}

View File

@@ -8,7 +8,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
@@ -79,9 +78,9 @@ public class ContentResource {
} catch (PathNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
throw new WebApplicationException(Status.NOT_FOUND);
} catch (RepositoryException e) {
LOG.info("error reading repository resource {} from {}/{}", path, namespace, name, e);
throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
} catch (RevisionNotFoundException e) {
LOG.debug("revision '{}' not found in repository {}/{}", revision, namespace, name, e);
throw new WebApplicationException(Status.NOT_FOUND);
}
};
}
@@ -124,7 +123,7 @@ public class ContentResource {
} catch (RevisionNotFoundException e) {
LOG.debug("revision '{}' not found in repository {}/{}", revision, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
} catch (IOException | RepositoryException e) {
} catch (IOException e) {
LOG.info("error reading repository resource {} from {}/{}", path, namespace, name, e);
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
@@ -137,7 +136,7 @@ public class ContentResource {
contentType.getLanguage().ifPresent(language -> responseBuilder.header("Language", language));
}
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException, RepositoryException {
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException, PathNotFoundException, RevisionNotFoundException {
InputStream stream = repositoryService.getCatCommand().setRevision(revision).getStream(path);
try {
byte[] buffer = new byte[HEAD_BUFFER_SIZE];

View File

@@ -1,15 +1,24 @@
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.AlreadyExistsException;
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;
public class GroupCollectionResource {
@@ -19,7 +28,7 @@ public class GroupCollectionResource {
private final GroupCollectionToDtoMapper groupCollectionToDtoMapper;
private final ResourceLinks resourceLinks;
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
private final IdResourceManagerAdapter<Group, GroupDto> adapter;
@Inject
public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupCollectionToDtoMapper groupCollectionToDtoMapper, ResourceLinks resourceLinks) {
@@ -76,7 +85,7 @@ public class GroupCollectionResource {
})
@TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created group"))
public Response create(GroupDto groupDto) throws IOException, GroupException {
public Response create(GroupDto groupDto) throws AlreadyExistsException {
return adapter.create(groupDto,
() -> dtoToGroupMapper.map(groupDto),
group -> resourceLinks.group().self(group.getName()));

View File

@@ -4,19 +4,24 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
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.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
public class GroupResource {
private final GroupToGroupDtoMapper groupToGroupDtoMapper;
private final GroupDtoToGroupMapper dtoToGroupMapper;
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
private final IdResourceManagerAdapter<Group, GroupDto> adapter;
@Inject
public GroupResource(GroupManager manager, GroupToGroupDtoMapper groupToGroupDtoMapper,

View File

@@ -1,12 +1,12 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import sonia.scm.AlreadyExistsException;
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.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -18,15 +18,14 @@ import java.util.function.Supplier;
*/
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
DTO extends HalRepresentation,
EXCEPTION extends Exception> {
DTO extends HalRepresentation> {
private final Manager<MODEL_OBJECT, EXCEPTION> manager;
private final Manager<MODEL_OBJECT> manager;
private final SingleResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> singleAdapter;
private final CollectionResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> collectionAdapter;
private final SingleResourceManagerAdapter<MODEL_OBJECT, DTO> singleAdapter;
private final CollectionResourceManagerAdapter<MODEL_OBJECT, DTO> collectionAdapter;
IdResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
IdResourceManagerAdapter(Manager<MODEL_OBJECT> manager, Class<MODEL_OBJECT> type) {
this.manager = manager;
singleAdapter = new SingleResourceManagerAdapter<>(manager, type);
collectionAdapter = new CollectionResourceManagerAdapter<>(manager, type);
@@ -48,7 +47,7 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
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 {
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws AlreadyExistsException {
return collectionAdapter.create(dto, modelObjectSupplier, uriCreator);
}

View File

@@ -5,7 +5,6 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import org.apache.shiro.SecurityUtils;
import sonia.scm.user.User;
import sonia.scm.user.UserException;
import sonia.scm.user.UserManager;
import sonia.scm.web.VndMediaType;
@@ -28,7 +27,7 @@ public class MeResource {
private final UserToUserDtoMapper userToDtoMapper;
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
private final IdResourceManagerAdapter<User, UserDto> adapter;
@Inject
public MeResource(UserToUserDtoMapper userToDtoMapper, UserManager manager) {
this.userToDtoMapper = userToDtoMapper;

View File

@@ -5,8 +5,8 @@ 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.AlreadyExistsException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.web.VndMediaType;
@@ -25,7 +25,7 @@ public class RepositoryCollectionResource {
private static final int DEFAULT_PAGE_SIZE = 10;
private final CollectionResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
private final CollectionResourceManagerAdapter<Repository, RepositoryDto> adapter;
private final RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper;
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
private final ResourceLinks resourceLinks;
@@ -87,7 +87,7 @@ public class RepositoryCollectionResource {
})
@TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created repository"))
public Response create(@Valid RepositoryDto repositoryDto) throws RepositoryException {
public Response create(@Valid RepositoryDto repositoryDto) throws AlreadyExistsException {
return adapter.create(repositoryDto,
() -> dtoToRepositoryMapper.map(repositoryDto, null),
repository -> resourceLinks.repository().self(repository.getNamespace(), repository.getName()));

View File

@@ -5,7 +5,6 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryIsNotArchivedException;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.web.VndMediaType;
@@ -30,7 +29,7 @@ public class RepositoryResource {
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
private final RepositoryManager manager;
private final SingleResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
private final SingleResourceManagerAdapter<Repository, RepositoryDto> adapter;
private final Provider<TagRootResource> tagRootResource;
private final Provider<BranchRootResource> branchRootResource;
private final Provider<ChangesetRootResource> changesetRootResource;

View File

@@ -22,22 +22,20 @@ import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
*
* @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}.
*
* @see CollectionResourceManagerAdapter
*/
@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> {
DTO extends HalRepresentation> extends AbstractManagerResource<MODEL_OBJECT> {
private final Function<Throwable, Optional<Response>> errorHandler;
SingleResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
SingleResourceManagerAdapter(Manager<MODEL_OBJECT> manager, Class<MODEL_OBJECT> type) {
this(manager, type, e -> Optional.empty());
}
SingleResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type, Function<Throwable, Optional<Response>> errorHandler) {
SingleResourceManagerAdapter(Manager<MODEL_OBJECT> manager, Class<MODEL_OBJECT> type, Function<Throwable, Optional<Response>> errorHandler) {
super(manager, type);
this.errorHandler = errorHandler;
}

View File

@@ -1,15 +1,24 @@
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.AlreadyExistsException;
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;
public class UserCollectionResource {
@@ -18,7 +27,7 @@ public class UserCollectionResource {
private final UserCollectionToDtoMapper userCollectionToDtoMapper;
private final ResourceLinks resourceLinks;
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
private final IdResourceManagerAdapter<User, UserDto> adapter;
@Inject
public UserCollectionResource(UserManager manager, UserDtoToUserMapper dtoToUserMapper,
@@ -78,7 +87,7 @@ public class UserCollectionResource {
})
@TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created user"))
public Response create(UserDto userDto) throws IOException, UserException {
public Response create(UserDto userDto) throws AlreadyExistsException {
return adapter.create(userDto,
() -> dtoToUserMapper.map(userDto, ""),
user -> resourceLinks.user().self(user.getName()));

View File

@@ -4,12 +4,17 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
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.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
public class UserResource {
@@ -17,7 +22,7 @@ public class UserResource {
private final UserDtoToUserMapper dtoToUserMapper;
private final UserToUserDtoMapper userToDtoMapper;
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
private final IdResourceManagerAdapter<User, UserDto> adapter;
@Inject
public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager) {