From 827c68d59754fc76f75aae18939b8a3820cca588 Mon Sep 17 00:00:00 2001 From: Patrick Schmitz Date: Tue, 20 Oct 2009 05:32:04 +0000 Subject: [PATCH] CSPACE-451 Finished up the functionality to support VocabularyItem sub-resource of Vocabularies. Reworked some of the ServiceContext and related classes to support alternate services when a sub-resource is involved. Renamed the vocabularyitem schemas and related classes to consistently use all-lower letters to prevent problems with the repository layer. --- .../services/client/BaseServiceClient.java | 6 +- .../client/test/AbstractServiceTest.java | 85 ++++- .../src/main/config/tenant-bindings.xml | 30 ++ .../AbstractCollectionSpaceResource.java | 7 +- .../common/CollectionSpaceResource.java | 14 +- .../context/AbstractServiceContext.java | 10 +- .../common/context/ServiceContext.java | 9 +- .../resources/OSGI-INF/core-types-contrib.xml | 2 +- .../resources/OSGI-INF/ecm-types-contrib.xml | 6 +- .../services/client/VocabularyClient.java | 66 +++- .../services/client/VocabularyProxy.java | 28 ++ .../client/test/VocabularyServiceTest.java | 312 +++++++++++++++++- .../main/resources/vocabularyitem_common.xsd | 52 +++ .../vocabulary/VocabularyResource.java | 243 +++++++++++++- .../nuxeo/VocabularyHandlerFactory.java | 2 +- .../nuxeo/VocabularyItemConstants.java | 35 ++ .../VocabularyItemDocumentModelHandler.java | 177 ++++++++++ .../nuxeo/VocabularyItemHandlerFactory.java | 56 ++++ 18 files changed, 1091 insertions(+), 49 deletions(-) create mode 100644 services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd create mode 100644 services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemConstants.java create mode 100644 services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java create mode 100644 services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemHandlerFactory.java diff --git a/services/client/src/main/java/org/collectionspace/services/client/BaseServiceClient.java b/services/client/src/main/java/org/collectionspace/services/client/BaseServiceClient.java index b7ca56bea..9756c1a9c 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/BaseServiceClient.java +++ b/services/client/src/main/java/org/collectionspace/services/client/BaseServiceClient.java @@ -44,7 +44,11 @@ public abstract class BaseServiceClient implements CollectionSpaceClient { private HttpClient httpClient; public String getCommonPartName() { - return getServicePathComponent() + return getCommonPartName(getServicePathComponent()); + } + + public String getCommonPartName(String servicePathComponent) { + return servicePathComponent + ServiceContext.PART_LABEL_SEPERATOR + ServiceContext.PART_COMMON_LABEL; } diff --git a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java index 98ba2f35c..b8faae103 100644 --- a/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java +++ b/services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTest.java @@ -53,7 +53,7 @@ public abstract class AbstractServiceTest implements ServiceTest { final Logger logger = LoggerFactory.getLogger(AbstractServiceTest.class); // A base-level client, used (only) to obtain the base service URL. - private static final TestServiceClient serviceClient = new TestServiceClient(); + protected static final TestServiceClient serviceClient = new TestServiceClient(); // A resource identifier believed to be non-existent in actual use, // used when testing service calls that reference non-existent resources. protected final String NON_EXISTENT_ID = createNonExistentIdentifier(); @@ -88,7 +88,11 @@ public abstract class AbstractServiceTest implements ServiceTest { } protected void setupCreate() { - clearSetup("Create"); + setupCreate("Create"); + } + + protected void setupCreate(String label) { + clearSetup(label); // Expected status code: 201 Created EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); // Type of service request being tested @@ -104,7 +108,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void createWithEmptyEntityBody(); protected void setupCreateWithEmptyEntityBody() { - clearSetup("CreateWithEmptyEntityBody"); + setupCreateWithEmptyEntityBody("CreateWithEmptyEntityBody"); + } + + protected void setupCreateWithEmptyEntityBody(String label) { + clearSetup(label); EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; } @@ -113,7 +121,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void createWithMalformedXml(); protected void setupCreateWithMalformedXml() { - clearSetup("CreateWithMalformedXml"); + setupCreateWithMalformedXml("CreateWithMalformedXml"); + } + + protected void setupCreateWithMalformedXml(String label) { + clearSetup(label); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; @@ -123,7 +135,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void createWithWrongXmlSchema(); protected void setupCreateWithWrongXmlSchema() { - clearSetup("CreateWithWrongXmlSchema"); + setupCreateWithWrongXmlSchema("CreateWithWrongXmlSchema"); + } + + protected void setupCreateWithWrongXmlSchema(String label) { + clearSetup(label); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.CREATE; @@ -137,7 +153,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void read(); protected void setupRead() { - clearSetup("Read"); + setupRead("Read"); + } + + protected void setupRead(String label) { + clearSetup(label); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ; @@ -148,7 +168,10 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void readNonExistent(); protected void setupReadNonExistent() { - clearSetup("ReadNonExistent"); + setupReadNonExistent("ReadNonExistent"); + } + protected void setupReadNonExistent(String label) { + clearSetup(label); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ; @@ -162,7 +185,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void readList(); protected void setupReadList() { - clearSetup("ReadList"); + setupReadList("ReadList"); + } + + protected void setupReadList(String label) { + clearSetup(label); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.READ_LIST; @@ -179,7 +206,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void update(); protected void setupUpdate() { - clearSetup("Update"); + setupUpdate("Update"); + } + + protected void setupUpdate(String label) { + clearSetup(label); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -190,7 +221,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateWithEmptyEntityBody(); protected void setupUpdateWithEmptyEntityBody() { - clearSetup("UpdateWithEmptyEntityBody"); + setupUpdateWithEmptyEntityBody("UpdateWithEmptyEntityBody"); + } + + protected void setupUpdateWithEmptyEntityBody(String label) { + clearSetup(label); EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; } @@ -199,7 +234,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateWithMalformedXml(); protected void setupUpdateWithMalformedXml() { - clearSetup("UpdateWithMalformedXml"); + setupUpdateWithMalformedXml("UpdateWithMalformedXml"); + } + + protected void setupUpdateWithMalformedXml(String label) { + clearSetup(label); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -209,7 +248,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateWithWrongXmlSchema(); protected void setupUpdateWithWrongXmlSchema() { - clearSetup("UpdateWithWrongXmlSchema"); + setupUpdateWithWrongXmlSchema("UpdateWithWrongXmlSchema"); + } + + protected void setupUpdateWithWrongXmlSchema(String label) { + clearSetup(label); // Expected status code: 400 Bad Request EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -219,7 +262,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void updateNonExistent(); protected void setupUpdateNonExistent() { - clearSetup("UpdateNonExistent"); + setupUpdateNonExistent("UpdateNonExistent"); + } + + protected void setupUpdateNonExistent(String label) { + clearSetup(label); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.UPDATE; @@ -233,7 +280,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void delete(); protected void setupDelete() { - clearSetup("Delete"); + setupDelete("Delete"); + } + + protected void setupDelete(String label) { + clearSetup(label); // Expected status code: 200 OK EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); REQUEST_TYPE = ServiceRequestType.DELETE; @@ -244,7 +295,11 @@ public abstract class AbstractServiceTest implements ServiceTest { public abstract void deleteNonExistent(); protected void setupDeleteNonExistent() { - clearSetup("DeleteNonExistent"); + setupDeleteNonExistent("DeleteNonExistent"); + } + + protected void setupDeleteNonExistent(String label) { + clearSetup(label); // Expected status code: 404 Not Found EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); REQUEST_TYPE = ServiceRequestType.DELETE; diff --git a/services/common/src/main/config/tenant-bindings.xml b/services/common/src/main/config/tenant-bindings.xml index 05e8caf71..e452193c7 100644 --- a/services/common/src/main/config/tenant-bindings.xml +++ b/services/common/src/main/config/tenant-bindings.xml @@ -106,6 +106,36 @@ + + + + nuxeo-java + + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java index e66ea566d..bac653c5f 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java +++ b/services/common/src/main/java/org/collectionspace/services/common/AbstractCollectionSpaceResource.java @@ -61,7 +61,12 @@ public abstract class AbstractCollectionSpaceResource @Override public RemoteServiceContext createServiceContext(MultipartInput input) throws Exception { - RemoteServiceContext ctx = new RemoteServiceContextImpl(getServiceName()); + return createServiceContext(input,getServiceName()); + } + + @Override + public RemoteServiceContext createServiceContext(MultipartInput input, String serviceName) throws Exception { + RemoteServiceContext ctx = new RemoteServiceContextImpl(serviceName); ctx.setInput(input); return ctx; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java index 11062548f..1375dd72b 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java +++ b/services/common/src/main/java/org/collectionspace/services/common/CollectionSpaceResource.java @@ -55,13 +55,23 @@ public interface CollectionSpaceResource { public RepositoryClient getRepositoryClient(ServiceContext ctx); /** - * createServiceContext is a facotry method to create a service context - * a service contex is created on every service request call + * createServiceContext is a factory method to create a service context + * a service context is created on every service request call + * This form uses the serviceName as the default context * @param input * @return */ public RemoteServiceContext createServiceContext(MultipartInput input) throws Exception; + /** + * createServiceContext is a factory method to create a service context + * a service context is created on every service request call + * @param input + * @param serviceName which service/repository context to use + * @return + */ + public RemoteServiceContext createServiceContext(MultipartInput input, String serviceName) throws Exception; + /** * createDocumentHandler creates a document handler and populates it with given * service context. document handler should never be used diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java index 333a5502b..aeea00ff3 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContext.java @@ -82,7 +82,15 @@ public abstract class AbstractServiceContext */ @Override public String getCommonPartLabel() { - return getServiceName().toLowerCase() + PART_LABEL_SEPERATOR + PART_COMMON_LABEL; + return getCommonPartLabel(getServiceName()); + } + + /** + * getCommonPartLabel get common part label + * @return + */ + public String getCommonPartLabel(String schemaName) { + return schemaName.toLowerCase() + PART_LABEL_SEPERATOR + PART_COMMON_LABEL; } @Override diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java index f3587cc57..c24c261e6 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java @@ -143,10 +143,17 @@ public interface ServiceContext { public Map getPartsMetadata(); /** - * getCommonPartLabel retruns label for common part of a service + * getCommonPartLabel returns label for common part of a service * @return label */ public String getCommonPartLabel(); + + /** + * getCommonPartLabel returns label for common part of a specified schema. + * This is useful for sub-resources. + * @return label + */ + public String getCommonPartLabel(String schemaName); } diff --git a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/core-types-contrib.xml b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/core-types-contrib.xml index fd3f4448b..16e331cc8 100644 --- a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/core-types-contrib.xml +++ b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/core-types-contrib.xml @@ -14,7 +14,7 @@ - + diff --git a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/ecm-types-contrib.xml b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/ecm-types-contrib.xml index 2d36a8f18..754987a80 100644 --- a/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/ecm-types-contrib.xml +++ b/services/vocabulary/3rdparty/nuxeo-platform-cs-vocabulary/src/main/resources/OSGI-INF/ecm-types-contrib.xml @@ -26,7 +26,7 @@ - + view_documents @@ -39,13 +39,13 @@ - VocabularyItem + Vocabularyitem - VocabularyItem + Vocabularyitem diff --git a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyClient.java b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyClient.java index fd8692412..bd45a7ffd 100644 --- a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyClient.java +++ b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyClient.java @@ -2,12 +2,11 @@ package org.collectionspace.services.client; import javax.ws.rs.core.Response; -import org.collectionspace.services.common.context.ServiceContext; import org.collectionspace.services.vocabulary.VocabulariesCommonList; - +import org.collectionspace.services.vocabulary.VocabularyitemsCommonList; +import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.client.ProxyFactory; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; -import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.spi.ResteasyProviderFactory; @@ -25,6 +24,10 @@ public class VocabularyClient extends BaseServiceClient { public String getServicePathComponent() { return "vocabularies"; } + + public String getItemCommonPartName() { + return getCommonPartName("vocabularyitems"); + } /** * @@ -57,7 +60,7 @@ public class VocabularyClient extends BaseServiceClient { /** * @return - * @see org.collectionspace.hello.client.VocabularyProxy#getVocabulary() + * @see org.collectionspace.services.client.VocabularyProxy#readList() */ public ClientResponse readList() { return vocabularyProxy.readList(); @@ -66,7 +69,7 @@ public class VocabularyClient extends BaseServiceClient { /** * @param csid * @return - * @see org.collectionspace.hello.client.VocabularyProxy#getVocabulary(java.lang.String) + * @see org.collectionspace.services.client.VocabularyProxy#read(java.lang.String) */ public ClientResponse read(String csid) { @@ -76,7 +79,7 @@ public class VocabularyClient extends BaseServiceClient { /** * @param vocabulary * @return - * @see org.collectionspace.hello.client.VocabularyProxy#createVocabulary(org.collectionspace.hello.Vocabulary) + * @see org.collectionspace.services.client.VocabularyProxy#createVocabulary(org.collectionspace.hello.Vocabulary) */ public ClientResponse create(MultipartOutput multipart) { return vocabularyProxy.create(multipart); @@ -86,7 +89,7 @@ public class VocabularyClient extends BaseServiceClient { * @param csid * @param vocabulary * @return - * @see org.collectionspace.hello.client.VocabularyProxy#updateVocabulary(java.lang.Long, org.collectionspace.hello.Vocabulary) + * @see org.collectionspace.services.client.VocabularyProxy#updateVocabulary(java.lang.Long, org.collectionspace.hello.Vocabulary) */ public ClientResponse update(String csid, MultipartOutput multipart) { return vocabularyProxy.update(csid, multipart); @@ -96,9 +99,56 @@ public class VocabularyClient extends BaseServiceClient { /** * @param csid * @return - * @see org.collectionspace.hello.client.VocabularyProxy#deleteVocabulary(java.lang.Long) + * @see org.collectionspace.services.client.VocabularyProxy#deleteVocabulary(java.lang.Long) */ public ClientResponse delete(String csid) { return vocabularyProxy.delete(csid); } + + /** + * @return + * @see org.collectionspace.services.client.VocabularyProxy#readItemList() + */ + public ClientResponse readItemList(String vcsid) { + return vocabularyProxy.readItemList(vcsid); + } + + /** + * @param csid + * @return + * @see org.collectionspace.services.client.VocabularyProxy#read(java.lang.String) + */ + + public ClientResponse readItem(String vcsid, String csid) { + return vocabularyProxy.readItem(vcsid, csid); + } + + /** + * @param vocabulary + * @return + * @see org.collectionspace.services.client.VocabularyProxy#createVocabulary(org.collectionspace.hello.Vocabulary) + */ + public ClientResponse createItem(String vcsid, MultipartOutput multipart) { + return vocabularyProxy.createItem(vcsid, multipart); + } + + /** + * @param csid + * @param vocabulary + * @return + * @see org.collectionspace.services.client.VocabularyProxy#updateVocabulary(java.lang.Long, org.collectionspace.hello.Vocabulary) + */ + public ClientResponse updateItem(String vcsid, String csid, MultipartOutput multipart) { + return vocabularyProxy.updateItem(vcsid, csid, multipart); + + } + + /** + * @param csid + * @return + * @see org.collectionspace.services.client.VocabularyProxy#deleteVocabulary(java.lang.Long) + */ + public ClientResponse deleteItem(String vcsid, String csid) { + return vocabularyProxy.deleteItem(vcsid, csid); + } } diff --git a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyProxy.java b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyProxy.java index 4b293363a..066e1f7cb 100644 --- a/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyProxy.java +++ b/services/vocabulary/client/src/main/java/org/collectionspace/services/client/VocabularyProxy.java @@ -11,6 +11,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import org.collectionspace.services.vocabulary.VocabulariesCommonList; +import org.collectionspace.services.vocabulary.VocabularyitemsCommonList; import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; @@ -23,6 +24,7 @@ import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; @Consumes({"multipart/mixed"}) public interface VocabularyProxy { + // List Vocabularies @GET @Produces({"application/xml"}) ClientResponse readList(); @@ -45,4 +47,30 @@ public interface VocabularyProxy { @DELETE @Path("/{csid}") ClientResponse delete(@PathParam("csid") String csid); + + // List Items + @GET + @Produces({"application/xml"}) + @Path("/{vcsid}/items/") + ClientResponse readItemList(@PathParam("vcsid") String vcsid); + + //(C)reate Item + @POST + @Path("/{vcsid}/items/") + ClientResponse createItem(@PathParam("vcsid") String vcsid, MultipartOutput multipart); + + //(R)ead + @GET + @Path("/{vcsid}/items/{csid}") + ClientResponse readItem(@PathParam("vcsid") String vcsid, @PathParam("csid") String csid); + + //(U)pdate + @PUT + @Path("/{vcsid}/items/{csid}") + ClientResponse updateItem(@PathParam("vcsid") String vcsid, @PathParam("csid") String csid, MultipartOutput multipart); + + //(D)elete + @DELETE + @Path("/{vcsid}/items/{csid}") + ClientResponse deleteItem(@PathParam("vcsid") String vcsid, @PathParam("csid") String csid); } diff --git a/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java b/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java index cf74fed98..b7c584bfa 100644 --- a/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java +++ b/services/vocabulary/client/src/test/java/org/collectionspace/services/client/test/VocabularyServiceTest.java @@ -23,15 +23,16 @@ package org.collectionspace.services.client.test; import java.util.List; + import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.collectionspace.services.client.VocabularyClient; import org.collectionspace.services.vocabulary.VocabulariesCommon; import org.collectionspace.services.vocabulary.VocabulariesCommonList; - +import org.collectionspace.services.vocabulary.VocabularyitemsCommon; +import org.collectionspace.services.vocabulary.VocabularyitemsCommonList; import org.jboss.resteasy.client.ClientResponse; - import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.plugins.providers.multipart.OutputPart; @@ -50,7 +51,9 @@ public class VocabularyServiceTest extends AbstractServiceTest { // Instance variables specific to this test. private VocabularyClient client = new VocabularyClient(); final String SERVICE_PATH_COMPONENT = "vocabularies"; + final String ITEM_SERVICE_PATH_COMPONENT = "items"; private String knownResourceId = null; + private String knownItemResourceId = null; // --------------------------------------------------------------- // CRUD tests : CREATE tests @@ -89,12 +92,48 @@ public class VocabularyServiceTest extends AbstractServiceTest { knownResourceId = extractId(res); verbose("create: knownResourceId=" + knownResourceId); } + + @Test(dependsOnMethods = {"create"}) + public void createItem() { + setupCreate("Create Item"); + + knownItemResourceId = createItemInVocab(knownResourceId); + verbose("createItem: knownItemResourceId=" + knownItemResourceId); + } + + private String createItemInVocab(String vcsid) { + // Submit the request to the service and store the response. + String identifier = createIdentifier(); + + verbose("createItem:..."); + MultipartOutput multipart = createVocabularyItemInstance(vcsid, identifier); + ClientResponse res = client.createItem(vcsid, multipart); + + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + // + // Specifically: + // Does it fall within the set of valid status codes? + // Does it exactly match the expected status code? + verbose("createItem: status = " + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + return extractId(res); + } @Override - @Test(dependsOnMethods = {"create"}) + @Test(dependsOnMethods = {"create", "createItem"}) public void createList() { for(int i = 0; i < 3; i++){ create(); + // Add 3 items to each vocab + for(int j = 0; j < 3; j++){ + createItem(); + } } } @@ -176,7 +215,7 @@ public class VocabularyServiceTest extends AbstractServiceTest { invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - */ + */ // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- @@ -209,6 +248,33 @@ public class VocabularyServiceTest extends AbstractServiceTest { } } + @Test(dependsOnMethods = {"createItem", "read"}) + public void readItem() { + + // Perform setup. + setupRead("Read Item"); + + // Submit the request to the service and store the response. + ClientResponse res = client.readItem(knownResourceId, knownItemResourceId); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("readItem: status = " + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + //FIXME: remove the following try catch once Aron fixes signatures + try{ + MultipartInput input = (MultipartInput) res.getEntity(); + VocabularyitemsCommon vocabularyItem = (VocabularyitemsCommon) extractPart(input, + client.getItemCommonPartName(), VocabularyitemsCommon.class); + Assert.assertNotNull(vocabularyItem); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + // Failure outcomes @Override @Test(dependsOnMethods = {"read"}) @@ -229,6 +295,23 @@ public class VocabularyServiceTest extends AbstractServiceTest { Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } + @Test(dependsOnMethods = {"readItem", "readNonExistent"}) + public void readItemNonExistent() { + + // Perform setup. + setupReadNonExistent("Read Non-Existent Item"); + + // Submit the request to the service and store the response. + ClientResponse res = client.readItem(knownResourceId, NON_EXISTENT_ID); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("readItemNonExistent: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } // --------------------------------------------------------------- // CRUD tests : READ_LIST tests // --------------------------------------------------------------- @@ -259,16 +342,57 @@ public class VocabularyServiceTest extends AbstractServiceTest { list.getVocabularyListItem(); int i = 0; for(VocabulariesCommonList.VocabularyListItem item : items){ + String csid = item.getCsid(); verbose("readList: list-item[" + i + "] csid=" + - item.getCsid()); + csid); verbose("readList: list-item[" + i + "] displayName=" + item.getDisplayName()); verbose("readList: list-item[" + i + "] URI=" + item.getUri()); + readItemList(csid); i++; } } + } + + @Test(dependsOnMethods = {"readItem"}) + public void readItemList() { + readItemList(knownResourceId); + } + + private void readItemList(String vcsid) { + // Perform setup. + setupReadList("Read Item List"); + + // Submit the request to the service and store the response. + ClientResponse res = + client.readItemList(vcsid); + VocabularyitemsCommonList list = res.getEntity(); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose(" readItemList: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = false; + if(iterateThroughList && logger.isDebugEnabled()){ + List items = + list.getVocabularyitemListItem(); + int i = 0; + for(VocabularyitemsCommonList.VocabularyitemListItem item : items){ + verbose(" readItemList: list-item[" + i + "] csid=" + + item.getCsid()); + verbose(" readItemList: list-item[" + i + "] displayName=" + + item.getDisplayName()); + verbose(" readItemList: list-item[" + i + "] URI=" + + item.getUri()); + i++; + } + } } // Failure outcomes @@ -291,7 +415,7 @@ public class VocabularyServiceTest extends AbstractServiceTest { verbose("update: read status = " + res.getStatus()); Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - verbose("got object to update with ID: " + knownResourceId); + verbose("got Vocabulary to update with ID: " + knownResourceId); MultipartInput input = (MultipartInput) res.getEntity(); VocabulariesCommon vocabulary = (VocabulariesCommon) extractPart(input, client.getCommonPartName(), VocabulariesCommon.class); @@ -299,8 +423,8 @@ public class VocabularyServiceTest extends AbstractServiceTest { // Update the content of this resource. vocabulary.setDisplayName("updated-" + vocabulary.getDisplayName()); - vocabulary.setVocabType("updated-" + vocabulary.getVocabType()); - verbose("to be updated object", vocabulary, VocabulariesCommon.class); + vocabulary.setVocabType("updated-" + vocabulary.getVocabType()); + verbose("to be updated Vocabulary", vocabulary, VocabulariesCommon.class); // Submit the request to the service and store the response. MultipartOutput output = new MultipartOutput(); OutputPart commonPart = output.addPart(vocabulary, MediaType.APPLICATION_XML_TYPE); @@ -329,6 +453,57 @@ public class VocabularyServiceTest extends AbstractServiceTest { } } + @Test(dependsOnMethods = {"readItem", "update"}) + public void updateItem() { + + // Perform setup. + setupUpdate("Update Item"); + + try{ //ideally, just remove try-catch and let the exception bubble up + // Retrieve an existing resource that we can update. + ClientResponse res = + client.readItem(knownResourceId, knownItemResourceId); + verbose("updateItem: read status = " + res.getStatus()); + Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); + + verbose("got VocabularyItem to update with ID: " + knownItemResourceId + + " in Vocab: " + knownResourceId ); + MultipartInput input = (MultipartInput) res.getEntity(); + VocabularyitemsCommon vocabularyItem = (VocabularyitemsCommon) extractPart(input, + client.getItemCommonPartName(), VocabularyitemsCommon.class); + Assert.assertNotNull(vocabularyItem); + + // Update the content of this resource. + vocabularyItem.setDisplayName("updated-" + vocabularyItem.getDisplayName()); + verbose("to be updated VocabularyItem", vocabularyItem, VocabularyitemsCommon.class); + // Submit the request to the service and store the response. + MultipartOutput output = new MultipartOutput(); + OutputPart commonPart = output.addPart(vocabularyItem, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", client.getItemCommonPartName()); + + res = client.updateItem(knownResourceId, knownItemResourceId, output); + int statusCode = res.getStatus(); + // Check the status code of the response: does it match the expected response(s)? + verbose("updateItem: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + + input = (MultipartInput) res.getEntity(); + VocabularyitemsCommon updatedVocabularyItem = + (VocabularyitemsCommon) extractPart(input, + client.getItemCommonPartName(), VocabularyitemsCommon.class); + Assert.assertNotNull(updatedVocabularyItem); + + Assert.assertEquals(updatedVocabularyItem.getDisplayName(), + vocabularyItem.getDisplayName(), + "Data in updated VocabularyItem did not match submitted data."); + }catch(Exception e){ + e.printStackTrace(); + } + } + // Failure outcomes // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. @@ -408,6 +583,7 @@ public class VocabularyServiceTest extends AbstractServiceTest { Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } */ + @Override @Test(dependsOnMethods = {"update", "testSubmitRequest"}) public void updateNonExistent() { @@ -433,6 +609,30 @@ public class VocabularyServiceTest extends AbstractServiceTest { Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } + @Test(dependsOnMethods = {"updateItem", "testItemSubmitRequest"}) + public void updateNonExistentItem() { + + // Perform setup. + setupUpdateNonExistent("Update Non-Existent Item"); + + // Submit the request to the service and store the response. + // Note: The ID used in this 'create' call may be arbitrary. + // The only relevant ID may be the one used in update(), below. + + // The only relevant ID may be the one used in update(), below. + MultipartOutput multipart = createVocabularyItemInstance(knownResourceId, NON_EXISTENT_ID); + ClientResponse res = + client.updateItem(knownResourceId, NON_EXISTENT_ID, multipart); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("updateNonExistentItem: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + // --------------------------------------------------------------- // CRUD tests : DELETE tests // --------------------------------------------------------------- @@ -456,6 +656,24 @@ public class VocabularyServiceTest extends AbstractServiceTest { Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } + @Test(dependsOnMethods = {"createItem", "readItemList", "testItemSubmitRequest", "updateItem"}) + public void deleteItem() { + + // Perform setup. + setupDelete("Delete Item"); + + // Submit the request to the service and store the response. + ClientResponse res = client.deleteItem(knownResourceId, knownItemResourceId); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("delete: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + // Failure outcomes @Override @Test(dependsOnMethods = {"delete"}) @@ -476,6 +694,24 @@ public class VocabularyServiceTest extends AbstractServiceTest { Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } + @Test(dependsOnMethods = {"deleteItem"}) + public void deleteNonExistentItem() { + + // Perform setup. + setupDeleteNonExistent("Delete Non-Existent Item"); + + // Submit the request to the service and store the response. + ClientResponse res = client.deleteItem(knownResourceId, NON_EXISTENT_ID); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("deleteNonExistent: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + // --------------------------------------------------------------- // Utility tests : tests of code used in tests above // --------------------------------------------------------------- @@ -501,6 +737,24 @@ public class VocabularyServiceTest extends AbstractServiceTest { } + @Test(dependsOnMethods = {"createItem", "readItem", "testSubmitRequest"}) + public void testItemSubmitRequest() { + + // Expected status code: 200 OK + final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + + // Submit the request to the service and store the response. + String method = ServiceRequestType.READ.httpMethodName(); + String url = getItemResourceURL(knownResourceId, knownItemResourceId); + int statusCode = submitRequest(method, url); + + // Check the status code of the response: does it match + // the expected response(s)? + verbose("testItemSubmitRequest: url=" + url + " status=" + statusCode); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + } + // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- @@ -509,6 +763,35 @@ public class VocabularyServiceTest extends AbstractServiceTest { return SERVICE_PATH_COMPONENT; } + public String getItemServicePathComponent() { + return ITEM_SERVICE_PATH_COMPONENT; + } + + /** + * Returns the root URL for a service. + * + * This URL consists of a base URL for all services, followed by + * a path component for the owning vocabulary, followed by the + * path component for the items. + * + * @return The root URL for a service. + */ + protected String getItemServiceRootURL(String parentResourceIdentifier) { + return getResourceURL(parentResourceIdentifier)+"/"+getItemServicePathComponent(); + } + + /** + * Returns the URL of a specific resource managed by a service, and + * designated by an identifier (such as a universally unique ID, or UUID). + * + * @param resourceIdentifier An identifier (such as a UUID) for a resource. + * + * @return The URL of a specific resource managed by a service. + */ + protected String getItemResourceURL(String parentResourceIdentifier, String resourceIdentifier) { + return getItemServiceRootURL(parentResourceIdentifier) + "/" + resourceIdentifier; + } + private MultipartOutput createVocabularyInstance(String identifier) { return createVocabularyInstance( "displayName-" + identifier, @@ -527,4 +810,17 @@ public class VocabularyServiceTest extends AbstractServiceTest { return multipart; } + + private MultipartOutput createVocabularyItemInstance(String inVocabulary, String displayName) { + VocabularyitemsCommon vocabularyItem = new VocabularyitemsCommon(); + vocabularyItem.setInVocabulary(inVocabulary); + vocabularyItem.setDisplayName(displayName); + MultipartOutput multipart = new MultipartOutput(); + OutputPart commonPart = multipart.addPart(vocabularyItem, MediaType.APPLICATION_XML_TYPE); + commonPart.getHeaders().add("label", client.getItemCommonPartName()); + + verbose("to be created, vocabularyitem common ", vocabularyItem, VocabularyitemsCommon.class); + + return multipart; + } } diff --git a/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd b/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd new file mode 100644 index 000000000..9b62ae270 --- /dev/null +++ b/services/vocabulary/jaxb/src/main/resources/vocabularyitem_common.xsd @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java index cf7b7e276..f0ea4e94b 100644 --- a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/VocabularyResource.java @@ -24,13 +24,13 @@ package org.collectionspace.services.vocabulary; import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; import javax.ws.rs.DELETE; +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.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; @@ -38,13 +38,15 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import org.collectionspace.services.common.AbstractCollectionSpaceResource; -import org.collectionspace.services.vocabulary.nuxeo.VocabularyHandlerFactory; import org.collectionspace.services.common.ClientType; import org.collectionspace.services.common.ServiceMain; import org.collectionspace.services.common.context.RemoteServiceContext; import org.collectionspace.services.common.context.ServiceContext; -import org.collectionspace.services.common.repository.DocumentNotFoundException; import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentNotFoundException; +import org.collectionspace.services.vocabulary.nuxeo.VocabularyHandlerFactory; +import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemDocumentModelHandler; +import org.collectionspace.services.vocabulary.nuxeo.VocabularyItemHandlerFactory; import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.jboss.resteasy.util.HttpResponseCodes; @@ -56,7 +58,8 @@ import org.slf4j.LoggerFactory; @Produces("multipart/mixed") public class VocabularyResource extends AbstractCollectionSpaceResource { - private final static String serviceName = "vocabularies"; + private final static String vocabularyServiceName = "vocabularies"; + private final static String vocabularyItemServiceName = "vocabularyitems"; final Logger logger = LoggerFactory.getLogger(VocabularyResource.class); //FIXME retrieve client type from configuration final static ClientType CLIENT_TYPE = ServiceMain.getInstance().getClientType(); @@ -67,9 +70,21 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { @Override public String getServiceName() { - return serviceName; + return vocabularyServiceName; + } + + public String getItemServiceName() { + return vocabularyItemServiceName; } + /* + public RemoteServiceContext createItemServiceContext(MultipartInput input) throws Exception { + RemoteServiceContext ctx = new RemoteServiceContextImpl(getItemServiceName()); + ctx.setInput(input); + return ctx; + } + */ + @Override public DocumentHandler createDocumentHandler(RemoteServiceContext ctx) throws Exception { DocumentHandler docHandler = VocabularyHandlerFactory.getInstance().getHandler( @@ -84,6 +99,23 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { return docHandler; } + private DocumentHandler createItemDocumentHandler( + RemoteServiceContext ctx, + String inVocabulary) throws Exception { + DocumentHandler docHandler = VocabularyItemHandlerFactory.getInstance().getHandler( + ctx.getRepositoryClientType().toString()); + docHandler.setServiceContext(ctx); + ((VocabularyItemDocumentModelHandler)docHandler).setInVocabulary(inVocabulary); + if(ctx.getInput() != null){ + Object obj = ctx.getInputPart(ctx.getCommonPartLabel(getItemServiceName()), + VocabularyitemsCommon.class); + if(obj != null){ + docHandler.setCommonPart((VocabularyitemsCommon) obj); + } + } + return docHandler; + } + @POST public Response createVocabulary(MultipartInput input) { try{ @@ -240,4 +272,201 @@ public class VocabularyResource extends AbstractCollectionSpaceResource { } } + + /************************************************************************* + * VocabularyItem parts - this is a sub-resource of Vocabulary + *************************************************************************/ + + @POST + @Path("{csid}/items") + public Response createVocabularyItem(@PathParam("csid") String parentcsid, MultipartInput input) { + try{ + RemoteServiceContext ctx = createServiceContext(input, getItemServiceName()); + DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid); + String itemcsid = getRepositoryClient(ctx).create(ctx, handler); + UriBuilder path = UriBuilder.fromResource(VocabularyResource.class); + path.path(parentcsid + "/items/" + itemcsid); + Response response = Response.created(path.build()).build(); + return response; + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception in createVocabularyItem", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Create failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + } + + @GET + @Path("{csid}/items/{itemcsid}") + public MultipartOutput getVocabularyItem( + @PathParam("csid") String parentcsid, + @PathParam("itemcsid") String itemcsid) { + if(logger.isDebugEnabled()){ + logger.debug("getVocabularyItem with parentcsid=" + + parentcsid + " and itemcsid=" + itemcsid); + } + if(parentcsid == null || "".equals(parentcsid)){ + logger.error("getVocabularyItem: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "get failed on VocabularyItem csid=" + parentcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + if(itemcsid == null || "".equals(itemcsid)){ + logger.error("getVocabularyItem: missing itemcsid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "get failed on VocabularyItem itemcsid=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + MultipartOutput result = null; + try{ + // Note that we have to create the service context for the Items, not the main service + RemoteServiceContext ctx = createServiceContext(null, getItemServiceName()); + DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid); + getRepositoryClient(ctx).get(ctx, itemcsid, handler); + // TODO should we assert that the item is in the passed vocab? + result = ctx.getOutput(); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("getVocabularyItem", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed on VocabularyItem csid=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("getVocabularyItem", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Get failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + if(result == null){ + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Get failed, the requested VocabularyItem CSID:" + itemcsid + ": was not found.").type( + "text/plain").build(); + throw new WebApplicationException(response); + } + return result; + } + + @GET + @Path("{csid}/items") + @Produces("application/xml") + public VocabularyitemsCommonList getVocabularyItemList( + @PathParam("csid") String parentcsid, + @Context UriInfo ui) { + VocabularyitemsCommonList vocabularyItemObjectList = new VocabularyitemsCommonList(); + try{ + // Note that we have to create the service context for the Items, not the main service + RemoteServiceContext ctx = createServiceContext(null, getItemServiceName()); + DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid); + // HACK This should be a search with the parentcsid. The + // handler.getCommonPartList method will filter these for us, + // which is really silly, but works for now. + getRepositoryClient(ctx).getAll(ctx, handler); + vocabularyItemObjectList = (VocabularyitemsCommonList) handler.getCommonPartList(); + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception in getVocabularyItemList", e); + } + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Index failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + return vocabularyItemObjectList; + } + + @PUT + @Path("{csid}/items/{itemcsid}") + public MultipartOutput updateVocabularyItem( + @PathParam("csid") String parentcsid, + @PathParam("itemcsid") String itemcsid, + MultipartInput theUpdate) { + if(logger.isDebugEnabled()){ + logger.debug("updateVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid); + } + if(parentcsid == null || "".equals(parentcsid)){ + logger.error("updateVocabularyItem: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "update failed on VocabularyItem parentcsid=" + parentcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + if(itemcsid == null || "".equals(itemcsid)){ + logger.error("updateVocabularyItem: missing itemcsid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "update failed on VocabularyItem=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + MultipartOutput result = null; + try{ + // Note that we have to create the service context for the Items, not the main service + RemoteServiceContext ctx = createServiceContext(theUpdate, getItemServiceName()); + DocumentHandler handler = createItemDocumentHandler(ctx, parentcsid); + getRepositoryClient(ctx).update(ctx, itemcsid, handler); + result = ctx.getOutput(); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("caugth exception in updateVocabularyItem", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Update failed on VocabularyItem csid=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Update failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + return result; + } + + @DELETE + @Path("{csid}/items/{itemcsid}") + public Response deleteVocabularyItem( + @PathParam("csid") String parentcsid, + @PathParam("itemcsid") String itemcsid) { + if(logger.isDebugEnabled()){ + logger.debug("deleteVocabularyItem with parentcsid=" + parentcsid + " and itemcsid=" + itemcsid); + } + if(parentcsid == null || "".equals(parentcsid)){ + logger.error("deleteVocabularyItem: missing csid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "delete failed on VocabularyItem parentcsid=" + parentcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + if(itemcsid == null || "".equals(itemcsid)){ + logger.error("deleteVocabularyItem: missing itemcsid!"); + Response response = Response.status(Response.Status.BAD_REQUEST).entity( + "delete failed on VocabularyItem=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + } + try{ + // Note that we have to create the service context for the Items, not the main service + RemoteServiceContext ctx = createServiceContext(null, getItemServiceName()); + getRepositoryClient(ctx).delete(ctx, itemcsid); + return Response.status(HttpResponseCodes.SC_OK).build(); + }catch(DocumentNotFoundException dnfe){ + if(logger.isDebugEnabled()){ + logger.debug("caught exception in deleteVocabulary", dnfe); + } + Response response = Response.status(Response.Status.NOT_FOUND).entity( + "Delete failed on VocabularyItem itemcsid=" + itemcsid).type( + "text/plain").build(); + throw new WebApplicationException(response); + }catch(Exception e){ + Response response = Response.status( + Response.Status.INTERNAL_SERVER_ERROR).entity("Delete failed").type("text/plain").build(); + throw new WebApplicationException(response); + } + + } } diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyHandlerFactory.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyHandlerFactory.java index 721c30083..709df73e5 100644 --- a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyHandlerFactory.java +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyHandlerFactory.java @@ -29,7 +29,7 @@ import org.collectionspace.services.common.repository.DocumentHandlerFactory; /** - * VocabularyHandlerFactory creates handlers for collectionobject based + * VocabularyHandlerFactory creates handlers for vocabulary based * on type of Nuxeo client used * * $LastChangedRevision: $ diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemConstants.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemConstants.java new file mode 100644 index 000000000..bbedce4c4 --- /dev/null +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemConstants.java @@ -0,0 +1,35 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + */ +package org.collectionspace.services.vocabulary.nuxeo; + +/** + * VocabularyConstants processes CollectionObject document + * + */ +public class VocabularyItemConstants { + + public final static String NUXEO_DOCTYPE = "Vocabularyitem"; + public final static String NUXEO_SCHEMA_NAME = "vocabularyitem"; + public final static String NUXEO_DC_TITLE = "CollectionSpace-Vocabularyitem"; +} diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java new file mode 100644 index 000000000..9c9556071 --- /dev/null +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemDocumentModelHandler.java @@ -0,0 +1,177 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + */ +package org.collectionspace.services.vocabulary.nuxeo; + +import java.util.Iterator; +import java.util.List; + +import org.collectionspace.services.VocabularyItemJAXBSchema; +import org.collectionspace.services.common.repository.DocumentWrapper; +import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandler; +import org.collectionspace.services.vocabulary.VocabularyitemsCommon; +import org.collectionspace.services.vocabulary.VocabularyitemsCommonList; +import org.collectionspace.services.vocabulary.VocabularyitemsCommonList.VocabularyitemListItem; +import org.nuxeo.ecm.core.api.DocumentModel; +import org.nuxeo.ecm.core.api.DocumentModelList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * VocabularyItemDocumentModelHandler + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class VocabularyItemDocumentModelHandler + extends RemoteDocumentModelHandler { + + private final Logger logger = LoggerFactory.getLogger(VocabularyItemDocumentModelHandler.class); + /** + * vocabularyItem is used to stash JAXB object to use when handle is called + * for Action.CREATE, Action.UPDATE or Action.GET + */ + private VocabularyitemsCommon vocabularyItem; + /** + * vocabularyItemList is stashed when handle is called + * for ACTION.GET_ALL + */ + private VocabularyitemsCommonList vocabularyItemList; + + /** + * inVocabulary is the parent vocabulary for this context + */ + private String inVocabulary; + + public String getInVocabulary() { + return inVocabulary; + } + + public void setInVocabulary(String inVocabulary) { + this.inVocabulary = inVocabulary; + } + + @Override + public void prepare(Action action) throws Exception { + //no specific action needed + } + + /** + * getCommonPart get associated vocabularyItem + * @return + */ + @Override + public VocabularyitemsCommon getCommonPart() { + return vocabularyItem; + } + + /** + * setCommonPart set associated vocabularyItem + * @param vocabularyItem + */ + @Override + public void setCommonPart(VocabularyitemsCommon vocabularyItem) { + this.vocabularyItem = vocabularyItem; + } + + /** + * getCommonPartList get associated vocabularyItem (for index/GET_ALL) + * @return + */ + @Override + public VocabularyitemsCommonList getCommonPartList() { + return vocabularyItemList; + } + + @Override + public void setCommonPartList(VocabularyitemsCommonList vocabularyItemList) { + this.vocabularyItemList = vocabularyItemList; + } + + @Override + public VocabularyitemsCommon extractCommonPart(DocumentWrapper wrapDoc) + throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public void fillCommonPart(VocabularyitemsCommon vocabularyItemObject, DocumentWrapper wrapDoc) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public VocabularyitemsCommonList extractCommonPartList(DocumentWrapper wrapDoc) + throws Exception { + VocabularyitemsCommonList coList = new VocabularyitemsCommonList(); + try{ + DocumentModelList docList = (DocumentModelList) wrapDoc.getWrappedObject(); + + List list = + coList.getVocabularyitemListItem(); + + //FIXME: iterating over a long list of documents is not a long term + //strategy...need to change to more efficient iterating in future + Iterator iter = docList.iterator(); + while(iter.hasNext()){ + DocumentModel docModel = iter.next(); + String parentVocab = (String)docModel.getProperty(getServiceContext().getCommonPartLabel("vocabularyItems"), + VocabularyItemJAXBSchema.IN_VOCABULARY); + if( !inVocabulary.equals(parentVocab)) + continue; + VocabularyitemListItem ilistItem = new VocabularyitemListItem(); + ilistItem.setDisplayName((String) docModel.getProperty(getServiceContext().getCommonPartLabel("vocabularyItems"), + VocabularyItemJAXBSchema.DISPLAY_NAME)); + String id = docModel.getId(); + ilistItem.setUri("/vocabularies/"+inVocabulary+"/items/" + id); + ilistItem.setCsid(id); + list.add(ilistItem); + } + }catch(Exception e){ + if(logger.isDebugEnabled()){ + logger.debug("Caught exception in extractCommonPartList", e); + } + throw e; + } + return coList; + } + + + /* (non-Javadoc) + * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#getDocumentType() + */ + @Override + public String getDocumentType() { + return VocabularyItemConstants.NUXEO_DOCTYPE; + } + + /** + * getQProperty converts the given property to qualified schema property + * @param prop + * @return + */ + @Override + public String getQProperty(String prop) { + return VocabularyItemConstants.NUXEO_SCHEMA_NAME + ":" + prop; + } +} + diff --git a/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemHandlerFactory.java b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemHandlerFactory.java new file mode 100644 index 000000000..89440fadc --- /dev/null +++ b/services/vocabulary/service/src/main/java/org/collectionspace/services/vocabulary/nuxeo/VocabularyItemHandlerFactory.java @@ -0,0 +1,56 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + + * http://www.collectionspace.org + * http://wiki.collectionspace.org + + * Copyright 2009 University of California at Berkeley + + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + + * You may obtain a copy of the ECL 2.0 License at + + * https://source.collectionspace.org/collection-space/LICENSE.txt + + * 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. + */ +package org.collectionspace.services.vocabulary.nuxeo; + +import org.collectionspace.services.common.ClientType; +import org.collectionspace.services.common.repository.DocumentHandler; +import org.collectionspace.services.common.repository.DocumentHandlerFactory; + + +/** + * VocabularyItemHandlerFactory creates handlers for vocabularyitem based + * on type of Nuxeo client used + * + * $LastChangedRevision: $ + * $LastChangedDate: $ + */ +public class VocabularyItemHandlerFactory implements DocumentHandlerFactory { + + private static final VocabularyItemHandlerFactory self = new VocabularyItemHandlerFactory(); + + private VocabularyItemHandlerFactory() { + } + + public static VocabularyItemHandlerFactory getInstance() { + return self; + } + + @Override + public DocumentHandler getHandler(String clientType) { + if(ClientType.JAVA.toString().equals(clientType)){ + return new VocabularyItemDocumentModelHandler(); + } + throw new IllegalArgumentException("Not supported client=" + clientType); + } +} -- 2.47.3