Author: radu
Date: Mon Aug 17 12:08:51 2015
New Revision: 1696254
URL: http://svn.apache.org/r1696254
Log:
SLING-4953 - Enhance the JavaScript API provided by the
org.apache.sling.scripting.javascript bundle
* added a wrapper for Map objects so that Map keys are mapped as object
properties for the JavaScript object
representing the map
* added a 'properties' property for Javascript objects representing resources
Added:
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMap.java
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMapTest.java
Modified:
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableResource.java
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/wrapper/ScriptableResourceTest.java
Modified:
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java?rev=1696254&r1=1696253&r2=1696254&view=diff
==============================================================================
---
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java
(original)
+++
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java
Mon Aug 17 12:08:51 2015
@@ -42,6 +42,7 @@ import org.apache.sling.scripting.javasc
import org.apache.sling.scripting.javascript.helper.SlingWrapFactory;
import org.apache.sling.scripting.javascript.wrapper.ScriptableCalendar;
import org.apache.sling.scripting.javascript.wrapper.ScriptableItemMap;
+import org.apache.sling.scripting.javascript.wrapper.ScriptableMap;
import org.apache.sling.scripting.javascript.wrapper.ScriptableNode;
import org.apache.sling.scripting.javascript.wrapper.ScriptablePrintWriter;
import org.apache.sling.scripting.javascript.wrapper.ScriptableProperty;
@@ -99,7 +100,7 @@ public class RhinoJavaScriptEngineFactor
ScriptableResource.class, ScriptableNode.class,
ScriptableProperty.class, ScriptableItemMap.class,
ScriptablePrintWriter.class, ScriptableVersionHistory.class,
- ScriptableVersion.class, ScriptableCalendar.class
+ ScriptableVersion.class, ScriptableCalendar.class,
ScriptableMap.class
};
/**
Added:
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMap.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMap.java?rev=1696254&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMap.java
(added)
+++
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMap.java
Mon Aug 17 12:08:51 2015
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.sling.scripting.javascript.wrapper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.scripting.javascript.SlingWrapper;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.Undefined;
+
+/**
+ * The {@code ScriptableMap} wrapper provides easier access to a map's values
by setting the map's keys as properties to the JavaScript
+ * object representing the {@link Map}.
+ */
+public class ScriptableMap extends ScriptableBase implements SlingWrapper {
+
+ public static final String CLASSNAME = "Map";
+ private static final Class<?> [] WRAPPED_CLASSES = { Map.class };
+
+ private Map<String, Object> map = new HashMap<String, Object>();
+
+ public void jsConstructor(Object map) {
+ this.map = (Map) map;
+ }
+
+ @Override
+ public Object get(String name, Scriptable start) {
+ final Object fromSuperClass = super.get(name, start);
+ if (fromSuperClass != Scriptable.NOT_FOUND) {
+ return fromSuperClass;
+ }
+
+ if (map == null) {
+ return Undefined.instance;
+ }
+
+ Object result = map.get(name);
+ if (result == null) {
+ result = getNative(name, start);
+ }
+ return result;
+ }
+
+ @Override
+ public Object getDefaultValue(Class<?> typeHint) {
+ return map;
+ }
+
+ @Override
+ protected Object getWrappedObject() {
+ return map;
+ }
+
+ @Override
+ protected Class<?> getStaticType() {
+ return Map.class;
+ }
+
+ @Override
+ public String getClassName() {
+ return CLASSNAME;
+ }
+
+ @Override
+ public Class<?>[] getWrappedClasses() {
+ return WRAPPED_CLASSES;
+ }
+
+ @Override
+ public Object unwrap() {
+ return map;
+ }
+}
Modified:
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableResource.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableResource.java?rev=1696254&r1=1696253&r2=1696254&view=diff
==============================================================================
---
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableResource.java
(original)
+++
sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/wrapper/ScriptableResource.java
Mon Aug 17 12:08:51 2015
@@ -18,6 +18,7 @@ package org.apache.sling.scripting.javas
import org.apache.commons.collections.IteratorUtils;
import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.scripting.javascript.SlingWrapper;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
@@ -51,6 +52,7 @@ import org.slf4j.LoggerFactory;
* <li>[Resource[]] getChildren()</li>
* <li>[Resource[]] listChildren()</li>
* <li>[Boolean] isResourceType(String)</li>
+ * <li>[Object] properties</li>
* </ul>
*/
public class ScriptableResource extends ScriptableObject implements
@@ -63,6 +65,7 @@ public class ScriptableResource extends
private static final Class<?>[] WRAPPED_CLASSES = { Resource.class };
private Resource resource;
+ private ValueMap properties;
public ScriptableResource() {
}
@@ -307,6 +310,13 @@ public class ScriptableResource extends
return Undefined.instance;
}
+ public Object jsGet_properties() {
+ if (properties == null) {
+ properties = resource.adaptTo(ValueMap.class);
+ }
+ return properties;
+ }
+
// --------- ScriptableObject API
@Override
Added:
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMapTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMapTest.java?rev=1696254&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMapTest.java
(added)
+++
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/wrapper/ScriptableMapTest.java
Mon Aug 17 12:08:51 2015
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.sling.scripting.javascript.wrapper;
+
+import java.util.HashMap;
+import javax.script.ScriptException;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.scripting.RepositoryScriptingTestBase;
+import org.apache.sling.scripting.javascript.internal.ScriptEngineHelper;
+import org.junit.After;
+import org.junit.Before;
+
+public class ScriptableMapTest extends RepositoryScriptingTestBase {
+
+ private ValueMap valueMap;
+ private ScriptEngineHelper.Data data;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ valueMap = new ValueMapDecorator(new HashMap<String, Object>() {{
+ put("a", "a");
+ put("b", 1);
+ }});
+ data = new ScriptEngineHelper.Data();
+ data.put("properties", valueMap);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ valueMap.clear();
+ data.clear();
+ super.tearDown();
+ }
+
+ public void testPropertyAccess() throws ScriptException {
+ assertEquals("a", script.eval("properties['a']", data));
+ assertEquals("a", script.eval("properties.a", data));
+ assertEquals(1, script.eval("properties['b']", data));
+ assertEquals(1, script.eval("properties.b", data));
+ assertEquals(null, script.eval("properties['c']", data));
+ }
+
+ public void testJavaMethods() throws ScriptException {
+ assertEquals(2, script.eval("properties.size()", data));
+ }
+}
\ No newline at end of file
Modified:
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/wrapper/ScriptableResourceTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/wrapper/ScriptableResourceTest.java?rev=1696254&r1=1696253&r2=1696254&view=diff
==============================================================================
---
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/wrapper/ScriptableResourceTest.java
(original)
+++
sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/wrapper/ScriptableResourceTest.java
Mon Aug 17 12:08:51 2015
@@ -19,25 +19,37 @@
package org.apache.sling.scripting.wrapper;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-
+import java.util.Map;
import javax.jcr.Item;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.commons.testing.sling.MockResourceResolver;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.apache.sling.scripting.RepositoryScriptingTestBase;
import org.apache.sling.scripting.javascript.internal.ScriptEngineHelper;
import org.mozilla.javascript.Wrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ScriptableResourceTest extends RepositoryScriptingTestBase {
@@ -49,6 +61,8 @@ public class ScriptableResourceTest exte
private static final String RESOURCE_SUPER_TYPE =
"testWrappedResourceSuperType";
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ScriptableResourceTest.class);
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -215,6 +229,17 @@ public class ScriptableResourceTest exte
assertEquals(true,
script.eval("resource.adaptTo(Packages.java.util.Date) == undefined", data));
}
+ public void testProperties() throws Exception {
+ final ScriptEngineHelper.Data data = new ScriptEngineHelper.Data();
+ Calendar date = new GregorianCalendar();
+ node.setProperty(JcrConstants.JCR_LASTMODIFIED, date);
+ node.setProperty("test", "testProperties");
+ node.getSession().save();
+ data.put("resource", new TestResource(node));
+ assertEquals(date.getTimeInMillis(),
script.eval("(resource.properties['jcr:lastModified']).getTimeInMillis()",
data));
+ assertEquals("testProperties", script.eval("resource.properties.test",
data));
+ }
+
private void assertEquals(Node expected, Object actual) {
while (actual instanceof Wrapper) {
actual = ((Wrapper) actual).unwrap();
@@ -271,6 +296,75 @@ public class ScriptableResourceTest exte
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == Node.class || type == Item.class) {
return (AdapterType) node;
+ } else if (type == ValueMap.class) {
+ try {
+
+ PropertyIterator iterator = node.getProperties();
+ Map<String, Object> properties = new HashMap<String,
Object>();
+ while (iterator.hasNext()) {
+ Property prop = iterator.nextProperty();
+ if (prop.isMultiple()) {
+ Value[] values = prop.getValues();
+ Object[] array = new Object[values.length];
+ int index = 0;
+ for (Value value : values) {
+ switch (value.getType()) {
+ case PropertyType.BINARY:
+ array[index++] = value.getBinary();
+ break;
+ case PropertyType.BOOLEAN:
+ array[index++] = value.getBoolean();
+ break;
+ case PropertyType.DATE:
+ array[index++] = value.getDate();
+ break;
+ case PropertyType.DECIMAL:
+ array[index++] = value.getDecimal();
+ break;
+ case PropertyType.DOUBLE:
+ array[index++] = value.getDouble();
+ break;
+ case PropertyType.LONG:
+ array[index++] = value.getLong();
+ break;
+ default:
+ array[index++] = value.getString();
+ break;
+ }
+ }
+ properties.put(prop.getName(), array);
+
+ } else {
+ Value value = prop.getValue();
+ switch (value.getType()) {
+ case PropertyType.BINARY:
+ properties.put(prop.getName(),
value.getBinary());
+ break;
+ case PropertyType.BOOLEAN:
+ properties.put(prop.getName(),
value.getBoolean());
+ break;
+ case PropertyType.DATE:
+ properties.put(prop.getName(),
value.getDate());
+ break;
+ case PropertyType.DECIMAL:
+ properties.put(prop.getName(),
value.getDecimal());
+ break;
+ case PropertyType.DOUBLE:
+ properties.put(prop.getName(),
value.getDouble());
+ break;
+ case PropertyType.LONG:
+ properties.put(prop.getName(),
value.getLong());
+ break;
+ default:
+ properties.put(prop.getName(),
value.getString());
+ break;
+ }
+ }
+ }
+ return ((AdapterType) (new ValueMapDecorator(properties)));
+ } catch (RepositoryException e) {
+ LOGGER.error("Unable to adapt resource " + getPath() + "
to a ValueMap.", e);
+ }
}
return null;