Rhinoscript Engine:

- Allow actions to be invoked via JavaScript

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3499 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2006-08-14 18:04:08 +00:00
parent 5e0163001f
commit 354834c25f
12 changed files with 758 additions and 179 deletions

View File

@@ -20,9 +20,6 @@ import java.io.Serializable;
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;
import java.util.Map;
@@ -61,12 +58,8 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;
import org.springframework.util.StringUtils;
/**
@@ -93,6 +86,9 @@ public final class Node implements Serializable, Scopeable
/** Root scope for this object */
private Scriptable scope;
/** Node Value Converter */
private NodeValueConverter converter = null;
/** Cached values */
private NodeRef nodeRef;
private String name;
@@ -117,6 +113,7 @@ public final class Node implements Serializable, Scopeable
// NOTE: see the reset() method when adding new cached members!
// ------------------------------------------------------------------------------
// Construction
@@ -158,6 +155,7 @@ public final class Node implements Serializable, Scopeable
this.nodeService = services.getNodeService();
this.imageResolver = resolver;
this.scope = scope;
this.converter = new NodeValueConverter();
}
/**
@@ -407,7 +405,7 @@ public final class Node implements Serializable, Scopeable
Serializable propValue = props.get(qname);
// perform the conversion to a script safe value and store
this.properties.put(qname.toString(), convertValueForScript(qname, propValue));
this.properties.put(qname.toString(), converter.convertValueForScript(qname, propValue));
}
}
@@ -900,148 +898,13 @@ 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 = convertValueForRepo(value);
value = converter.convertValueForRepo(value);
props.put(createQName(key), value);
}
this.nodeService.setProperties(this.nodeRef, props);
}
/**
* Convert an object from any script wrapper value to a valid repository serializable value.
* This includes converting JavaScript Array objects to Lists of valid objects.
*
* @param value Value to convert from script wrapper object to repo serializable value
*
* @return valid repo value
*/
private static Serializable convertValueForRepo(Serializable value)
{
if (value == null)
{
return null;
}
else if (value instanceof Node)
{
// convert back to NodeRef
value = ((Node)value).getNodeRef();
}
else if (value instanceof ScriptContentData)
{
// convert back to ContentData
value = ((ScriptContentData)value).contentData;
}
else if (value instanceof Wrapper)
{
// unwrap a Java object from a JavaScript wrapper
// recursively call this method to convert the unwrapped value
value = convertValueForRepo((Serializable)((Wrapper)value).unwrap());
}
else if (value instanceof ScriptableObject)
{
// a scriptable object will probably indicate a multi-value property
// set using a JavaScript Array object
ScriptableObject values = (ScriptableObject)value;
if (value instanceof NativeArray)
{
// convert JavaScript array of values to a List of Serializable objects
Object[] propIds = values.getIds();
List<Serializable> propValues = new ArrayList<Serializable>(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 indicate a list of values
if (propId instanceof Integer)
{
// 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(convertValueForRepo(val));
}
}
value = (Serializable)propValues;
}
else
{
// TODO: add code here to use the dictionary and convert to correct value type
Object javaObj = Context.jsToJava(value, Date.class);
if (javaObj instanceof Serializable)
{
value = (Serializable)javaObj;
}
}
}
else if (value instanceof Serializable[])
{
// convert back a list of Java values
Serializable[] array = (Serializable[])value;
ArrayList<Serializable> list = new ArrayList<Serializable>(array.length);
for (int i=0; i<array.length; i++)
{
list.add(convertValueForRepo(array[i]));
}
value = list;
}
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<Serializable> collection = (Collection<Serializable>)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.
@@ -1346,7 +1209,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 = convertValueForRepo((Serializable)value);
value = converter.convertValueForRepo((Serializable)value);
aspectProps.put(createQName((String)propId), (Serializable)value);
}
}
@@ -1770,6 +1633,68 @@ public final class Node implements Serializable, Scopeable
}
// ------------------------------------------------------------------------------
// Value Conversion
/**
* Value converter with knowledge of Node specific value types
*/
private final class NodeValueConverter extends ValueConverter
{
/**
* 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
*/
public Serializable convertValueForScript(QName qname, Serializable value)
{
return convertValueForScript(services, scope, qname, value);
}
/* (non-Javadoc)
* @see org.alfresco.repo.jscript.ValueConverter#convertValueForScript(org.alfresco.service.ServiceRegistry, org.mozilla.javascript.Scriptable, org.alfresco.service.namespace.QName, java.io.Serializable)
*/
@Override
public Serializable convertValueForScript(ServiceRegistry services, Scriptable scope, QName qname, Serializable value)
{
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
{
value = super.convertValueForScript(services, scope, qname, value);
}
return value;
}
/* (non-Javadoc)
* @see org.alfresco.repo.jscript.ValueConverter#convertValueForRepo(java.io.Serializable)
*/
@Override
public Serializable convertValueForRepo(Serializable value)
{
if (value instanceof ScriptContentData)
{
// convert back to ContentData
value = ((ScriptContentData)value).contentData;
}
else
{
value = super.convertValueForRepo(value);
}
return value;
}
}
// ------------------------------------------------------------------------------
// Inner Classes
@@ -1789,7 +1714,7 @@ public final class Node implements Serializable, Scopeable
this.contentData = contentData;
this.property = property;
}
/**
* @return the content stream
*/