diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
index 66d29848e4..04118eebb8 100644
--- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
+++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 Jesper Steen Møller
+ * Copyright (C) 2005 Jesper Steen Møller
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
@@ -43,7 +43,7 @@ import org.alfresco.service.namespace.QName;
* otherwise they are left as is.
* This may change if the action gets parameterized in future.
*
- * @author Jesper Steen Møller
+ * @author Jesper Steen Møller
*/
public class ContentMetadataExtracter extends ActionExecuterAbstractBase
{
diff --git a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
index 779ad2dd2d..8ae227fd17 100644
--- a/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
+++ b/source/java/org/alfresco/repo/content/transform/HtmlParserContentTransformerTest.java
@@ -25,8 +25,6 @@ import org.alfresco.repo.content.MimetypeMap;
*/
public class HtmlParserContentTransformerTest extends AbstractContentTransformerTest
{
- private static final String SOME_CONTENT = "azAz10!£$%^&*()\t\r\n";
-
private ContentTransformer transformer;
@Override
diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index 5644a16d51..f9b4824997 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -21,6 +21,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -405,33 +406,8 @@ public final class Node implements Serializable, Scopeable
{
Serializable propValue = props.get(qname);
- // perform conversions from Java objects to JavaScript scriptable instances
- if (propValue instanceof NodeRef)
- {
- // NodeRef object properties are converted to new Node objects
- // so they can be used as objects within a template
- propValue = new Node(
- ((NodeRef)propValue), this.services, this.imageResolver, this.scope);
- }
- else if (propValue instanceof ContentData)
- {
- // ContentData object properties are converted to ScriptContentData objects
- // so the content and other properties of those objects can be accessed
- propValue = new ScriptContentData((ContentData)propValue, qname);
- }
- else if (propValue instanceof Date)
- {
- // convert Date to JavaScript native Date object
- // call the "Date" constructor on the root scope object - passing in the millisecond
- // value from the Java date - this will construct a JavaScript Date with the same value
- Date date = (Date)propValue;
- Object val = ScriptRuntime.newObject(
- Context.getCurrentContext(), this.scope, "Date", new Object[] {date.getTime()});
- propValue = (Serializable)val;
- }
- // simple numbers and strings are handled automatically by Rhino
-
- this.properties.put(qname.toString(), propValue);
+ // perform the conversion to a script safe value and store
+ this.properties.put(qname.toString(), convertValueForScript(qname, propValue));
}
}
@@ -924,7 +900,7 @@ public final class Node implements Serializable, Scopeable
Serializable value = (Serializable)this.properties.get(key);
// perform the conversion from script wrapper object to repo serializable values
- value = convertValue(value);
+ value = convertValueForRepo(value);
props.put(createQName(key), value);
}
@@ -939,9 +915,13 @@ public final class Node implements Serializable, Scopeable
*
* @return valid repo value
*/
- private static Serializable convertValue(Serializable value)
+ private static Serializable convertValueForRepo(Serializable value)
{
- if (value instanceof Node)
+ if (value == null)
+ {
+ return null;
+ }
+ else if (value instanceof Node)
{
// convert back to NodeRef
value = ((Node)value).getNodeRef();
@@ -955,7 +935,7 @@ public final class Node implements Serializable, Scopeable
{
// unwrap a Java object from a JavaScript wrapper
// recursively call this method to convert the unwrapped value
- value = convertValue((Serializable)((Wrapper)value).unwrap());
+ value = convertValueForRepo((Serializable)((Wrapper)value).unwrap());
}
else if (value instanceof ScriptableObject)
{
@@ -979,7 +959,7 @@ public final class Node implements Serializable, Scopeable
// get the value out for the specified key
Serializable val = (Serializable)values.get((Integer)propId, values);
// recursively call this method to convert the value
- propValues.add(convertValue(val));
+ propValues.add(convertValueForRepo(val));
}
}
value = (Serializable)propValues;
@@ -997,6 +977,61 @@ public final class Node implements Serializable, Scopeable
return value;
}
+ /**
+ * Convert an object from any repository serialized value to a valid script object.
+ * This includes converting Collection multi-value properties into JavaScript Array objects.
+ *
+ * @param qname QName of the property value for conversion
+ * @param value Property value
+ *
+ * @return Value safe for scripting usage
+ */
+ private Serializable convertValueForScript(QName qname, Serializable value)
+ {
+ // perform conversions from Java objects to JavaScript scriptable instances
+ if (value == null)
+ {
+ return null;
+ }
+ else if (value instanceof NodeRef)
+ {
+ // NodeRef object properties are converted to new Node objects
+ // so they can be used as objects within a template
+ value = new Node(((NodeRef)value), this.services, this.imageResolver, this.scope);
+ }
+ else if (value instanceof ContentData)
+ {
+ // ContentData object properties are converted to ScriptContentData objects
+ // so the content and other properties of those objects can be accessed
+ value = new ScriptContentData((ContentData)value, qname);
+ }
+ else if (value instanceof Date)
+ {
+ // convert Date to JavaScript native Date object
+ // call the "Date" constructor on the root scope object - passing in the millisecond
+ // value from the Java date - this will construct a JavaScript Date with the same value
+ Date date = (Date)value;
+ Object val = ScriptRuntime.newObject(
+ Context.getCurrentContext(), this.scope, "Date", new Object[] {date.getTime()});
+ value = (Serializable)val;
+ }
+ else if (value instanceof Collection)
+ {
+ // recursively convert each value in the collection
+ Collection collection = (Collection)value;
+ Serializable[] array = new Serializable[collection.size()];
+ int index = 0;
+ for (Serializable obj : collection)
+ {
+ array[index++] = convertValueForScript(qname, obj);
+ }
+ value = array;
+ }
+ // simple numbers and strings are wrapped automatically by Rhino
+
+ return value;
+ }
+
/**
* Re-sets the type of the node. Can be called in order specialise a node to a sub-type.
*
@@ -1300,7 +1335,7 @@ public final class Node implements Serializable, Scopeable
{
// get the value out for the specified key - make sure it is Serializable
Object value = props.get((String)propId, props);
- value = convertValue((Serializable)value);
+ value = convertValueForRepo((Serializable)value);
aspectProps.put(createQName((String)propId), (Serializable)value);
}
}
@@ -1502,19 +1537,22 @@ public final class Node implements Serializable, Scopeable
if (reader != null)
{
// Copy the content node to a new node
+ String copyName = TransformActionExecuter.transformName(
+ this.services.getMimetypeService(), getName(), mimetype);
NodeRef copyNodeRef = this.services.getCopyService().copy(
this.nodeRef,
destination,
ContentModel.ASSOC_CONTAINS,
- getPrimaryParentAssoc().getQName(),
+ QName.createQName(
+ ContentModel.PROP_CONTENT.getNamespaceURI(),
+ QName.createValidLocalName(copyName)),
false);
// modify the name of the copy to reflect the new mimetype
this.nodeService.setProperty(
copyNodeRef,
ContentModel.PROP_NAME,
- TransformActionExecuter.transformName(
- this.services.getMimetypeService(), getName(), mimetype));
+ copyName);
// get the writer and set it up
ContentWriter writer = contentService.getWriter(copyNodeRef, ContentModel.PROP_CONTENT, true);
diff --git a/source/java/org/alfresco/repo/jscript/Search.java b/source/java/org/alfresco/repo/jscript/Search.java
index adde07b567..79ee477ae5 100644
--- a/source/java/org/alfresco/repo/jscript/Search.java
+++ b/source/java/org/alfresco/repo/jscript/Search.java
@@ -80,6 +80,40 @@ public final class Search implements Scopeable
this.scope = scope;
}
+ /**
+ * Find a single Node by the Node reference
+ *
+ * @param ref The NodeRef of the Node to find
+ *
+ * @return the Node if found or null if failed to find
+ */
+ public Node findNode(NodeRef ref)
+ {
+ return findNode(ref.toString());
+ }
+
+ /**
+ * Find a single Node by the Node reference
+ *
+ * @param ref The fully qualified NodeRef in String format
+ *
+ * @return the Node if found or null if failed to find
+ */
+ public Node findNode(String ref)
+ {
+ String query = ref.replace(":", "\\:");
+ query = query.replace("/", "\\/");
+ Node[] result = query("ID:" + query);
+ if (result.length == 1)
+ {
+ return result[0];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
/**
* Execute a Lucene search
*
diff --git a/source/java/org/alfresco/repo/template/NamePathResultsMap.java b/source/java/org/alfresco/repo/template/NamePathResultsMap.java
index 3cf8a77267..9641da39af 100644
--- a/source/java/org/alfresco/repo/template/NamePathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/NamePathResultsMap.java
@@ -28,7 +28,7 @@ import org.alfresco.service.cmr.repository.TemplateNode;
*
* @author Kevin Roast
*/
-public final class NamePathResultsMap extends BasePathResultsMap
+public class NamePathResultsMap extends BasePathResultsMap
{
/**
* Constructor
diff --git a/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java b/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java
new file mode 100644
index 0000000000..2ae5213683
--- /dev/null
+++ b/source/java/org/alfresco/repo/template/NodeSearchResultsMap.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/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.alfresco.repo.template;
+
+import java.util.List;
+
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.TemplateNode;
+
+/**
+ * Provides functionality to execute a Lucene search for a single node by NodeRef.
+ *
+ * @author Kevin Roast
+ */
+public class NodeSearchResultsMap extends BaseSearchResultsMap
+{
+ /**
+ * Constructor
+ *
+ * @param parent The parent TemplateNode to execute searches from
+ * @param services The ServiceRegistry to use
+ */
+ public NodeSearchResultsMap(TemplateNode parent, ServiceRegistry services)
+ {
+ super(parent, services);
+ }
+
+ /**
+ * @see org.alfresco.repo.template.BaseTemplateMap#get(java.lang.Object)
+ */
+ public Object get(Object key)
+ {
+ TemplateNode result = null;
+ if (key != null)
+ {
+ String ref = key.toString().replace(":", "\\:");
+ ref = ref.replace("/", "\\/");
+
+ List results = query(ref);
+
+ if (results.size() == 1)
+ {
+ result = results.get(0);
+ }
+ }
+ return result;
+ }
+}
diff --git a/source/java/org/alfresco/repo/template/XPathResultsMap.java b/source/java/org/alfresco/repo/template/XPathResultsMap.java
index dcc6a23b47..dc0ae7210e 100644
--- a/source/java/org/alfresco/repo/template/XPathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/XPathResultsMap.java
@@ -25,7 +25,7 @@ import org.alfresco.service.cmr.repository.TemplateNode;
*
* @author Kevin Roast
*/
-public final class XPathResultsMap extends BasePathResultsMap
+public class XPathResultsMap extends BasePathResultsMap
{
/**
* Constructor
diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java
index c9b64e52a4..5b76de0058 100644
--- a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java
+++ b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java
@@ -30,6 +30,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.template.LuceneSearchResultsMap;
import org.alfresco.repo.template.NamePathResultsMap;
+import org.alfresco.repo.template.NodeSearchResultsMap;
import org.alfresco.repo.template.SavedSearchResultsMap;
import org.alfresco.repo.template.XPathResultsMap;
import org.alfresco.service.ServiceRegistry;
@@ -235,6 +236,14 @@ public final class TemplateNode implements Serializable
return new LuceneSearchResultsMap(this, this.services);
}
+ /**
+ * @return A map capable of returning a TemplateNode for a single specified NodeRef reference.
+ */
+ public Map getNodeByReference()
+ {
+ return new NodeSearchResultsMap(this, this.services);
+ }
+
/**
* @return The associations for this Node. As a Map of assoc name to a List of TemplateNodes.
*/