/*
* GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Contact info: xamjadmin@users.sourceforge.net
*/
package org.cobra_grendel.html.js;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.cobra_grendel.html.UserAgentContext;
import org.cobra_grendel.html.domimpl.NodeImpl;
import org.cobra_grendel.js.JavaScript;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.w3c.dom.Document;
public class Executor
{
/**
* A document <code>UserData</code> key used to map Javascript scope in the HTML document.
*/
public static final String SCOPE_KEY = "cobra.js.scope";
private static final Logger logger = Logger.getLogger(Executor.class.getName());
/**
* This method should be invoked instead of <code>Context.enter</code>.
*
* @param codeSource
* @param ucontext
*/
public static Context createContext(final java.net.URL codeSource, final UserAgentContext ucontext)
{
Context prev = Context.getCurrentContext();
Context ctx = Context.enter();
ctx.setOptimizationLevel(ucontext.getScriptingOptimizationLevel());
if (prev == null)
{
// If there was a previous context, this one must be nested.
// We still need to create a context because of exit() but
// we cannot set a new security controller.
ctx.setSecurityController(new SecurityControllerImpl(codeSource, ucontext.getSecurityPolicy()));
}
return ctx;
}
public static boolean executeFunction(final NodeImpl element, final Function f, final Event event)
{
return Executor.executeFunction(element, element, f, event);
}
public static boolean executeFunction(final NodeImpl element, final Object thisObject, final Function f, final Event event)
{
Document doc = element.getOwnerDocument();
if (doc == null)
{
throw new IllegalStateException("Element does not belong to a document.");
}
Context ctx = createContext(element.getDocumentURL(), element.getUserAgentContext());
try
{
Scriptable scope = (Scriptable) doc.getUserData(Executor.SCOPE_KEY);
if (scope == null)
{
throw new IllegalStateException("Scriptable (scope) instance was expected to be keyed as UserData to document using " + Executor.SCOPE_KEY);
}
JavaScript js = JavaScript.getInstance();
Scriptable thisScope = (Scriptable) js.getJavascriptObject(thisObject, scope);
try
{
Scriptable eventScriptable = (Scriptable) js.getJavascriptObject(event, thisScope);
ScriptableObject.defineProperty(thisScope, "event", eventScriptable, ScriptableObject.READONLY);
Object result = f.call(ctx, thisScope, thisScope, new Object[0]);
if (!(result instanceof Boolean))
{
return true;
}
return ((Boolean) result).booleanValue();
}
catch (Exception thrown)
{
logger.log(Level.WARNING, "executeFunction(): There was an error in Javascript code.", thrown);
return true;
}
}
finally
{
Context.exit();
}
}
public static boolean executeFunction(final Scriptable thisScope, final Function f, final java.net.URL codeSource, final UserAgentContext ucontext)
{
Context ctx = createContext(codeSource, ucontext);
try
{
try
{
Object result = f.call(ctx, thisScope, thisScope, new Object[0]);
if (!(result instanceof Boolean))
{
return true;
}
return ((Boolean) result).booleanValue();
}
catch (Exception err)
{
logger.log(Level.WARNING, "executeFunction(): Unable to execute Javascript function " + f.getClassName() + ".", err);
return true;
}
}
finally
{
Context.exit();
}
}
}