/*
GNU GENERAL LICENSE
Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
verion 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
General License for more details.
You should have received a copy of the GNU General Public
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it
*/
package org.lobobrowser.html.js;
import java.net.URL;
import java.util.MissingResourceException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lobobrowser.html.domimpl.DOMNodeImpl;
import org.lobobrowser.http.UserAgentContext;
import org.lobobrowser.js.JavaScript;
import org.lobobrowser.w3c.events.Event;
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;
/**
* The Class Executor.
*/
public class Executor {
/** The Constant logger. */
private static final Logger logger = LogManager.getLogger(Executor.class
.getName());
/**
* This method should be invoked instead of <code>Context.enter</code>.
*
* @param codeSource
* the code source
* @param ucontext
* the ucontext
* @return the context
*/
public static Context createContext(URL codeSource,
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.
try {
ctx.setSecurityController(new SecurityControllerImpl(
codeSource, ucontext.getSecurityPolicy()));
} catch (MissingResourceException err) {
logger.error("Missing Resource");
}
}
return ctx;
}
/**
* Execute function.
*
* @param element
* the element
* @param f
* the f
* @param event
* the event
* @return true, if successful
*/
public static boolean executeFunction(DOMNodeImpl element, Function f,
Event event) {
return Executor.executeFunction(element, element, f, event);
}
/**
* Execute function.
*
* @param element
* the element
* @param thisObject
* the this object
* @param f
* the f
* @param event
* the event
* @return true, if successful
*/
public static boolean executeFunction(DOMNodeImpl element,
Object thisObject, Function f, 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 ex) {
logger.log(
Level.WARN,
"executeFunction(): There was an error in Javascript code.",
ex);
return true;
}
} finally {
Context.exit();
}
}
/**
* Execute function.
*
* @param thisScope
* the this scope
* @param f
* the f
* @param codeSource
* the code source
* @param ucontext
* the ucontext
* @return true, if successful
*/
public static boolean executeFunction(Scriptable thisScope, Function f,
URL codeSource, 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 (Throwable err) {
err.getCause();
return true;
}
} finally {
Context.exit();
}
}
/**
* A document <code>UserData</code> key used to map Javascript scope in the
* HTML document.
*/
public static final String SCOPE_KEY = "cobra.js.scope";
}