From a4010052d9f80a022e3a68ea55746b36794029c5 Mon Sep 17 00:00:00 2001 From: Aron Roberts Date: Tue, 8 May 2012 11:33:47 -0700 Subject: [PATCH] CSPACE-5123,CSPACE-4844: Updated Concept schemas, validator handler to reflect repeatable term info group. Concept module builds if built without compiling tests; e.g. 'mvn install -Dmaven.test.skip=true'. --- .../resources/schemas/concepts_common.xsd | 209 +++++++++-------- .../src/main/resources/concept_common.xsd | 215 ++++++++++-------- .../concept/ConceptAuthorityResource.java | 84 ++++--- .../nuxeo/ConceptValidatorHandler.java | 153 ++++++++----- 4 files changed, 365 insertions(+), 296 deletions(-) diff --git a/services/concept/3rdparty/nuxeo-platform-cs-concept/src/main/resources/schemas/concepts_common.xsd b/services/concept/3rdparty/nuxeo-platform-cs-concept/src/main/resources/schemas/concepts_common.xsd index 8325b07d8..e736298bd 100644 --- a/services/concept/3rdparty/nuxeo-platform-cs-concept/src/main/resources/schemas/concepts_common.xsd +++ b/services/concept/3rdparty/nuxeo-platform-cs-concept/src/main/resources/schemas/concepts_common.xsd @@ -12,115 +12,130 @@ --> + xmlns:ns="http://collectionspace.org/services/concept" + xmlns="http://collectionspace.org/services/concept" + targetNamespace="http://collectionspace.org/services/concept" version="0.1"> - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - + + + + + - - - - - - + + + + + + - + - - - - - + + + + + - - - - - - - + + + + + + + - + + + + + + - --> + + + + + + + + + + + + + + + + + + + diff --git a/services/concept/jaxb/src/main/resources/concept_common.xsd b/services/concept/jaxb/src/main/resources/concept_common.xsd index be910222d..48b222567 100644 --- a/services/concept/jaxb/src/main/resources/concept_common.xsd +++ b/services/concept/jaxb/src/main/resources/concept_common.xsd @@ -7,126 +7,141 @@ xmlns="http://collectionspace.org/services/concept" targetNamespace="http://collectionspace.org/services/concept" version="0.1" - > +> - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - + + + + + + + - - + + - - - - - + + + + + + + + - - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/concept/service/src/main/java/org/collectionspace/services/concept/ConceptAuthorityResource.java b/services/concept/service/src/main/java/org/collectionspace/services/concept/ConceptAuthorityResource.java index 4a2a036a1..4478f4457 100644 --- a/services/concept/service/src/main/java/org/collectionspace/services/concept/ConceptAuthorityResource.java +++ b/services/concept/service/src/main/java/org/collectionspace/services/concept/ConceptAuthorityResource.java @@ -1,75 +1,67 @@ /** - * 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. + * 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.concept; +import javax.ws.rs.Consumes; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import org.collectionspace.services.client.ConceptAuthorityClient; -import org.collectionspace.services.client.PersonAuthorityClient; import org.collectionspace.services.common.vocabulary.AuthorityResource; import org.collectionspace.services.concept.nuxeo.ConceptDocumentModelHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.Consumes; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - +/** + * ConceptAuthorityResource + * + * Handles, dispatches, and returns responses to RESTful requests related to + * Concept authority-related resources. + */ @Path(ConceptAuthorityClient.SERVICE_PATH) @Consumes("application/xml") @Produces("application/xml") -public class ConceptAuthorityResource - extends AuthorityResource { +public class ConceptAuthorityResource + extends AuthorityResource { - private final static String conceptAuthorityServiceName = "conceptauthorities"; - private final static String CONCEPTAUTHORITIES_COMMON = "conceptauthorities_common"; - - private final static String conceptServiceName = "concepts"; - private final static String CONCEPTS_COMMON = "concepts_common"; - final Logger logger = LoggerFactory.getLogger(ConceptAuthorityResource.class); public ConceptAuthorityResource() { - super(ConceptauthoritiesCommon.class, ConceptAuthorityResource.class, - CONCEPTAUTHORITIES_COMMON, CONCEPTS_COMMON); + super(ConceptauthoritiesCommon.class, ConceptAuthorityResource.class, + ConceptAuthorityClient.SERVICE_COMMON_PART_NAME, ConceptAuthorityClient.SERVICE_ITEM_COMMON_PART_NAME); } @Override public String getServiceName() { - return conceptAuthorityServiceName; + return ConceptAuthorityClient.SERVICE_NAME; } + @Override public String getItemServiceName() { - return conceptServiceName; + return ConceptAuthorityClient.SERVICE_ITEM_NAME; } @Override - public Class getCommonPartClass() { - return ConceptauthoritiesCommon.class; - } - - @Override - public String getItemTermInfoGroupXPathBase() { + public String getItemTermInfoGroupXPathBase() { return ConceptAuthorityClient.TERM_INFO_GROUP_XPATH_BASE; - } + } } diff --git a/services/concept/service/src/main/java/org/collectionspace/services/concept/nuxeo/ConceptValidatorHandler.java b/services/concept/service/src/main/java/org/collectionspace/services/concept/nuxeo/ConceptValidatorHandler.java index 222f312d9..1bd1a5b56 100644 --- a/services/concept/service/src/main/java/org/collectionspace/services/concept/nuxeo/ConceptValidatorHandler.java +++ b/services/concept/service/src/main/java/org/collectionspace/services/concept/nuxeo/ConceptValidatorHandler.java @@ -23,78 +23,125 @@ */ package org.collectionspace.services.concept.nuxeo; +import java.util.List; import java.util.regex.Pattern; - -import org.collectionspace.services.concept.ConceptsCommon; -import org.collectionspace.services.common.context.MultipartServiceContext; -import org.collectionspace.services.common.context.ServiceContext; -import org.collectionspace.services.common.document.DocumentHandler.Action; +import org.collectionspace.services.common.api.Tools; import org.collectionspace.services.common.document.InvalidDocumentException; -import org.collectionspace.services.common.document.ValidatorHandler; +import org.collectionspace.services.common.document.ValidatorHandlerImpl; +import org.collectionspace.services.concept.ConceptTermGroup; +import org.collectionspace.services.concept.ConceptTermGroupList; +import org.collectionspace.services.concept.ConceptsCommon; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ConceptValidatorHandler * - * Validates data supplied when attempting to create and/or update Concept records. - * - * $LastChangedRevision: $ - * $LastChangedDate: $ + * Performs validation when making requests related to Concept 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 ConceptValidatorHandler implements ValidatorHandler { +public class ConceptValidatorHandler extends ValidatorHandlerImpl { final Logger logger = LoggerFactory.getLogger(ConceptValidatorHandler.class); - private static final Pattern shortIdBadPattern = Pattern.compile("[\\W]"); //.matcher(input).matches() + // 'Bad pattern' for shortIdentifiers matches any non-word characters + private static final Pattern SHORT_ID_BAD_PATTERN = Pattern.compile("[\\W]"); //.matcher(input).matches() + private static final String VALIDATION_ERROR = "The record payload was invalid. See log file for more details."; + 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 HAS_AN_EMPTY_TERM_ERROR = + "Each term group in an authority item must contain " + + "a non-empty term name or " + + "a non-empty term display name."; @Override - public void validate(Action action, ServiceContext ctx) - throws InvalidDocumentException { - if (logger.isDebugEnabled()) { - logger.debug("validate() action=" + action.name()); - } - - // Bail out if the validation action is for delete. - if (action.equals(Action.DELETE)) { - return; - } - - try { - MultipartServiceContext mctx = (MultipartServiceContext) ctx; - ConceptsCommon concept = (ConceptsCommon) mctx.getInputPart(mctx.getCommonPartLabel(), - ConceptsCommon.class); - String msg = ""; - boolean invalid = false; - - // Validation occurring on both creates and updates - String displayName = concept.getDisplayName(); - if (!concept.isDisplayNameComputed() && ((displayName == null) || displayName.trim().isEmpty())) { - invalid = true; - msg += "displayName must be non-null and non-blank if displayNameComputed is false"; - } + protected Class getCommonPartClass() { + return ConceptsCommon.class; + } - // Validation specific to creates or updates - if (action.equals(Action.CREATE)) { + @Override + protected void handleCreate() throws InvalidDocumentException { + ConceptsCommon concept = (ConceptsCommon) getCommonPart(); + // No guarantee that there is a common part in every post/update. + if (concept != null) { + try { String shortId = concept.getShortIdentifier(); - // Per CSPACE-2215, shortIdentifier values that are null (missing) - // oe the empty string are now legally accepted in create payloads. - // In either of those cases, a short identifier will be synthesized from - // a display name or supplied in another manner. - if ((shortId != null) && (shortIdBadPattern.matcher(shortId).find())) { - invalid = true; - msg += "shortIdentifier must only contain standard word characters"; + if (shortId != null) { + CS_ASSERT(shortIdentifierContainsOnlyValidChars(shortId), SHORT_ID_BAD_CHARS_ERROR); + } + CS_ASSERT(containsAtLeastOneTerm(concept), HAS_NO_TERMS_ERROR); + CS_ASSERT(allTermsContainNameOrDisplayName(concept), HAS_AN_EMPTY_TERM_ERROR); + } catch (AssertionError e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + throw new InvalidDocumentException(VALIDATION_ERROR, e); + } + } + } + + @Override + protected void handleGet() throws InvalidDocumentException { + } + + @Override + protected void handleGetAll() throws InvalidDocumentException { + } + + @Override + protected void handleUpdate() throws InvalidDocumentException { + ConceptsCommon concept = (ConceptsCommon) getCommonPart(); + // No guarantee that there is a common part in every post/update. + if (concept != 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(concept), HAS_NO_TERMS_ERROR); + CS_ASSERT(allTermsContainNameOrDisplayName(concept), HAS_AN_EMPTY_TERM_ERROR); + } catch (AssertionError e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); } - } else if (action.equals(Action.UPDATE)) { + throw new InvalidDocumentException(VALIDATION_ERROR, 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(ConceptsCommon concept) { + ConceptTermGroupList termGroupList = concept.getConceptTermGroupList(); + if (termGroupList == null) { + return false; + } + List termGroups = termGroupList.getConceptTermGroup(); + if ((termGroups == null) || (termGroups.isEmpty())){ + return false; + } + return true; + } - if (invalid) { - logger.error(msg); - throw new InvalidDocumentException(msg); + private boolean allTermsContainNameOrDisplayName(ConceptsCommon concept) { + ConceptTermGroupList termGroupList = concept.getConceptTermGroupList(); + List termGroups = termGroupList.getConceptTermGroup(); + for (ConceptTermGroup termGroup : termGroups) { + if (Tools.isBlank(termGroup.getTermName()) || Tools.isBlank(termGroup.getTermDisplayName())) { + return false; } - } catch (InvalidDocumentException ide) { - throw ide; - } catch (Exception e) { - throw new InvalidDocumentException(e); } + return true; } } -- 2.47.3