/*
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.Stack;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.dataprocessing.DelegateModificationSubject;
import com.servoy.j2db.dataprocessing.IModificationSubject;
import com.servoy.j2db.persistence.ScriptVariable;
import com.servoy.j2db.util.Pair;
import com.servoy.j2db.util.ScopesUtils;
/**
* Scope that holds the global scopes.
*
* @author rgansevles
*
* @since 6.1
*/
public class ScopesScope extends DefaultScope
{
private volatile IServiceProvider application;
private final IExecutingEnviroment scriptEngine;
private final DelegateModificationSubject delegateModificationSubject = new DelegateModificationSubject();
public ScopesScope(Scriptable parent, IExecutingEnviroment scriptEngine, IServiceProvider application)
{
super(parent);
this.scriptEngine = scriptEngine;
this.application = application;
setLocked(true);
}
public IModificationSubject getModificationSubject()
{
return delegateModificationSubject;
}
public void createGlobalsScope()
{
getGlobalScope(ScriptVariable.GLOBAL_SCOPE);
}
/*
* (non-Javadoc)
*
* @see com.servoy.j2db.scripting.DefaultScope#get(java.lang.String, org.mozilla.javascript.Scriptable)
*/
@Override
public Object get(String name, Scriptable start)
{
Object object = super.get(name, start);
if (object == Scriptable.NOT_FOUND && application.getFlattenedSolution().getScopeNames().contains(name))
{
object = getGlobalScope(name);
}
else if (object instanceof GlobalScope && !((GlobalScope)object).isInitialized())
{
application.reportJSError("Scope '" + name +
"' was accessed while not fully created yet, check for scope variables recursively referring to each other, scope stack:" +
globalScopeCreateStack.toString(), null);
}
return object;
}
private final Stack<String> globalScopeCreateStack = new Stack<String>();
/**
* Get or create global scope.
* @param sc
* @return
*/
public GlobalScope getGlobalScope(String sc)
{
String scopeName = sc == null ? ScriptVariable.GLOBAL_SCOPE : sc;
GlobalScope gs;
Object gsObj = allVars.get(scopeName);
if (gsObj instanceof GlobalScope)
{
gs = (GlobalScope)gsObj;
}
else
{
gs = new GlobalScope(getParentScope(), scopeName, scriptEngine, application)
{
@Override
protected void putScriptVariable(String name, ScriptVariable var, boolean overwriteInitialValue)
{
globalScopeCreateStack.push("var:" + name);
try
{
super.putScriptVariable(name, var, overwriteInitialValue);
}
finally
{
globalScopeCreateStack.pop();
}
}
};
allVars.put(scopeName, gs);
globalScopeCreateStack.push(scopeName);
try
{
gs.createVars();
}
finally
{
globalScopeCreateStack.pop();
}
gs.getModificationSubject().addModificationListener(delegateModificationSubject);
}
return gs;
}
public void reloadVariablesAndScripts()
{
for (Object var : allVars.values().toArray())
{
if (var instanceof GlobalScope)
{
((GlobalScope)var).createScriptProviders(false);
globalScopeCreateStack.push(((GlobalScope)var).getScopeName());
try
{
((GlobalScope)var).createVars();
}
finally
{
globalScopeCreateStack.pop();
}
}
}
}
/**
* @param dataProviderID
* @return
*/
public Object get(String sc, String dataProviderID)
{
String scopeName;
String baseName;
if (sc == null)
{
Pair<String, String> scope = ScopesUtils.getVariableScope(dataProviderID);
scopeName = scope.getLeft();
baseName = scope.getRight();
}
else
{
scopeName = sc;
baseName = ScopesUtils.getVariableScope(dataProviderID).getRight();
}
GlobalScope gs = getGlobalScope(scopeName);
if (gs == null)
{
return null;
}
return gs.get(baseName);
}
public Object executeGlobalFunction(String scopeName, String methodName, Object[] args, boolean focusEvent, boolean throwException) throws Exception
{
GlobalScope gs = getGlobalScope(scopeName);
if (gs == null)
{
return null;
}
Object function = gs.get(methodName);
if (function instanceof Function)
{
return scriptEngine.executeFunction((Function)function, gs, gs, args, focusEvent, throwException);
}
return null;
}
@Override
public Object[] getIds()
{
// just return the names of the global scopes
return allVars.keySet().toArray();
}
@Override
public void destroy()
{
application = null;
for (Object gs : allVars.values())
{
if (gs instanceof GlobalScope)
{
((GlobalScope)gs).getModificationSubject().removeModificationListener(delegateModificationSubject);
((GlobalScope)gs).destroy();
}
}
super.destroy();
}
@Override
public String toString()
{
return "ScopesScope[" + allVars.keySet() + ']';
}
}