add support for java List usage as javascript Array in scripts

This commit is contained in:
kimchy 2010-10-03 13:10:33 +02:00
parent c9a47a126f
commit 80b8898542
3 changed files with 239 additions and 2 deletions

View File

@ -24,10 +24,12 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.javascript.support.NativeList;
import org.elasticsearch.script.javascript.support.NativeMap;
import org.elasticsearch.script.javascript.support.ScriptValueConverter;
import org.mozilla.javascript.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@ -162,6 +164,9 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements
if (javaObject instanceof Map) {
return new NativeMap(scope, (Map) javaObject);
}
if (javaObject instanceof List) {
return new NativeList(scope, (List) javaObject);
}
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
}
}

View File

@ -0,0 +1,207 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.script.javascript.support;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.Wrapper;
import java.util.List;
/**
* @author kimchy (shay.banon)
*/
public class NativeList implements Scriptable, Wrapper {
private static final long serialVersionUID = 3664761893203964569L;
private List<Object> list;
private Scriptable parentScope;
private Scriptable prototype;
public static NativeList wrap(Scriptable scope, List<Object> list) {
return new NativeList(scope, list);
}
public NativeList(Scriptable scope, List<Object> list) {
this.parentScope = scope;
this.list = list;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Wrapper#unwrap()
*/
public Object unwrap() {
return list;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#getClassName()
*/
public String getClassName() {
return "NativeList";
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#get(java.lang.String, org.mozilla.javascript.Scriptable)
*/
public Object get(String name, Scriptable start) {
if ("length".equals(name)) {
return list.size();
} else {
return Undefined.instance;
}
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#get(int, org.mozilla.javascript.Scriptable)
*/
public Object get(int index, Scriptable start) {
if (index < 0 || index >= list.size()) {
return Undefined.instance;
}
return list.get(index);
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#has(java.lang.String, org.mozilla.javascript.Scriptable)
*/
public boolean has(String name, Scriptable start) {
if ("length".equals(name)) {
return true;
}
return false;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#has(int, org.mozilla.javascript.Scriptable)
*/
public boolean has(int index, Scriptable start) {
return index >= 0 && index < list.size();
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public void put(String name, Scriptable start, Object value) {
// do nothing here...
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#put(int, org.mozilla.javascript.Scriptable, java.lang.Object)
*/
public void put(int index, Scriptable start, Object value) {
if (index == list.size()) {
list.add(value);
} else {
list.set(index, value);
}
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#delete(java.lang.String)
*/
public void delete(String name) {
// nothing here
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#delete(int)
*/
public void delete(int index) {
list.remove(index);
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#getPrototype()
*/
public Scriptable getPrototype() {
return this.prototype;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#setPrototype(org.mozilla.javascript.Scriptable)
*/
public void setPrototype(Scriptable prototype) {
this.prototype = prototype;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#getParentScope()
*/
public Scriptable getParentScope() {
return this.parentScope;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#setParentScope(org.mozilla.javascript.Scriptable)
*/
public void setParentScope(Scriptable parent) {
this.parentScope = parent;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#getIds()
*/
public Object[] getIds() {
int size = list.size();
Object[] ids = new Object[size];
for (int i = 0; i < size; ++i) {
ids[i] = i;
}
return ids;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#getDefaultValue(java.lang.Class)
*/
public Object getDefaultValue(Class hint) {
return null;
}
/* (non-Javadoc)
* @see org.mozilla.javascript.Scriptable#hasInstance(org.mozilla.javascript.Scriptable)
*/
public boolean hasInstance(Scriptable value) {
if (!(value instanceof Wrapper))
return false;
Object instance = ((Wrapper) value).unwrap();
return List.class.isInstance(instance);
}
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.script.javascript;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.script.ExecutableScript;
@ -48,17 +49,20 @@ public class JavaScriptScriptEngineTests {
assertThat(((Number) o).intValue(), equalTo(3));
}
@Test public void testMapPassedMapReturned() {
@Test public void testMapAccess() {
Map<String, Object> vars = new HashMap<String, Object>();
Map<String, Object> obj2 = MapBuilder.<String, Object>newMapBuilder().put("prop2", "value2").map();
Map<String, Object> obj1 = MapBuilder.<String, Object>newMapBuilder().put("prop1", "value1").put("obj2", obj2).map();
Map<String, Object> obj1 = MapBuilder.<String, Object>newMapBuilder().put("prop1", "value1").put("obj2", obj2).put("l", Lists.newArrayList("2", "1")).map();
vars.put("obj1", obj1);
Object o = se.execute(se.compile("obj1"), vars);
assertThat(o, instanceOf(Map.class));
obj1 = (Map<String, Object>) o;
assertThat((String) obj1.get("prop1"), equalTo("value1"));
assertThat((String) ((Map<String, Object>) obj1.get("obj2")).get("prop2"), equalTo("value2"));
o = se.execute(se.compile("obj1.l[0]"), vars);
assertThat(((String) o), equalTo("2"));
}
@Test public void testJavaScriptObjectToMap() {
@ -69,6 +73,27 @@ public class JavaScriptScriptEngineTests {
assertThat((String) ((Map<String, Object>) obj1.get("obj2")).get("prop2"), equalTo("value2"));
}
@Test public void testAccessListInScript() {
Map<String, Object> vars = new HashMap<String, Object>();
Map<String, Object> obj2 = MapBuilder.<String, Object>newMapBuilder().put("prop2", "value2").map();
Map<String, Object> obj1 = MapBuilder.<String, Object>newMapBuilder().put("prop1", "value1").put("obj2", obj2).map();
vars.put("l", Lists.newArrayList("1", "2", "3", obj1));
Object o = se.execute(se.compile("l.length"), vars);
assertThat(((Number) o).intValue(), equalTo(4));
o = se.execute(se.compile("l[0]"), vars);
assertThat(((String) o), equalTo("1"));
o = se.execute(se.compile("l[3]"), vars);
obj1 = (Map<String, Object>) o;
assertThat((String) obj1.get("prop1"), equalTo("value1"));
assertThat((String) ((Map<String, Object>) obj1.get("obj2")).get("prop2"), equalTo("value2"));
o = se.execute(se.compile("l[3].prop1"), vars);
assertThat(((String) o), equalTo("value1"));
}
@Test public void testChangingVarsCrossExecution1() {
Map<String, Object> vars = new HashMap<String, Object>();
Map<String, Object> ctx = new HashMap<String, Object>();