/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 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.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.dltk.rhino.dbgp.LazyInitScope; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.debug.Debugger; import org.mozilla.javascript.debug.IDebuggerWithWatchPoints; import com.servoy.j2db.persistence.IScriptProvider; import com.servoy.j2db.persistence.ISupportScriptProviders; import com.servoy.j2db.persistence.ScriptMethod; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.Utils; /** * @author jblok */ public abstract class LazyCompilationScope extends DefaultScope implements LazyInitScope { protected volatile IExecutingEnviroment scriptEngine; private final Map<Integer, String> idVars; //id -> name (not in the same so it will not be in runtime env) private volatile Scriptable functionParent;//default this private volatile ISupportScriptProviders scriptLookup; public LazyCompilationScope(Scriptable parent, IExecutingEnviroment scriptEngine, ISupportScriptProviders scriptLookup) { super(parent); this.scriptLookup = scriptLookup; this.scriptEngine = scriptEngine; idVars = new HashMap<Integer, String>(); functionParent = this; createScriptProviders(true); } // final because called from constructor protected final void createScriptProviders(boolean overwriteInitialValue) { Iterator< ? extends IScriptProvider> it = scriptLookup.getScriptMethods(false); while (it.hasNext()) { IScriptProvider sm = it.next(); put(sm, sm, overwriteInitialValue); } } /** * @return the scriptLookup */ public ISupportScriptProviders getScriptLookup() { return scriptLookup; } public void setFunctionParentScriptable(Scriptable functionParent) { this.functionParent = functionParent; } public Scriptable getFunctionParentScriptable() { return functionParent; } /** * @see com.servoy.j2db.scripting.DefaultScope#has(int, org.mozilla.javascript.Scriptable) */ @Override public boolean has(int index, Scriptable start) { return idVars.containsKey(Integer.valueOf(index)); } public void put(IScriptProvider sm, Object function) { put(sm, function, true); } public void put(IScriptProvider sm, Object function, boolean overwriteInitialValue) { if (!overwriteInitialValue && allVars.containsKey(sm.getDataProviderID())) { return; } remove(sm.getName()); allVars.put(sm.getDataProviderID(), function); idVars.put(new Integer(sm.getID()), sm.getDataProviderID()); } public Object remove(IScriptProvider sm) { String sName = idVars.remove(new Integer(sm.getID())); if (sName != null) { Object o = allVars.remove(sName); // Script method may be either a interpreted rhino Function or a (yet to be interpreted ScriptMethod) return (o instanceof Function || o instanceof ScriptMethod) ? o : null; } return null; } @Override public Object get(String name, Scriptable start) { Object o = getImpl(name, start); if (o != Scriptable.NOT_FOUND) { Context currentContext = Context.getCurrentContext(); if (currentContext != null) { Debugger debugger = currentContext.getDebugger(); if (debugger instanceof IDebuggerWithWatchPoints) { IDebuggerWithWatchPoints wp = (IDebuggerWithWatchPoints)debugger; wp.access(name, this); } } } return o; } /** * @param name * @param start * @return */ protected final Object getImpl(String name, Scriptable start) { IScriptProvider sp = getScriptProvider(name); if (sp != null) { try { Scriptable compileScope = functionParent; Scriptable functionSuper = getFunctionSuper(sp); if (functionSuper != null) { compileScope = new DefaultScope(functionParent) { @Override public String getClassName() { return "RunScope"; //$NON-NLS-1$ } }; compileScope.setPrototype(functionParent); // _formname_ is used in a lot of plugins (getParent of a function object, see FunctionDef) to get the form name compileScope.put("_formname_", compileScope, functionParent.get("_formname_", functionParent)); //$NON-NLS-1$ //$NON-NLS-2$ compileScope.put("_super", compileScope, functionSuper); //$NON-NLS-1$ } Function function = scriptEngine.compileFunction(sp, compileScope); put(name, start, function);//replace to prevent more compiles } catch (Exception e) { Debug.error(e); } } return super.get(name, start); } /** * @param name */ private IScriptProvider getScriptProvider(String name) { Object o = allVars.get(name); if (o instanceof IScriptProvider) return (IScriptProvider)o; return null; } /** * @param sp * @return */ protected Scriptable getFunctionSuper(IScriptProvider sp) { return null; } /** * @see org.eclipse.dltk.rhino.dbgp.LazyInitScope#getInitializedIds() */ public Object[] getInitializedIds() { List<Object> array = new ArrayList<Object>(allVars.size() + allIndex.size() + 2); array.add("allnames"); //$NON-NLS-1$ array.add("length"); //$NON-NLS-1$ for (Object element : allVars.keySet()) { String name = (String)element; Object o = super.get(name, this); if (!(o instanceof IScriptProvider)) { array.add(name); } } // for (Iterator iter = allIndex.keySet().iterator(); iter.hasNext();) // { // array.add(iter.next()); // } return array.toArray(); } public String getFunctionName(Integer id) { return idVars.get(id); } public Function getFunctionByName(String name) { if (name == null) return null; Object o = getImpl(name, this); return (o instanceof Function ? (Function)o : null); } /** * @param persist */ public void reload() { Iterator<Object> it = allVars.values().iterator(); while (it.hasNext()) { Object object = it.next(); if (object instanceof IScriptProvider || object instanceof Function) { it.remove(); } } idVars.clear(); createScriptProviders(true); } public abstract String getScopeName(); /** * @see java.lang.Object#toString() */ @Override public String toString() { return "LazyCompilationScope[parent:" + (getParentScope() == this ? "this" : getParentScope()) + ", scriptLookup:" + scriptLookup + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } @Override public void remove(String name) { Utils.mapRemoveByValue(name, idVars); super.remove(name); } @Override public void destroy() { this.scriptEngine = null; this.idVars.clear(); this.functionParent = null; this.scriptLookup = null; super.destroy(); } }