/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2013 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.scripting;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.mozilla.javascript.MemberBox;
import org.mozilla.javascript.NativeJavaMethod;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.annotations.JSFunction;
import com.servoy.j2db.scripting.annotations.AnnotationManagerReflection;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.Utils;
/**
* Scope for classes with dynamic members and js functions.
*
* @author rgansevles
*
* @since 7.4
*
*/
public abstract class DefaultJavaScope extends DefaultScope implements IJavaScriptType
{
private boolean filled;
private final Map<String, NativeJavaMethod> jsFunctions;
protected DefaultJavaScope(Scriptable scriptParent, Map<String, NativeJavaMethod> jsFunctions)
{
super(scriptParent);
this.jsFunctions = jsFunctions;
}
/*
* To be overridden when subclass wants to fill itself dynamically.
*/
protected boolean fill()
{
return true;
}
protected void setFilled(boolean filled)
{
this.filled = filled;
}
private void checkFill()
{
if (!filled)
{
filled = fill();
}
}
@Override
public Object get(String name, Scriptable start)
{
checkFill();
NativeJavaMethod jm = jsFunctions.get(name);
if (jm != null)
{
ScriptRuntime.setFunctionProtoAndParent(jm, start);
return jm;
}
return super.get(name, start);
}
@Override
public boolean has(String name, Scriptable start)
{
checkFill();
return jsFunctions.containsKey(name) || super.has(name, start);
}
@Override
public Object get(int index, Scriptable start)
{
checkFill();
return super.get(index, start);
}
@Override
public Object[] getIds()
{
checkFill();
return super.getIds();
}
@Override
public Object[] getValues()
{
checkFill();
return super.getValues();
}
@Override
public boolean has(int index, Scriptable start)
{
checkFill();
return super.has(index, start);
}
public static Map<String, NativeJavaMethod> getJsFunctions(Class< ? > clazz)
{
Map<String, NativeJavaMethod> jsFunctions = new HashMap<String, NativeJavaMethod>();
try
{
for (Method method : clazz.getMethods())
{
if (AnnotationManagerReflection.getInstance().isAnnotationPresent(method, clazz, JSFunction.class))
{
String name = method.getName();
NativeJavaMethod nativeJavaMethod = jsFunctions.get(name);
if (nativeJavaMethod == null)
{
nativeJavaMethod = new NativeJavaMethod(method, name);
}
else
{
nativeJavaMethod = new NativeJavaMethod(Utils.arrayAdd(nativeJavaMethod.getMethods(), new MemberBox(method), true), name);
}
jsFunctions.put(name, nativeJavaMethod);
}
}
}
catch (Exception e)
{
Debug.error(e);
}
return jsFunctions;
}
}