From: Sanjay Dalal Date: Fri, 6 Nov 2009 00:59:20 +0000 (+0000) Subject: CSPACE-515, CSPACE-266 Added support for multivalue elements in schema. Supports... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=f5f18c3d476658a732688a81faa92b47bdbe42b1;p=tmp%2Fjakarta-migration.git CSPACE-515, CSPACE-266 Added support for multivalue elements in schema. Supports 1 level depth. e.g. otherNumbers in collectionobjects_common urn:org.collectionspace.id:24082390 urn:org.walkerart.id:123 woudl be stored by nuxeo with each item (otherNumber) having value such as "otherNumber|urn:org.collectionspace.id:24082390". marshalling and unmarshalling code takes care of qualifying or unqualifying the value with the name of the property. test: collectionobjects, all service tests. will require re-initializing nuxeo db M collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd M collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects_common.xsd M collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java M common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java --- diff --git a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects_common.xsd b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects_common.xsd index c01906760..c3545ded9 100644 --- a/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects_common.xsd +++ b/services/collectionobject/3rdparty/nuxeo-platform-cs-collectionobject/src/main/resources/schemas/collectionobjects_common.xsd @@ -19,113 +19,119 @@ version="0.1"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java index dc6b6c6ce..2c05547e5 100644 --- a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java @@ -30,7 +30,7 @@ import org.collectionspace.services.client.CollectionObjectClient; import org.collectionspace.services.collectionobject.CollectionobjectsCommon; import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionObjectNaturalhistory; import org.collectionspace.services.collectionobject.CollectionobjectsCommonList; - +import org.collectionspace.services.collectionobject.OtherNumberList; import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.plugins.providers.multipart.MultipartInput; @@ -52,12 +52,11 @@ import org.slf4j.LoggerFactory; public class CollectionObjectServiceTest extends AbstractServiceTest { private final Logger logger = - LoggerFactory.getLogger(CollectionObjectServiceTest.class); - + LoggerFactory.getLogger(CollectionObjectServiceTest.class); // Instance variables specific to this test. private CollectionObjectClient client = new CollectionObjectClient(); private String knownResourceId = null; - + /* * This method is called only by the parent class, AbstractServiceTest */ @@ -66,13 +65,12 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { return client.getServicePathComponent(); } - // --------------------------------------------------------------- + // --------------------------------------------------------------- // CRUD tests : CREATE tests // --------------------------------------------------------------- - // Success outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class) public void create(String testName) throws Exception { // Perform setup, such as initializing the type of service request @@ -83,7 +81,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Submit the request to the service and store the response. String identifier = createIdentifier(); MultipartOutput multipart = - createCollectionObjectInstance(client.getCommonPartName(), identifier); + createCollectionObjectInstance(client.getCommonPartName(), identifier); ClientResponse res = client.create(multipart); int statusCode = res.getStatus(); @@ -93,7 +91,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Specifically: // Does it fall within the set of valid status codes? // Does it exactly match the expected status code? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -103,123 +101,125 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Store the ID returned from this create operation // for additional tests below. knownResourceId = extractId(res); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": knownResourceId=" + knownResourceId); } } - /* (non-Javadoc) - * @see org.collectionspace.services.client.test.ServiceTest#createList() - */ + /* (non-Javadoc) + * @see org.collectionspace.services.client.test.ServiceTest#createList() + */ @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"create"}) public void createList(String testName) throws Exception { - for(int i = 0; i < 3; i++){ + for (int i = 0; i < 3; i++) { create(testName); } } // Failure outcomes - // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. @Override - public void createWithEmptyEntityBody(String testName) throws Exception {} + public void createWithEmptyEntityBody(String testName) throws Exception { + } + @Override - public void createWithMalformedXml(String testName) throws Exception {} + public void createWithMalformedXml(String testName) throws Exception { + } + @Override - public void createWithWrongXmlSchema(String testName) throws Exception {} + public void createWithWrongXmlSchema(String testName) throws Exception { + } -/* + /* @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "testSubmitRequest"}) + dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithEmptyEntityBody(String testName) throwsException { - // Perform setup. - setupCreateWithEmptyEntityBody(testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithEmptyEntityBody(testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "testSubmitRequest"}) + dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithMalformedXml(String testName) throws Exception { - // Perform setup. - setupCreateWithMalformedXml(testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = MALFORMED_XML_DATA; // Constant from base class. - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithMalformedXml(testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = MALFORMED_XML_DATA; // Constant from base class. + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "testSubmitRequest"}) + dependsOnMethods = {"create", "testSubmitRequest"}) public void createWithWrongXmlSchema(String testName) throws Exception { - // Perform setup. - setupCreateWithWrongXmlSchema(testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getServiceRootURL(); - String mediaType = MediaType.APPLICATION_XML; - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupCreateWithWrongXmlSchema(testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getServiceRootURL(); + String mediaType = MediaType.APPLICATION_XML; + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); } -*/ - + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + */ // --------------------------------------------------------------- // CRUD tests : READ tests // --------------------------------------------------------------- - // Success outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"create"}) public void read(String testName) throws Exception { // Perform setup. @@ -231,25 +231,24 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - + MultipartInput input = (MultipartInput) res.getEntity(); CollectionobjectsCommon collectionObject = - (CollectionobjectsCommon) extractPart(input, - client.getCommonPartName(), CollectionobjectsCommon.class); + (CollectionobjectsCommon) extractPart(input, + client.getCommonPartName(), CollectionobjectsCommon.class); Assert.assertNotNull(collectionObject); } - - // Failure outcomes + // Failure outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"read"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"read"}) public void readNonExistent(String testName) throws Exception { // Perform setup. @@ -261,7 +260,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -274,8 +273,8 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // --------------------------------------------------------------- // Success outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"createList", "read"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"createList", "read"}) public void readList(String testName) throws Exception { // Perform setup. @@ -288,7 +287,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -299,16 +298,16 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { boolean iterateThroughList = false; if (iterateThroughList && logger.isDebugEnabled()) { List items = - list.getCollectionObjectListItem(); + list.getCollectionObjectListItem(); int i = 0; - for(CollectionobjectsCommonList.CollectionObjectListItem item : items){ + for (CollectionobjectsCommonList.CollectionObjectListItem item : items) { logger.debug(testName + ": list-item[" + i + "] csid=" + - item.getCsid()); + item.getCsid()); logger.debug(testName + ": list-item[" + i + "] objectNumber=" + - item.getObjectNumber()); + item.getObjectNumber()); logger.debug(testName + ": list-item[" + i + "] URI=" + - item.getUri()); + item.getUri()); i++; } @@ -317,14 +316,13 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Failure outcomes // None at present. - // --------------------------------------------------------------- // CRUD tests : UPDATE tests // --------------------------------------------------------------- // Success outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"read"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"read"}) public void update(String testName) throws Exception { // Perform setup. @@ -332,26 +330,26 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { ClientResponse res = client.read(knownResourceId); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": read status = " + res.getStatus()); } Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug("got object to update with ID: " + knownResourceId); } MultipartInput input = (MultipartInput) res.getEntity(); CollectionobjectsCommon collectionObject = - (CollectionobjectsCommon) extractPart(input, + (CollectionobjectsCommon) extractPart(input, client.getCommonPartName(), CollectionobjectsCommon.class); Assert.assertNotNull(collectionObject); // Update the content of this resource. collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber()); collectionObject.setObjectName("updated-" + collectionObject.getObjectName()); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { verbose("updated object", collectionObject, - CollectionobjectsCommon.class); + CollectionobjectsCommon.class); } // Submit the request to the service and store the response. MultipartOutput output = new MultipartOutput(); @@ -361,7 +359,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { res = client.update(knownResourceId, output); int statusCode = res.getStatus(); // Check the status code of the response: does it match the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -372,7 +370,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { input = (MultipartInput) res.getEntity(); CollectionobjectsCommon updatedCollectionObject = (CollectionobjectsCommon) extractPart(input, - client.getCommonPartName(), CollectionobjectsCommon.class); + client.getCommonPartName(), CollectionobjectsCommon.class); Assert.assertNotNull(updatedCollectionObject); Assert.assertEquals(updatedCollectionObject.getObjectName(), @@ -380,101 +378,104 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { "Data in updated object did not match submitted data."); } - - // Failure outcomes + // Failure outcomes // Placeholders until the three tests below can be uncommented. // See Issue CSPACE-401. @Override - public void updateWithEmptyEntityBody(String testName) throws Exception {} + public void updateWithEmptyEntityBody(String testName) throws Exception { + } + @Override - public void updateWithMalformedXml(String testName) throws Exception {} + public void updateWithMalformedXml(String testName) throws Exception { + } + @Override - public void updateWithWrongXmlSchema(String testName) throws Exception {} + public void updateWithWrongXmlSchema(String testName) throws Exception { + } -/* + /* @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "update", "testSubmitRequest"}) + dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithEmptyEntityBody(String testName) throws Exception { - // Perform setup. - setupUpdateWithEmptyEntityBody(testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = ""; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithEmptyEntityBody(testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = ""; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "update", "testSubmitRequest"}) + dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithMalformedXml() throws Exception { - // Perform setup. - setupUpdateWithMalformedXml(testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - final String entity = MALFORMED_XML_DATA; - String mediaType = MediaType.APPLICATION_XML; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithMalformedXml(testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + final String entity = MALFORMED_XML_DATA; + String mediaType = MediaType.APPLICATION_XML; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); + } + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } @Override @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "update", "testSubmitRequest"}) + dependsOnMethods = {"create", "update", "testSubmitRequest"}) public void updateWithWrongXmlSchema(String testName) throws Exception { - // Perform setup. - setupUpdateWithWrongXmlSchema(String testName); - - // Submit the request to the service and store the response. - String method = REQUEST_TYPE.httpMethodName(); - String url = getResourceURL(knownResourceId); - String mediaType = MediaType.APPLICATION_XML; - final String entity = WRONG_XML_SCHEMA_DATA; - int statusCode = submitRequest(method, url, mediaType, entity); - - // Check the status code of the response: does it match - // the expected response(s)? - if(logger.isDebugEnabled()){ - logger.debug(testName + ": url=" + url + - " status=" + statusCode); - } - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // Perform setup. + setupUpdateWithWrongXmlSchema(String testName); + + // Submit the request to the service and store the response. + String method = REQUEST_TYPE.httpMethodName(); + String url = getResourceURL(knownResourceId); + String mediaType = MediaType.APPLICATION_XML; + final String entity = WRONG_XML_SCHEMA_DATA; + int statusCode = submitRequest(method, url, mediaType, entity); + + // Check the status code of the response: does it match + // the expected response(s)? + if(logger.isDebugEnabled()){ + logger.debug(testName + ": url=" + url + + " status=" + statusCode); } -*/ - + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + */ @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"update", "testSubmitRequest"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"update", "testSubmitRequest"}) public void updateNonExistent(String testName) throws Exception { // Perform setup. @@ -485,15 +486,15 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Note: The ID used in this 'create' call may be arbitrary. // The only relevant ID may be the one used in updateCollectionObject(), below. MultipartOutput multipart = - createCollectionObjectInstance(client.getCommonPartName(), + createCollectionObjectInstance(client.getCommonPartName(), NON_EXISTENT_ID); ClientResponse res = - client.update(NON_EXISTENT_ID, multipart); + client.update(NON_EXISTENT_ID, multipart); int statusCode = res.getStatus(); // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -506,8 +507,8 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // --------------------------------------------------------------- // Success outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"}) public void delete(String testName) throws Exception { // Perform setup. @@ -519,7 +520,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -529,8 +530,8 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Failure outcomes @Override - @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class, - dependsOnMethods = {"delete"}) + @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTest.class, + dependsOnMethods = {"delete"}) public void deleteNonExistent(String testName) throws Exception { // Perform setup. @@ -542,7 +543,7 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug(testName + ": status = " + statusCode); } Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), @@ -570,29 +571,32 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { // Check the status code of the response: does it match // the expected response(s)? - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { logger.debug("testSubmitRequest: url=" + url + - " status=" + statusCode); + " status=" + statusCode); } Assert.assertEquals(statusCode, EXPECTED_STATUS); - } + } // --------------------------------------------------------------- // Utility methods used by tests above // --------------------------------------------------------------- - private MultipartOutput createCollectionObjectInstance(String commonPartName, - String identifier) { + String identifier) { return createCollectionObjectInstance(commonPartName, - "objectNumber-" + identifier, - "objectName-" + identifier); + "objectNumber-" + identifier, + "objectName-" + identifier); } private MultipartOutput createCollectionObjectInstance(String commonPartName, - String objectNumber, String objectName) { + String objectNumber, String objectName) { CollectionobjectsCommon collectionObject = new CollectionobjectsCommon(); - + OtherNumberList onList = new OtherNumberList(); + List ons = onList.getOtherNumber(); + ons.add("urn:org.collectionspace.id:24082390"); + ons.add("urn:org.walkerart.id:123"); + collectionObject.setOtherNumbers(onList); collectionObject.setObjectNumber(objectNumber); collectionObject.setObjectName(objectName); collectionObject.setAge(""); //test for null string @@ -601,12 +605,12 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { "Puerto Rico. ca. 8" high, 6" wide, projects 10" (with horns)."); MultipartOutput multipart = new MultipartOutput(); OutputPart commonPart = multipart.addPart(collectionObject, - MediaType.APPLICATION_XML_TYPE); + MediaType.APPLICATION_XML_TYPE); commonPart.getHeaders().add("label", commonPartName); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { verbose("to be created, collectionobject common ", - collectionObject, CollectionobjectsCommon.class); + collectionObject, CollectionobjectsCommon.class); } CollectionObjectNaturalhistory conh = new CollectionObjectNaturalhistory(); @@ -616,9 +620,9 @@ public class CollectionObjectServiceTest extends AbstractServiceTest { OutputPart nhPart = multipart.addPart(conh, MediaType.APPLICATION_XML_TYPE); nhPart.getHeaders().add("label", getNHPartName()); - if(logger.isDebugEnabled()){ + if (logger.isDebugEnabled()) { verbose("to be created, collectionobject nhistory", - conh, CollectionObjectNaturalhistory.class); + conh, CollectionObjectNaturalhistory.class); } return multipart; diff --git a/services/collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd b/services/collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd index 4aca87598..0ad19e79a 100644 --- a/services/collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd +++ b/services/collectionobject/jaxb/src/main/resources/collectionobjects_common.xsd @@ -33,7 +33,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -112,38 +112,44 @@ - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java index a38670b35..0bfdc9c17 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/repository/DocumentUtils.java @@ -25,8 +25,10 @@ package org.collectionspace.services.common.repository; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; @@ -51,6 +53,14 @@ import org.w3c.dom.Text; */ public class DocumentUtils { + private static String NAME_VALUE_SEPARATOR = "|"; + + private static class NameValue { + + String name; + String value; + }; + /** * parseProperties given payload to create XML document. this * method also closes given stream after parsing. @@ -60,7 +70,7 @@ public class DocumentUtils { */ public static Document parseDocument(InputStream payload) throws Exception { - try{ + try { // Create a builder factory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false);//TODO take validating value from meta @@ -68,8 +78,8 @@ public class DocumentUtils { // Create the builder and parse the file return factory.newDocumentBuilder().parse(payload); - }finally{ - if(payload != null){ + } finally { + if (payload != null) { payload.close(); } @@ -87,29 +97,88 @@ public class DocumentUtils { HashMap objectProps = new HashMap(); // Get a list of all elements in the document Node root = document.getFirstChild(); - NodeList children = root.getChildNodes(); - for(int i = 0; i < children.getLength(); i++){ - Node node = (Node) children.item(i); - if(node.getNodeType() == Node.ELEMENT_NODE){ - Node cnode = node.getFirstChild(); - if(cnode == null){ - //if element is present but no value, set to "" - //FIXME what about non-string types? - objectProps.put(node.getNodeName(), ""); - }else{ - if(cnode.getNodeType() != Node.TEXT_NODE){ - continue; - } - Node textNode = (Text) cnode; - //FIXME what about other native xml types? - objectProps.put(node.getNodeName(), - textNode.getNodeValue()); + NodeList rootChildren = root.getChildNodes(); + for (int i = 0; i < rootChildren.getLength(); i++) { + Node node = rootChildren.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + NodeList childNodes = node.getChildNodes(); + if (childNodes.getLength() > 1) { + //must be multi value element + String[] vals = getMultiValues(node); + objectProps.put(node.getNodeName(), vals); + } else if (childNodes.getLength() == 1) { + objectProps.put(node.getNodeName(), getTextNodeValue(node)); } } } return objectProps; } + /** + * getMultiValues retrieve multi-value element values + * @param node + * @return + */ + private static String[] getMultiValues(Node node) { + ArrayList vals = new ArrayList(); + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node cnode = children.item(i); + vals.add(qualify(cnode.getNodeName(), getTextNodeValue(cnode))); + } + return vals.toArray(new String[0]); + } + + /** + * getTextNodeValue retrieves text node value + * @param cnode + * @return + */ + private static String getTextNodeValue(Node cnode) { + String value = ""; + Node ccnode = cnode.getFirstChild(); + if (ccnode != null && ccnode.getNodeType() == Node.TEXT_NODE) { + value = ccnode.getNodeValue(); + } + return value; + } + + /** + * isQualified check if the given value is already qualified with given property name + * e.g. otherNumber|urn:org.collectionspace.id:24082390 is qualified with otherNumber + * but urn:org.walkerart.id:123 is not qualified + * @param name of the property, e.g. otherNumber + * @param value of the property e.g. otherNumber + * @return + */ + private static boolean isQualified(String name, String value) { + StringTokenizer stz = new StringTokenizer(value, NAME_VALUE_SEPARATOR); + int tokens = stz.countTokens(); + if (tokens == 2) { + String n = stz.nextToken(); + return name.equals(n); + } + return false; + } + + /** + * qualify qualifies given property value with given property name, e.g. + * name=otherNumber and value=urn:org.collectionspace.id:24082390 would be + * qualified as otherNumber|urn:org.collectionspace.id:24082390. however, + * name=otherNumber and value=otherNumber|urn:org.collectionspace.id:24082390 + * would be ignored as the given value is already qualified once. + * @param name + * @param value + * @return + */ + private static String qualify(String name, String value) { + if (isQualified(name, value)) { + return value; + } + return name + NAME_VALUE_SEPARATOR + value; + + } + /** * buildDocument builds org.w3c.dom.Document from given properties using * given metadata for a part @@ -124,7 +193,7 @@ public class DocumentUtils { throws Exception { ObjectPartContentType partContentMeta = partMeta.getContent(); XmlContentType xc = partContentMeta.getXmlContent(); - if(xc == null){ + if (xc == null) { return null; } @@ -146,20 +215,62 @@ public class DocumentUtils { root.setAttribute("xmlns:" + ns, xc.getNamespaceURI()); document.appendChild(root); - for(String prop : objectProps.keySet()){ + for (String prop : objectProps.keySet()) { Object value = objectProps.get(prop); - if(value != null){ + if (value != null) { //no need to qualify each element name as namespace is already added Element e = document.createElement(prop); root.appendChild(e); - String strValue = objectProps.get(prop).toString(); - Text tNode = document.createTextNode(strValue); - e.appendChild(tNode); + if (value instanceof ArrayList) { + //multi-value element + insertMultiValues(document, e, (ArrayList) value); + } else { + String strValue = objectProps.get(prop).toString(); + insertTextNode(document, e, strValue); + } } } return document; } + private static void insertMultiValues(Document document, Element e, ArrayList vals) { + String parentName = e.getNodeName(); + for (Object o : vals) { + String val = (String) o; //force cast + NameValue nv = unqualify(val); + Element c = document.createElement(nv.name); + e.appendChild(c); + insertTextNode(document, c, nv.value); + } + } + + private static void insertTextNode(Document document, Element e, String strValue) { + Text tNode = document.createTextNode(strValue); + e.appendChild(tNode); + } + + /** + * unqualify given value. if the given input value is not qualified, throw exception + * input of otherNumber|urn:org.collectionspace.id:24082390 would be unqualified + * as name=otherNumber and value=urn:org.collectionspace.id:24082390 + * @param input + * @return name and value + * @exception IllegalStateException + */ + private static NameValue unqualify(String input) { + NameValue nv = new NameValue(); + StringTokenizer stz = new StringTokenizer(input, NAME_VALUE_SEPARATOR); + int tokens = stz.countTokens(); + if (tokens == 2) { + nv.name = stz.nextToken(); + nv.value = stz.nextToken(); + } else { + throw new IllegalStateException("Found multi valued element " + input + + " without qualification"); + } + return nv; + } + /** * writeDocument streams out given document to given output stream * @param document