From: Ray Lee Date: Thu, 3 Mar 2016 20:54:14 +0000 (-0800) Subject: CSPACE-6918: Add material authority and materials profile. X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=9b42f9a28bc5cfffcc97c14687040238c5153183;p=tmp%2Fjakarta-migration.git CSPACE-6918: Add material authority and materials profile. --- diff --git a/services/JaxRsServiceProvider/pom.xml b/services/JaxRsServiceProvider/pom.xml index e91061e95..e97387126 100644 --- a/services/JaxRsServiceProvider/pom.xml +++ b/services/JaxRsServiceProvider/pom.xml @@ -274,6 +274,11 @@ org.collectionspace.services.work.service ${project.version} + + org.collectionspace.services + org.collectionspace.services.material.service + ${project.version} + org.collectionspace.services org.collectionspace.services.concept.service diff --git a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java index 23edf527b..81fa6b8e9 100644 --- a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java +++ b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java @@ -39,6 +39,7 @@ import org.collectionspace.services.imports.ImportsResource; import org.collectionspace.services.location.LocationAuthorityResource; import org.collectionspace.services.place.PlaceAuthorityResource; import org.collectionspace.services.work.WorkAuthorityResource; +import org.collectionspace.services.material.MaterialAuthorityResource; import org.collectionspace.services.concept.ConceptAuthorityResource; import org.collectionspace.services.taxonomy.TaxonomyAuthorityResource; import org.collectionspace.services.movement.MovementResource; @@ -110,6 +111,7 @@ public class CollectionSpaceJaxRsApplication extends Application addResourceToMapAndSingletons(new TaxonomyAuthorityResource()); addResourceToMapAndSingletons(new PlaceAuthorityResource()); addResourceToMapAndSingletons(new WorkAuthorityResource()); + addResourceToMapAndSingletons(new MaterialAuthorityResource()); addResourceToMapAndSingletons(new AcquisitionResource()); addResourceToMapAndSingletons(new ContactResource()); addResourceToMapAndSingletons(new CollectionObjectResource()); diff --git a/services/build.xml b/services/build.xml index 04b75699e..e44f38413 100644 --- a/services/build.xml +++ b/services/build.xml @@ -179,6 +179,7 @@ + @@ -209,6 +210,7 @@ + @@ -269,6 +271,7 @@ + diff --git a/services/common/src/main/cspace/config/services/tenants/materials/materials-tenant-bindings.delta.xml b/services/common/src/main/cspace/config/services/tenants/materials/materials-tenant-bindings.delta.xml new file mode 100644 index 000000000..ad75d5374 --- /dev/null +++ b/services/common/src/main/cspace/config/services/tenants/materials/materials-tenant-bindings.delta.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/services/material/3rdparty/build.xml b/services/material/3rdparty/build.xml new file mode 100644 index 000000000..abe0abc08 --- /dev/null +++ b/services/material/3rdparty/build.xml @@ -0,0 +1,135 @@ + + + + material service 3rdparty + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/material/3rdparty/nuxeo-platform-cs-material/build.xml b/services/material/3rdparty/nuxeo-platform-cs-material/build.xml new file mode 100644 index 000000000..ac8bbf549 --- /dev/null +++ b/services/material/3rdparty/nuxeo-platform-cs-material/build.xml @@ -0,0 +1,167 @@ + + + + material nuxeo document type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/material/3rdparty/nuxeo-platform-cs-material/pom.xml b/services/material/3rdparty/nuxeo-platform-cs-material/pom.xml new file mode 100644 index 000000000..08bbc1053 --- /dev/null +++ b/services/material/3rdparty/nuxeo-platform-cs-material/pom.xml @@ -0,0 +1,42 @@ + + + org.collectionspace.services + org.collectionspace.services.material.3rdparty + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.material.3rdparty.nuxeo + services.material.3rdparty.nuxeo + jar + + Material Nuxeo Document Type + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-jar-plugin + + + src/main/resources/META-INF/MANIFEST.MF + + ${eclipseVersion} + 2 + + + + + + + + diff --git a/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/META-INF/README.txt b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/META-INF/README.txt new file mode 100644 index 000000000..5f8c5a6d0 --- /dev/null +++ b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/META-INF/README.txt @@ -0,0 +1,16 @@ +Files formerly located in this directory are no longer needed +------------------------------------------------------------- + +In CollectionSpace versions 4.0 and higher, changes were introduced +which streamline and simplify the process through which you configure +fields in CollectionSpace's main record types. + +In most cases now, you will typically change the behavior of existing fields, +or create extension schemas to add new fields specific to your museum and/or +community of practice, merely by editing simpler XML-based configuration +files within CollectionSpace's Application layer. + +Services layer files that were formerly located in this directory and +other, similar directories - which you previously needed to manually +create or edit - are now generated automatically from your configuration +in the Application layer. \ No newline at end of file diff --git a/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/OSGI-INF/README.txt b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/OSGI-INF/README.txt new file mode 100644 index 000000000..5f8c5a6d0 --- /dev/null +++ b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/OSGI-INF/README.txt @@ -0,0 +1,16 @@ +Files formerly located in this directory are no longer needed +------------------------------------------------------------- + +In CollectionSpace versions 4.0 and higher, changes were introduced +which streamline and simplify the process through which you configure +fields in CollectionSpace's main record types. + +In most cases now, you will typically change the behavior of existing fields, +or create extension schemas to add new fields specific to your museum and/or +community of practice, merely by editing simpler XML-based configuration +files within CollectionSpace's Application layer. + +Services layer files that were formerly located in this directory and +other, similar directories - which you previously needed to manually +create or edit - are now generated automatically from your configuration +in the Application layer. \ No newline at end of file diff --git a/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/schemas/README.txt b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/schemas/README.txt new file mode 100644 index 000000000..5f8c5a6d0 --- /dev/null +++ b/services/material/3rdparty/nuxeo-platform-cs-material/src/main/resources/schemas/README.txt @@ -0,0 +1,16 @@ +Files formerly located in this directory are no longer needed +------------------------------------------------------------- + +In CollectionSpace versions 4.0 and higher, changes were introduced +which streamline and simplify the process through which you configure +fields in CollectionSpace's main record types. + +In most cases now, you will typically change the behavior of existing fields, +or create extension schemas to add new fields specific to your museum and/or +community of practice, merely by editing simpler XML-based configuration +files within CollectionSpace's Application layer. + +Services layer files that were formerly located in this directory and +other, similar directories - which you previously needed to manually +create or edit - are now generated automatically from your configuration +in the Application layer. \ No newline at end of file diff --git a/services/material/3rdparty/pom.xml b/services/material/3rdparty/pom.xml new file mode 100644 index 000000000..5cdbd87fe --- /dev/null +++ b/services/material/3rdparty/pom.xml @@ -0,0 +1,24 @@ + + + + org.collectionspace.services + org.collectionspace.services.material + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.material.3rdparty + services.material.3rdparty + pom + + 3rd party build for material service + + + + + + diff --git a/services/material/build.xml b/services/material/build.xml new file mode 100644 index 000000000..5a4ad7c4c --- /dev/null +++ b/services/material/build.xml @@ -0,0 +1,131 @@ + + + Material Authority service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/material/client/pom.xml b/services/material/client/pom.xml new file mode 100644 index 000000000..b370576e7 --- /dev/null +++ b/services/material/client/pom.xml @@ -0,0 +1,88 @@ + + + + org.collectionspace.services + org.collectionspace.services.material + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.material.client + services.material.client + + + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.common + true + + + org.collectionspace.services + org.collectionspace.services.material.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.authority.jaxb + true + ${project.version} + + + + org.testng + testng + + + org.jboss.resteasy + resteasy-jaxrs + + + + tjws + webserver + + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + commons-httpclient + commons-httpclient + + + + + collectionspace-services-material-client + + + + + diff --git a/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClient.java b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClient.java new file mode 100644 index 000000000..38dae0e30 --- /dev/null +++ b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClient.java @@ -0,0 +1,72 @@ +/** + * 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 The Regents of the University of California + * + * 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 + */ +package org.collectionspace.services.client; + +import org.collectionspace.services.material.MaterialsCommon; + +/** + * The Class MaterialAuthorityClient. + */ +public class MaterialAuthorityClient extends AuthorityClientImpl { + + public static final String SERVICE_NAME = "materialauthorities"; + public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME; + public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT; + public static final String SERVICE_PAYLOAD_NAME = SERVICE_NAME; + public static final String TERM_INFO_GROUP_XPATH_BASE = "materialTermGroupList"; + // + // Subitem constants + // + public static final String SERVICE_ITEM_NAME = "materials"; + public static final String SERVICE_ITEM_PAYLOAD_NAME = SERVICE_ITEM_NAME; + // + // Payload Part/Schema part names + // + public static final String SERVICE_COMMON_PART_NAME = SERVICE_NAME + + PART_LABEL_SEPARATOR + PART_COMMON_LABEL; + public static final String SERVICE_ITEM_COMMON_PART_NAME = SERVICE_ITEM_NAME + + PART_LABEL_SEPARATOR + PART_COMMON_LABEL; + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + @Override + public String getServicePathComponent() { + return SERVICE_PATH_COMPONENT; + } + + @Override + public String getItemCommonPartName() { + return getCommonPartName(SERVICE_ITEM_NAME); + } + + @Override + public Class getProxyClass() { + return MaterialAuthorityProxy.class; + } + + @Override + public String getInAuthority(MaterialsCommon item) { + return item.getInAuthority(); + } + + @Override + public void setInAuthority(MaterialsCommon item, String inAuthorityCsid) { + item.setInAuthority(inAuthorityCsid); + } +} diff --git a/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClientUtils.java b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClientUtils.java new file mode 100644 index 000000000..399e6b364 --- /dev/null +++ b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityClientUtils.java @@ -0,0 +1,294 @@ +package org.collectionspace.services.client; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import org.apache.commons.io.FileUtils; +import org.collectionspace.services.MaterialJAXBSchema; +import org.collectionspace.services.client.test.ServiceRequestType; +import org.collectionspace.services.common.api.Tools; +import org.collectionspace.services.material.MaterialTermGroup; +import org.collectionspace.services.material.MaterialTermGroupList; +import org.collectionspace.services.material.MaterialauthoritiesCommon; +import org.collectionspace.services.material.MaterialsCommon; +import org.dom4j.DocumentException; +import org.jboss.resteasy.client.ClientResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MaterialAuthorityClientUtils { + private static final Logger logger = + LoggerFactory.getLogger(MaterialAuthorityClientUtils.class); + + /** + * Creates a new Material Authority + * @param displayName The displayName used in UI, etc. + * @param refName The proper refName for this authority + * @param headerLabel The common part label + * @return The PoxPayloadOut payload for the create call + */ + public static PoxPayloadOut createMaterialAuthorityInstance( + String displayName, String shortIdentifier, String headerLabel ) { + MaterialauthoritiesCommon materialAuthority = new MaterialauthoritiesCommon(); + materialAuthority.setDisplayName(displayName); + materialAuthority.setShortIdentifier(shortIdentifier); + String refName = createMaterialAuthRefName(shortIdentifier, displayName); + materialAuthority.setRefName(refName); + materialAuthority.setVocabType("MaterialAuthority"); //FIXME: REM - Should this really be hard-coded? + PoxPayloadOut multipart = new PoxPayloadOut(MaterialAuthorityClient.SERVICE_PAYLOAD_NAME); + PayloadOutputPart commonPart = multipart.addPart(materialAuthority, MediaType.APPLICATION_XML_TYPE); + commonPart.setLabel(headerLabel); + + if(logger.isDebugEnabled()){ + logger.debug("to be created, materialAuthority common ", + materialAuthority, MaterialauthoritiesCommon.class); + } + + return multipart; + } + + /** + * @param materialRefName The proper refName for this authority + * @param materialInfo the properties for the new Material. Can pass in one condition + * note and date string. + * @param headerLabel The common part label + * @return The PoxPayloadOut payload for the create call + */ + public static PoxPayloadOut createMaterialInstance( + String materialAuthRefName, Map materialInfo, + List terms, String headerLabel){ + MaterialsCommon material = new MaterialsCommon(); + String shortId = materialInfo.get(MaterialJAXBSchema.SHORT_IDENTIFIER); + material.setShortIdentifier(shortId); + + // Set values in the Term Information Group + MaterialTermGroupList termList = new MaterialTermGroupList(); + if (terms == null || terms.isEmpty()) { + terms = getTermGroupInstance(getGeneratedIdentifier()); + } + termList.getMaterialTermGroup().addAll(terms); + material.setMaterialTermGroupList(termList); + + PoxPayloadOut multipart = new PoxPayloadOut(MaterialAuthorityClient.SERVICE_ITEM_PAYLOAD_NAME); + PayloadOutputPart commonPart = multipart.addPart(material, + MediaType.APPLICATION_XML_TYPE); + commonPart.setLabel(headerLabel); + + if(logger.isDebugEnabled()){ + logger.debug("to be created, material common ", material, MaterialsCommon.class); + } + + return multipart; + } + + /** + * @param vcsid CSID of the authority to create a new material + * @param materialAuthorityRefName The refName for the authority + * @param materialMap the properties for the new Material + * @param client the service client + * @return the CSID of the new item + */ + public static String createItemInAuthority(String vcsid, + String materialAuthorityRefName, Map materialMap, + List terms, MaterialAuthorityClient client ) { + // Expected status code: 201 Created + int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); + // Type of service request being tested + ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; + + String displayName = ""; + if ((terms !=null) && (! terms.isEmpty())) { + displayName = terms.get(0).getTermDisplayName(); + } + if(logger.isDebugEnabled()){ + logger.debug("Creating item with display name: \"" + displayName + +"\" in locationAuthority: \"" + vcsid +"\""); + } + PoxPayloadOut multipart = + createMaterialInstance( materialAuthorityRefName, + materialMap, terms, client.getItemCommonPartName() ); + String newID = null; + Response res = client.createItem(vcsid, multipart); + try { + int statusCode = res.getStatus(); + + if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { + throw new RuntimeException("Could not create Item: \"" + +materialMap.get(MaterialJAXBSchema.SHORT_IDENTIFIER) + +"\" in materialAuthority: \"" + materialAuthorityRefName + +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + } + if(statusCode != EXPECTED_STATUS_CODE) { + throw new RuntimeException("Unexpected Status when creating Item: \"" + +materialMap.get(MaterialJAXBSchema.SHORT_IDENTIFIER) + +"\" in materialAuthority: \"" + materialAuthorityRefName +"\", Status:"+ statusCode); + } + newID = extractId(res); + } finally { + res.close(); + } + + return newID; + } + + public static PoxPayloadOut createMaterialInstance( + String commonPartXML, String headerLabel) throws DocumentException { + PoxPayloadOut multipart = new PoxPayloadOut(MaterialAuthorityClient.SERVICE_ITEM_PAYLOAD_NAME); + PayloadOutputPart commonPart = multipart.addPart(commonPartXML, + MediaType.APPLICATION_XML_TYPE); + commonPart.setLabel(headerLabel); + + if(logger.isDebugEnabled()){ + logger.debug("to be created, material common ", commonPartXML); + } + + return multipart; + } + + public static String createItemInAuthority(String vcsid, + String commonPartXML, + MaterialAuthorityClient client ) throws DocumentException { + // Expected status code: 201 Created + int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); + // Type of service request being tested + ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; + + PoxPayloadOut multipart = + createMaterialInstance(commonPartXML, client.getItemCommonPartName()); + String newID = null; + Response res = client.createItem(vcsid, multipart); + try { + int statusCode = res.getStatus(); + + if(!REQUEST_TYPE.isValidStatusCode(statusCode)) { + throw new RuntimeException("Could not create Item: \""+commonPartXML + +"\" in materialAuthority: \"" + vcsid + +"\" "+ invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + } + if(statusCode != EXPECTED_STATUS_CODE) { + throw new RuntimeException("Unexpected Status when creating Item: \""+commonPartXML + +"\" in materialAuthority: \"" + vcsid +"\", Status:"+ statusCode); + } + newID = extractId(res); + } finally { + res.close(); + } + + return newID; + } + + /** + * Creates the from xml file. + * + * @param fileName the file name + * @return new CSID as string + * @throws Exception the exception + */ + private String createItemInAuthorityFromXmlFile(String vcsid, String commonPartFileName, + MaterialAuthorityClient client) throws Exception { + byte[] b = FileUtils.readFileToByteArray(new File(commonPartFileName)); + String commonPartXML = new String(b); + return createItemInAuthority(vcsid, commonPartXML, client ); + } + + /** + * Creates the materialAuthority ref name. + * + * @param shortId the materialAuthority shortIdentifier + * @param displaySuffix displayName to be appended, if non-null + * @return the string + */ + public static String createMaterialAuthRefName(String shortId, String displaySuffix) { + String refName = "urn:cspace:org.collectionspace.demo:materialauthority:name(" + +shortId+")"; + if(displaySuffix!=null&&!displaySuffix.isEmpty()) + refName += "'"+displaySuffix+"'"; + return refName; + } + + /** + * Creates the material ref name. + * + * @param materialAuthRefName the materialAuthority ref name + * @param shortId the material shortIdentifier + * @param displaySuffix displayName to be appended, if non-null + * @return the string + */ + public static String createMaterialRefName( + String materialAuthRefName, String shortId, String displaySuffix) { + String refName = materialAuthRefName+":material:name("+shortId+")"; + if(displaySuffix!=null&&!displaySuffix.isEmpty()) + refName += "'"+displaySuffix+"'"; + return refName; + } + + public static String extractId(Response res) { + MultivaluedMap mvm = res.getMetadata(); + String uri = (String) ((ArrayList) mvm.get("Location")).get(0); + if(logger.isDebugEnabled()){ + logger.debug("extractId:uri=" + uri); + } + String[] segments = uri.split("/"); + String id = segments[segments.length - 1]; + if(logger.isDebugEnabled()){ + logger.debug("id=" + id); + } + return id; + } + + /** + * Returns an error message indicating that the status code returned by a + * specific call to a service does not fall within a set of valid status + * codes for that service. + * + * @param serviceRequestType A type of service request (e.g. CREATE, DELETE). + * + * @param statusCode The invalid status code that was returned in the response, + * from submitting that type of request to the service. + * + * @return An error message. + */ + public static String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) { + return "Status code '" + statusCode + "' in response is NOT within the expected set: " + + requestType.validStatusCodesAsString(); + } + + + + /** + * Produces a default displayName from one or more supplied field(s). + * @see MaterialAuthorityDocumentModelHandler.prepareDefaultDisplayName() which + * duplicates this logic, until we define a service-general utils package + * that is neither client nor service specific. + * @param materialName + * @return a display name + */ + public static String prepareDefaultDisplayName( + String materialName ) { + StringBuilder newStr = new StringBuilder(); + newStr.append(materialName); + return newStr.toString(); + } + + public static List getTermGroupInstance(String identifier) { + if (Tools.isBlank(identifier)) { + identifier = getGeneratedIdentifier(); + } + List terms = new ArrayList(); + MaterialTermGroup term = new MaterialTermGroup(); + term.setTermDisplayName(identifier); + term.setTermName(identifier); + terms.add(term); + return terms; + } + + private static String getGeneratedIdentifier() { + return "id" + new Date().getTime(); + } + +} diff --git a/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityProxy.java b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityProxy.java new file mode 100644 index 000000000..a74b03928 --- /dev/null +++ b/services/material/client/src/main/java/org/collectionspace/services/client/MaterialAuthorityProxy.java @@ -0,0 +1,11 @@ +package org.collectionspace.services.client; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +@Path(MaterialAuthorityClient.SERVICE_PATH + "/") +@Produces("application/xml") +@Consumes("application/xml") +public interface MaterialAuthorityProxy extends AuthorityProxy { +} diff --git a/services/material/client/src/main/resources/collectionspace-client.properties b/services/material/client/src/main/resources/collectionspace-client.properties new file mode 100644 index 000000000..de4600ee1 --- /dev/null +++ b/services/material/client/src/main/resources/collectionspace-client.properties @@ -0,0 +1,6 @@ +#url of the collectionspace server +cspace.url=http://localhost:8180/cspace-services/ +cspace.ssl=false +cspace.auth=true +cspace.user=admin@materials.collectionspace.org +cspace.password=Administrator diff --git a/services/material/client/src/test/java/org/collectionspace/services/client/test/MaterialAuthorityServiceTest.java b/services/material/client/src/test/java/org/collectionspace/services/client/test/MaterialAuthorityServiceTest.java new file mode 100644 index 000000000..dac1a84e5 --- /dev/null +++ b/services/material/client/src/test/java/org/collectionspace/services/client/test/MaterialAuthorityServiceTest.java @@ -0,0 +1,513 @@ +/** + * 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 (c)) 2009 Regents of the University of California + * + * 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.client.test; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.Response; + +import org.collectionspace.services.MaterialJAXBSchema; +import org.collectionspace.services.client.AbstractCommonListUtils; +import org.collectionspace.services.client.AuthorityClient; +import org.collectionspace.services.client.CollectionSpaceClient; +import org.collectionspace.services.client.PayloadOutputPart; +import org.collectionspace.services.client.PoxPayloadIn; +import org.collectionspace.services.client.PoxPayloadOut; +import org.collectionspace.services.client.MaterialAuthorityClient; +import org.collectionspace.services.client.MaterialAuthorityClientUtils; +import org.collectionspace.services.jaxb.AbstractCommonList; +import org.collectionspace.services.material.MaterialTermGroup; +import org.collectionspace.services.material.MaterialTermGroupList; +import org.collectionspace.services.material.MaterialauthoritiesCommon; +import org.collectionspace.services.material.MaterialsCommon; +import org.jboss.resteasy.client.ClientResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +/** + * MaterialAuthorityServiceTest, carries out tests against a + * deployed and running MaterialAuthority Service. + * + */ +public class MaterialAuthorityServiceTest extends AbstractAuthorityServiceTest { + + /** The logger. */ + private final String CLASS_NAME = MaterialAuthorityServiceTest.class.getName(); + private final Logger logger = LoggerFactory.getLogger(MaterialAuthorityServiceTest.class); + + @Override + public String getServicePathComponent() { + return MaterialAuthorityClient.SERVICE_PATH_COMPONENT; + } + + @Override + protected String getServiceName() { + return MaterialAuthorityClient.SERVICE_NAME; + } + + public String getItemServicePathComponent() { + return AuthorityClient.ITEMS; + } + + // Instance variables specific to this test. + +// /** The SERVICE path component. */ +// final String SERVICE_PATH_COMPONENT = "materialauthorities"; +// +// /** The ITEM service path component. */ +// final String ITEM_SERVICE_PATH_COMPONENT = "items"; +// + + final String TEST_MATERIAL_TERM_DISPLAY_NAME = "SuperGlass 2"; + final String TEST_MATERIAL_TERM_NAME = "SuperGlass"; + final String TEST_MATERIAL_TERM_STATUS = "accepted"; + final String TEST_MATERIAL_TERM_SOURCE = "source"; + final String TEST_MATERIAL_TERM_SOURCE_DETAIL = "internal"; + final String TEST_MATERIAL_DESCRIPTION = "Really strong glass"; + final String TEST_MATERIAL_SHORT_IDENTIFIER = "superglass"; + + /* (non-Javadoc) + * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance() + */ + @Override + protected CollectionSpaceClient getClientInstance() { + return new MaterialAuthorityClient(); + } + + /** + * Creates the item in authority. + * + * @param vcsid the vcsid + * @param authRefName the auth ref name + * @return the string + */ + private String createItemInAuthority(String vcsid, String authRefName) { + final String testName = "createItemInAuthority("+vcsid+","+authRefName+")"; + + // Submit the request to the service and store the response. + MaterialAuthorityClient client = new MaterialAuthorityClient(); + Map materialMap = new HashMap(); + // TODO Make material type and status be controlled vocabs. + materialMap.put(MaterialJAXBSchema.SHORT_IDENTIFIER, TEST_MATERIAL_SHORT_IDENTIFIER); + materialMap.put(MaterialJAXBSchema.MATERIAL_DESCRIPTION, TEST_MATERIAL_DESCRIPTION); + + List terms = new ArrayList(); + MaterialTermGroup term = new MaterialTermGroup(); + term.setTermDisplayName(TEST_MATERIAL_TERM_DISPLAY_NAME); + term.setTermName(TEST_MATERIAL_TERM_NAME); + term.setTermSource(TEST_MATERIAL_TERM_SOURCE); + term.setTermSourceDetail(TEST_MATERIAL_TERM_SOURCE_DETAIL); + term.setTermStatus(TEST_MATERIAL_TERM_STATUS); + terms.add(term); + + String newID = MaterialAuthorityClientUtils.createItemInAuthority(vcsid, + authRefName, materialMap, terms, client ); + + // Store the ID returned from the first item resource created + // for additional tests below. + if (knownItemResourceId == null){ + setKnownItemResource(newID, TEST_MATERIAL_SHORT_IDENTIFIER); + if (logger.isDebugEnabled()) { + logger.debug(testName + ": knownItemResourceId=" + newID); + } + } + + // Store the IDs from any item resources created + // by tests, along with the IDs of their parents, so these items + // can be deleted after all tests have been run. + allResourceItemIdsCreated.put(newID, vcsid); + + return newID; + } + + /** + * Verify illegal item display name. + * + * @param testName the test name + * @throws Exception the exception + */ + @Test(dataProvider="testName") + public void verifyIllegalItemDisplayName(String testName) throws Exception { + // Perform setup for read. + setupRead(); + + // Submit the request to the service and store the response. + MaterialAuthorityClient client = new MaterialAuthorityClient(); + Response res = client.readItem(knownResourceId, knownItemResourceId); + MaterialsCommon material = null; + try { + assertStatusCode(res, testName); + PoxPayloadIn input = new PoxPayloadIn(res.readEntity(String.class)); + material = (MaterialsCommon) extractPart(input, + client.getItemCommonPartName(), MaterialsCommon.class); + Assert.assertNotNull(material); + } finally { + if (res != null) { + res.close(); + } + } + + // + // Make an invalid UPDATE request, without a display name + // + MaterialTermGroupList termList = material.getMaterialTermGroupList(); + Assert.assertNotNull(termList); + List terms = termList.getMaterialTermGroup(); + Assert.assertNotNull(terms); + Assert.assertTrue(terms.size() > 0); + terms.get(0).setTermDisplayName(null); + terms.get(0).setTermName(null); + + setupUpdateWithInvalidBody(); // we expect a failure + + // Submit the updated resource to the service and store the response. + PoxPayloadOut output = new PoxPayloadOut( + MaterialAuthorityClient.SERVICE_ITEM_PAYLOAD_NAME); + PayloadOutputPart commonPart = output.addPart( + client.getItemCommonPartName(), material); + setupUpdateWithInvalidBody(); // we expected a failure here. + res = client.updateItem(knownResourceId, knownItemResourceId, output); + try { + assertStatusCode(res, testName); + } finally { + if (res != null) { + res.close(); + } + } + } + + /** + * Read item list. + */ + @Test(dataProvider = "testName", groups = {"readList"}, + dependsOnMethods = {"readList"}) + public void readItemList(String testName) { + readItemList(knownAuthorityWithItems, null); + } + + /** + * Read item list by authority name. + */ + @Test(dataProvider = "testName", groups = {"readList"}, + dependsOnMethods = {"readItemList"}) + public void readItemListByAuthorityName(String testName) { + readItemList(null, READITEMS_SHORT_IDENTIFIER); + } + + /** + * Read item list. + * + * @param vcsid + * the vcsid + * @param name + * the name + */ + private void readItemList(String vcsid, String shortId) { + String testName = "readItemList"; + + // Perform setup. + setupReadList(); + + // Submit the request to the service and store the response. + MaterialAuthorityClient client = new MaterialAuthorityClient(); + Response res = null; + if (vcsid != null) { + res = client.readItemList(vcsid, null, null); + } else if (shortId != null) { + res = client.readItemListForNamedAuthority(shortId, null, null); + } else { + Assert.fail("readItemList passed null csid and name!"); + } + + AbstractCommonList list = null; + try { + assertStatusCode(res, testName); + list = res.readEntity(AbstractCommonList.class); + } finally { + if (res != null) { + res.close(); + } + } + + List items = list.getListItem(); + int nItemsReturned = items.size(); + // There will be 'nItemsToCreateInList' + // items created by the createItemList test, + // all associated with the same parent resource. + int nExpectedItems = nItemsToCreateInList; + if (logger.isDebugEnabled()) { + logger.debug(testName + ": Expected " + nExpectedItems + + " items; got: " + nItemsReturned); + } + Assert.assertEquals(nItemsReturned, nExpectedItems); + + for (AbstractCommonList.ListItem item : items) { + String value = AbstractCommonListUtils.ListItemGetElementValue( + item, MaterialJAXBSchema.REF_NAME); + Assert.assertTrue((null != value), "Item refName is null!"); + value = AbstractCommonListUtils.ListItemGetElementValue(item, + MaterialJAXBSchema.MATERIAL_TERM_DISPLAY_NAME); + Assert.assertTrue((null != value), "Item termDisplayName is null!"); + } + if (logger.isTraceEnabled()) { + AbstractCommonListUtils.ListItemsInAbstractCommonList(list, logger, + testName); + } + } + + @Override + public void delete(String testName) throws Exception { + // Do nothing. See localDelete(). This ensure proper test order. + } + + @Test(dataProvider = "testName", dependsOnMethods = {"localDeleteItem"}) + public void localDelete(String testName) throws Exception { + super.delete(testName); + } + + @Override + public void deleteItem(String testName) throws Exception { + // Do nothing. We need to wait until after the test "localDelete" gets run. When it does, + // its dependencies will get run first and then we can call the base class' delete method. + } + + @Test(dataProvider = "testName", groups = {"delete"}, + dependsOnMethods = {"verifyIllegalItemDisplayName"}) + public void localDeleteItem(String testName) throws Exception { + super.deleteItem(testName); + } + + // --------------------------------------------------------------- + // Cleanup of resources created during testing + // --------------------------------------------------------------- + + /** + * Deletes all resources created by tests, after all tests have been run. + * + * This cleanup method will always be run, even if one or more tests fail. + * For this reason, it attempts to remove all resources created + * at any point during testing, even if some of those resources + * may be expected to be deleted by certain tests. + */ + + @AfterClass(alwaysRun=true) + public void cleanUp() { + String noTest = System.getProperty("noTestCleanup"); + if(Boolean.TRUE.toString().equalsIgnoreCase(noTest)) { + if (logger.isDebugEnabled()) { + logger.debug("Skipping Cleanup phase ..."); + } + return; + } + if (logger.isDebugEnabled()) { + logger.debug("Cleaning up temporary resources created for testing ..."); + } + String parentResourceId; + String itemResourceId; + // Clean up contact resources. + MaterialAuthorityClient client = new MaterialAuthorityClient(); + parentResourceId = knownResourceId; + // Clean up item resources. + for (Map.Entry entry : allResourceItemIdsCreated.entrySet()) { + itemResourceId = entry.getKey(); + parentResourceId = entry.getValue(); + // Note: Any non-success responses from the delete operation + // below are ignored and not reported. + client.deleteItem(parentResourceId, itemResourceId).close(); + } + // Clean up parent resources. + for (String resourceId : allResourceIdsCreated) { + // Note: Any non-success responses from the delete operation + // below are ignored and not reported. + client.delete(resourceId).close(); + } + } + + // --------------------------------------------------------------- + // Utility methods used by tests above + // --------------------------------------------------------------- + /* (non-Javadoc) + * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent() + */ + + /** + * Returns the root URL for the item service. + * + * This URL consists of a base URL for all services, followed by + * a path component for the owning parent, followed by the + * path component for the items. + * + * @param parentResourceIdentifier An identifier (such as a UUID) for the + * parent authority resource of the relevant item resource. + * + * @return The root URL for the item service. + */ + protected String getItemServiceRootURL(String parentResourceIdentifier) { + return getResourceURL(parentResourceIdentifier) + "/" + getItemServicePathComponent(); + } + + /** + * Returns the URL of a specific item resource managed by a service, and + * designated by an identifier (such as a universally unique ID, or UUID). + * + * @param parentResourceIdentifier An identifier (such as a UUID) for the + * parent authority resource of the relevant item resource. + * + * @param itemResourceIdentifier An identifier (such as a UUID) for an + * item resource. + * + * @return The URL of a specific item resource managed by a service. + */ + protected String getItemResourceURL(String parentResourceIdentifier, String itemResourceIdentifier) { + return getItemServiceRootURL(parentResourceIdentifier) + "/" + itemResourceIdentifier; + } + + @Override + public void authorityTests(String testName) { + // TODO Auto-generated method stub + + } + + // + // Material specific overrides + // + + @Override + protected PoxPayloadOut createInstance(String commonPartName, + String identifier) { + // Submit the request to the service and store the response. + String shortId = identifier; + String displayName = "displayName-" + shortId; + // String baseRefName = MaterialAuthorityClientUtils.createMaterialAuthRefName(shortId, null); + PoxPayloadOut result = + MaterialAuthorityClientUtils.createMaterialAuthorityInstance( + displayName, shortId, commonPartName); + return result; + } + + @Override + protected PoxPayloadOut createNonExistenceInstance(String commonPartName, String identifier) { + String displayName = "displayName-NON_EXISTENT_ID"; + PoxPayloadOut result = MaterialAuthorityClientUtils.createMaterialAuthorityInstance( + displayName, "nonEx", commonPartName); + return result; + } + + @Override + protected MaterialauthoritiesCommon updateInstance(MaterialauthoritiesCommon materialauthoritiesCommon) { + MaterialauthoritiesCommon result = new MaterialauthoritiesCommon(); + + result.setDisplayName("updated-" + materialauthoritiesCommon.getDisplayName()); + result.setVocabType("updated-" + materialauthoritiesCommon.getVocabType()); + + return result; + } + + @Override + protected void compareUpdatedInstances(MaterialauthoritiesCommon original, + MaterialauthoritiesCommon updated) throws Exception { + Assert.assertEquals(updated.getDisplayName(), + original.getDisplayName(), + "Display name in updated object did not match submitted data."); + } + + protected void compareReadInstances(MaterialauthoritiesCommon original, + MaterialauthoritiesCommon fromRead) throws Exception { + Assert.assertNotNull(fromRead.getDisplayName()); + Assert.assertNotNull(fromRead.getShortIdentifier()); + Assert.assertNotNull(fromRead.getRefName()); + } + + // + // Authority item specific overrides + // + + @Override + protected String createItemInAuthority(String authorityId) { + return createItemInAuthority(authorityId, null /*refname*/); + } + + @Override + protected MaterialsCommon updateItemInstance(MaterialsCommon materialsCommon) { + + MaterialTermGroupList termList = materialsCommon.getMaterialTermGroupList(); + Assert.assertNotNull(termList); + List terms = termList.getMaterialTermGroup(); + Assert.assertNotNull(terms); + Assert.assertTrue(terms.size() > 0); + terms.get(0).setTermDisplayName("updated-" + terms.get(0).getTermDisplayName()); + terms.get(0).setTermName("updated-" + terms.get(0).getTermName()); + materialsCommon.setMaterialTermGroupList(termList); + + return materialsCommon; + } + + @Override + protected void compareUpdatedItemInstances(MaterialsCommon original, + MaterialsCommon updated) throws Exception { + + MaterialTermGroupList originalTermList = original.getMaterialTermGroupList(); + Assert.assertNotNull(originalTermList); + List originalTerms = originalTermList.getMaterialTermGroup(); + Assert.assertNotNull(originalTerms); + Assert.assertTrue(originalTerms.size() > 0); + + MaterialTermGroupList updatedTermList = updated.getMaterialTermGroupList(); + Assert.assertNotNull(updatedTermList); + List updatedTerms = updatedTermList.getMaterialTermGroup(); + Assert.assertNotNull(updatedTerms); + Assert.assertTrue(updatedTerms.size() > 0); + + Assert.assertEquals(updatedTerms.get(0).getTermDisplayName(), + originalTerms.get(0).getTermDisplayName(), + "Value in updated record did not match submitted data."); + } + + @Override + protected void verifyReadItemInstance(MaterialsCommon item) + throws Exception { + // TODO Auto-generated method stub + + } + + @Override + protected PoxPayloadOut createNonExistenceItemInstance( + String commonPartName, String identifier) { + Map nonexMap = new HashMap(); + nonexMap.put(MaterialJAXBSchema.MATERIAL_TERM_DISPLAY_NAME, TEST_MATERIAL_TERM_DISPLAY_NAME); + nonexMap.put(MaterialJAXBSchema.SHORT_IDENTIFIER, "nonEx"); + nonexMap.put(MaterialJAXBSchema.MATERIAL_TERM_STATUS, TEST_MATERIAL_TERM_STATUS); + final String EMPTY_REFNAME = ""; + PoxPayloadOut result = + MaterialAuthorityClientUtils.createMaterialInstance(EMPTY_REFNAME, nonexMap, + MaterialAuthorityClientUtils.getTermGroupInstance(TEST_MATERIAL_TERM_DISPLAY_NAME), commonPartName); + return result; + } +} diff --git a/services/material/client/src/test/resources/log4j.properties b/services/material/client/src/test/resources/log4j.properties new file mode 100644 index 000000000..148a3e865 --- /dev/null +++ b/services/material/client/src/test/resources/log4j.properties @@ -0,0 +1,23 @@ +log4j.rootLogger=debug, stdout, R + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + +# Pattern to output the caller's file name and line number. +log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%t] [%c:%L] %m%n + +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=target/test-client.log + +log4j.appender.R.MaxFileSize=100KB +# Keep one backup file +log4j.appender.R.MaxBackupIndex=1 + +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%d %-5p [%t] [%c:%L] %m%n + +#packages +log4j.logger.org.collectionspace=DEBUG +log4j.logger.org.apache=INFO +log4j.logger.httpclient=INFO +log4j.logger.org.jboss.resteasy=INFO diff --git a/services/material/installer/build.xml b/services/material/installer/build.xml new file mode 100644 index 000000000..369c653de --- /dev/null +++ b/services/material/installer/build.xml @@ -0,0 +1,61 @@ + + + + material service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/material/jaxb/pom.xml b/services/material/jaxb/pom.xml new file mode 100644 index 000000000..f6904ea1e --- /dev/null +++ b/services/material/jaxb/pom.xml @@ -0,0 +1,58 @@ + + + + org.collectionspace.services + org.collectionspace.services.material + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.material.jaxb + services.material.jaxb + + + + org.collectionspace.services + org.collectionspace.services.common + + + com.sun.xml.bind + jaxb-impl + + + + org.collectionspace.services + org.collectionspace.services.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.authority.jaxb + true + ${project.version} + + + + + collectionspace-services-material-jaxb + install + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + + + + + diff --git a/services/material/jaxb/src/main/java/org/collectionspace/services/MaterialJAXBSchema.java b/services/material/jaxb/src/main/java/org/collectionspace/services/MaterialJAXBSchema.java new file mode 100644 index 000000000..3790f9d47 --- /dev/null +++ b/services/material/jaxb/src/main/java/org/collectionspace/services/MaterialJAXBSchema.java @@ -0,0 +1,29 @@ +/** + * + */ +package org.collectionspace.services; +import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema; + +public interface MaterialJAXBSchema extends AuthorityItemJAXBSchema { + final static String MATERIALS_COMMON = "materials_common"; + + final static String MATERIAL_DESCRIPTION = "description"; + + final static String MATERIAL_TERM_GROUP_LIST = "materialTermGroupList"; + final static String MATERIAL_TERM_DISPLAY_NAME = "termDisplayName"; + final static String MATERIAL_TERM_NAME = "termName"; + final static String MATERIAL_TERM_TYPE = "termType"; + final static String MATERIAL_TERM_STATUS = "termStatus"; + final static String MATERIAL_TERM_QUALIFIER = "termQualifier"; + final static String MATERIAL_TERM_LANGUAGE = "termLanguage"; + final static String MATERIAL_TERM_PREFFORLANGUAGE = "termPrefForLang"; + final static String MATERIAL_TERM_SOURCE = "termSource"; + final static String MATERIAL_TERM_SOURCE_DETAIL = "termSourceDetail"; + final static String MATERIAL_TERM_SOURCE_ID = "termSourceID"; + final static String MATERIAL_TERM_SOURCE_NOTE = "termSourceNote"; + + final static String MATERIAL_SHORT_IDENTIFIER = "shortIdentifier"; + final static String MATERIAL_REFNAME = "refName"; + final static String MATERIAL_INAUTHORITY = "inAuthority"; +} + diff --git a/services/material/jaxb/src/main/resources/material_common.xsd b/services/material/jaxb/src/main/resources/material_common.xsd new file mode 100644 index 000000000..c462941ad --- /dev/null +++ b/services/material/jaxb/src/main/resources/material_common.xsd @@ -0,0 +1,471 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/services/material/jaxb/src/main/resources/materialauthority_common.xsd b/services/material/jaxb/src/main/resources/materialauthority_common.xsd new file mode 100644 index 000000000..3746b5cc9 --- /dev/null +++ b/services/material/jaxb/src/main/resources/materialauthority_common.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/material/pom.xml b/services/material/pom.xml new file mode 100644 index 000000000..bac43bb96 --- /dev/null +++ b/services/material/pom.xml @@ -0,0 +1,41 @@ + + + + org.collectionspace.services + org.collectionspace.services.main + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services + org.collectionspace.services.material + services.material + pom + + + + + + + jaxb + service + 3rdparty + client + + + + + samples + + + + + + + + diff --git a/services/material/service/pom.xml b/services/material/service/pom.xml new file mode 100644 index 000000000..8ac3536da --- /dev/null +++ b/services/material/service/pom.xml @@ -0,0 +1,142 @@ + + + + org.collectionspace.services + org.collectionspace.services.material + 4.4-SNAPSHOT + + + 4.0.0 + org.collectionspace.services.material.service + services.material.service + jar + + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + + + + org.collectionspace.services + org.collectionspace.services.common + + + org.collectionspace.services + org.collectionspace.services.material.jaxb + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.material.client + ${project.version} + + + org.collectionspace.services + org.collectionspace.services.authority.service + true + ${project.version} + + + + junit + junit + test + + + org.testng + testng + + + + + commons-beanutils + commons-beanutils + 1.6.1 + + + + commons-logging + commons-logging + 1.1 + + + + + + javax.security + jaas + 1.0.01 + provided + + + + dom4j + dom4j + 1.6.1 + provided + + + + + + org.jboss.resteasy + resteasy-jaxrs + + + tjws + webserver + + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + resteasy-multipart-provider + + + + + + org.nuxeo.ecm.core + nuxeo-core-api + + + jboss-remoting + jboss + + + + + + org.restlet + org.restlet + 1.0.7 + + + com.noelios.restlet + com.noelios.restlet.ext.httpclient + 1.0.7 + + + com.noelios.restlet + com.noelios.restlet + 1.0.7 + + + + + + collectionspace-services-material + + + + + diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/MaterialAuthorityResource.java b/services/material/service/src/main/java/org/collectionspace/services/material/MaterialAuthorityResource.java new file mode 100644 index 000000000..4b05fea04 --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/MaterialAuthorityResource.java @@ -0,0 +1,69 @@ +/** + * 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.material; + +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import org.collectionspace.services.client.MaterialAuthorityClient; +import org.collectionspace.services.common.vocabulary.AuthorityResource; +import org.collectionspace.services.material.nuxeo.MaterialDocumentModelHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * MaterialAuthorityResource + * + * Handles, dispatches, and returns responses to RESTful requests + * related to Material authority-related resources. + */ + +@Path(MaterialAuthorityClient.SERVICE_PATH) +@Consumes("application/xml") +@Produces("application/xml") +public class MaterialAuthorityResource + extends AuthorityResource { + + final Logger logger = LoggerFactory.getLogger(MaterialAuthorityResource.class); + + public MaterialAuthorityResource() { + super(MaterialauthoritiesCommon.class, MaterialAuthorityResource.class, + MaterialAuthorityClient.SERVICE_COMMON_PART_NAME, MaterialAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME); + } + + @Override + public String getServiceName() { + return MaterialAuthorityClient.SERVICE_NAME; + } + + @Override + public String getItemServiceName() { + return MaterialAuthorityClient.SERVICE_ITEM_NAME; + } + + @Override + public String getItemTermInfoGroupXPathBase() { + return MaterialAuthorityClient.TERM_INFO_GROUP_XPATH_BASE; + } + +} diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityConstants.java b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityConstants.java new file mode 100644 index 000000000..17c5e68d0 --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityConstants.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.material.nuxeo; + +/** + * Constants for the Material Authority service + * + */ +public class MaterialAuthorityConstants { + + public final static String NUXEO_DOCTYPE = "MaterialAuthority"; + public final static String NUXEO_SCHEMA_NAME = "materialauthority"; + public final static String NUXEO_DC_TITLE = "CollectionSpace-MaterialAuthority"; +} diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityDocumentModelHandler.java b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityDocumentModelHandler.java new file mode 100644 index 000000000..dd50b2271 --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialAuthorityDocumentModelHandler.java @@ -0,0 +1,55 @@ +/** + * 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.material.nuxeo; + +import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityDocumentModelHandler; +import org.collectionspace.services.material.MaterialauthoritiesCommon; + +/** + * MaterialAuthorityDocumentModelHandler + * + */ +public class MaterialAuthorityDocumentModelHandler + extends AuthorityDocumentModelHandler { + + /** + * Common part schema label + */ + private static final String COMMON_PART_LABEL = "materialauthorities_common"; + + public MaterialAuthorityDocumentModelHandler() { + super(COMMON_PART_LABEL); + } + + /** + * getQProperty converts the given property to qualified schema property + * @param prop + * @return + */ + @Override + public String getQProperty(String prop) { + return MaterialAuthorityConstants.NUXEO_SCHEMA_NAME + ":" + prop; + } +} + diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialConstants.java b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialConstants.java new file mode 100644 index 000000000..691b5466d --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialConstants.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.material.nuxeo; + +/** + * Constants for the Material service + * + */ +public class MaterialConstants { + + public final static String NUXEO_DOCTYPE = "Material"; + public final static String NUXEO_SCHEMA_NAME = "material"; + public final static String NUXEO_DC_TITLE = "CollectionSpace-Material"; +} diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialDocumentModelHandler.java b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialDocumentModelHandler.java new file mode 100644 index 000000000..de974099d --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialDocumentModelHandler.java @@ -0,0 +1,114 @@ +/** + * 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.material.nuxeo; + +import org.collectionspace.services.MaterialJAXBSchema; +import org.collectionspace.services.client.MaterialAuthorityClient; +import org.collectionspace.services.common.document.DocumentWrapper; +import org.collectionspace.services.common.vocabulary.nuxeo.AuthorityItemDocumentModelHandler; +import org.collectionspace.services.material.MaterialsCommon; +import org.nuxeo.ecm.core.api.DocumentModel; + +/** + * MaterialDocumentModelHandler + * + */ +public class MaterialDocumentModelHandler + extends AuthorityItemDocumentModelHandler { + + /** + * Common part schema label + */ + private static final String COMMON_PART_LABEL = "materials_common"; + + public MaterialDocumentModelHandler() { + super(COMMON_PART_LABEL); + } + + @Override + public String getAuthorityServicePath(){ + return MaterialAuthorityClient.SERVICE_PATH_COMPONENT; // CSPACE-3932 + } + + /** + * Handle display name. + * + * @param docModel the doc model + * @throws Exception the exception + */ +// @Override +// protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception { +// String commonPartLabel = getServiceContext().getCommonPartLabel("materials"); +// Boolean displayNameComputed = (Boolean) docModel.getProperty(commonPartLabel, +// MaterialJAXBSchema.DISPLAY_NAME_COMPUTED); +// Boolean shortDisplayNameComputed = (Boolean) docModel.getProperty(commonPartLabel, +// MaterialJAXBSchema.SHORT_DISPLAY_NAME_COMPUTED); +// if(displayNameComputed==null) +// displayNameComputed = true; +// if(shortDisplayNameComputed==null) +// shortDisplayNameComputed = true; +// if (displayNameComputed || shortDisplayNameComputed) { +// // Obtain the primary material name from the list of material names, for computing the display name. +// String xpathToMaterialName = MaterialJAXBSchema.MATERIAL_TERM_NAME_GROUP_LIST +// + "/[0]/" + MaterialeJAXBSchema.MATERIAL_TERM_NAME; +// String materialName = getXPathStringValue(docModel, COMMON_PART_LABEL, xpathToMaterialName); +// String displayName = prepareDefaultDisplayName(materialName); +// if (displayNameComputed) { +// docModel.setProperty(commonPartLabel, MaterialJAXBSchema.DISPLAY_NAME, +// displayName); +// } +// if (shortDisplayNameComputed) { +// docModel.setProperty(commonPartLabel, MaterialJAXBSchema.SHORT_DISPLAY_NAME, +// displayName); +// } +// } +// } + + /** + * Produces a default displayName from one or more supplied fields. + * @see MaterialAuthorityClientUtils.prepareDefaultDisplayName() which + * duplicates this logic, until we define a service-general utils package + * that is neither client nor service specific. + * @param materialName + * @return the default display name + * @throws Exception + */ + private static String prepareDefaultDisplayName( + String materialName ) throws Exception { + StringBuilder newStr = new StringBuilder(); + newStr.append(materialName); + return newStr.toString(); + } + + /** + * getQProperty converts the given property to qualified schema property + * @param prop + * @return + */ + @Override + public String getQProperty(String prop) { + return MaterialConstants.NUXEO_SCHEMA_NAME + ":" + prop; + } +} + diff --git a/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialValidatorHandler.java b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialValidatorHandler.java new file mode 100644 index 000000000..71f0f3a92 --- /dev/null +++ b/services/material/service/src/main/java/org/collectionspace/services/material/nuxeo/MaterialValidatorHandler.java @@ -0,0 +1,148 @@ +/** + * 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, 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.material.nuxeo; + +import java.util.List; +import java.util.regex.Pattern; +import org.collectionspace.services.common.api.Tools; +import org.collectionspace.services.common.document.InvalidDocumentException; +import org.collectionspace.services.common.document.ValidatorHandlerImpl; +import org.collectionspace.services.material.MaterialTermGroup; +import org.collectionspace.services.material.MaterialTermGroupList; +import org.collectionspace.services.material.MaterialsCommon; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * MaterialValidatorHandler + * + * Performs validation when making requests related to Material records. + * As an example, you can modify this class to customize validation of + * payloads supplied in requests to create and/or update records. + */ +public class MaterialValidatorHandler extends ValidatorHandlerImpl { + + final Logger logger = LoggerFactory.getLogger(MaterialValidatorHandler.class); + // 'Bad pattern' for shortIdentifiers matches any non-word characters + private static final Pattern SHORT_ID_BAD_PATTERN = Pattern.compile("[\\W]"); + private static final String SHORT_ID_BAD_CHARS_ERROR = + "shortIdentifier must only contain standard word characters"; + private static final String HAS_NO_TERMS_ERROR = + "Authority items must contain at least one term."; + private static final String TERM_HAS_EMPTY_DISPLAYNAME_ERROR = + "Each term group in an authority item must contain " + + "a non-empty display name."; + + @Override + protected Class getCommonPartClass() { + return MaterialsCommon.class; + } + + @Override + protected void handleCreate() throws InvalidDocumentException { + MaterialsCommon material = (MaterialsCommon) getCommonPart(); + // No guarantee that there is a common part in every post/update. + if (material != null) { + try { + String shortId = material.getShortIdentifier(); + if (shortId != null) { + CS_ASSERT(shortIdentifierContainsOnlyValidChars(shortId), SHORT_ID_BAD_CHARS_ERROR); + } + CS_ASSERT(containsAtLeastOneTerm(material), HAS_NO_TERMS_ERROR); + CS_ASSERT(allTermsContainDisplayName(material), TERM_HAS_EMPTY_DISPLAYNAME_ERROR); + } catch (AssertionError e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + throw new InvalidDocumentException(e.getMessage(), e); + } + } + } + + @Override + protected void handleGet() throws InvalidDocumentException { + } + + @Override + protected void handleGetAll() throws InvalidDocumentException { + } + + @Override + protected void handleUpdate() throws InvalidDocumentException { + MaterialsCommon material = (MaterialsCommon) getCommonPart(); + // No guarantee that there is a common part in every post/update. + if (material != null) { + try { + // shortIdentifier is among a set of fields that are + // prevented from being changed on an update, and thus + // we don't need to check its value here. + CS_ASSERT(containsAtLeastOneTerm(material), HAS_NO_TERMS_ERROR); + CS_ASSERT(allTermsContainDisplayName(material), TERM_HAS_EMPTY_DISPLAYNAME_ERROR); + } catch (AssertionError e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + throw new InvalidDocumentException(e.getMessage(), e); + } + } + } + + @Override + protected void handleDelete() throws InvalidDocumentException { + } + + private boolean shortIdentifierContainsOnlyValidChars(String shortId) { + // Check whether any characters match the 'bad' pattern + if (SHORT_ID_BAD_PATTERN.matcher(shortId).find()) { + return false; + } + return true; + } + + private boolean containsAtLeastOneTerm(MaterialsCommon material) { + MaterialTermGroupList termGroupList = material.getMaterialTermGroupList(); + if (termGroupList == null) { + return false; + } + List termGroups = termGroupList.getMaterialTermGroup(); + if ((termGroups == null) || (termGroups.isEmpty())){ + return false; + } + return true; + } + + private boolean allTermsContainDisplayName(MaterialsCommon material) { + MaterialTermGroupList termGroupList = material.getMaterialTermGroupList(); + List termGroups = termGroupList.getMaterialTermGroup(); + for (MaterialTermGroup termGroup : termGroups) { + if (Tools.isBlank(termGroup.getTermDisplayName())) { + return false; + } + } + return true; + } +} + diff --git a/services/pom.xml b/services/pom.xml index 6d921f513..50d13d1b7 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -72,6 +72,7 @@ location place work + material concept taxonomy movement