/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA 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 version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher.expressions.tmlscript.wgaglobal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.beanutils.WrapDynaBean;
import org.apache.log4j.Logger;
import org.hibernate.mapping.Fetchable;
import de.innovationgate.ext.org.mozilla.javascript.Context;
import de.innovationgate.ext.org.mozilla.javascript.EvaluatorException;
import de.innovationgate.ext.org.mozilla.javascript.Function;
import de.innovationgate.ext.org.mozilla.javascript.JavaScriptException;
import de.innovationgate.ext.org.mozilla.javascript.NativeJavaObject;
import de.innovationgate.ext.org.mozilla.javascript.NativeObject;
import de.innovationgate.ext.org.mozilla.javascript.Scriptable;
import de.innovationgate.ext.org.mozilla.javascript.ScriptableObject;
import de.innovationgate.ext.org.mozilla.javascript.Wrapper;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDesignProvider;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGLanguage;
import de.innovationgate.wga.common.CodeCompletion;
import de.innovationgate.wga.common.beans.csconfig.v1.PluginConfig;
import de.innovationgate.wgpublisher.design.OverlayDesignProvider;
import de.innovationgate.wgpublisher.design.db.PluginDesignProvider;
import de.innovationgate.wgpublisher.expressions.tmlscript.ContextRedirector;
import de.innovationgate.wgpublisher.expressions.tmlscript.RhinoContext;
import de.innovationgate.wgpublisher.expressions.tmlscript.RhinoExpressionEngine;
import de.innovationgate.wgpublisher.expressions.tmlscript.RhinoExpressionEngineImpl;
import de.innovationgate.wgpublisher.expressions.tmlscript.TMLScriptGlobal;
import de.innovationgate.wgpublisher.expressions.tmlscript.TMLScriptRootScope;
import de.innovationgate.wgpublisher.expressions.tmlscript.ThreadLocalPreserver;
import de.innovationgate.wgpublisher.expressions.tmlscript.VarArgParser;
import de.innovationgate.wgpublisher.expressions.tmlscript.VarArgParser.Arguments;
import de.innovationgate.wgpublisher.labels.WGAResourceBundle;
import de.innovationgate.wgpublisher.labels.WGAResourceBundleManager;
import de.innovationgate.wgpublisher.plugins.WGAPluginSet;
import de.innovationgate.wgpublisher.webtml.utils.TMLAction;
import de.innovationgate.wgpublisher.webtml.utils.TMLActionException;
import de.innovationgate.wgpublisher.webtml.utils.TMLContext;
import de.innovationgate.wgpublisher.webtml.utils.TMLDesignContext;
@CodeCompletion(delegate=DesignCC.class)
public class Design extends NativeObject {
public static VarArgParser _getGlobalArgs;
private static VarArgParser _registerGlobalVarargs;
private static VarArgParser _getLabelBundleVarargs;
static {
_getGlobalArgs = new VarArgParser("getGlobal")
.add("global", String.class)
.pack();
_registerGlobalVarargs = (new VarArgParser("registerGlobal"))
.add("name", String.class, false)
.add("ref", Object.class, false)
.pack();
_getLabelBundleVarargs = (new VarArgParser("getLabelBundle"))
.add("container", String.class, true)
.add("file", String.class, true)
.add("language", String.class, false)
.pack();
}
public static Design getCurrent() throws JavaScriptException, WGException {
return new Design(null);
}
private TMLDesignContext _designContext;
private TMLAction _currentAction = null;
private NativeObject _currentObject = null;
private boolean _isCurrentScriptDesign = false;
public Design(Object ref) throws JavaScriptException, WGException {
String[] functions = {
"callAction",
"createObject",
"db",
"getLabelBundle",
"isCustomized",
"label",
"loadObjectDefinition",
"getGlobal",
"plugin",
"registerDbGlobal",
"registerGlobal"
};
defineFunctionProperties(functions, Design.class, DONTENUM);
if (ref instanceof Wrapper) {
ref = ((Wrapper) ref).unwrap();
}
TMLContext tmlContext = WGAGlobal.fetchInitialContext(Context.getCurrentContext());
if (ref == null) {
_designContext = tmlContext.getDesignContext();
_currentAction = WGAGlobal.currentAction(Context.getCurrentContext(), null);
_isCurrentScriptDesign = true;
}
else if (ref instanceof WGDatabase) {
_designContext = tmlContext.getDesignContext().createContextDelegate((WGDatabase) ref, null);
}
else if (ref instanceof String) {
WGDatabase designDB = tmlContext.db((String) ref);
if (designDB != null && designDB.isSessionOpen()) {
_designContext = tmlContext.getDesignContext().createContextDelegate((WGDatabase) designDB, null);
}
}
else if (ref instanceof NativeObject) {
_currentObject = (NativeObject) ref;
_currentAction = WGAGlobal.currentAction(Context.getCurrentContext(), _currentObject);
if (_currentAction == null) {
throw new IllegalArgumentException("Cannot determine design of parameter object");
}
String dbKey = _currentAction.getModuleDatabase();
WGDatabase designDB = tmlContext.db(dbKey);
if (designDB != null && designDB.isSessionOpen()) {
_designContext = tmlContext.getDesignContext().createContextDelegate((WGDatabase) designDB, null);
}
}
else {
throw new IllegalArgumentException("Invalid parameter object type " + ref.getClass().getName());
}
if (_designContext == null) {
throw new IllegalArgumentException("Cannot determine design");
}
sealObject();
}
public static Object getGlobal(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException, WGAPIException {
Design design = unwrapThisObj(thisObj);
Arguments arguments = _getGlobalArgs.parse(args);
TMLContext context = WGAGlobal.fetchInitialContext(cx);
TMLScriptGlobal global = context.getwgacore().getTmlscriptGlobalRegistry().getGlobal((String) arguments.get("global"), design._designContext.getDesignDB());
if (global != null) {
return TMLScriptRootScope.provideGlobal(global, thisObj);
}
else {
return null;
}
}
public static String label(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException, WGAPIException {
Design design = unwrapThisObj(thisObj);
TMLContext context = WGAGlobal.fetchInitialContext(cx);
Arguments parsedArgs = WGAGlobal._localLabelVarargs.parse(args);
return context.label(design._designContext.getDesignDB(), (String) parsedArgs.get("container"), (String) parsedArgs.get("file"), (String) parsedArgs.get("key"), (List) parsedArgs.get("params"));
}
public static WGAResourceBundle getLabelBundle(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException, WGAPIException, IOException {
TMLContext tmlContext = WGAGlobal.fetchInitialContext(cx);
Design design = (Design) thisObj;
Arguments varArgs = _getLabelBundleVarargs.parse(args);
WGAResourceBundleManager manager = tmlContext.getwgacore().getResourceBundleManager(design._designContext.getDesignDB());
String container = (String) varArgs.get("container");
if (container == null) {
container = WGAResourceBundleManager.CONTAINER_DEFAULT;
}
String file = (String) varArgs.get("file");
if (file == null) {
file = WGAResourceBundleManager.FILE_DEFAULT;
}
Locale locale = WGLanguage.languageNameToLocale((String) varArgs.get("language"));
return manager.getBundle(container, file, locale);
}
public static void registerGlobal(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) {
VarArgParser.Arguments parsedArgs = _registerGlobalVarargs.parse(args);
TMLContext context = WGAGlobal.fetchInitialContext(cx);
String name = (String) parsedArgs.get("name");
Object ref = parsedArgs.get("ref");
// Register name against package or class name
if (ref instanceof String) {
context.getwgacore().getTmlscriptGlobalRegistry().registerGlobal(new TMLScriptGlobal(name, TMLScriptGlobal.TYPE_PACKAGE_OR_CLASS, ref));
}
else {
context.getwgacore().getTmlscriptGlobalRegistry().registerGlobal(new TMLScriptGlobal(name, TMLScriptGlobal.TYPE_OBJECT, ref));
}
}
public static void registerDbGlobal(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) {
Design design = unwrapThisObj(thisObj);
VarArgParser.Arguments parsedArgs = _registerGlobalVarargs.parse(args);
TMLContext context = WGAGlobal.fetchInitialContext(cx);
String name = (String) parsedArgs.get("name");
Object ref = parsedArgs.get("ref");
// Register name against package or class name
if (ref instanceof String) {
context.getwgacore().getTmlscriptGlobalRegistry().registerDBGlobal(new TMLScriptGlobal(name, TMLScriptGlobal.TYPE_PACKAGE_OR_CLASS, ref), design._designContext.getDesignDB());
}
else {
context.getwgacore().getTmlscriptGlobalRegistry().registerDBGlobal(new TMLScriptGlobal(name, TMLScriptGlobal.TYPE_OBJECT, ref), design._designContext.getDesignDB());
}
}
public static WGDatabase db(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException {
Design design = unwrapThisObj(thisObj);
return design._designContext.getDesignDB();
}
private static Design unwrapThisObj(Scriptable thisObj) {
return (Design) thisObj;
}
public static Plugin plugin(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException, WGException {
TMLContext context = WGAGlobal.fetchInitialContext(cx);
Design design = unwrapThisObj(thisObj);
WGDatabase designDb = design._designContext.getDesignDB();
// Look if the design db is a plugin itself
if (designDb.getDbReference().startsWith(PluginConfig.PLUGIN_DBKEY_PREFIX)) {
return new Plugin(designDb);
}
// Follow to the design provider
WGDesignProvider provider = designDb.getDesignProvider();
if (!(provider instanceof PluginDesignProvider)) {
return null;
}
PluginDesignProvider pluginProvider = (PluginDesignProvider) provider;
String dbKey = pluginProvider.getDesignDBKey();
WGDatabase db = context.db(dbKey);
if (db == null) {
return null;
}
return new Plugin(db);
}
public static Object callAction(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException {
Design design = unwrapThisObj(thisObj);
// For the current design redirect to WGAGlobal.callAction() which uses all location info from the current design
if (design._isCurrentScriptDesign) {
RhinoExpressionEngineImpl runtime = WGAGlobal.fetchRuntime(cx);
return WGAGlobal.callAction(cx, runtime.getSharedScope().getWgaGlobal(), args, funObj);
}
VarArgParser.Arguments parsedArgs = WGAGlobal._callActionVarargs.parse(args);
// Determine action id and action context
TMLContext context = (TMLContext) parsedArgs.get("context");
if (context == null) {
context = WGAGlobal.fetchInitialContext(cx);
}
String actionID = (String) parsedArgs.get("id");
List actionArgs = new ArrayList(parsedArgs.getOverflowArgs());
// Locate action
TMLAction action;
if (design._currentObject != null) {
TMLAction.Locator locator = WGAGlobal.determineActionLocator(cx, design._currentObject, context, actionID);
action = context.getActionByID(locator.getId(), locator.getDbkey());
}
else {
action = context.getActionByID(actionID, design._designContext.getDesignDB().getDbReference());
}
if (action == null) {
throw new EvaluatorException("Could not retrieve action for ID '" + actionID + "'");
}
// Call action
Object actionResult;
try {
TMLScriptRootScope rootScope = WGAGlobal.fetchRootScope(cx);
actionResult = context.callCustomAction(action, actionArgs, rootScope.getData().getUnwrappedGlobalScopeObjects());
}
catch (WGAPIException e) {
throw Context.throwAsScriptRuntimeEx(e);
}
return Context.javaToJS(actionResult, thisObj);
}
public static Scriptable createObject(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException {
Design design = unwrapThisObj(thisObj);
// For the current design redirect to WGAGlobal.createObject() which uses all location info from the current design
if (design._isCurrentScriptDesign) {
RhinoExpressionEngineImpl runtime = WGAGlobal.fetchRuntime(cx);
return WGAGlobal.createObject(cx, runtime.getSharedScope().getWgaGlobal(), args, funObj);
}
VarArgParser.Arguments parsedArgs = WGAGlobal._createObjectVarargs.parse(args);
// Retrieve object definition, either as script or as Function object
Object definition = parsedArgs.get("definition");
Function func;
if (definition instanceof Function) {
func = (Function) args[0];
}
else {
func = loadObjectDefinition(cx, design, args, funObj);
}
// Construct the object
Scriptable obj = func.construct(cx, thisObj, new Object[] {});
Scriptable topLevelScope = ScriptableObject.getTopLevelScope(thisObj);
// Put the action definition to the object, so it "knows" where it's
// definition came from
TMLAction action = (TMLAction) func.get(RhinoExpressionEngine.PARAM_ACTIONDEFINITION, func);
if (action != null) {
obj.put(RhinoExpressionEngine.PARAM_ACTIONDEFINITION, obj, action);
}
// Execute constructor
Object initObj = obj.get("init", obj);
if (initObj != null && initObj instanceof Function) {
((Function) initObj).call(cx, thisObj, obj, new ArrayList(parsedArgs.getOverflowArgs()).toArray());
}
return obj;
}
public static Function loadObjectDefinition(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) throws JavaScriptException {
Design design = unwrapThisObj(thisObj);
// For the current design redirect to WGAGlobal.loadObjectDefinition() which uses all location info from the current design
if (design._isCurrentScriptDesign) {
RhinoExpressionEngineImpl runtime = WGAGlobal.fetchRuntime(cx);
return WGAGlobal.loadObjectDefinition(cx, runtime.getSharedScope().getWgaGlobal(), args, funObj);
}
VarArgParser.Arguments parsedArgs = WGAGlobal._loadObjectDefVarags.parse(args);
TMLContext context = WGAGlobal.fetchInitialContext(cx);
String actionID = (String) parsedArgs.get("id");
NativeObject currentObject = (NativeObject) parsedArgs.get("currentObject");
// Get the function def (might need to expand local name by the name of
// the current action)
// Locate object definition
TMLAction action = null;
try {
if (design._currentObject != null) {
TMLAction.Locator locator = WGAGlobal.determineActionLocator(cx, design._currentObject, context, actionID);
action = context.getModuleActionByID(locator.getId(), locator.getDbkey());
}
else {
action = context.getModuleActionByID(actionID, design._designContext.getDesignDB().getDbReference());
}
}
catch (TMLActionException e) {
throw new EvaluatorException("Could not retrieve TMLScript module '" + args[0] + "': " + e.getMessage());
}
if (action == null) {
throw new EvaluatorException("Could not retrieve TMLScript module '" + args[0] + "'");
}
// Fetch runtime and return function object
RhinoExpressionEngineImpl runtime = WGAGlobal.fetchRuntime(cx);
// Use Context Redirector as scope, so the objects implicit context always directs to the current script's context
ContextRedirector redirector = new ContextRedirector();
// Preserve thread locals
ThreadLocalPreserver preserver = new ThreadLocalPreserver((RhinoContext) cx);
preserver.preserve(RhinoExpressionEngine.TL_ACTIONDEFINITION, action);
preserver.preserve(RhinoExpressionEngine.TL_SCRIPTNAME, "TMLScript-Object " + action.getModuleDatabase() + "/" + action.getModuleName());;
try {
Function func = runtime.getCompiledFunction(action.getCode(), (RhinoContext) cx, redirector);
func.put(RhinoExpressionEngine.PARAM_ACTIONDEFINITION, func, action);
return func;
}
finally {
preserver.restore();
}
}
public static boolean isCustomized(Context cx, Scriptable thisObj, java.lang.Object[] args, Function funObj) {
Design design = unwrapThisObj(thisObj);
WGDesignProvider designProvider = design._designContext.getDesignDB().getDesignProvider();
return (designProvider instanceof OverlayDesignProvider);
}
}