Program: 172182
Project: 172182
Buggy source:
/** 
 * Does differencing to add and/or remove properties.  Internally, the existing properties will be retrieved and a difference performed to work out which properties need to be created, updated or deleted.  It is only necessary to pass in old and new values for <i>changes</i> i.e. when setting a single property, it is only necessary to pass that property's value in the <b>old</b> and </b>new</b> maps; this improves execution speed significantly - although it has no effect on the number of resulting DB operations. <p/> Note: The cached properties are not updated
 * @param nodeId                the node ID
 * @param newProps              the properties to add or update
 * @param isAddOnly             <tt>true</tt> if the new properties are just an update or<tt>false</tt> if the properties are a complete set
 * @return                      Returns <tt>true</tt> if any properties were changed
 */
private boolean setNodePropertiesImpl(Long nodeId,Map<QName,Serializable> newProps,boolean isAddOnly){
  if (isAddOnly && newProps.size() == 0) {
    return false;
  }
  Node node=getNodeNotNull(nodeId);
  newProps=new HashMap<QName,Serializable>(newProps);
  AuditablePropertiesEntity auditableProps=null;
  if (!policyBehaviourFilter.isEnabled(node.getNodeRef(),ContentModel.ASPECT_AUDITABLE)) {
    auditableProps=node.getAuditableProperties();
    if (auditableProps == null) {
      auditableProps=new AuditablePropertiesEntity();
    }
    boolean containedAuditProperties=auditableProps.setAuditValues(null,null,newProps);
    if (!containedAuditProperties) {
      auditableProps=null;
    }
  }
  newProps.keySet().removeAll(AuditablePropertiesEntity.getAuditablePropertyQNames());
  ReferenceablePropertiesEntity.removeReferenceableProperties(node,newProps);
  Map<QName,Serializable> oldPropsCached=getNodePropertiesCached(nodeId);
  Map<QName,Serializable> oldProps=new HashMap<QName,Serializable>(oldPropsCached);
  if (isAddOnly) {
    oldProps.keySet().retainAll(newProps.keySet());
  }
  Map<NodePropertyKey,NodePropertyValue> oldPropsRaw=nodePropertyHelper.convertToPersistentProperties(oldProps);
  Map<NodePropertyKey,NodePropertyValue> newPropsRaw=nodePropertyHelper.convertToPersistentProperties(newProps);
  Map<NodePropertyKey,NodePropertyValue> propsToDelete=new HashMap<NodePropertyKey,NodePropertyValue>(oldPropsRaw);
  Map<NodePropertyKey,NodePropertyValue> propsToAdd=new HashMap<NodePropertyKey,NodePropertyValue>(newPropsRaw);
  Map<NodePropertyKey,MapValueComparison> persistableDiff=EqualsHelper.getMapComparison(propsToDelete,propsToAdd);
  for (  Map.Entry<NodePropertyKey,MapValueComparison> entry : persistableDiff.entrySet()) {
    NodePropertyKey key=entry.getKey();
    QName qname=qnameDAO.getQName(key.getQnameId()).getSecond();
    PropertyDefinition removePropDef=dictionaryService.getProperty(qname);
    boolean isContent=(removePropDef != null && removePropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT));
switch (entry.getValue()) {
case NULL:
case EQUAL:
      propsToDelete.remove(key);
    propsToAdd.remove(key);
  continue;
case RIGHT_ONLY:
propsToDelete.remove(key);
if (isContent) {
NodePropertyValue newPropValue=propsToAdd.get(key);
ContentData newContentData=(ContentData)newPropValue.getValue(DataTypeDefinition.CONTENT);
if (newContentData != null) {
  Long newContentDataId=contentDataDAO.createContentData(newContentData).getFirst();
  newPropValue=new NodePropertyValue(DataTypeDefinition.CONTENT,new ContentDataId(newContentDataId));
  propsToAdd.put(key,newPropValue);
  newPropsRaw.put(key,new NodePropertyValue(DataTypeDefinition.CONTENT,new ContentDataWithId(newContentData,newContentDataId)));
}
}
continue;
case LEFT_ONLY:
propsToAdd.remove(key);
if (isContent) {
NodePropertyValue valueToDelete=propsToDelete.get(key);
ContentDataWithId contentDataWithId=(ContentDataWithId)valueToDelete.getValue(DataTypeDefinition.CONTENT);
if (contentDataWithId != null) {
Long contentDataId=contentDataWithId.getId();
contentDataDAO.deleteContentData(contentDataId);
}
}
continue;
case NOT_EQUAL:
if (isContent) {
NodePropertyValue valueToDelete=propsToDelete.get(key);
ContentDataWithId contentDataWithId=(ContentDataWithId)valueToDelete.getValue(DataTypeDefinition.CONTENT);
if (contentDataWithId != null) {
Long contentDataId=contentDataWithId.getId();
contentDataDAO.deleteContentData(contentDataId);
}
NodePropertyValue newPropValue=propsToAdd.get(key);
ContentData newContentData=(ContentData)newPropValue.getValue(DataTypeDefinition.CONTENT);
if (newContentData != null) {
Long newContentDataId=contentDataDAO.createContentData(newContentData).getFirst();
newPropValue=new NodePropertyValue(DataTypeDefinition.CONTENT,new ContentDataId(newContentDataId));
propsToAdd.put(key,newPropValue);
newPropsRaw.put(key,new NodePropertyValue(DataTypeDefinition.CONTENT,new ContentDataWithId(newContentData,newContentDataId)));
}
}
continue;
default :
throw new IllegalStateException("String_Node_Str" + entry.getValue());
}
}
try {
List<NodePropertyKey> propKeysToDeleteList=new ArrayList<NodePropertyKey>(propsToDelete.keySet());
int deleted=deleteNodeProperties(nodeId,propKeysToDeleteList);
if (deleted != propKeysToDeleteList.size()) {
throw new DataIntegrityViolationException("String_Node_Str" + deleted + "String_Node_Str"+ propKeysToDeleteList.size());
}
insertNodeProperties(nodeId,propsToAdd);
}
 catch (RuntimeException e) {
propertiesCache.removeByKey(nodeId);
throw new AlfrescoRuntimeException("String_Node_Str" + "String_Node_Str" + nodeId + "String_Node_Str"+ "String_Node_Str"+ oldProps+ "String_Node_Str"+ "String_Node_Str"+ newProps+ "String_Node_Str"+ "String_Node_Str"+ oldPropsRaw+ "String_Node_Str"+ "String_Node_Str"+ newPropsRaw+ "String_Node_Str"+ "String_Node_Str"+ persistableDiff+ "String_Node_Str"+ "String_Node_Str"+ propsToDelete.keySet()+ "String_Node_Str"+ "String_Node_Str"+ propsToAdd,e);
}
boolean updated=propsToDelete.size() > 0 || propsToAdd.size() > 0;
if (updated) {
newProps=nodePropertyHelper.convertToPublicProperties(newPropsRaw);
Map<QName,Serializable> propsToCache=null;
if (isAddOnly) {
propsToCache=oldPropsCached;
propsToCache.putAll(newProps);
}
 else {
propsToCache=newProps;
}
setNodePropertiesCached(nodeId,propsToCache);
}
if (updated || auditableProps != null) {
touchNodeImpl(nodeId,auditableProps);
}
if (isDebugEnabled && updated) {
logger.debug("String_Node_Str" + nodeId + "String_Node_Str"+ "String_Node_Str"+ propsToDelete+ "String_Node_Str"+ "String_Node_Str"+ propsToAdd);
}
return updated;
}

