/**
  * Helper method to transactionally record <code>NodeRef</code> properties so that they can later
  * be fixed up to point to the relative, after-copy locations.
  *
  * <p>When the copy has been completed, the second stage of the process can be applied.
  *
  * @param sourceNodeRef the node that is being copied
  * @param properties the node properties being copied
  * @param propertyQName the qualified name of the property to check
  * @see #repointNodeRefs(NodeRef, QName, Map, NodeService)
  */
 public void recordNodeRefsForRepointing(
     NodeRef sourceNodeRef, Map<QName, Serializable> properties, QName propertyQName) {
   Serializable parameterValue = properties.get(propertyQName);
   if (parameterValue != null
       && (parameterValue instanceof Collection<?> || parameterValue instanceof NodeRef)) {
     String key = KEY_NODEREF_REPOINTING_PREFIX + propertyQName.toString();
     // Store it for later
     Map<NodeRef, Serializable> map = TransactionalResourceHelper.getMap(key);
     map.put(sourceNodeRef, parameterValue);
   }
 }
 /**
  * The second stage of the <code>NodeRef</code> repointing. Call this method to have any <code>
  * NodeRef</code> properties readjusted to reflect the copied node hierarchy. Only use this method
  * if it a requirement for the particular type or aspect that you are coding for.
  *
  * @param sourceNodeRef the source node
  * @param propertyQName the target node i.e. the copy of the source node
  * @param copyMap the full hierarchy copy map of source to copies
  * @see #recordNodeRefsForRepointing(NodeRef, Map, QName)
  */
 @SuppressWarnings("unchecked")
 public void repointNodeRefs(
     NodeRef sourceNodeRef,
     NodeRef targetNodeRef,
     QName propertyQName,
     Map<NodeRef, NodeRef> copyMap,
     NodeService nodeService) {
   String key = KEY_NODEREF_REPOINTING_PREFIX + propertyQName.toString();
   Map<NodeRef, Serializable> map = TransactionalResourceHelper.getMap(key);
   Serializable value = map.get(sourceNodeRef);
   if (value == null) {
     // Don't bother.  The source node did not have a NodeRef property
     return;
   }
   Serializable newValue = null;
   if (value instanceof Collection) {
     Collection<Serializable> oldList = (Collection<Serializable>) value;
     List<Serializable> newList = new ArrayList<Serializable>(oldList.size());
     for (Serializable oldListValue : oldList) {
       Serializable newListValue = oldListValue;
       if (oldListValue instanceof NodeRef) {
         newListValue = repointNodeRef(copyMap, (NodeRef) oldListValue);
       }
       // Put the value in the new list even though the new list might be discarded
       newList.add(newListValue);
       // Check if the value changed
       if (!newListValue.equals(oldListValue)) {
         // The value changed, so the new list will have to be set onto the target node
         newValue = (Serializable) newList;
       }
     }
   } else if (value instanceof NodeRef) {
     NodeRef newNodeRef = repointNodeRef(copyMap, (NodeRef) value);
     if (!newNodeRef.equals(value)) {
       // The value changed, so the new list will have to be set onto the target node
       newValue = newNodeRef;
     }
   } else {
     throw new IllegalStateException("Should only have Collections and NodeRef values");
   }
   // Fix the node property on the target, if necessary
   if (newValue != null) {
     nodeService.setProperty(targetNodeRef, propertyQName, newValue);
   }
 }