diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index 13deb28c83..cc5f23d28c 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -68,6 +68,7 @@ import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
+import org.alfresco.util.GUID;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -404,7 +405,7 @@ public class Node implements Serializable, Scopeable
}
/**
- * Return the associations for this Node. As a Map of assoc name to an Array of Nodes.
+ * Return the target associations from this Node. As a Map of assoc name to an Array of Nodes.
* The Map returned implements the Scriptable interface to allow access to the assoc arrays via JavaScript
* associative array access. This means associations of this node can be access thus:
* node.assocs["translations"][0]
@@ -988,7 +989,7 @@ public class Node implements Serializable, Scopeable
// Create and Modify API
/**
- * Persist the properties of this Node.
+ * Persist the modified properties of this Node.
*/
public void save()
{
@@ -1046,16 +1047,11 @@ public class Node implements Serializable, Scopeable
*/
public Node createFile(String name)
{
- Node node = null;
+ ParameterCheck.mandatoryString("Node Name", name);
- if (name != null && name.length() != 0)
- {
- FileInfo fileInfo = this.services.getFileFolderService().create(this.nodeRef, name,
- ContentModel.TYPE_CONTENT);
- node = newInstance(fileInfo.getNodeRef(), this.services, this.scope);
- }
-
- return node;
+ FileInfo fileInfo = this.services.getFileFolderService().create(this.nodeRef, name,
+ ContentModel.TYPE_CONTENT);
+ return newInstance(fileInfo.getNodeRef(), this.services, this.scope);
}
/**
@@ -1067,41 +1063,122 @@ public class Node implements Serializable, Scopeable
*/
public Node createFolder(String name)
{
- Node node = null;
+ ParameterCheck.mandatoryString("Node Name", name);
- if (name != null && name.length() != 0)
- {
- FileInfo fileInfo = this.services.getFileFolderService().create(this.nodeRef, name,
- ContentModel.TYPE_FOLDER);
- node = newInstance(fileInfo.getNodeRef(), this.services, this.scope);
- }
-
- return node;
+ FileInfo fileInfo = this.services.getFileFolderService().create(this.nodeRef, name,
+ ContentModel.TYPE_FOLDER);
+ return newInstance(fileInfo.getNodeRef(), this.services, this.scope);
}
/**
* Create a new Node of the specified type as a child of this node.
*
- * @param name Name of the node to create
- * @param type QName type (can either be fully qualified or short form such as 'cm:content')
+ * @param name Name of the node to create (can be null for a node without a 'cm:name' property)
+ * @param type QName type (fully qualified or short form such as 'cm:content')
*
* @return Newly created Node or null if failed to create.
*/
public Node createNode(String name, String type)
{
- Node node = null;
+ return createNode(name, type, null, ContentModel.ASSOC_CONTAINS.toString());
+ }
+
+ /**
+ * Create a new Node of the specified type as a child of this node.
+ *
+ * @param name Name of the node to create (can be null for a node without a 'cm:name' property)
+ * @param type QName type (fully qualified or short form such as 'cm:content')
+ * @param assocName QName of the child association (fully qualified or short form e.g. 'cm:contains')
+ *
+ * @return Newly created Node or null if failed to create.
+ */
+ public Node createNode(String name, String type, String assocName)
+ {
+ return createNode(name, type, null, assocName);
+ }
+
+ /**
+ * Create a new Node of the specified type as a child of this node.
+ *
+ * @param name Name of the node to create (can be null for a node without a 'cm:name' property)
+ * @param type QName type (fully qualified or short form such as 'cm:content')
+ * @param properties Associative array of the default properties for the node.
+ *
+ * @return Newly created Node or null if failed to create.
+ */
+ public Node createNode(String name, String type, Object properties)
+ {
+ return createNode(name, type, properties, ContentModel.ASSOC_CONTAINS.toString());
+ }
+
+ /**
+ * Create a new Node of the specified type as a child of this node.
+ *
+ * @param name Name of the node to create (can be null for a node without a 'cm:name' property)
+ * @param type QName type (fully qualified or short form such as 'cm:content')
+ * @param properties Associative array of the default properties for the node.
+ * @param assocName QName of the child association (fully qualified or short form e.g. 'cm:contains')
+ *
+ * @return Newly created Node or null if failed to create.
+ */
+ public Node createNode(String name, String type, Object properties, String assocName)
+ {
+ ParameterCheck.mandatoryString("Node Type", type);
+ ParameterCheck.mandatoryString("Association Name", assocName);
- if (name != null && name.length() != 0 && type != null && type.length() != 0)
+ Map props = null;
+
+ if (properties instanceof ScriptableObject)
{
- Map props = new HashMap(1);
- props.put(ContentModel.PROP_NAME, name);
- ChildAssociationRef childAssocRef = this.nodeService.createNode(this.nodeRef, ContentModel.ASSOC_CONTAINS,
- QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(name)),
- createQName(type), props);
- node = newInstance(childAssocRef.getChildRef(), this.services, this.scope);
+ props = new HashMap(4, 1.0f);
+ extractScriptableProperties((ScriptableObject)properties, props);
}
- return node;
+ if (name != null)
+ {
+ if (props == null) props = new HashMap(1, 1.0f);
+ props.put(ContentModel.PROP_NAME, name);
+ }
+ else
+ {
+ // set name for the assoc local name
+ name = GUID.generate();
+ }
+
+ ChildAssociationRef childAssocRef = this.nodeService.createNode(
+ this.nodeRef, createQName(assocName),
+ QName.createQName(NamespaceService.ALFRESCO_URI, QName.createValidLocalName(name)),
+ createQName(type), props);
+
+ return newInstance(childAssocRef.getChildRef(), this.services, this.scope);
+ }
+
+ /**
+ * Create an association between this node and the specified target node.
+ *
+ * @param target Destination node for the association
+ * @param assocType Association type qname (short form or fully qualified)
+ */
+ public void createAssociation(Node target, String assocType)
+ {
+ ParameterCheck.mandatory("Target", target);
+ ParameterCheck.mandatoryString("Association Type Name", assocType);
+
+ this.nodeService.createAssociation(this.nodeRef, target.nodeRef, createQName(assocType));
+ }
+
+ /**
+ * Remove an association between this node and the specified target node.
+ *
+ * @param target Destination node on the end of the association
+ * @param assocType Association type qname (short form or fully qualified)
+ */
+ public void removeAssociation(Node target, String assocType)
+ {
+ ParameterCheck.mandatory("Target", target);
+ ParameterCheck.mandatoryString("Association Type Name", assocType);
+
+ this.nodeService.removeAssociation(this.nodeRef, target.nodeRef, createQName(assocType));
}
/**
@@ -1211,26 +1288,8 @@ public class Node implements Serializable, Scopeable
Map aspectProps = null;
if (props instanceof ScriptableObject)
{
- ScriptableObject properties = (ScriptableObject) props;
-
- // we need to get all the keys to the properties provided
- // and convert them to a Map of QName to Serializable objects
- Object[] propIds = properties.getIds();
- aspectProps = new HashMap(propIds.length);
- for (int i = 0; i < propIds.length; i++)
- {
- // work on each key in turn
- Object propId = propIds[i];
-
- // we are only interested in keys that are formed of Strings i.e. QName.toString()
- if (propId instanceof String)
- {
- // get the value out for the specified key - make sure it is Serializable
- Object value = properties.get((String) propId, properties);
- value = getValueConverter().convertValueForRepo((Serializable) value);
- aspectProps.put(createQName((String) propId), (Serializable) value);
- }
- }
+ aspectProps = new HashMap(4, 1.0f);
+ extractScriptableProperties((ScriptableObject)props, aspectProps);
}
QName aspectQName = createQName(type);
this.nodeService.addAspect(this.nodeRef, aspectQName, aspectProps);
@@ -1240,6 +1299,37 @@ public class Node implements Serializable, Scopeable
return true;
}
+
+ /**
+ * Extract a map of properties from a scriptable object (generally an associative array)
+ *
+ * @param scriptable The scriptable object to extract name/value pairs from.
+ * @param map The map to add the converted name/value pairs to.
+ */
+ private void extractScriptableProperties(ScriptableObject scriptable, Map map)
+ {
+ // we need to get all the keys to the properties provided
+ // and convert them to a Map of QName to Serializable objects
+ Object[] propIds = scriptable.getIds();
+ for (int i = 0; i < propIds.length; i++)
+ {
+ // work on each key in turn
+ Object propId = propIds[i];
+
+ // we are only interested in keys that are formed of Strings i.e. QName.toString()
+ if (propId instanceof String)
+ {
+ // get the value out for the specified key - it must be Serializable
+ String key = (String)propId;
+ Object value = scriptable.get(key, scriptable);
+ if (value instanceof Serializable)
+ {
+ value = getValueConverter().convertValueForRepo((Serializable)value);
+ map.put(createQName(key), (Serializable)value);
+ }
+ }
+ }
+ }
/**
* Remove aspect from the node.
@@ -1566,7 +1656,7 @@ public class Node implements Serializable, Scopeable
public String processTemplate(Node template, Object args)
{
ParameterCheck.mandatory("Template Node", template);
- return processTemplate(template.getContent(), null, (ScriptableObject) args);
+ return processTemplate(template.getContent(), null, (ScriptableObject)args);
}
/**
@@ -1594,7 +1684,7 @@ public class Node implements Serializable, Scopeable
public String processTemplate(String template, Object args)
{
ParameterCheck.mandatoryString("Template", template);
- return processTemplate(template, null, (ScriptableObject) args);
+ return processTemplate(template, null, (ScriptableObject)args);
}
private String processTemplate(String template, NodeRef templateRef, ScriptableObject args)
@@ -1636,7 +1726,7 @@ public class Node implements Serializable, Scopeable
{
// get the value out for the specified key - make sure it is Serializable
Object value = args.get((String) propId, args);
- value = getValueConverter().convertValueForRepo((Serializable) value);
+ value = getValueConverter().convertValueForRepo((Serializable)value);
if (value != null)
{
templateArgs.put((String) propId, value.toString());
diff --git a/source/java/org/alfresco/repo/template/TemplateNode.java b/source/java/org/alfresco/repo/template/TemplateNode.java
index 989ec04fa4..383633b14c 100644
--- a/source/java/org/alfresco/repo/template/TemplateNode.java
+++ b/source/java/org/alfresco/repo/template/TemplateNode.java
@@ -72,12 +72,6 @@ public class TemplateNode extends BasePermissionsNode
private static Log logger = LogFactory.getLog(TemplateNode.class);
- /** The target associations from this node */
- private Map> targetAssocs = null;
-
- /** The child associations from this node */
- private Map> childAssocs = null;
-
/** All associations from this node */
private Map> assocs = null;
@@ -227,68 +221,28 @@ public class TemplateNode extends BasePermissionsNode
// Repository Node API
/**
- * @return The child associations for this Node. As a Map of assoc name to a List of TemplateNodes.
- */
- public Map> getChildAssocs()
- {
- if (this.childAssocs == null)
- {
- List refs = this.services.getNodeService().getChildAssocs(this.nodeRef);
- this.childAssocs = new QNameMap>(this.services.getNamespaceService());
- for (ChildAssociationRef ref : refs)
- {
- String qname = ref.getTypeQName().toString();
- List nodes = this.childAssocs.get(qname);
- if (nodes == null)
- {
- // first access for the list for this qname
- nodes = new ArrayList(4);
- this.childAssocs.put(ref.getTypeQName().toString(), nodes);
- }
- nodes.add( new TemplateNode(ref.getChildRef(), this.services, this.imageResolver) );
- }
- }
-
- return this.childAssocs;
- }
-
- /**
- * @return The target associations for this Node. As a Map of assoc name to a List of TemplateNodes.
- */
- public Map> getTargetAssocs()
- {
- if (this.targetAssocs == null)
- {
- List refs = this.services.getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
- this.targetAssocs = new QNameMap>(this.services.getNamespaceService());
- for (AssociationRef ref : refs)
- {
- String qname = ref.getTypeQName().toString();
- List nodes = this.targetAssocs.get(qname);
- if (nodes == null)
- {
- // first access for the list for this qname
- nodes = new ArrayList(4);
- this.targetAssocs.put(ref.getTypeQName().toString(), nodes);
- }
- nodes.add( new TemplateNode(ref.getTargetRef(), this.services, this.imageResolver) );
- }
- }
-
- return this.targetAssocs;
- }
-
- /**
- * @return All associations for this Node. As a Map of assoc name to a List of TemplateNodes.
+ * @return Target associations for this Node. As a Map of assoc name to a List of TemplateNodes.
*/
public Map> getAssocs()
{
if (this.assocs == null)
{
+ List refs = this.services.getNodeService().getTargetAssocs(this.nodeRef, RegexQNamePattern.MATCH_ALL);
this.assocs = new QNameMap>(this.services.getNamespaceService());
- this.assocs.putAll(getTargetAssocs());
- this.assocs.putAll(getChildAssocs());
+ for (AssociationRef ref : refs)
+ {
+ String qname = ref.getTypeQName().toString();
+ List nodes = this.assocs.get(qname);
+ if (nodes == null)
+ {
+ // first access for the list for this qname
+ nodes = new ArrayList(4);
+ this.assocs.put(ref.getTypeQName().toString(), nodes);
+ }
+ nodes.add( new TemplateNode(ref.getTargetRef(), this.services, this.imageResolver) );
+ }
}
+
return this.assocs;
}