From: remillet Date: Tue, 11 Jul 2017 00:30:08 +0000 (-0700) Subject: CSPACE-7124: Added workaround to Nuxeo bug that prevented the clearing of structured... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=0f928a8a3bc313ea112428a66a6f4dc26dddff76;p=tmp%2Fjakarta-migration.git CSPACE-7124: Added workaround to Nuxeo bug that prevented the clearing of structured date fields in some records. --- diff --git a/services/claim/client/src/main/resources/collectionspace-client.properties b/services/claim/client/src/main/resources/collectionspace-client.properties new file mode 100644 index 000000000..0ec3d7629 --- /dev/null +++ b/services/claim/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@anthro.collectionspace.org +cspace.password=Administrator diff --git a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java index 78c134e52..65e2ca771 100644 --- a/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java @@ -24,7 +24,9 @@ package org.collectionspace.services.nuxeo.client.java; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -85,7 +87,11 @@ import org.dom4j.Element; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentNotFoundException; +import org.nuxeo.ecm.core.api.impl.DataModelImpl; +import org.nuxeo.ecm.core.api.model.DocumentPart; +import org.nuxeo.ecm.core.api.model.Property; import org.nuxeo.ecm.core.api.model.PropertyException; +import org.nuxeo.ecm.core.api.model.impl.ScalarProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -433,20 +439,105 @@ public abstract class RemoteDocumentModelHandlerImpl * @param partMeta metadata for the object to fill * @throws Exception */ - protected void fillPart(PayloadInputPart part, DocumentModel docModel, - ObjectPartType partMeta, Action action, ServiceContext ctx) - throws Exception { - //check if this is an xml part - if (part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)) { - Element element = part.getElementBody(); - Map objectProps = DocumentUtils.parseProperties(partMeta, element, ctx); - if (action == Action.UPDATE) { - this.filterReadOnlyPropertiesForPart(objectProps, partMeta); - } - docModel.setProperties(partMeta.getLabel(), objectProps); - } - } - + protected void fillPart(PayloadInputPart part, DocumentModel docModel, ObjectPartType partMeta, Action action, + ServiceContext ctx) throws Exception { + // check if this is an xml part + if (part.getMediaType().equals(MediaType.APPLICATION_XML_TYPE)) { + Element element = part.getElementBody(); + Map objectProps = DocumentUtils.parseProperties(partMeta, element, ctx); + if (action == Action.UPDATE) { + this.filterReadOnlyPropertiesForPart(objectProps, partMeta); + } + String schemaName = partMeta.getLabel(); + docModel.setProperties(schemaName, objectProps); + Set fieldNameSet = getFieldNamesSet(objectProps); + setFieldsDirty(docModel, schemaName, fieldNameSet); // Force Nuxeo to update EVERY field by marking them dirty/modified + } + } + + + /** + * Due to an apparent Nuxeo bug, we need to explicitly mark all fields as dirty for updates + * to take place properly. See https://issues.collectionspace.org/browse/CSPACE-7124 + * + * We should improve this code by marking dirty/modified only the fields that were part of the UPDATE/PUT request + * payload. The current code will mark any field with a name in the 'fieldNameSet' set. Since field names do not + * have to be unique in document/record, we might end up unnecessarily marking some fields as modified -not ideal but + * better than brute-force marking ALL fields as modified. + * + * @param docModel + * @param schemaName + */ + private void setFieldsDirty(DocumentModel docModel, String schemaName, Set fieldNameSet) { + DataModelImpl dataModel = (DataModelImpl) docModel.getDataModel(schemaName); + DocumentPart documentPart = dataModel.getDocumentPart(); + setFieldsDirty(documentPart.getChildren(), fieldNameSet); + } + + /** + * Recursively step through all the children and sub-children setting their dirty flags. + * See https://issues.collectionspace.org/browse/CSPACE-7124 + * @param children + */ + private void setFieldsDirty(Collection children, Set fieldNameSet) { + if (children != null && (children.size() > 0)) { + for (Property prop : children ) { + String propName = prop.getName(); + logger.debug(propName); + if (prop.isPhantom() == false) { + if (prop.isScalar() == false) { + setFieldsDirty(prop.getChildren(), fieldNameSet); + } else if (fieldNameSet.contains(propName)) { + ScalarProperty scalarProp = (ScalarProperty)prop; + scalarProp.setIsModified(); + } + } + } + } + } + + /* + * Gets the set of field names used in a map of properties. We'll use this make our workaround to a + * bug (See https://issues.collectionspace.org/browse/CSPACE-7124) more efficient by only marking fields + * with names in this set as modified -ie, needing persisting. + * + * Since the map of properties can contain other maps of properties as values, there can be duplicate + * field names in the 'objectProps' map. And since we're creating a set, there can be no duplicates in the result. + * + */ + private Set getFieldNamesSet(Map objectProps) { + HashSet result = new HashSet(); + + addFieldNamesToSet(result, objectProps); + + return result; + } + + private void addFieldNamesToSet(Set fieldNameSet, List valueList) { + for (Object value : valueList) { + if (value instanceof List) { + addFieldNamesToSet(fieldNameSet, (List)value); + } else if (value instanceof Map) { + addFieldNamesToSet(fieldNameSet, (Map)value); + } else { + logger.debug(value.toString()); + } + } + } + + private void addFieldNamesToSet(Set fieldNameSet, Map objectProps) { + for (String key : objectProps.keySet()) { + Object value = objectProps.get(key); + if (value instanceof Map) { + addFieldNamesToSet(fieldNameSet, (Map)value); + } else if (value instanceof List) { + addFieldNamesToSet(fieldNameSet, (List)value); + } else { + fieldNameSet.add(key); + } + } + } + /** * Filters out read only properties, so they cannot be set on update. * TODO: add configuration support to do this generally