/*******************************************************************************
* 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.webtml.utils;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import de.innovationgate.utils.UIDGenerator;
import de.innovationgate.utils.URLBuilder;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGAuthorisationException;
import de.innovationgate.webgate.api.WGCSSJSModule;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGIllegalStateException;
import de.innovationgate.webgate.api.WGScriptModule;
import de.innovationgate.webgate.api.WGUnavailableException;
import de.innovationgate.webgate.api.locking.LockException;
import de.innovationgate.wgpublisher.LoginException;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.WGPRequestPath;
import de.innovationgate.wgpublisher.expressions.tmlscript.RhinoExpressionEngine;
import de.innovationgate.wgpublisher.expressions.tmlscript.TMLScriptException;
import de.innovationgate.wgpublisher.webtml.Base;
public class TMLAction implements Serializable {
public static final int ORIGIN_TML = 1;
public static final int ORIGIN_SCRIPT_MODULE = 2;
public static final int ORIGIN_DEFAULT = 3;
public static class Locator {
private String _dbkey;
private String _id;
public Locator(String dbkey, String id) {
_dbkey = dbkey;
_id = id;
}
/**
* @return Returns the dbkey.
*/
public String getDbkey() {
return _dbkey;
}
/**
* @return Returns the id.
*/
public String getId() {
return _id;
}
}
public static final String DEFAULTACTION_RESET = "reset";
public static final String DEFAULTACTION_REFRESH = "refresh";
public static final String DEFAULTACTION_CHANGELANGUAGE = "changelanguage";
public static final String DEFAULTACTION_STORE = "store";
public static final String DEFAULTACTION_ATTACH = "attach";
public static final String DEFAULTACTION_LOGIN = "login";
public static final String DEFAULTACTION_SETSESSIONVAR = "setsessionvar";
public static final String DEFAULTACTION_SETPSESSIONVAR = "setpsessionvar";
public static final String DEFAULTACTION_SETVAR = "setvar";
public static final String DEFAULTACTION_SETPVAR = "setpvar";
public static final String DEFAULTACTION_HDBSTORE = "hdbstore";
public static final String DEFAULTACTION_INCVAR = "incvar";
public abstract static class DefaultAction {
private String _name;
private boolean _debounced;
public DefaultAction(String name, boolean debounced) {
_name = name;
_debounced = debounced;
}
public DefaultAction() {
}
/**
* @return Returns the debounced.
*/
public boolean isDebounced() {
return _debounced;
}
/**
* @return Returns the name.
*/
public String getName() {
return _name;
}
public abstract Object call(TMLContext context, List params) throws TMLException, TMLScriptException, WGException, IOException;
}
public static Map _defaultActions = new HashMap();
static {
DefaultAction action;
action = new DefaultAction(DEFAULTACTION_ATTACH, true) {
public Object call(TMLContext context, List params) throws WGAPIException, IOException, TMLException {
return TMLAction.defaultActionAttach(context);
}
};
_defaultActions.put(action.getName(), action);
// This default action MUST remain un-debounced, bc. it normally is not directly invoked via action-URL but via ~changelanguage-Pathsyntax in a regular URL
action = new DefaultAction(DEFAULTACTION_CHANGELANGUAGE, false) {
public Object call(TMLContext context, List params) throws WGAuthorisationException, WGUnavailableException, LockException, TMLException {
return TMLAction.defaultActionChangeLanguage(context, (String) params.get(0));
}
};
_defaultActions.put(action.getName(), action);
action = new DefaultAction(DEFAULTACTION_REFRESH, true) {
public Object call(TMLContext context, List params) throws WGAuthorisationException, WGUnavailableException, LockException, TMLException {
return new Boolean(true);
}
};
_defaultActions.put(action.getName(), action);
action = new DefaultAction(DEFAULTACTION_RESET, true) {
public Object call(TMLContext context, List params) throws WGAuthorisationException, WGUnavailableException, LockException, TMLException {
return TMLAction.defaultActionReset(context);
}
};
_defaultActions.put(action.getName(), action);
action = new DefaultAction(DEFAULTACTION_STORE, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
return TMLAction.defaultActionStore(context);
}
};
_defaultActions.put(action.getName(), action);
action= new DefaultAction(DEFAULTACTION_SETSESSIONVAR, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
return TMLAction.defaultActionSetSessionVar(context, params);
}
};
_defaultActions.put(action.getName(), action);
action= new DefaultAction(DEFAULTACTION_SETVAR, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
return TMLAction.defaultActionSetVar(context, params);
}
};
_defaultActions.put(action.getName(), action);
action= new DefaultAction(DEFAULTACTION_SETPVAR, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
return TMLAction.defaultActionSetPortletVar(context, params);
}
};
_defaultActions.put(action.getName(), action);
action= new DefaultAction(DEFAULTACTION_SETPSESSIONVAR, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
return TMLAction.defaultActionSetPortetSessionVar(context, params);
}
};
_defaultActions.put(action.getName(), action);
action= new DefaultAction(DEFAULTACTION_HDBSTORE, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException, TMLScriptException {
return TMLAction.defaultActionHDBStore(context, params);
}
};
_defaultActions.put(action.getName(), action);
action = new DefaultAction(DEFAULTACTION_INCVAR, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException, TMLScriptException {
return TMLAction.defaultActionIncVar(context, params);
}
};
_defaultActions.put(action.getName(), action);
action = new DefaultAction(DEFAULTACTION_LOGIN, true) {
public Object call(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException, TMLScriptException, LoginException {
TMLAction.defaultActionLogin(context, params);
return null;
}
};
_defaultActions.put(action.getName(), action);
}
public static final String CUSTOMACTION = "custom";
private boolean _async;
private boolean _master;
private String _code;
private String _moduleName;
private Date _moduleDate;
private String _moduleDatabase = null;
private String _ID;
//private int _sequence;
private String _type;
private int _origin;
private boolean _debounce;
private int _timeout;
private Set _calledSequenceIds = new LinkedHashSet();
public static final String OBJ_ACTION_PARAMS = "actionparams";
public TMLAction() {
_debounce = true;
_timeout = RhinoExpressionEngine.DEFAULT_SCRIPTTIMEOUT;
}
protected static void defaultActionLogin(TMLContext context, List params) throws WGAPIException, LoginException, IOException, TMLException {
String username = null;
String password = null;
String domain = (String) context.meta("db", "domain");
String redirect = null;
TMLForm form = context.gettmlform();
if (form != null) {
if (form.hasfield("user")) {
username = (String) form.field("user");
}
else if (form.hasfield("username")) {
username = (String) form.field("username");
}
if (form.hasfield("password")) {
password = (String) form.field("password");
}
else if (form.hasfield("pwd")) {
password = (String) form.field("pwd");
}
if (form.hasfield("domain")) {
domain = (String) form.field("domain");
}
if (form.hasfield("redirect")) {
redirect = (String) form.field("redirect");
}
}
if (username == null && params.size() >= 1 && params.get(0) != null) {
username = String.valueOf(params.get(0));
}
if (password == null && params.size() >= 2 && params.get(1) != null) {
password = String.valueOf(params.get(1));
}
if (domain == null && params.size() >= 3 && params.get(2) != null) {
domain = String.valueOf(params.get(2));
}
if (redirect == null && params.size() >= 4 && params.get(3) != null) {
redirect = String.valueOf(params.get(3));
}
if (context.login(username, password, domain)) {
if (redirect != null) {
context.redirectto(redirect);
}
}
else {
context.setvar("loginerror", 1);
throw new TMLException("Login failed", false);
}
}
public static Object defaultActionSetSessionVar(TMLContext context, List params) throws TMLException {
if (params.size() < 2) {
throw new TMLException("Default action $" + DEFAULTACTION_SETSESSIONVAR + " needs 2 arguments while only " + params.size() + " were provided", false);
}
context.setsessionvar(String.valueOf(params.get(0)), params.get(1));
try {
return context.item("tmlparam2");
}
catch (WGAPIException e) {
throw new TMLException("Error retrieving item tmlparam2", false);
}
}
public static Object defaultActionSetPortetSessionVar(TMLContext context, List params) throws TMLException, WGAPIException {
if (params.size() < 2) {
throw new TMLException("Default action $" + DEFAULTACTION_SETPSESSIONVAR + " needs 2 arguments while only " + params.size() + " were provided", false);
}
if (context.getportlet() == null) {
throw new TMLException("Default action $" + DEFAULTACTION_SETPSESSIONVAR + " can only be called inside a WebTML portlet", false);
}
context.getportlet().setsessionvar(String.valueOf(params.get(0)), params.get(1));
try {
return context.item("tmlparam2");
}
catch (WGAPIException e) {
throw new TMLException("Error retrieving item tmlparam2", false);
}
}
public static Object defaultActionSetVar(TMLContext context, List params) throws TMLException, WGAPIException {
if (params.size() < 2) {
throw new TMLException("Default action $" + DEFAULTACTION_SETVAR + " needs 2 arguments while only " + params.size() + " were provided", false);
}
context.setvar(String.valueOf(params.get(0)), params.get(1));
try {
return context.item("tmlparam2");
}
catch (WGAPIException e) {
throw new TMLException("Error retrieving item tmlparam2", false);
}
}
public static Object defaultActionIncVar(TMLContext context, List params) throws TMLException, WGAPIException {
if (params.size() < 1) {
throw new TMLException("Default action $" + DEFAULTACTION_INCVAR + " needs 1 arguments while only " + params.size() + " were provided", false);
}
try {
String varName = String.valueOf(params.get(0));
Number num = (Number) context.item(varName);
if (num == null) {
num = 0;
}
num = num.intValue() + 1;
context.updateOrSetVar(varName, num);
return num;
}
catch (Exception e) {
throw new TMLException("Error executing default action 'incvar'", e, false);
}
}
public static Object defaultActionSetPortletVar(TMLContext context, List params) throws TMLException, WGAPIException {
if (params.size() < 2) {
throw new TMLException("Default action $" + DEFAULTACTION_SETPVAR + " needs 2 arguments while only " + params.size() + " were provided", false);
}
if (context.getportlet() == null) {
throw new TMLException("Default action $" + DEFAULTACTION_SETPVAR + " can only be called inside a WebTML portlet", false);
}
context.getportlet().setvar(String.valueOf(params.get(0)), params.get(1));
try {
return context.item("tmlparam2");
}
catch (WGAPIException e) {
throw new TMLException("Error retrieving item tmlparam2", false);
}
}
public TMLAction(String code, boolean master, boolean async, boolean debounce, int origin) {
_type = CUSTOMACTION;
_code = code;
_master = master;
_async = async;
_debounce = debounce;
_origin = origin;
_timeout = RhinoExpressionEngine.DEFAULT_SCRIPTTIMEOUT;
}
/**
* Constructor for default actions.
* @param type The type of the default action
*/
public TMLAction(String type) {
_code = "";
_master = false;
_async = false;
_debounce = true;
_timeout = RhinoExpressionEngine.DEFAULT_SCRIPTTIMEOUT;
_origin = ORIGIN_DEFAULT;
// remove leading "$"
String checkType = type.substring(1);
// check for supported action and set
if (_defaultActions.containsKey(checkType)) {
_type = checkType;
}
else {
throw new IllegalArgumentException("unsupported defaultaction '" + type + "'");
}
setID(type);
}
/**
* Returns the code.
* @return String
*/
public String getCode() {
return _code;
}
/**
* Returns the key.
* hashcode from all properties
* @return Integer
*/
public Integer getKey() {
return new Integer(new HashCodeBuilder()
.append(_async)
.append(_master)
.append(_code)
.append(_type)
.append(_debounce)
.append(_timeout)
.append(_moduleDatabase != null ? _moduleDatabase : "nodb")
.toHashCode());
}
public static Boolean defaultActionAttach(TMLContext context) throws WGAPIException, IOException, TMLException {
TMLForm tmlForm = context.gettmlform();
if (!context.getdocument().getDatabase().getSessionContext().isMasterSession()) {
TMLContext.MasterAction masterAction = new TMLContext.MasterAction(context, TMLAction.DEFAULTACTION_ATTACH, new ArrayList());
masterAction.start();
context.getdocument().getDatabase().reopenSession();
}
else {
WGDocument doc = context.getdocument();
tmlForm.attach(doc);
doc.save();
}
return new Boolean(true);
}
/**
* @param context
* @throws IOException
* @throws WGAPIException
* @throws WGIllegalStateException
*/
public static Boolean defaultActionStore(TMLContext context) throws TMLException, WGAPIException, IOException, WGIllegalStateException {
TMLForm tmlForm = context.gettmlform();
if (tmlForm == null) {
throw new TMLException("Cannot store form because there is no form", false);
}
String formSource = tmlForm.getFormSource();
if (formSource == null) {
throw new TMLException("Cannot store form because the form source is empty", false);
}
if( context.isbrowserinterface() ){
context.getcontent().getDatabase().getSessionContext().setClient( WGACore.getBIClientString() );
}
else{
context.getcontent().getDatabase().getSessionContext().setClient( WGACore.getWebformClientString() );
}
if (formSource.equals("content")) {
tmlForm.storeincontent();
}
else if (formSource.equals("profile")) {
tmlForm.storeinprofile();
}
else if (formSource.equals("portlet")) {
tmlForm.storeinportlet();
}
else {
throw new TMLException(
"Cannot store form because the form source is invalid for this action: " + String.valueOf(formSource),
false);
}
// There are files to attach
if (tmlForm.getfilenames().size() > 0) {
defaultActionAttach(context);
}
return new Boolean(true);
}
public static Boolean defaultActionHDBStore(TMLContext context, List params) throws TMLException, WGAPIException, IOException, WGIllegalStateException, TMLScriptException {
TMLForm tmlForm = context.gettmlform();
if (tmlForm == null) {
throw new TMLException("Cannot store form because there is no form", false);
}
String formSource = tmlForm.getFormSource();
if (formSource == null) {
throw new TMLException("Cannot store form because the form source is empty", false);
}
if( context.isbrowserinterface() ){
context.getcontent().getDatabase().getSessionContext().setClient( WGACore.getBIClientString() );
}
else{
context.getcontent().getDatabase().getSessionContext().setClient( WGACore.getWebformClientString() );
}
if (formSource.equals("content") || formSource.equals("none") || formSource.equals("newcontent")) {
Object param = null;
if (params.size() >= 1) {
param = params.get(0);
}
tmlForm.storeinhdb(param);
}
else {
throw new TMLException(
"Cannot store form in HDB because the form source is invalid for this action: " + String.valueOf(formSource),
false);
}
// There are files to attach
if (tmlForm.getfilenames().size() > 0) {
defaultActionAttach(context);
}
return new Boolean(true);
}
public static Boolean defaultActionChangeLanguage(TMLContext context, String lang) throws TMLException {
lang = lang.toLowerCase();
if (lang == null || lang.equals("")) {
throw new TMLException("Cannot set language because language parameter was empty", false);
}
TMLContext langContext = null;
try {
TMLContext mainContext = context.getmaincontext();
if (!mainContext.meta("language").equals(lang)) {
langContext = context.context("this<" + lang + ">");
if (!langContext.meta("language").equals(lang)) {
throw new TMLException(
"Cannot change language because the current document is not available in language '" + lang + "'",
false);
}
}
else {
langContext = mainContext;
}
} catch (WGAPIException e) {
throw new TMLException("Error retrieving current document in new language" , e, true);
}
// Obsolete
//context.setpreferredlanguage(lang);
HttpServletRequest request = context.getrequest();
WGPRequestPath path = (WGPRequestPath) request.getAttribute(WGACore.ATTRIB_REQUESTPATH);
try {
URLBuilder urlBuilder = new URLBuilder(null, 0, null, langContext.contenturl(path.getMediaKey(), path.getLayoutKey()), context.getrequest().getQueryString());
if (urlBuilder.hasParameter("$action")) {
urlBuilder.removeParameter("$action");
}
context.redirectto(urlBuilder.rebuild(false));
}
catch (IOException e) {
throw new TMLException("Error redirecting to new language", e, true);
}
catch (WGAPIException e) {
throw new TMLException("Error redirecting to new language" ,e, true);
}
return new Boolean(true);
}
public static Boolean defaultActionReset(TMLContext context) throws TMLException {
TMLForm tmlForm = context.gettmlform();
if (tmlForm == null) {
throw new TMLException("Cannot reset form because there is no form", false);
}
tmlForm.reset();
return new Boolean(true);
}
public boolean isAsync() {
return _async;
}
/**
* @return
*/
public boolean isMaster() {
return _master;
}
/**
* @param b
*/
public void setAsync(boolean b) {
_async = b;
}
/**
* @param string
*/
public void setCode(String string) {
_code = string;
}
/**
* @param b
*/
public void setMaster(boolean b) {
_master = b;
}
/**
* @return Returns the sequence.
* @throws WGAPIException
*/
/*public int getSequence() {
return _sequence;
}*/
/*
public void incrementSequence() {
_sequence++;
}*/
public TMLActionLink createActionLink(List params, TMLContext context) throws WGAPIException {
TMLActionLink actionLink = new TMLActionLink(context.gethttpsession());
actionLink.setSequenceId(isDebounce() ? UIDGenerator.generateUID() : TMLActionLink.EMPTY_PARAM);
if (_type.equals(CUSTOMACTION)) {
actionLink.setActionKey(this.getKey().toString());
} else {
actionLink.setActionKey("$" + this._type);
}
// Determine db key and context path
actionLink.setDbKey((String) context.getdocument().getDatabase().getAttribute(WGACore.DBATTRIB_DBKEY));
if (!context.getdocument().isTemporary()) {
actionLink.setContextPath(context.getpath());
}
else {
actionLink.setContextPath(TMLActionLink.EMPTY_PARAM);
}
// Determine portlet key, if present
String portletKey = TMLActionLink.EMPTY_PARAM;
TMLPortlet portlet = context.getportlet();
if (portlet != null && !portlet.isroot()) {
portletKey = portlet.getportletkey();
}
actionLink.setPortletKey(portletKey);
// Determine WebTML scope
String scope = (String) context.option(Base.OPTION_WEBTML_SCOPE);
if (scope != null) {
actionLink.setWebtmlScope(scope);
}
// Set action params
if (params == null) {
params = new ArrayList();
}
Iterator paramsIt = params.iterator();
actionLink.setParam1((String) (paramsIt.hasNext() ? paramsIt.next() : null));
actionLink.setParam2((String) (paramsIt.hasNext() ? paramsIt.next() : null));
actionLink.setParam3((String) (paramsIt.hasNext() ? paramsIt.next() : null));
actionLink.setParam4((String) (paramsIt.hasNext() ? paramsIt.next() : null));
actionLink.setParam5((String) (paramsIt.hasNext() ? paramsIt.next() : null));
return actionLink;
}
public String getType() {
return _type;
}
public void setType(String type) {
_type = type;
}
public boolean isDebounce() {
return _debounce;
}
public void setDebounce(boolean debounce) {
_debounce = debounce;
}
public int getTimeout() {
return _timeout;
}
public void setTimeout(int timeout) {
_timeout = timeout;
}
public boolean sequenceIdAlreadyUsed(String sequenceId) {
return _calledSequenceIds.contains(sequenceId);
}
public void calledWithSequenceId(String sequenceId) {
// add sequence Id to set
_calledSequenceIds.add(sequenceId);
if (_calledSequenceIds.size() > 1000) {
// if size exceeded remove first
Iterator it = _calledSequenceIds.iterator();
it.next();
it.remove();
}
}
public static DefaultAction getDefaultAction(String name) {
return (DefaultAction) _defaultActions.get(name);
}
/**
* @return Returns the moduleName.
*/
public String getModuleName() {
return _moduleName;
}
/**
* @param moduleName The moduleName to set.
*/
public void setModuleName(String moduleName) {
_moduleName = moduleName;
}
/**
* @return Returns the moduleDatabase.
*/
public String getModuleDatabase() {
return _moduleDatabase;
}
/**
* @param moduleDatabase The moduleDatabase to set.
*/
public void setModuleDatabase(String moduleDatabase) {
_moduleDatabase = moduleDatabase;
}
private WGCSSJSModule retrieveModule(TMLContext context) throws WGException {
WGDatabase db = context.db(getModuleDatabase());
if (db == null) {
throw new WGException("Database " + getModuleDatabase() + " not found");
}
if (!db.isSessionOpen()) {
throw new WGException("User has no access to database " + getModuleDatabase());
}
WGCSSJSModule mod = db.getCSSJSModule(getModuleName(), WGScriptModule.CODETYPE_TMLSCRIPT);
// Module not available or was deleted. We just return null.
if (mod == null) {
return null;
}
if (!mod.getCodeType().equals(WGCSSJSModule.CODETYPE_TMLSCRIPT)) {
throw new WGException("Script module '" + getModuleName() + "' in database " + getModuleDatabase() + " is no TMLScript module");
}
return mod;
}
/**
* @return Returns the iD.
*/
public String getID() {
return _ID;
}
/**
* @param id The iD to set.
*/
public void setID(String id) {
_ID = id;
}
/**
* @return Returns the moduleDate.
*/
public Date getModuleDate() {
return _moduleDate;
}
/**
* @param moduleDate The moduleDate to set.
*/
public void setModuleDate(Date moduleDate) {
_moduleDate = moduleDate;
}
/**
* Tests if this action definition is up-to-date. This only applies to actions that
* base on TMLScript modules, which might have been updated.
* @param context A context that this method needs to test for up-to-date-ness
* @return true, if the action definition is up-to-date, false (surprise) if not
*/
public boolean upToDate(TMLContext context) {
if (_origin != ORIGIN_SCRIPT_MODULE) {
return true;
}
try {
WGCSSJSModule mod = retrieveModule(context);
if (mod != null) {
return mod.getLastModified().equals(getModuleDate());
}
else {
return false;
}
}
catch (WGException e) {
context.getlog().error("Error testing module action up-to-date", e);
return false;
}
}
public static TMLAction buildActionFromScriptModule(WGCSSJSModule mod) throws TMLActionException, WGAPIException {
String code = mod.getCode().trim();
TMLAction action = null;
// See if code is surrounded by <tml:action> Tag. Parse it out to get flags
if (code.startsWith("<tml:action")) {
List codelines = WGUtils.deserializeCollection(code, "\n");
if (codelines.size() < 2) {
throw new TMLActionException("Too few lines for action script module. A script module that begins with <tml:action> must a) have this tag on a separate line and b) end with </tml:action> on a separate line");
}
// Take first and last line of code and try to parse them as XML
String actionXML = TMLContext.ACTION_XML_PREFIX + ((String) codelines.get(0)) + ((String) codelines.get(codelines.size() - 1)) + TMLContext.ACTION_XML_SUFFIX;
String actionCode = "";
if (codelines.size() >= 3) {
actionCode = WGUtils.serializeCollection(codelines.subList(1, codelines.size() -1), "\n");
}
// Parse out action flags
boolean master = false;
boolean async = false;
boolean debounce = true;
int timeout = RhinoExpressionEngine.DEFAULT_SCRIPTTIMEOUT;
try {
Document actionDOM = DocumentHelper.parseText(actionXML);
Element actionElement = actionDOM.getRootElement().element(new QName("action", new Namespace("tml", "urn:webtml")));
master = WGUtils.stringToBoolean(actionElement.attributeValue("master", "false"));
async = WGUtils.stringToBoolean(actionElement.attributeValue("async", "false"));
debounce = WGUtils.stringToBoolean(actionElement.attributeValue("debounce", "true"));
try {
timeout = Integer.parseInt(actionElement.attributeValue("timeout", new Integer(RhinoExpressionEngine.DEFAULT_SCRIPTTIMEOUT).toString()));
}
catch (NumberFormatException e) {
throw new TMLActionException("Unparseable action timeout: " + actionElement.attributeValue("timeout"));
}
action = new TMLAction(actionCode, master, async, debounce, ORIGIN_SCRIPT_MODULE);
action.setTimeout(timeout);
}
catch (DocumentException e) {
throw new TMLActionException("Unable to build action from script module", e);
}
}
// No tag surrounds the action code. Take the code unmodified
else {
action = new TMLAction(code, false, false, true, ORIGIN_SCRIPT_MODULE);
}
if (action != null) {
action.setModuleName(mod.getName());
action.setModuleDatabase(mod.getDatabase().getDbReference());
action.setModuleDate(mod.getLastModified());
action.setID(action.getModuleDatabase() + "/" + action.getModuleName());
}
return action;
}
public int getOrigin() {
return _origin;
}
public String getDescription() {
if (getOrigin() == TMLAction.ORIGIN_SCRIPT_MODULE) {
return "TMLScript-Module " + getModuleDatabase() + "/" + getModuleName();
}
else if (getID() != null) {
return "WebTML-Action " + getID() + " from WebTML-Module " + getModuleDatabase() + "/" + getModuleName();
}
else {
return "Anonymous WebTML-Action from WebTML-Module " + getModuleDatabase() + "/" + getModuleName();
}
}
}