Fixed version (ground truth):
/** 
 * Does differencing to add and/or remove properties.  Internally, the existing properties will be retrieved and a difference performed to work out which properties need to be created, updated or deleted.  It is only necessary to pass in old and new values for <i>changes</i> i.e. when setting a single property, it is only necessary to pass that property's value in the <b>old</b> and </b>new</b> maps; this improves execution speed significantly - although it has no effect on the number of resulting DB operations. <p/> Note: The cached properties are not updated
 * @param nodeId                the node ID
 * @param newProps              the properties to add or update
 * @param isAddOnly             <tt>true</tt> if the new properties are just an update or<tt>false</tt> if the properties are a complete set
 * @return                      Returns <tt>true</tt> if any properties were changed
 */
private boolean setNodePropertiesImpl(Long nodeId,Map<QName,Serializable> newProps,boolean isAddOnly){
  if (isAddOnly && newProps.size() == 0) {
    return false;
  }
  Node node=getNodeNotNull(nodeId);
  newProps=new HashMap<QName,Serializable>(newProps);
  AuditablePropertiesEntity auditableProps=null;
  if (!policyBehaviourFilter.isEnabled(node.getNodeRef(),ContentModel.ASPECT_AUDITABLE)) {
    auditableProps=node.getAuditableProperties();
    if (auditableProps == null) {
      auditableProps=new AuditablePropertiesEntity();
    }
    boolean containedAuditProperties=auditableProps.setAuditValues(null,null,newProps);
    if (!containedAuditProperties) {
      auditableProps=null;
    }
  }
  newProps.keySet().removeAll(AuditablePropertiesEntity.getAuditablePropertyQNames());
  ReferenceablePropertiesEntity.removeReferenceableProperties(node,newProps);
  Map<QName,Serializable> oldPropsCached=getNodePropertiesCached(nodeId);
  Map<QName,Serializable> oldProps=new HashMap<QName,Serializable>(oldPropsCached);
  if (isAddOnly) {
    oldProps.keySet().retainAll(newProps.keySet());
  }
  Map<NodePropertyKey,NodePropertyValue> newPropsRaw=nodePropertyHelper.convertToPersistentProperties(newProps);
  newProps=nodePropertyHelper.convertToPublicProperties(newPropsRaw);
  Map<QName,MapValueComparison> diff=EqualsHelper.getMapComparison(oldProps,newProps);
  Set<QName> propsToDelete=new HashSet<QName>(oldProps.size() * 2);
  Map<QName,Serializable> propsToAdd=new HashMap<QName,Serializable>(newProps.size() * 2);
  Set<QName> contentQNamesToDelete=new HashSet<QName>(5);
  for (  Map.Entry<QName,MapValueComparison> entry : diff.entrySet()) {
    QName qname=entry.getKey();
    PropertyDefinition removePropDef=dictionaryService.getProperty(qname);
    boolean isContent=(removePropDef != null && removePropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT));
switch (entry.getValue()) {
case EQUAL:
      break;
case LEFT_ONLY:
    propsToDelete.add(qname);
  if (isContent) {
    contentQNamesToDelete.add(qname);
  }
break;
case NOT_EQUAL:
propsToDelete.add(qname);
if (isContent) {
contentQNamesToDelete.add(qname);
}
case RIGHT_ONLY:
Serializable value=newProps.get(qname);
if (isContent && value != null) {
ContentData newContentData=(ContentData)value;
Long newContentDataId=contentDataDAO.createContentData(newContentData).getFirst();
value=new ContentDataWithId(newContentData,newContentDataId);
}
propsToAdd.put(qname,value);
break;
default :
throw new IllegalStateException("String_Node_Str" + entry.getValue());
}
}
boolean updated=propsToDelete.size() > 0 || propsToAdd.size() > 0;
if (updated) {
try {
if (contentQNamesToDelete.size() > 0) {
Set<Long> contentQNameIdsToDelete=qnameDAO.convertQNamesToIds(contentQNamesToDelete,false);
contentDataDAO.deleteContentDataForNode(nodeId,contentQNameIdsToDelete);
}
}
 catch (Throwable e) {
throw new AlfrescoRuntimeException("String_Node_Str" + "String_Node_Str" + nodeId + "String_Node_Str"+ "String_Node_Str"+ contentQNamesToDelete,e);
}
try {
Set<Long> propQNameIdsToDelete=qnameDAO.convertQNamesToIds(propsToDelete,true);
deleteNodeProperties(nodeId,propQNameIdsToDelete);
newPropsRaw=nodePropertyHelper.convertToPersistentProperties(propsToAdd);
insertNodeProperties(nodeId,newPropsRaw);
}
 catch (Throwable e) {
propertiesCache.removeByKey(nodeId);
throw new AlfrescoRuntimeException("String_Node_Str" + "String_Node_Str" + nodeId + "String_Node_Str"+ "String_Node_Str"+ oldProps+ "String_Node_Str"+ "String_Node_Str"+ newProps+ "String_Node_Str"+ "String_Node_Str"+ diff+ "String_Node_Str"+ "String_Node_Str"+ propsToDelete+ "String_Node_Str"+ "String_Node_Str"+ propsToAdd,e);
}
Map<QName,Serializable> propsToCache=null;
if (isAddOnly) {
propsToCache=oldPropsCached;
propsToCache.putAll(propsToAdd);
}
 else {
propsToCache=newProps;
propsToCache.putAll(propsToAdd);
}
setNodePropertiesCached(nodeId,propsToCache);
}
if (updated || auditableProps != null) {
touchNodeImpl(nodeId,auditableProps);
}
if (isDebugEnabled && updated) {
logger.debug("String_Node_Str" + nodeId + "String_Node_Str"+ "String_Node_Str"+ propsToDelete+ "String_Node_Str"+ "String_Node_Str"+ propsToAdd);
}
return updated;
}