Merge pull request #1750 from 4Science/DS-3593

DS-3593 allow aggregation of endpoints by category / Include UUID in serialization
This commit is contained in:
Andrea Bollini
2017-05-25 18:29:56 +02:00
committed by GitHub
24 changed files with 117 additions and 53 deletions

View File

@@ -49,7 +49,7 @@ import org.springframework.web.bind.annotation.RestController;
*
*/
@RestController
@RequestMapping("/api/core/{model}")
@RequestMapping("/api/{apiCategory}/{model}")
@SuppressWarnings("rawtypes")
public class RestResourceController implements InitializingBean {
@Autowired
@@ -65,8 +65,9 @@ public class RestResourceController implements InitializingBean {
// this doesn't work as we don't have an active http request
// see https://github.com/spring-projects/spring-hateoas/issues/408
// Link l = linkTo(this.getClass(), r).withRel(r);
String plural = English.plural(r);
Link l = new Link("/api/core/" + plural, plural);
String[] split = r.split("\\.", 2);
String plural = English.plural(split[1]);
Link l = new Link("/api/" + split[0] + "/" + plural, plural);
links.add(l);
System.out.println(l.getRel() + " " + l.getHref());
}
@@ -75,44 +76,44 @@ public class RestResourceController implements InitializingBean {
@RequestMapping(method = RequestMethod.GET, value = "/{id:\\d+}")
@SuppressWarnings("unchecked")
DSpaceResource<RestModel> findOne(@PathVariable String model, @PathVariable Integer id, @RequestParam(required=false) String projection) {
return findOneInternal(model, id, projection);
DSpaceResource<RestModel> findOne(@PathVariable String apiCategory, @PathVariable String model, @PathVariable Integer id, @RequestParam(required=false) String projection) {
return findOneInternal(apiCategory, model, id, projection);
}
@RequestMapping(method = RequestMethod.GET, value = "/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}")
@SuppressWarnings("unchecked")
DSpaceResource<RestModel> findOne(@PathVariable String model, @PathVariable UUID uuid, @RequestParam(required=false) String projection) {
return findOneInternal(model, uuid, projection);
DSpaceResource<RestModel> findOne(@PathVariable String apiCategory, @PathVariable String model, @PathVariable UUID uuid, @RequestParam(required=false) String projection) {
return findOneInternal(apiCategory, model, uuid, projection);
}
private <ID extends Serializable> DSpaceResource<RestModel> findOneInternal(String model, ID id, String projection) {
DSpaceRestRepository<RestModel, ID> repository = utils.getResourceRepository(model);
private <ID extends Serializable> DSpaceResource<RestModel> findOneInternal(String apiCategory, String model, ID id, String projection) {
DSpaceRestRepository<RestModel, ID> repository = utils.getResourceRepository(apiCategory, model);
RestModel modelObject = null;
try {
modelObject = repository.findOne(id);
} catch (ClassCastException e) {
}
if (modelObject == null) {
throw new ResourceNotFoundException(model + " with id: " + id + " not found");
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found");
}
DSpaceResource result = repository.wrapResource(modelObject);
return result;
}
@RequestMapping(method = RequestMethod.GET, value = "/{id:\\d+}/{rel}")
ResourceSupport findRel(@PathVariable String model, @PathVariable Integer id, @PathVariable String rel, @RequestParam(required=false) String projection) {
return findRelInternal(model, id, rel, projection);
ResourceSupport findRel(@PathVariable String apiCategory, @PathVariable String model, @PathVariable Integer id, @PathVariable String rel, @RequestParam(required=false) String projection) {
return findRelInternal(apiCategory, model, id, rel, projection);
}
@RequestMapping(method = RequestMethod.GET, value = "/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}/{rel}")
ResourceSupport findRel(@PathVariable String model, @PathVariable UUID uuid, @PathVariable String rel, @RequestParam(required=false) String projection) {
return findRelInternal(model, uuid, rel, projection);
ResourceSupport findRel(@PathVariable String apiCategory, @PathVariable String model, @PathVariable UUID uuid, @PathVariable String rel, @RequestParam(required=false) String projection) {
return findRelInternal(apiCategory, model, uuid, rel, projection);
}
private <ID extends Serializable> ResourceSupport findRelInternal(String model, ID uuid, String rel, String projection) {
private <ID extends Serializable> ResourceSupport findRelInternal(String apiCategory, String model, ID uuid, String rel, String projection) {
// FIXME this is a very bad implementation as it leads most of times to
// more round-trip on the database and retrieval of unneeded infromation
DSpaceRestRepository<RestModel, ID> repository = utils.getResourceRepository(model);
DSpaceRestRepository<RestModel, ID> repository = utils.getResourceRepository(apiCategory, model);
RestModel modelObject = repository.findOne(uuid);
DSpaceResource result = repository.wrapResource(modelObject, rel);
if (result.getLink(rel) == null) {
@@ -126,15 +127,14 @@ public class RestResourceController implements InitializingBean {
@RequestMapping(method = RequestMethod.GET)
@SuppressWarnings("unchecked")
<T extends RestModel> PagedResources<DSpaceResource<T>> findAll(@PathVariable String model, Pageable page, PagedResourcesAssembler assembler, @RequestParam(required=false) String projection) {
DSpaceRestRepository<T, ?> repository = utils.getResourceRepository(model);
<T extends RestModel> PagedResources<DSpaceResource<T>> findAll(@PathVariable String apiCategory, @PathVariable String model, Pageable page, PagedResourcesAssembler assembler, @RequestParam(required=false) String projection) {
DSpaceRestRepository<T, ?> repository = utils.getResourceRepository(apiCategory, model);
// Link link = entityLinks.linkFor(getResourceClass(model), model, page).withSelfRel();
Link link = linkTo(this.getClass(), model).withSelfRel();
Link link = linkTo(this.getClass(), apiCategory, model).withSelfRel();
Page<DSpaceResource<T>> resources;
try {
resources = repository.findAll(page).map(repository::wrapResource);
// resources.forEach(r -> {
// Link linkToSingleResource = Utils.linkToSingleResource(r, Link.REL_SELF);
// r.add(linkToSingleResource);
// });

View File

@@ -18,9 +18,11 @@ import org.springframework.web.bind.annotation.ResponseStatus;
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "This endpoint is not found in the system")
public class RepositoryNotFoundException extends RuntimeException {
String apiCategory;
String model;
public RepositoryNotFoundException(String model) {
public RepositoryNotFoundException(String apiCategory, String model) {
this.apiCategory = apiCategory;
this.model = model;
}

View File

@@ -21,7 +21,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class BitstreamFormatRest extends BaseObjectRest<Integer> {
public static final String NAME = "bitstreamformat";
public static final String CATEGORY = RestModel.CORE;
private String shortDescription;
private String description;
@@ -82,6 +84,12 @@ public class BitstreamFormatRest extends BaseObjectRest<Integer> {
this.extensions = extensions;
}
@JsonIgnore
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty.Access;
*/
public class BitstreamRest extends DSpaceObjectRest {
public static final String NAME = "bitstream";
public static final String CATEGORY = RestModel.CORE;
private String bundleName;
// avoid to serialize this object inline as we want a full resource embedded
@@ -68,6 +69,11 @@ public class BitstreamRest extends DSpaceObjectRest {
this.sequenceId = sequenceId;
}
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -15,7 +15,13 @@ package org.dspace.app.rest.model;
*/
public class CollectionRest extends DSpaceObjectRest {
public static final String NAME = "collection";
public static final String CATEGORY = RestModel.CORE;
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -15,7 +15,13 @@ package org.dspace.app.rest.model;
*/
public class CommunityRest extends DSpaceObjectRest {
public static final String NAME = "community";
public static final String CATEGORY = RestModel.CORE;
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -11,8 +11,6 @@ import java.util.List;
import org.dspace.app.rest.RestResourceController;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Base REST representation for all the DSpaceObjects
*
@@ -20,17 +18,14 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*
*/
public abstract class DSpaceObjectRest extends BaseObjectRest<String> {
@JsonIgnore
private String uuid;
private String name;
private String handle;
private String type;
List<MetadataEntryRest> metadata;
@Override
@JsonIgnore
public String getId() {
return uuid;
}
@@ -68,7 +63,6 @@ public abstract class DSpaceObjectRest extends BaseObjectRest<String> {
}
@Override
@JsonIgnore
public Class getController() {
return RestResourceController.class;
}

View File

@@ -12,8 +12,6 @@ import java.util.List;
import org.dspace.app.rest.RestResourceController;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* The EPerson REST Resource
*
@@ -22,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class EPersonRest extends DSpaceObjectRest {
public static final String NAME = "eperson";
public static final String CATEGORY = RestModel.EPERSON;
private String netid;
private Date lastActive;
@@ -102,7 +100,11 @@ public class EPersonRest extends DSpaceObjectRest {
}
@Override
@JsonIgnore
public String getCategory() {
return CATEGORY;
}
@Override
public Class getController() {
return RestResourceController.class;
}

View File

@@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class GroupRest extends DSpaceObjectRest {
public static final String NAME = "group";
public static final String CATEGORY = RestModel.EPERSON;
private String name;
@@ -31,6 +33,11 @@ public class GroupRest extends DSpaceObjectRest {
// https://jira.duraspace.org/browse/DS-3483
private List<GroupRest> groups;
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class ItemRest extends DSpaceObjectRest {
public static final String NAME = "item";
public static final String CATEGORY = RestModel.CORE;
private boolean inArchive = false;
private boolean discoverable = false;
private boolean withdrawn = false;
@@ -32,6 +33,11 @@ public class ItemRest extends DSpaceObjectRest {
List<BitstreamRest> bitstreams;
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -19,7 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class MetadataFieldRest extends BaseObjectRest<Integer> {
public static final String NAME = "metadatafield";
public static final String CATEGORY = RestModel.CORE;
@JsonIgnore
private MetadataSchemaRest schema;
@@ -67,8 +68,12 @@ public class MetadataFieldRest extends BaseObjectRest<Integer> {
}
@Override
@JsonIgnore
public Class getController() {
return RestResourceController.class;
}
@Override
public String getCategory() {
return CATEGORY;
}
}

View File

@@ -21,7 +21,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class MetadataSchemaRest extends BaseObjectRest<Integer> {
public static final String NAME = "metadataschema";
public static final String CATEGORY = RestModel.CORE;
private String prefix;
private String namespace;
@@ -48,8 +49,12 @@ public class MetadataSchemaRest extends BaseObjectRest<Integer> {
}
@Override
@JsonIgnore
public Class getController() {
return RestResourceController.class;
}
@Override
public String getCategory() {
return CATEGORY;
}
}

View File

@@ -7,6 +7,8 @@
*/
package org.dspace.app.rest.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* Methods to implement to make a REST resource addressable
*
@@ -14,7 +16,15 @@ package org.dspace.app.rest.model;
*
*/
public interface RestModel {
public static final String CORE = "core";
public static final String EPERSON = "eperson";
public static final String DISCOVER = "discover";
@JsonIgnore
public String getCategory();
public String getType();
@JsonIgnore
public Class getController();
}

View File

@@ -15,7 +15,13 @@ package org.dspace.app.rest.model;
*/
public class SiteRest extends DSpaceObjectRest {
public static final String NAME = "site";
public static final String CATEGORY = RestModel.CORE;
@Override
public String getCategory() {
return CATEGORY;
}
@Override
public String getType() {
return NAME;

View File

@@ -55,11 +55,12 @@ public abstract class DSpaceResource<T extends RestModel> extends ResourceSuppor
RestModel linkedObject = (RestModel) readMethod.invoke(data);
if (linkedObject != null) {
embedded.put(pd.getName(),
utils.getResourceRepository(linkedObject.getType()).wrapResource(linkedObject));
utils.getResourceRepository(linkedObject.getCategory(), linkedObject.getType())
.wrapResource(linkedObject));
} else {
embedded.put(pd.getName(), null);
}
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(data, new Object[] { null });
}

View File

@@ -28,7 +28,7 @@ import org.springframework.stereotype.Component;
* @author Andrea Bollini (andrea.bollini at 4science.it)
*
*/
@Component(BitstreamFormatRest.NAME)
@Component(BitstreamFormatRest.CATEGORY + "." + BitstreamFormatRest.NAME)
public class BitstreamFormatRestRepository extends DSpaceRestRepository<BitstreamFormatRest, Integer> {
BitstreamFormatService bfs = ContentServiceFactory.getInstance().getBitstreamFormatService();
@Autowired

View File

@@ -33,7 +33,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(BitstreamRest.NAME)
@Component(BitstreamRest.CATEGORY + "." + BitstreamRest.NAME)
public class BitstreamRestRepository extends DSpaceRestRepository<BitstreamRest, UUID> {
BitstreamService bs = ContentServiceFactory.getInstance().getBitstreamService();
@Autowired

View File

@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(CollectionRest.NAME)
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
public class CollectionRestRepository extends DSpaceRestRepository<CollectionRest, UUID> {
CollectionService cs = ContentServiceFactory.getInstance().getCollectionService();
@Autowired

View File

@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(CommunityRest.NAME)
@Component(CommunityRest.CATEGORY + "." + CommunityRest.NAME)
public class CommunityRestRepository extends DSpaceRestRepository<CommunityRest, UUID> {
CommunityService cs = ContentServiceFactory.getInstance().getCommunityService();
@Autowired

View File

@@ -31,7 +31,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(EPersonRest.NAME)
@Component(EPersonRest.CATEGORY + "." + EPersonRest.NAME)
public class EPersonRestRepository extends DSpaceRestRepository<EPersonRest, UUID> {
EPersonService es = EPersonServiceFactory.getInstance().getEPersonService();

View File

@@ -31,7 +31,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(GroupRest.NAME)
@Component(GroupRest.CATEGORY + "." + GroupRest.NAME)
public class GroupRestRepository extends DSpaceRestRepository<GroupRest, UUID> {
GroupService gs = EPersonServiceFactory.getInstance().getGroupService();

View File

@@ -33,7 +33,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(ItemRest.NAME)
@Component(ItemRest.CATEGORY + "." + ItemRest.NAME)
public class ItemRestRepository extends DSpaceRestRepository<ItemRest, UUID> {
ItemService is = ContentServiceFactory.getInstance().getItemService();
@Autowired

View File

@@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
*
*/
@Component(SiteRest.NAME)
@Component(SiteRest.CATEGORY + "." + SiteRest.NAME)
public class SiteRestRepository extends DSpaceRestRepository<SiteRest, UUID> {
SiteService sitesv = ContentServiceFactory.getInstance().getSiteService();
@Autowired

View File

@@ -59,19 +59,19 @@ public class Utils {
}
public Link linkToSingleResource(RestModel data, String rel) {
return linkTo(data.getController(), data.getType()).slash(data).withRel(rel);
return linkTo(data.getController(), data.getCategory(), data.getType()).slash(data).withRel(rel);
}
public Link linkToSubResource(RestModel data, String rel) {
return linkTo(data.getController(), data.getType()).slash(data).slash(rel).withRel(rel);
return linkTo(data.getController(), data.getCategory(), data.getType()).slash(data).slash(rel).withRel(rel);
}
public DSpaceRestRepository getResourceRepository(String modelPlural) {
public DSpaceRestRepository getResourceRepository(String apiCategory, String modelPlural) {
String model = makeSingular(modelPlural);
try {
return applicationContext.getBean(model, DSpaceRestRepository.class);
return applicationContext.getBean(apiCategory + "." + model, DSpaceRestRepository.class);
} catch (NoSuchBeanDefinitionException e) {
throw new RepositoryNotFoundException(model);
throw new RepositoryNotFoundException(apiCategory, model);
}
}