Package de.innovationgate.wgpublisher.webtml.utils

Source Code of de.innovationgate.wgpublisher.webtml.utils.TMLContext$ListVarContainer

/*******************************************************************************
* 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.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.cyberneko.html.parsers.DOMParser;
import org.dom4j.Document;
import org.dom4j.io.DOMReader;
import org.jdom.IllegalDataException;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import de.innovationgate.utils.Base64;

import de.innovationgate.utils.FormattingChain;
import de.innovationgate.utils.FormattingException;
import de.innovationgate.utils.ImageScaler;
import de.innovationgate.utils.NullPlaceHolder;
import de.innovationgate.utils.ObjectFormatter;
import de.innovationgate.utils.TemporaryFile;
import de.innovationgate.utils.TextualDateFormat;
import de.innovationgate.utils.TransientMap;
import de.innovationgate.utils.TransientObjectWrapper;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGArea;
import de.innovationgate.webgate.api.WGCSSJSModule;
import de.innovationgate.webgate.api.WGContent;
import de.innovationgate.webgate.api.WGContentEventListener;
import de.innovationgate.webgate.api.WGContentNavigator;
import de.innovationgate.webgate.api.WGContentType;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDesignDocument;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGExpressionException;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.webgate.api.WGFileContainer;
import de.innovationgate.webgate.api.WGHierarchicalDatabase;
import de.innovationgate.webgate.api.WGIllegalArgumentException;
import de.innovationgate.webgate.api.WGIllegalStateException;
import de.innovationgate.webgate.api.WGLanguage;
import de.innovationgate.webgate.api.WGLanguageChooser;
import de.innovationgate.webgate.api.WGNotSupportedException;
import de.innovationgate.webgate.api.WGPortlet;
import de.innovationgate.webgate.api.WGPortletRegistry;
import de.innovationgate.webgate.api.WGQueryException;
import de.innovationgate.webgate.api.WGResultSet;
import de.innovationgate.webgate.api.WGScriptModule;
import de.innovationgate.webgate.api.WGStructEntry;
import de.innovationgate.webgate.api.WGTMLModule;
import de.innovationgate.webgate.api.WGUserAccess;
import de.innovationgate.webgate.api.WGUserDetails;
import de.innovationgate.webgate.api.WGUserProfile;
import de.innovationgate.webgate.api.auth.AuthenticationModule;
import de.innovationgate.webgate.api.auth.PasswordCachingAuthenticationModule;

import de.innovationgate.wga.common.CodeCompletion;
import de.innovationgate.wga.common.Constants;
import de.innovationgate.wga.common.beans.LuceneConfiguration;
import de.innovationgate.wga.common.beans.LuceneIndexItemRule;
import de.innovationgate.wga.common.beans.csconfig.v1.MediaKey;
import de.innovationgate.wga.common.beans.csconfig.v1.PluginID;
import de.innovationgate.wga.common.beans.csconfig.v1.Version;
import de.innovationgate.wga.config.AuthenticationSource;
import de.innovationgate.wga.config.WGAConfiguration;
import de.innovationgate.wga.modules.ModuleDefinition;
import de.innovationgate.wga.modules.ModuleInstantiationException;
import de.innovationgate.wga.modules.types.ImageScalerModuleType;
import de.innovationgate.wgpublisher.DBLoginInfo;
import de.innovationgate.wgpublisher.LoginException;
import de.innovationgate.wgpublisher.RenderServletRequest;
import de.innovationgate.wgpublisher.RenderServletResponse;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.WGAFilter;
import de.innovationgate.wgpublisher.WGPDispatcher;
import de.innovationgate.wgpublisher.WGACore.DomainConfiguration;
import de.innovationgate.wgpublisher.WGAFilter.GETRequestWrapper;
import de.innovationgate.wgpublisher.auth.CSAuthModule;
import de.innovationgate.wgpublisher.auth.Login;
import de.innovationgate.wgpublisher.design.OverlayDesignProvider;
import de.innovationgate.wgpublisher.expressions.ExpressionEngine;
import de.innovationgate.wgpublisher.expressions.ExpressionEngineFactory;
import de.innovationgate.wgpublisher.expressions.ExpressionResult;
import de.innovationgate.wgpublisher.expressions.tmlscript.RhinoExpressionEngine;
import de.innovationgate.wgpublisher.expressions.tmlscript.TMLScriptException;
import de.innovationgate.wgpublisher.labels.WGAResourceBundle;
import de.innovationgate.wgpublisher.labels.WGAResourceBundleManager;
import de.innovationgate.wgpublisher.lang.LanguageBehaviour;
import de.innovationgate.wgpublisher.lang.LanguageBehaviourTools;
import de.innovationgate.wgpublisher.lang.WebTMLLanguageChooser;
import de.innovationgate.wgpublisher.lucene.LuceneManager;
import de.innovationgate.wgpublisher.plugins.WGAPlugin;
import de.innovationgate.wgpublisher.url.DefaultURLBuilder;
import de.innovationgate.wgpublisher.url.WGAURLBuilder;
import de.innovationgate.wgpublisher.webtml.Base;
import de.innovationgate.wgpublisher.webtml.BaseTagStatus;
import de.innovationgate.wgpublisher.webtml.ForEach;
import de.innovationgate.wgpublisher.webtml.IterationTag;
import de.innovationgate.wgpublisher.webtml.Query;
import de.innovationgate.wgpublisher.webtml.Root;
import de.innovationgate.wgpublisher.webtml.Root.Status;
import de.innovationgate.wgpublisher.webtml.utils.TMLContextEnvironment.RootEnvironmentUserData;

/**
* Object representing a TML context, i.e. a pointer on a WGA Content Document that is used somewhere inside WebTML.
* This object is identical to the "this" object in TMLScript and provides the same functionalities.
*/
@CodeCompletion (methodMode=CodeCompletion.MODE_EXCLUDE, beanMode=CodeCompletion.BEAN_MODE_LOWERCASED)
public class TMLContext implements TMLObject {
   
    private static final String WEBTML_SCOPE_DIVIDER = "_";
   
    public class WebTMLDesignContext implements TMLDesignContext {
       
        private BaseTagStatus _tag;
        private WGDatabase _designDB;
        private WebTMLContextEnvironment _environment;
        private String _baseReference;
       
        private WebTMLDesignContext(WebTMLContextEnvironment env, BaseTagStatus tag, WGDatabase designDB, String baseReference) {
            _environment = env;
            _tag = tag;
            _designDB = designDB;
             _baseReference = baseReference;
        }

        public WGDatabase getDesignDB() {
            if (_designDB != null) {
                return _designDB;
            }
           
            String dbKey = _tag.getDesignDBKey();
           
            // In case of staticTML we return the main context db as design db
            if (dbKey != null && dbKey.equals(WGACore.STATICTML_DESIGNDBKEY)) {
                return getmaincontext().db();
            }
           
           
            return _environment.fetchDB(dbKey);
        }

        public BaseTagStatus getTag() {
            return _tag;
        }

        public void addWarning(String msg, boolean severe) {
            _tag.addWarning(msg, severe);
        }

        public boolean isTagAvailable() {
            return true;
        }

        public TMLDesignContext createContextDelegate(WGDatabase designdb, String baseReference) {
            return new WebTMLDesignContext(_environment, _tag, designdb, baseReference);
        }

        public String getBaseReference() {
            if(_baseReference != null) {
                return _baseReference;
            }
            else {
                return _tag.getTMLModuleName();
            }
        }
       
    }
   
    public static class WebTMLContextEnvironment implements TMLContextEnvironment {
       
        public static final String PROCESSCONTEXTS_ATTRIBUTE = "processContexts";
       
        private TMLContext _mainContext;
        private Map _sessionVars;
        private Map _vars = new HashMap();
        private Map _actionRegistration;
        private PageContext _pageContext;
        private WGACore _core;
        private WGDatabase _mainDesignDB;

        private WebTMLContextEnvironment(TMLContext mainContext, PageContext pageContext) {
            _mainContext = mainContext;
            _pageContext = pageContext;
            _core = WGACore.retrieve(pageContext);
            _mainDesignDB = mainContext.db();
           
            // Retrieve session vars
            HttpSession session = _pageContext.getSession();
            _sessionVars =  (Map) session.getAttribute(WGPDispatcher.SESSION_VARS);
            if (_sessionVars == null) {
                _sessionVars = Collections.synchronizedMap(new HashMap());
                session.setAttribute(WGPDispatcher.SESSION_VARS, _sessionVars);
            }
           
            // Retrieve action registration
            _actionRegistration = (Map) _pageContext.getAttribute(WGACore.SESSION_ACTIONS, PageContext.SESSION_SCOPE);
            if (_actionRegistration == null) {
                _actionRegistration = WGUtils.createSynchronizedMap();
                _pageContext.setAttribute(WGACore.SESSION_ACTIONS, _actionRegistration, PageContext.SESSION_SCOPE);
            }
           
        }

        public Map getActionRegistration() {
            return _actionRegistration;
        }

        public WGACore getCore() {
            return _core;
        }

        public TMLForm getForm() {
           
            ServletRequest request = _pageContext.getRequest();
            if (request == null) {
                return null;
            }
           
            TMLForm form = (TMLForm) request.getAttribute(WGACore.ATTRIB_LASTFORM);
            return form;
        }

        public TMLContext getMainContext() {
            return _mainContext;
        }

        public Map getSessionVars() {
            return _sessionVars;
        }

        public TMLContext getTMLContextForDocument(TMLContext parentContext, WGDocument doc) {
           
            if (doc == null) {
                return null;
            }

            TMLContext tmlContext = new TMLContext(doc, parentContext);
            tmlContext.setLastError(null);
            return tmlContext;
        }

        public TMLUserProfile getUserProfile(WGDatabase db) {
            DomainConfiguration domainConfig = getCore().getDomainConfigForDatabase(db);
           
            TMLUserProfile profile = (TMLUserProfile) _pageContext.getRequest().getAttribute(WGACore.ATTRIB_PROFILE + db.getDbReference());
            if (profile == null) {
                try {
                   return getCore().getDispatcher().fetchUserProfile((HttpServletRequest) _pageContext.getRequest(), (HttpServletResponse) _pageContext.getResponse(), db, _pageContext.getSession());
                }
                catch (WGAPIException e) {
                    getCore().getLog().error("Unable to retrieve user profile", e);
                }
            }
            return profile;
        }

        public Map getVars() {
            return _vars;
        }

        public List<Warning> getWarnings() {
            List<Warning> warnings = (List<Warning>) _pageContext.getAttribute(Base.class.getName() + ":Warnings", PageContext.REQUEST_SCOPE);
            if (warnings == null) {
                warnings = new ArrayList();
                _pageContext.setAttribute(Base.class.getName() + ":Warnings", warnings, PageContext.REQUEST_SCOPE);
            }
            return warnings;       
        }

        public void importEnvironmentData(TMLContext context) throws TMLException {
            throw new TMLException("Importing settings is illegal on WebTML TMLScript environment");           
        }

        public void setForm(TMLForm form) {
            if (form.getforminfo().isPersistent()) {
                getPersistentForms().put(form.getformid(), form);
            }
            else {
                getTransientForms().put(form.getformid(), form);
            }
        }
       
        public Map getPersistentForms() {
            Map forms = (Map) _pageContext.getSession().getAttribute(WGACore.ATTRIB_TMLFORM);
            if (forms == null) {
                // create transient map to prevent persistent forms from session serialization
                forms = new TransientMap(new HashMap());
                _pageContext.getSession().setAttribute(WGACore.ATTRIB_TMLFORM, forms);
            }
            return forms;
        }
       
        public Map getTransientForms() {
            ServletRequest request = _pageContext.getRequest();
            Map forms = (Map) request.getAttribute(WGACore.ATTRIB_TMLFORM);
            if (forms == null) {
                forms = new HashMap();
                request.setAttribute(WGACore.ATTRIB_TMLFORM, forms);
            }
            return forms;
        }

        public boolean isPageContextAvailable() {
            return true;
        }

        public boolean isWebEnvironment() {
            return true;
        }

        public WGDatabase getMainDesignDB() {
            return _mainDesignDB;
        }
       
        public WGDatabase openDB(WGDatabase db) throws WGException {
            return _core.openContentDB(db, (HttpServletRequest) _pageContext.getRequest(), false);
        }
       
        public WGDatabase fetchDB(String dbKey) {
            if (dbKey != null) {
                return (WGDatabase) _core.getContentdbs().get(dbKey);
            }
            else {
                return null;
            }
        }

        public Map<String, ProcessContext> getProcessContextRegistration() {
           
            HttpSession session = getMainContext().gethttpsession();
           
            synchronized (session) {
                Map<String, ProcessContext> contexts = (Map<String, ProcessContext>) session.getAttribute(PROCESSCONTEXTS_ATTRIBUTE);
                if (contexts == null) {
                    contexts = new TransientMap(new ConcurrentHashMap<String, ProcessContext>());
                    session.setAttribute(PROCESSCONTEXTS_ATTRIBUTE, contexts);
                }
                return contexts;
            }
        }

        public RootEnvironmentUserData getRootEnvironmentUserData() {
            return null;
        }

    public void removeForm(String id) {
      TMLForm form = (TMLForm) getTransientForms().get(id);
      if (form != null) {
        form.reset();
        getTransientForms().remove(id);
      }
      form = (TMLForm) getPersistentForms().get(id);
      if (form != null) {
        form.reset();
        getPersistentForms().remove(id);
      }
    }

        public PageContext getPageContext() {
            return _pageContext;
        }

        public String getPublisherURL() {
            return _pageContext.getRequest().getAttribute(WGACore.ATTRIB_WGPPATH).toString();
        }


      
    }
   
    public class IndependentDesignContext implements TMLDesignContext {
       
        private WGDatabase _designDB;
        private IndependentTMLScriptEnvironment _environment;
        private String _baseReference;

        private IndependentDesignContext (IndependentTMLScriptEnvironment env, WGDatabase designDB, String baseDesignReference) {
            _environment = env;
            _designDB = (designDB != null ? designDB : _environment.getMainDesignDB());
            _baseReference = baseDesignReference;
        }

        public WGDatabase getDesignDB() {
            return _designDB;
        }

        public BaseTagStatus getTag() {
            return null;
        }

        public void addWarning(String msg, boolean severe) {
            Warning warning = new Warning(null, TMLContext.this, msg, severe);
            _environment.getWarnings().add(warning);
           
            if (getwgacore().getWgaConfiguration().isWarningsOutputOnConsole()) {
                getlog().warn(warning.getConsoleText());
            }
        }

        public boolean isTagAvailable() {
            return false;
        }

        public TMLDesignContext createContextDelegate(WGDatabase designdb, String baseReference) {
            return new IndependentDesignContext(_environment, designdb, baseReference);
        }

        public String getBaseReference() {
            return _baseReference;
        }
       
    }
   
    public static class IndependentTMLScriptEnvironment implements TMLContextEnvironment {
       
        private WGDatabase _mainDesignDB;
        private IndependentTMLScriptEnvironment(TMLContext mainContext, WGACore core, TMLUserProfile userProfile, TMLForm form) {
            _mainContext = mainContext;
            _core = core;
            _userProfile = userProfile;
            _form = form;
            _mainDesignDB = mainContext.db();
        }
       
        private Map _actionRegistration = new HashMap();
        private Map _vars = new HashMap();
        private Map _sessionVars = new HashMap();
        private TMLContext _mainContext = null;
        private Map<String, ProcessContext> _processContextRegistration = new ConcurrentHashMap<String, ProcessContext>();
        private List<Warning> _warnings = new ArrayList<Warning>();
       
        private TMLForm _form;
        private TMLUserProfile _userProfile = null;
        private WGACore _core = null;
        private RootEnvironmentUserData _rootEnvironmentUserData = null;
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getMainContext()
         */
        public TMLContext getMainContext() {
            return _mainContext;
        }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getActionRegistration()
         */
        public Map getActionRegistration() {
            return _actionRegistration;
        }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getWarnings()
         */
        public List getWarnings() {
            return _warnings;
        }

        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getSessionVars()
         */
        public Map getSessionVars() {
            return _sessionVars;
        }
       
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getVars()
         */
        public Map getVars() {
            return _vars;
        }
       
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#importSettings(de.innovationgate.wgpublisher.webtml.utils.TMLContext)
         */
        public void importEnvironmentData(TMLContext context) {
            this._vars = context.getVars();
            this._sessionVars = context.getEnvironment().getSessionVars();
            this._actionRegistration = context.getActionRegistration();
            this._processContextRegistration = context.getEnvironment().getProcessContextRegistration();
            this._warnings = context.getEnvironment().getWarnings();
           
            if (context.getEnvironment().getRootEnvironmentUserData() != null) {
                _rootEnvironmentUserData = context.getEnvironment().getRootEnvironmentUserData();
            }
            else {
                try {
                    WGDatabase theDB = context.db(getMainContext().getdocument().getDatabase().getDbReference());
                    // We try to take the root environent user data of our main context db. If the root user has no access to it we take the parent context dbs data instead.
                    if (theDB.isSessionOpen()) {
                        _rootEnvironmentUserData = new RootEnvironmentUserData(theDB.getDbReference(), theDB.getSessionContext().getUserAccess());
                    }
                    else {
                        _rootEnvironmentUserData = new RootEnvironmentUserData(context.db().getDbReference(), context.db().getSessionContext().getUserAccess());
                    }
                }
                catch (WGException e) {
                    e.printStackTrace();
                }
            }
        }
       
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getTMLContextForDocument(de.innovationgate.webgate.api.WGDocument)
         */
        public TMLContext getTMLContextForDocument(TMLContext parentContext, WGDocument doc) {
           
            TMLContext tmlContext = new TMLContext(doc, _core, _userProfile, _form, parentContext);
            tmlContext.setLastError(null);
            return tmlContext;

            }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getForm()
         */
        public TMLForm getForm() {
            return _form;
                }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getUserProfile()
         */
        public TMLUserProfile getUserProfile(WGDatabase db) {
            return _userProfile;
        }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#getCore()
         */
        public WGACore getCore() {
            return _core;
        }
        /* (non-Javadoc)
         * @see de.innovationgate.wgpublisher.webtml.utils.TMLScriptEnvironment#setForm(de.innovationgate.wgpublisher.webtml.utils.TMLForm)
         */
        public void setForm(TMLForm form) {
            this._form = form;
        }
        public boolean isPageContextAvailable() {
            return false;
        }
        public boolean isWebEnvironment() {
            return false;
        }
        public Map getPersistentForms() {
            return Collections.EMPTY_MAP;
        }
        public WGDatabase getMainDesignDB() {
            return _mainDesignDB;
        }
        public Map getTransientForms() {
            return Collections.EMPTY_MAP;
        }

        public WGDatabase openDB(WGDatabase db) throws WGException {
          // B00005CCA
          boolean useMaster = false;
          WGDatabase hintDB = _mainContext.getdocument().getDatabase();         
          if (hintDB != null && hintDB.getSessionContext() != null) {
            useMaster = hintDB.getSessionContext().isMasterSession();
          }
            return _core.openContentDB(db, null, useMaster, hintDB);
        }
       
        public WGDatabase fetchDB(String dbKey) {
           
            if (dbKey == null) {
                return null;
            }
           
            // Special behaviour for setup scripts. The main design db may not yet be registered at wgacore at this time
            if (dbKey != null && dbKey.equals(getMainDesignDB().getDbReference())) {
                return getMainDesignDB();
            }
           
            return (WGDatabase) _core.getContentdbs().get(dbKey);
        }
        public Map<String, ProcessContext> getProcessContextRegistration() {
            return _processContextRegistration;
        }
        public RootEnvironmentUserData getRootEnvironmentUserData() {
            return _rootEnvironmentUserData;
        }
       
    public void removeForm(String id) {
      if (_form != null) {
        _form.reset();
        _form = null;
      }     
    }
        public PageContext getPageContext() {
            return null;
        }
       
        public String getPublisherURL() {
            WGAConfiguration config = _core.getWgaConfiguration();
            return config.getRootURL();
        }

       
    }
   
    @CodeCompletion
    public static final String ACTIONID_DIVIDER = "/";
   
    private static final String LABELPARAM_CLOSER = "}";
    private static final String LABELPARAM_OPENER = "{";
   
    /**
     * Set as session attribute for tasks that execute master/async actions.
     * Contains the definition of the action that is executed in this task.
     */
    @CodeCompletion
    public static final Object SESSIONATTRIB_ASYNCACTION = "AsyncAction";
   
    @CodeCompletion
    public static ThreadLocal<LinkedList<TMLContext>> _threadMainContexts = new ThreadLocal<LinkedList<TMLContext>>();
   
    public static TMLContext getThreadMainContext() {
       
        LinkedList<TMLContext> contexts = _threadMainContexts.get();
        if (contexts != null && contexts.size() > 0) {
            return contexts.getLast();
        }
        else {
            return null;
        }
       
    }
   
    public void makeThreadMainContext() {
       
        LinkedList<TMLContext> contexts = _threadMainContexts.get();
        if (contexts == null) {
            contexts = new LinkedList<TMLContext>();
            _threadMainContexts.set(contexts);
        }
       
        contexts.add(this);       
       
        if (contexts.size() == 100) {
            getlog().warn("Size of main contexts list on thread '" + Thread.currentThread().getName() + "' exceeds 100 entries. The main contexts management is most likely leaking!");
        }
       
    }
   
    public void removeThreadMainContext() {
       
        LinkedList<TMLContext> contexts = _threadMainContexts.get();
        if (contexts != null) {
            TMLContext lastContext = contexts.removeLast();
            if (lastContext != this) {
                getlog().error("Error in WebTML context management: Thread main context mismatch on removal");
            }
        }
       
    }
   
    public static void clearThreadMainContext() {
        LinkedList<TMLContext> contexts = _threadMainContexts.get();
        if (contexts != null) {
            contexts.clear();
        }
    }
   
   
   
    static class ListVarContainer implements Serializable {

        private static final long serialVersionUID = -7274704419920612617L;
       
        private List _list;
       
        public ListVarContainer(List list) {
            _list = list;
        }

        /**
         * @return Returns the list.
         */
        public List getList() {
            return _list;
        }
       
    }
 
  public static class MasterAction implements Runnable {
     
    private TMLContext _context;

    private List _params;

    private TMLAction _customAction = null;
   
    private String _defaultAction = null;
   
    private Object _returnValue = null;
   
    public MasterAction(TMLContext context, TMLAction action, List params) throws WGAPIException {
      init(context, params);
      _customAction = action;
    }

    private void init(TMLContext context, List params) throws WGAPIException {
       
        // Fill fields
      _params = params;
     
      // Init master action context
       _context = createMasterSessionContext(context);
    }

        public MasterAction(TMLContext context, String actionName, List params) throws WGAPIException, TMLException {
      init(context, params);
      _defaultAction = actionName;
    }
   
    private boolean isDefaultAction() {
      return (_defaultAction != null);
    }
    
    /* (Kein Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
           
      try {
                String taskDescr = "TMLScript Master Action: " + getActionID();
               
                // Open database in master thread
                WGDatabase db = _context.getdocument().getDatabase();
          db.openSession();
                db.getSessionContext().setTask(taskDescr);
               
                // Eventually open pers db too so profile is available
                TMLUserProfile profile = _context.getprofile();
               
                if (profile != null && !profile.getprofile().getDatabase().isSessionOpen()) {
                    WGDatabase persDB = profile.getprofile().getDatabase();
                    persDB.openSession();
                    persDB.getSessionContext().setTask(taskDescr);
                }

        if (isDefaultAction()) {
          _returnValue = _context.callDefaultAction(_defaultAction, _params);
        }
        else {
            if (_customAction.isAsync()) {
                db.getSessionContext().setAttribute(SESSIONATTRIB_ASYNCACTION, _customAction);
            }
          _returnValue = _context.callCustomAction(_customAction, _params);
        }

      }
      catch (Exception e) {
        _context.getwgacore().getLog().error("Error creating TML Context for master action", e);
      }
      finally {
        WGFactory.getInstance().closeSessions();
      }
     
    }
   
    public void start() {
     
      Thread actionThread = new Thread(this);
      actionThread.start();
      if (_customAction == null || !_customAction.isAsync()) {
        try {
          actionThread.join();
        }
        catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
     
    }

    public Object getReturnValue() {
      return _returnValue;
    }
       
        private String getActionID() {
           
            if (isDefaultAction()) {
                return _defaultAction;
            }
            else {
                return _customAction.getID();
            }
           
        }





  }
 
  static final String ACTION_XML_SUFFIX = "</doc>";
    static final String ACTION_XML_PREFIX = "<doc xmlns:tml=\"urn:webtml\">";


  private TMLContextEnvironment _environment = null;
  private TMLDesignContext _designContext = null;
    public TMLContextEnvironment getEnvironment() {
        return _environment;
    }


    public void importEnvironmentData(TMLContext context) throws TMLException {
        _environment.importEnvironmentData(context);
    }
   


    public Map getActionRegistration() {
        return _environment.getActionRegistration();
    }
   
    public Object callDefaultAction(String string, List params) {
   
    try {
            TMLAction.DefaultAction defaultAction = TMLAction.getDefaultAction(string);
            if (defaultAction != null) {
                return defaultAction.call(this, params);
            }
      else {
        addwarning("Unknown default action: " + string, false);
        return null;
      }
    }
    catch (TMLException e) {
        addwarning("Error executing default action " + string  + ": " + e.getMessage(), false);
        return null;
    }
    catch (Exception e) {
      addwarning("Error executing default action " + string  + ": " + e.getMessage(), false);
      getlog().error("Error executing default action " + string, e);
      return null;
    }
 
  }

  public Object callCustomAction(TMLAction tmlAction, List params) throws WGAPIException {
      return callCustomAction(tmlAction, params, null);
  }
 
  public Object callCustomAction(TMLAction tmlAction, List params, Map parentScopeObjects) throws WGAPIException {

    // Look if we must execute the action in a separate master action task.
      // We must do so if
      // a) we call a master action and are not already working under master rights
      // b) we call an async action and are not already in a master action task to execute this action
      boolean switchToMaster = tmlAction.isMaster() && !getdocument().getDatabase().getSessionContext().isMasterSession();
      boolean switchToAsync = tmlAction.isAsync() && !WGUtils.nullSafeEquals(getdocument().getDatabase().getSessionContext().getAttribute(SESSIONATTRIB_ASYNCACTION), tmlAction);
    if (switchToMaster || switchToAsync) {
      MasterAction masterAction = new MasterAction(this, tmlAction, params);
      masterAction.start();
      return masterAction.getReturnValue();
    }

    // Set params
        if (params == null) {
            params = new ArrayList();
        }
       
    for (int idx = 0; idx < params.size(); idx++) {
      setvar("tmlparam" + (idx + 1), params.get(idx));
    }
   
        // set additional objects and params. Keys must be lowercase so we have no doublettes in case-insensitive TMLScript
        Map additionalObjects = new HashMap();
        if (parentScopeObjects != null) {
            Iterator entries = parentScopeObjects.entrySet().iterator();
            while (entries.hasNext()) {
                Map.Entry entry = (Map.Entry) entries.next();
                additionalObjects.put(String.valueOf(entry.getKey()).toLowerCase(), entry.getValue());
            }
        }
       
        additionalObjects.put(RhinoExpressionEngine.PARAM_SCRIPTTIMEOUT, new Integer(tmlAction.getTimeout()));
        additionalObjects.put(RhinoExpressionEngine.PARAM_ACTIONDEFINITION, tmlAction);
        additionalObjects.put(TMLAction.OBJ_ACTION_PARAMS, params);
       
        // Temporarily set design db to originating db of action
        boolean designDBSwitched = false;
        TMLContext actionContext = this;
        if (tmlAction.getModuleDatabase() != null) {
            try {
                TMLDesignContext actionDesignContext = _designContext.createContextDelegate(db(tmlAction.getModuleDatabase()), tmlAction.getID());
                actionContext = new TMLContext(this, actionDesignContext);              
            }
            catch (WGException e) {
                addwarning("Unable to switch design context bc. target database '" + tmlAction.getModuleDatabase() + "' cannot be opened", false);
            }
        }
       

            // evaluate
            ExpressionEngine engine = ExpressionEngineFactory.getEngine(ExpressionEngineFactory.ENGINE_TMLSCRIPT);
        ExpressionResult result = engine.evaluateExpression(tmlAction.getCode(), actionContext, ExpressionEngine.TYPE_SCRIPT, additionalObjects);
        if (result.isError()) {
            WGExpressionException exc = result.getException();
               
                if (iswebenvironment()) {
                    addwarning(WGUtils.encodeHTML(exc.getMessage() + (exc.getExpression() != null ? "\nExpression line: " + exc.getExpression() : "\nExpression:\n" + tmlAction.getCode())), false);
                }
               
                getwgacore().getLog().error(
                        "Error executing " + tmlAction.getDescription() + " : " + result.getException().getMessage(),
                        result.getException());
                        
        }
       
        setvar("actionresult", result);
        return result.getResult();
   
  }

  public void setvar(String name, Object value, boolean keepList) throws WGAPIException {
   
        if (this.document.getDatabase().hasFeature(WGDatabase.FEATURE_STORESVARS) &&
            this.document.getDatabase().getBooleanAttribute(WGACore.DBATTRIB_VARPROVISIONING, true) == true) {
           
            try {
                this.document.setItemValue(name, value);
            }
            catch (WGAPIException e) {
                getlog().warn("Could not store WebTML variable as item on document bc. of exception. It will not be available in native expressions.", e);
            }
        }
        
        if (value instanceof List && keepList) {
            value = new ListVarContainer((List) value);
        }
       
    _environment.getVars().put(name.toLowerCase(), value);
   
   
  }
 
  public Object getvar(String name) {
    if (name == null) {
          return null;
      }     
    name = name.toLowerCase();
   
    Map vars = _environment.getVars();
    if (vars.containsKey(name)) {
      return vars.get(name);
    }
    return null;
  }
 
  public Object getsessionvar(String name) {
      if (name == null) {
          return null;
      }     
    name = name.toLowerCase();
   
    Map sessionVars = _environment.getSessionVars();
    if (sessionVars.containsKey(name)) {
      return unwrapSessionVar(sessionVars.get(name));
    }
    return null;
  }
   
    public void setvar(String name, Object value) throws WGAPIException {
        setvar(name, value, true);
    }
 
  /**
   * Tool method for the TMLScript engine defining the behaviour of setvar() short syntax
   * Will look for possible existing variables to update before setting a new variable
   * @param name Variable to set
   * @param value Value to Set
   * @throws WGAPIException
   */
  public void updateOrSetVar(String name, Object value) throws WGAPIException {
   
     
      // Look for portlet vars and session vars of that name (B00005E12)
        TMLPortlet portlet = getportlet();
        if (portlet != null) {
            String pItemName = portlet.getVarPrefix() + name;
            if (_environment.getVars().containsKey(pItemName.toLowerCase())) {
                portlet.setvar(name, value);
                return;
            }
            if (_environment.getSessionVars().containsKey(pItemName.toLowerCase())) {
                portlet.setsessionvar(name, value);
                return;
            }
        }
     
      // Look for session var of that name
    if (_environment.getSessionVars().containsKey(name.toLowerCase())) {
        this.setsessionvar(name, value);
        return;
    }

        // So we just set - or update - a normal var
        this.setvar(name, value);
   
  }

  private WGDocument document;
  private String role = null;
  private String lastError = null;
   
  /**
   * Constructor for the main context of a WebTML request
   * @param doc
   * @param tag
   */
  @CodeCompletion
    public TMLContext(WGDocument doc, de.innovationgate.wgpublisher.webtml.Base tag) {
     
      this.document = doc;
        _environment = new WebTMLContextEnvironment(this, tag.getPageContext());
        _designContext = new WebTMLDesignContext((WebTMLContextEnvironment) _environment, tag.getStatus(), null, null);
       
        if (this.document == null) {
            getwgacore().getLog().error("Request context with null content");
        }
    }
 
 
     
    /**
     * Constructor to create new contextes that take environment and designcontext from a parent context
     * @param doc
     * @param parentContext
     */
    protected TMLContext(WGDocument doc, TMLContext parentContext) {

        this.document = doc;
        this._environment = parentContext.getEnvironment();
        this._designContext = parentContext.getDesignContext();
       
    if (this.document == null) {
      getwgacore().getLog().error("Request context with null content");
    }
  }

    /**
     * Constructor to create clones of a context with a design context for a different WebTML tag
     * @param doc
     * @param parentContext
     */
    public TMLContext(TMLContext parentContext, BaseTagStatus status) {
   
        this.document = parentContext.getdocument();
        _environment = parentContext.getEnvironment();
        if (!(_environment instanceof WebTMLContextEnvironment)) {
            throw new IllegalArgumentException("This constructor is only usable in WebTML context environments");
        }
     
        _designContext = new WebTMLDesignContext((WebTMLContextEnvironment) _environment, status, null, null);
       
        if (this.document == null) {
            throw new IllegalArgumentException("Request context with null content");
        }
    }
     
    /**
     * Constructor to create clones of a context with the custom design context of a WebTML action
     * @param doc
     * @param parentContext
     */
    private TMLContext(TMLContext parentContext, TMLDesignContext designContext) {

        this.document = parentContext.getdocument();
        _environment = parentContext.getEnvironment();
        _designContext = designContext;
       
    if (this.document == null) {
            throw new IllegalArgumentException("Request context with null content");
    }
  }
 
  private TMLContext(WGDocument doc, WGACore core, TMLUserProfile userProfile, TMLForm form, TMLContext parentContext) {

      this.document = doc;
   
        // No environment given. This is a new independent TMLScript environmeent
        if (parentContext == null) {
            _environment = new IndependentTMLScriptEnvironment(this, core, userProfile, form);
            _designContext = new IndependentDesignContext((IndependentTMLScriptEnvironment) _environment, null, "");
        }
        // Derived context. We will load vars of the given environment
        else {
            _environment = parentContext.getEnvironment();
            _designContext =  parentContext.getDesignContext();
        }
       
       
  }
 
  @CodeCompletion
  public TMLContext(WGDocument doc, WGACore core, TMLUserProfile userProfile, TMLForm form) throws WGAPIException {
    this(doc, core, userProfile, form, null);
  }

  public TMLContext getmaincontext() {
    return _environment.getMainContext();
  }

  public Object item(String name) throws WGAPIException {

    Object value = flattenList(retrieveItem(name));
        if (value instanceof NullPlaceHolder) {
            value = db().getNoItemBehaviour().getForTMLItem();
        }
        return value;

  }

  public Object item(String type, String name) throws WGAPIException {

    name = name.toLowerCase();

    if (type.equals("content")) {
      return item(name);
    }
    else if (type.equals("profile")) {
      TMLUserProfile profile = getprofile();
      if (profile == null) {
        addwarning("Current user has no profile", true);
        return "";
      }
      return profile.item(name);
    }
    else if (type.equals("portlet")) {
      TMLPortlet portlet = getportlet();
      if (portlet == null) {
          if (!isbotrequest()) {
              this.addwarning("Current user has no portlet registry", true);
          }
        return "";
      }
      return portlet.item(name);
    }
   
    return "";
  }
 
  public boolean isbotrequest() throws WGAPIException {
        TMLUserProfile profile = getprofile();
        return (profile != null && profile.isdummy());
    }

  public Object itemlist(String type, String name) throws WGAPIException {

    name = name.toLowerCase();

    if (type.equals("content")) {
      return itemlist(name);
    }
    else if (type.equals("profile")) {
      TMLUserProfile profile = getprofile();
      if (profile == null) {
        addwarning("Current user has no profile", true);
        return "";
      }
      return profile.itemlist(name);
    }
    else if (type.equals("portlet")) {
      TMLPortlet portlet = getportlet();
      if (portlet == null) {
          if (!isbotrequest()) {
              this.addwarning("Current user has no portlet registry", true);
          }
        return "";
      }
      return portlet.itemlist(name);
    }
   
    return "";
  }
 


  public WGDocument getdocument() {
    return document;
  }
   
    public boolean hasVariable(String name) {
        name = name.toLowerCase();
       
        if (_environment.getVars().containsKey(name)) {
            return true;
        }
        if (_environment.getSessionVars().containsKey(name)) {
            return true;
        }
        return false;
    }
   
    public boolean hasMappedItemValue(String name) {
        name = name.toLowerCase();
       
        if (this.getMappedItemValue(name) == null) {
            return false;
        } else {
            return true;
        }
    }

  private Object retrieveItem(String name) throws WGAPIException {

      if (name == null) {
          return null;
      }
     
    String lcName = name.toLowerCase();
    TMLPortlet portlet = getportlet();
    Map vars = _environment.getVars();
    Map sessionVars = _environment.getSessionVars();
       
        // Portlet variables
        if (portlet != null && !portlet.isroot()) {
           
            String pName = portlet.getVarPrefix() + lcName;
           
            // Request variables
           
            if (vars.containsKey(pName)) {
                return vars.get(pName);
            }

            // Session variables
            if (sessionVars.containsKey(pName)) {
          // unwrap transient session vars
              return unwrapSessionVar(sessionVars.get(pName));
            }
           
        }
       
    // Request variables
    if (vars.containsKey(lcName)) {
      return vars.get(lcName);
    }

    // Session variables
    if (sessionVars.containsKey(lcName)) {     
      // unwrap transient session vars
      return unwrapSessionVar(sessionVars.get(lcName));
    }

    // Mapped item values
    Object result = this.getMappedItemValue(lcName);
    if (result != null) {
      return result;
    }

    // Content items
        if (this.document.hasItem(name)) {
            return this.document.getItemValue(name);
        }
        else {
            // Symbolizes that no value could be found
            return new NullPlaceHolder();
        }
  }


  private Object unwrapSessionVar(Object var) {
    if (var instanceof TransientObjectWrapper && var != null) {
      return ((TransientObjectWrapper)var).get();
    } else {
      return var;
    }
  }

  public static Object flattenList(Object object) {
 
    if (object == null) {
      return null;
    }

    if (object instanceof List) {
      List list = (List) object;
      if (list.size() == 0) {
        return null;
      }
      else {
        return ((List) object).get(0);
      }

    }
        else if (object instanceof ListVarContainer) {
            return ((ListVarContainer) object).getList();
        }
    else {
      return object;
    }

  }

  public List itemlist(String name) throws WGAPIException {

        Object value = retrieveItem(name);
        if (value instanceof NullPlaceHolder) {
            return db().getNoItemBehaviour().getForTMLItemList();
        }
        else {
            return toList(value);
        }

  }
 
    /**
     * returns a singleton list with itemvalues highlighted (surrounded with given <prefix> and <suffix>) based uppon the last lucene query with highlight attribute set to true
     * if highlighting is not possible this method returns itemlist(<name>);
     * @param name
     * @param prefix
     * @param suffix
     * @return list
     * @throws WGAPIException
     */
  @CodeCompletion
  public String highlightitem(String name, String prefix, String suffix) throws WGAPIException {
    return highlightitem(name, prefix, suffix, null);
  }
 
    /**
     * returns a singleton list with itemvalues highlighted (surrounded with given <prefix> and <suffix>) based uppon the last lucene query with highlight attribute set to true
     * if highlighting is not possible this method returns itemlist(<name>);
     * @param name
     * @param prefix
     * @param suffix
     * @param encode encode the result in the given encoding - prefix and suffix will not be encoded
     * @return list
     * @throws WGAPIException
     */
  @CodeCompletion
    public String highlightitem(String name, String prefix, String suffix, String encode) throws WGAPIException {
        if (name == null) {
            return itemTextValue(name, encode);
        }
        if (!getwgacore().isLuceneEnabled()) {
            addwarning("Unable to highlight item '" + name + "' bc. lucene is not enabled.");
            return itemTextValue(name, encode);
        }
        // try to retrieve last lucene query for highlighting
        org.apache.lucene.search.Query query = (org.apache.lucene.search.Query) getrequest().getSession().getAttribute(Query.SESSION_ATTRIBUTE_SIMPLIFIED_LUCENEQUERY);
        if (query == null) {
            // no query in session - highlighting not possible
            addwarning("Lucene highlighting not possible because there is no query with enabled highlighting support");
            return itemTextValue(name, encode);
        }
       
        // lowercase name
        name = name.toLowerCase();          
       
        // create htmlformatter to highlight fragments with "$HIGHLIGHT_PREFIX$", "$HIGHLIGHT_SUFFIX$"
        // these placeholders are later on replaced by the given prefix and suffix
        // this additional step is necessary to encode the fragment text properly
        // see F00004C66
        String prefixPlaceholder = "$HIGHLIGHT_PREFIX$";
        String suffixPlaceholder = "$HIGHLIGHT_SUFFIX$";       
        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(prefixPlaceholder, suffixPlaceholder);

        // create highlighter
        Highlighter highlighter = getwgacore().getLuceneManager().createHighlighter(name, query, formatter);
       
        // retrieve itemtext
        String originalText = itemTextValue(name, encode);       
        if (originalText == null) {
            return null;
        }
       
        // create text to analyze
        LuceneConfiguration config = getwgacore().getLuceneManager().retrieveLuceneConfig(content().getDatabase().getDbReference());
        LuceneIndexItemRule rule = config.getMatchingItemRule(name);
        String analyzeText = rule.parseItemValue(originalText);

        // create tokenstream
        TokenStream tokenStream = getwgacore().getLuceneManager().createTokenStream(analyzeText, content());
       
        // create fragmenter and set fragmentsize to itemText.length to ensure only one fragments with the whole itemText is returned       
        Fragmenter fragmenter = new SimpleFragmenter(originalText.length() + 1); // if analyzeText.length == originalText.length we might get two fragments from lucene without the +1 (possible lucene bug)
        highlighter.setTextFragmenter(fragmenter);
               
        try {
            String highlighted = highlighter.getBestFragment(tokenStream, originalText.toString());
            if (highlighted != null) {
              // replace highlight placeholders with correct prefix and suffix
              highlighted = WGUtils.strReplace(highlighted, prefixPlaceholder, prefix, true);
              highlighted = WGUtils.strReplace(highlighted, suffixPlaceholder, suffix, true);

              return highlighted;
            }
            else {
                return itemTextValue(name, encode);
            }
            }
        catch (IOException e) {
            addwarning("Unable to highlight item '" + name + "' bc. of exception '" + e.getMessage() + "'.");
            return itemTextValue(name, encode);
        } catch (InvalidTokenOffsetsException e) {
          addwarning("Unable to highlight item '" + name + "' bc. of exception '" + e.getMessage() + "'.");
            return itemTextValue(name, encode);
    }               

    }

    /**
     * returns a singleton list with metavalues highlighted (surrounded with given <prefix> and <suffix>) based uppon the last lucene query with highlight attribute set to true
     * if highlighting is not possible this method returns metalist(<name>);
     * @param name
     * @param prefix
     * @param suffix
     * @return list
     * @throws WGAPIException
     * @throws WGAPIException
     */
  @CodeCompletion
    public List highlightMeta(String name, String prefix, String suffix) throws WGAPIException {
      return highlightMeta(name, prefix, suffix, null);
    }

   

    /**
     * returns a singleton list with metavalues highlighted (surrounded with given <prefix> and <suffix>) based uppon the last lucene query with highlight attribute set to true
     * if highlighting is not possible this method returns metalist(<name>);
     * @param name
     * @param prefix
     * @param suffix
     * @param encode
     * @return list
     * @throws WGAPIException
     */
  @CodeCompletion
    public List highlightMeta(String name, String prefix, String suffix, String encode) throws WGAPIException {
        if (name == null) {
            return metalist(name);
        }
        if (!getwgacore().isLuceneEnabled()) {
            addwarning("Unable to highlight meta '" + name + "' bc. lucene is not enabled.");
            return metalist(name);
        }
        // try to retrieve last lucene query for highlighting
        org.apache.lucene.search.Query query = (org.apache.lucene.search.Query) getrequest().getSession().getAttribute(Query.SESSION_ATTRIBUTE_SIMPLIFIED_LUCENEQUERY);
        if (query == null) {
            // no query in session - highlighting not possible
            return metalist(name);
        }
               
        // create htmlformatter to highlight fragments with "$HIGHLIGHT_PREFIX$", "$HIGHLIGHT_SUFFIX$"
        // these placeholders are later on replaced by the given prefix and suffix
        // this additional step is necessary to encode the fragment text properly
        String prefixPlaceholder = "$HIGHLIGHT_PREFIX$";
        String suffixPlaceholder = "$HIGHLIGHT_SUFFIX$";
        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(prefixPlaceholder, suffixPlaceholder);

        // create highlighter
        Highlighter highlighter = getwgacore().getLuceneManager().createHighlighter(name.toUpperCase(), query, formatter);
       
        // retrieve metatext
        String originalText = metaTextValue(name, encode);       
        if (originalText == null) {
            return metalist(name);
        }
       
        // create tokenstream
        TokenStream tokenStream = getwgacore().getLuceneManager().createTokenStream(originalText, content());
       
        // create fragmenter and set fragmentsize to metaText.length to ensure only one fragments with the whole metaText is returned       
        Fragmenter fragmenter = new SimpleFragmenter(originalText.length() + 1); // +1 is necessary here
        highlighter.setTextFragmenter(fragmenter);
               
        try {
            String highlighted = highlighter.getBestFragment(tokenStream, originalText);
            if (highlighted != null) {

                // replace highlight placeholders with correct prefix and suffix
              highlighted = WGUtils.strReplace(highlighted, prefixPlaceholder, prefix, true);
              highlighted = WGUtils.strReplace(highlighted, suffixPlaceholder, suffix, true);
                           
                return Collections.singletonList(highlighted);
            } else {
                return metalist(name);
            }
        } catch (IOException e) {
            addwarning("Unable to highlight meta '" + name + "' bc. of exception '" + e.getMessage() + "'.");
            return metalist(name);
        } catch (InvalidTokenOffsetsException e) {
          addwarning("Unable to highlight meta '" + name + "' bc. of exception '" + e.getMessage() + "'.");
            return metalist(name);
    }               

    }
   

    /**
     * retrieves a list of the best fragments from the given contentItem based upon the last lucene query with highlight attribute set to true
     * query hits are not highlighted in fragments
     * @param itemname the item fragements should be retrieved from
     * @param fragmentSize the number of characters for each fragment
     * @param maxFragments the maximum number of fragements returned
     * @return list of fragements (Strings) - if no lucene query present returns EMPTY_LIST
     * @throws WGAPIException
     */
    @CodeCompletion
    public List bestfragments(String itemname, int fragmentSize, int maxFragments) throws WGAPIException {
        return bestfragments(itemname, fragmentSize, maxFragments, "", "");
    }
   
   
    /**
     * retrieves a list of the best fragments from the given contentItem based upon the last lucene query with highlight attribute set to true
     * query hits are highlighted (surrounded by given <prefix> and <suffix>) in fragments
     * @param itemname the item fragements should be retrieved from
     * @param fragmentSize the number of characters for each fragment
     * @param maxFragments the maximum number of fragements returned
     * @param prefix the prefix for highlighting the search term in fragements
     * @param suffix the suffix for highlighting the search term in fragements
     * @return list of fragements (Strings) - if no lucene query present returns EMPTY_LIST
     * @throws WGAPIException
     */
    @CodeCompletion
    public List bestfragments(String itemname, int fragmentSize, int maxFragments, String prefix, String suffix) throws WGAPIException {
      return bestfragments(itemname, fragmentSize, maxFragments, prefix, suffix, null);
    }
   
    /**
     * retrieves a list of the best fragments from the given contentItem based upon the last lucene query with highlight attribute set to true
     * query hits are highlighted (surrounded by given <prefix> and <suffix>) in fragments
     * @param itemname the item fragements should be retrieved from
     * @param fragmentSize the number of characters for each fragment
     * @param maxFragments the maximum number of fragements returned
     * @param prefix the prefix for highlighting the search term in fragements
     * @param suffix the suffix for highlighting the search term in fragements
     * @param encode encode each fragment in the given encoding - prefix and suffix will not be encoded
     * @return list of fragements (Strings) - if no lucene query present returns EMPTY_LIST
     * @throws WGAPIException
     */
    @CodeCompletion
    public List bestfragments(String itemname, int fragmentSize, int maxFragments, String prefix, String suffix, String encode) throws WGAPIException {
        // check preconditions for highlighting
        if (itemname == null) {
            throw new WGIllegalArgumentException("Unable to retrieve best fragments for item 'null'.");
        }       
        if (!getwgacore().isLuceneEnabled()) {
            addwarning("Unable to highlight item '" + itemname + "' bc. lucene is not enabled.");
            return Collections.EMPTY_LIST;
        }
        // try to retrieve last lucene query for highlighting
        org.apache.lucene.search.Query query = (org.apache.lucene.search.Query) getrequest().getSession().getAttribute(Query.SESSION_ATTRIBUTE_SIMPLIFIED_LUCENEQUERY);
        if (query == null) {
            // no query in session - highlighting not possible
            return Collections.EMPTY_LIST;
        }
                       
        // lowercase name
        itemname = itemname.toLowerCase();          
       
        // create htmlformatter to highlight fragments with "$HIGHLIGHT_PREFIX$", "$HIGHLIGHT_SUFFIX$"
        // these placeholders are later on replaced by the given prefix and suffix
        // this additional step is necessary to encode the fragment text properly
        // see B00004BBE
        String prefixPlaceholder = "$HIGHLIGHT_PREFIX$";
        String suffixPlaceholder = "$HIGHLIGHT_SUFFIX$";
        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(prefixPlaceholder, suffixPlaceholder);

        // create highlighter
        Highlighter highlighter = getwgacore().getLuceneManager().createHighlighter(itemname, query, formatter);
       
        // retrieve itemtext
        String text = itemTextValue(itemname, encode);       
        if (text == null) {
            return Collections.EMPTY_LIST;
        }
       
        // remove html/xml from text
        // fragments should not contain html/xml bc. of design issues
        try {
            text = WGUtils.toPlainText(text, " ", false);
            // B000049EA
            // if the item value contains encoded html entities these entities has been converted to their characters
            // we should do an html encode for sure
            // text = WGUtils.encodeHTML(text); --> has side effects @see B00004BBE
        }
        catch (IOException e) {
            addwarning("Unable to highlight item '" + itemname + "' bc. of exception '" + e.getMessage() + "'.");
            return Collections.EMPTY_LIST;
        }
       
        // create tokenstream
        TokenStream tokenStream = getwgacore().getLuceneManager().createTokenStream(text, content());
               
        // create fragmenter
        Fragmenter fragmenter = new SimpleFragmenter(fragmentSize);
        highlighter.setTextFragmenter(fragmenter);
       
        try {
            String[] highlighted = highlighter.getBestFragments(tokenStream, text, maxFragments);           
            if (highlighted != null) {
                ArrayList list = new ArrayList();
                for (int i=0; i < highlighted.length; i++) {
                  // B00004BBE
                  // evtl. encode fragment
                  String fragment  = highlighted[i];             
                  if (encode != null) {
                    try {
              fragment = multiencode(encode, fragment);
            } catch (FormattingException e) {
              addwarning("Unable to highlight item '" + itemname + "' bc. of formating exception '" + e.getMessage() + "'.");
                    return Collections.EMPTY_LIST;
            }
                  }
                  // B00004BBE
                  // replace highlight placeholders with correct prefix and suffix
                  fragment = WGUtils.strReplace(fragment, prefixPlaceholder, prefix, true);
                  fragment = WGUtils.strReplace(fragment, suffixPlaceholder, suffix, true);
                    list.add(fragment);
                }
                return list;
            } else {
                return Collections.EMPTY_LIST;
            }
        } catch (IOException e) {
            addwarning("Unable to highlight item '" + itemname + "' bc. of exception '" + e.getMessage() + "'.");
            return Collections.EMPTY_LIST;
        } catch (InvalidTokenOffsetsException e) {
          addwarning("Unable to highlight item '" + itemname + "' bc. of exception '" + e.getMessage() + "'.");
            return Collections.EMPTY_LIST;
    }               
    }
   
    /**
     * removes the last lucene query from session
     * should be called when you are sure you do not need further highlighting of content items
     * for the last executed lucene query with highlight=="true"
     */
    @CodeCompletion
    public void removelucenequery() {
        getrequest().getSession().removeAttribute(Query.SESSION_ATTRIBUTE_SIMPLIFIED_LUCENEQUERY);
    }
   
    /**
     * returns the itemvalue as text, concatenating eventual list elements and doing encoding
     * @param name Item name
     * @param Optional WebTML encoding. Use null to have none.
     * @return itemvalue as text, null if item is not found or itemvalue is null or itemvalues are no Strings
     * @throws WGAPIException
     */
    private String itemTextValue(String name, String encode) throws WGAPIException {
        if (name == null) {
            return null;
        }
       
        StringBuffer text = new StringBuffer();
        name = name.toLowerCase();
        List itemValues = itemlist(name);
        if (itemValues == null) {
            return null;
        }
       
        Iterator values = itemValues.iterator();
        boolean firstPart = true;
        while (values.hasNext()) {
            Object itemValue = values.next();           
            if (itemValue instanceof String) {
                String value = (String) itemValue;
                if (value != null) {
                    if (firstPart) {
                        firstPart = false;
                    }
                    else {
                        text.append(" ");
                    }
                   
                    text.append(value);
                }
            }
        }
       
       
        // Optionally encode
        String finalText;
        if (encode != null && !encode.equals("none") && true) {
            try {
                finalText = multiencode(encode, text.toString());
            }
            catch (FormattingException e) {
                addwarning("Unable to highlight item '" + name + "' bc. of formating exception '" + e.getMessage() + "'.");
                return itemTextValue(name, null);
            }
        }
        else {
            finalText = text.toString();
        }
       
       
        return finalText;
       

    }
   
   
    /**
     * returns the metavalue as single text, concatenating eventual list elements and doing encoding
     * @param name
     * @return metavalue as text, null if item is not found or metavalue is null or metavalues are no Strings
     * @throws WGAPIException
     */
    private String metaTextValue(String name, String encode) throws WGAPIException {
       
        if (name == null) {
            return null;
        }
       
        StringBuffer text = new StringBuffer();
        name = name.toLowerCase();
        List metaValues = metalist(name);
        if (metaValues == null) {
            return null;
        }
       
        Iterator values = metaValues.iterator();
        boolean firstPart = true;
        while (values.hasNext()) {
            Object metaValue = values.next();           
            if (metaValue instanceof String) {
                String value = (String) metaValue;
                if (value != null) {
                    if (firstPart == true) {
                        firstPart = false;
                    }
                    else {
                        text.append(" ");
                    }
                    text.append(value);
                }
            }
        }
       
        // Optionally encode
        String finalText;
        if (encode != null && !encode.equals("none") && true) {
            try {
                finalText = multiencode(encode, text.toString());
            }
            catch (FormattingException e) {
                addwarning("Unable to highlight meta '" + name + "' bc. of formating exception '" + e.getMessage() + "'.");
                return metaTextValue(name, null);
            }
        }
        else {
            finalText = text.toString();
        }
       
        return text.toString();
       
    }

  public static List toList(Object value) {

    if (value == null) {
      return new ArrayList();
    }
    else if (value instanceof Object[]) {
      List list = new ArrayList();
      list.addAll(Arrays.asList((Object[]) value));
      return list;
    }
    else if (value instanceof List) {
      return (List) value;
    }
        else if (value instanceof ListVarContainer) {
            return ((ListVarContainer) value).getList();
        }
    else if (value instanceof java.util.Collection) {
      return new ArrayList((java.util.Collection) value);
    }
        else if (ExpressionEngineFactory.getTMLScriptEngine().determineTMLScriptType(value) == RhinoExpressionEngine.TYPE_XMLLIST) {
            return ExpressionEngineFactory.getTMLScriptEngine().convertXMLListToList(value);
        }
    else {
      List list = new ArrayList();
      list.add(value);
      return list;
    }
  }

  public List metalist(String type, String name) throws WGAPIException {

    return toList(retrieveMeta(type, name));

  }

  public List metalist(String name) throws WGAPIException {
    return metalist("content", name);
  }

  private Object getMappedMetaValue(String name) {

    String expression = getMetaMappingExpression(name);

    if (expression != null) {
      ExpressionEngine engine =
        ExpressionEngineFactory.getEngine(
          this.content().getDatabase().getAttribute(WGACore.DBATTRIB_EXPRESSION_DEFAULT).toString());
      ExpressionResult result = engine.evaluateExpression(expression, this, ExpressionEngine.TYPE_EXPRESSION, null);
      return result.getResult();
    }
    else {
      return null;
    }

  }

  private String getMetaMappingExpression(String name) {
   
    String expression = null;
    Map mappings = null;
    mappings = (Map) option(WGACore.ATTRIB_META_MAPPINGS);
    if (mappings != null) {
      expression = (String) mappings.get(name.toLowerCase());
    }
   
    if (expression == null) {
            mappings = (Map) this.document.getDatabase().getAttribute(WGACore.DBATTRIB_META_MAPPINGS);
      expression = (String) mappings.get(name.toLowerCase());
    }
    return expression;
  }

  private Object getMappedItemValue(String name) {
 
    String expression = getItemMappingExpression(name);

    if (expression != null) {
      ExpressionEngine engine =
        ExpressionEngineFactory.getEngine(this.content().getDatabase().getAttribute(WGACore.DBATTRIB_EXPRESSION_DEFAULT).toString());
      ExpressionResult result = engine.evaluateExpression(expression, this, ExpressionEngine.TYPE_EXPRESSION, null);
      return result.getResult();
    }
    else {
      return null;
    }

  }

  private String getItemMappingExpression(String name) {
   
    String expression = null;
    Map mappings = null;
   
    // Try to retrieve from tag options (set by queries)
    mappings = (Map) option(WGACore.ATTRIB_ITEM_MAPPINGS);
    if (mappings != null) {
      expression = (String) mappings.get(name.toLowerCase());
    }
   
    // Try to retrieve from database
    if (expression == null) {
      mappings = (Map) this.getdocument().getDatabase().getAttribute(WGACore.DBATTRIB_ITEM_MAPPINGS);
      expression = (String) mappings.get(name.toLowerCase());
    }
    return expression;
  }

  public void setSessionVar(String name, Object value, boolean allowSerialization, boolean keepList) {
       
      name = name.toLowerCase();
     
        if (value instanceof List && keepList) {
            value = new ListVarContainer((List) value);
        }
       
        if (!allowSerialization) {
            TransientObjectWrapper wrapper = null;
            Object currentValue = _environment.getSessionVars().get(name);
            if (currentValue instanceof TransientObjectWrapper) {
               wrapper = (TransientObjectWrapper) currentValue;
            }
            else {
               wrapper = new TransientObjectWrapper();
                _environment.getSessionVars().put(name, wrapper);
            }
            wrapper.set(value);
        }
       
        else {       
          _environment.getSessionVars().put(name, value);
        }
  }
   
  public void setsessionvar(String name, Object value, boolean allowSerialisation) {
    setSessionVar(name, value, allowSerialisation, true);
  }
 
    public void setsessionvar(String name, Object value) {
        setSessionVar(name, value, true, true);
    }
 
  public void removesessionvar(String name) {
    _environment.getSessionVars().remove(name.toLowerCase());
  }
 


  public WGContent content() {
    return getcontent();
  }
 
  @CodeCompletion
  public WGContent getcontent() {

    if (this.document instanceof WGContent) {
      return (WGContent) this.document;
    }
    else {
      return null;
    }

  }

  public TMLContext context(String expression, boolean returnContextOnError) {
      try {
            TMLContextExpression expr = new TMLContextExpression(expression, this, db().getDefaultLanguage());
            return expr.processExpression(this, returnContextOnError);
        }
        catch (WGAPIException e) {
            this.setLastError("Unable to change context to (" + expression + ") bc. of exception: " + e.getClass().getName() + " message: " + e.getMessage());
            return (returnContextOnError ? this : null);
        }
  }
 
 



    public TMLContext context(String expression) {
        return context(expression, true);
    }

  public Object meta(String type, String name) throws WGAPIException {

    return flattenList(retrieveMeta(type, name));

  }

  private Object retrieveMeta(String type, String originalName) throws WGAPIException {

    this.setLastError(null);

    type = (type != null ? type.toLowerCase().trim() : "content");
    String name = originalName.toLowerCase().trim();
    if (type.equals("content")) {
      return getContentMetaData(name);
    }
    else if (type.equals("profile")) {
      if (this.getprofile() != null) {
        return this.getprofile().metalist(name);
      }
      else {
        this.addwarning("Current user has no profile", false);
        return "";
      }
    }
    else if (type.equals("database") || type.equals("db")) {
      return getDatabaseMetaData(name, originalName);
    }
    else if (type.equals("session")) {
      return getSessionMetaData(name);
    }
    else if (type.startsWith("domain")) {
          return getDomainMetaData(type, name);
        }
    else if (type.equals("request")) {
      return getRequestMetaData(name);
    }
    else if (type.equals("response")) {
      return getResponseMetaData(name);
    }
    else if (type.equals("taginfo")) {
      this.setLastError("Taginfos not reachable via this.meta. Use this.taginfo instead!");
      return null;
    }
    else {
      return null;
    }

  }

  private Object getDomainMetaData(String type, String name) {
       
      String domainName = (String) db().getAttribute(WGACore.DBATTRIB_DOMAIN);
      int colonPos = type.indexOf(":");
      if (colonPos != -1) {
          domainName = type.substring(colonPos + 1).trim();
      }
     
      if (name.equalsIgnoreCase("name")) {
          return domainName;
      }
     
      else if (name.equalsIgnoreCase("username")) {
          DBLoginInfo loginInfo = getwgacore().getSessionLogins(gethttpsession()).get(domainName);
          if (loginInfo != null) {
              return loginInfo.getUserName();
          }
          else {
              return WGDatabase.ANONYMOUS_USER;
          }
      }
     
      else if (name.equalsIgnoreCase("defaultmanager")) {
          DomainConfiguration dc = getwgacore().getDomainConfig(domainName);
          if (dc == null) {
                addwarning("No configuration found for domain: " + domainName);
                return null;
            }
         
          return dc.getDefaultManager();
      }
     
      else if (name.equalsIgnoreCase("authentication") || name.equalsIgnoreCase("auth")) {
          DomainConfiguration dc = getwgacore().getDomainConfig(domainName);
            if (dc == null) {
                addwarning("No configuration found for domain: " + domainName);
                return null;
            }
           
            AuthenticationModule authModule = dc.getAuthModule();
            if (authModule != null) {
                return authModule.getAuthenticationSource();
            }
            else {
                return null;
            }
      }
     
      else if (name.equalsIgnoreCase("databases")) {
          return getwgacore().getDatabasesForDomain(domainName);
      }
     
      else {
          this.addwarning("Unknown domain metadata name: " + name, true);
            return "";
      }
     
    }


    private Object getRequestMetaData(String name) {
   
    if (!getEnvironment().isPageContextAvailable()) {
      this.setLastError("Cannot retrieve request metadata because this script does not run inside a WebTML page");
      return null;
    }
   
    BaseTagStatus tag = _designContext.getTag();

    if (name.equals("url")) {
      return tag.getRequestURL();
    }
    else if (name.equals("wgaurl")) {
      return getwgacore().getDispatcher().getPublisherURL(getrequest(), false);
    }
    else if (name.equals("absolutewgaurl")) {
      return getwgacore().getDispatcher().getPublisherURL(getrequest(), true);
    }
    else if (name.equals("query_string")) {
      return getrequest().getQueryString();
    }
    else if (name.equals("http_referer")) {
      return getrequest().getHeader("REFERER");
    }
    else if (name.equals("http_user_agent")) {
      return getrequest().getHeader("USER-AGENT");
    }
    else if (name.equals("http_host") || name.equals("server_name")) {
      return getrequest().getServerName();
    }
    else if (name.equals("path_info")) {
      return getrequest().getPathInfo();
    }
    else if (name.equals("path_info_decoded")) {
      return getrequest().getPathTranslated();
    }
    else if (name.equals("remote_addr")) {
      return getrequest().getRemoteAddr();
    }
    else if (name.equals("remote_host")) {
      return getrequest().getRemoteHost();
    }
    else if (name.equals("remote_user")) {
      return getrequest().getRemoteUser();
    }
    else if (name.equals("request_method")) {
      return getrequest().getMethod();
    }
    else if (name.equals("server_protocol")) {
      return getrequest().getProtocol();
    }
    else if (name.equals("server_port")) {
      return new Integer(getrequest().getServerPort());
    }
    else if (name.equals("mainmedium")) {
        return gettag().getMainMediaKey();
    }
    else {
      return null;
    }

  }
 
  private Object getResponseMetaData(String name) {
   
    if (!getEnvironment().isPageContextAvailable()) {
      this.setLastError("Cannot retrieve response metadata because this script does not run inside a WebTML page");
      return null;
    }

    if (name.equals("character_encoding")) {
      return this.getresponse().getCharacterEncoding();
    }
    else {
      return null;
    }

  }
 

  /**
   * Returns the user profile for the current context
     * For WebTML-Environments: the profile in the personalisation db, that belongs to the domain of the current context database
     * For Event scripts and master actions: The profile of the user that triggered the event or master action
     * For other environments: null
   */
  public TMLUserProfile getprofile() {
      return _environment.getUserProfile(getdocument().getDatabase());
  }

  /**
   * Returns the current portlet object, containing configuration information for the current portlet
     * Portlet informations are always stored in the personalisation db of the request's main context.
   * @throws WGAPIException
   */
  public TMLPortlet getportlet() throws WGAPIException {
   
    if (!_environment.isPageContextAvailable()) {
      return null;
    }

    String nameSpace = (String) option(Base.OPTION_PORTLET_NAMESPACE);
   
    return getportletbykey(nameSpace);
  }


    public TMLPortlet getportletbykey(String nameSpace) throws WGAPIException {
        TMLUserProfile profile = this.getmaincontext().getprofile();
        if (profile == null) {
            return null;
        }
       
        WGPortletRegistry portletRegistry = profile.getprofile().getPortletRegistry();
        if (portletRegistry == null) {
            return null;
        }
       
    WGPortlet portlet;
        if (nameSpace != null) {
        portlet = portletRegistry.getPortlet(getmaincontext().db().getDbReference(), nameSpace);
    }
    else {
      portlet = portletRegistry.getRootPortlet(getmaincontext().db().getDbReference());
    }

    if (portlet != null) {
        return new TMLPortlet(_designContext.getTag(), profile, portlet);
    }
    else {
        return null;
    }
    }


  public Object meta(String name) throws WGAPIException {

    return this.meta("content", name);
  }

  private Object getContentMetaData(String name) throws WGAPIException {

    WGContent content = this.content();
    if (content == null) {
      return this.getdocument().getMetaData(name);
    }

    Object mappingresult = this.getMappedMetaValue(name);
    if (mappingresult != null) {
      return mappingresult;
    }

    if (name.equals("created")) {
      return content.getCreated();
    }
    else if (name.equals("modified")) {
      return content.getLastModified();
    }
    else if (name.equals("title")) {
      return content.getTitle();
    }
        else if (name.equals("titlepath")) {
            return content.getStructEntry().getTitlePath();
        }
    else if (name.equals("uniquename") || name.equals("name") || name.equals("docname")) {
      return content.getUniqueName();
    }
    else if (name.equals("pageuniquename") || name.equals("pagename") || name.equals("pagedocname")) {
            return content.getStructEntry().getUniqueName();
        }
    else if (name.equals("position")) {
      return content.getStructEntry().getPosition();
    }
    else if (name.equals("key")) {
      return content.getContentKey(true).toString();
    }
    else if (name.equals("area")) {
            if (!content.isDummy()) {
                return content.getStructEntry().getArea().getName();
            }
            else {
                return "";
            }
    }
    else if (name.equals("level")) {
        WGContentNavigator nav = new WGContentNavigator(null, new WebTMLLanguageChooser(db(), this));
      return nav.getContentLevel(content);
    }
    else if (name.equals("index")) {
        WGContentNavigator nav = new WGContentNavigator(null, new WebTMLLanguageChooser(db(), this));
      return nav.getSiblingsIndex(content);
    }
        else if (name.equals("navindex")) {
            WGContentNavigator nav = new WGContentNavigator(WGContent.DISPLAYTYPE_NAVIGATOR, new WebTMLLanguageChooser(db(), this));
            return nav.getSiblingsIndex(content);
        }
    else if (name.equals("language")) {
      return content.getLanguage().getName();
    }
    else if (name.equals("languagetitle")) {
      return content.getLanguage().getTitle();
    }
    else if (name.equals("attachments")) {
      return content.getFileNames();
    }
    else if (name.equals("doctype") || name.equals("contenttype")) {
        if (!content.isDummy()) {
            return content.getStructEntry().getContentType().getName();
        }
        else {
            return null;
        }
    }
        else if (name.equals("contenttypetitle")) {
            return content.getStructEntry().getContentType().getNameForLanguage(getpreferredlanguage());
        }
        else if (name.equals("contenttypedescription")) {
            return content.getStructEntry().getContentType().getDescriptionForLanguage(getpreferredlanguage());
        }
    else if (name.equals("siblings")) {
        WGContentNavigator nav = new WGContentNavigator(null, new WebTMLLanguageChooser(db(), this));
      return new Integer(nav.getSiblingsCount(content));
    }
    else if (name.equals("workflow")) {
      //return content.getStructEntry().getContentType().getMetaData(WGContentType.META_WORKFLOW);
      return content.getStructEntry().getWorkflowName();
    }
    else if (name.equals("status")) {
      return content.getStatus();
    }
    else if (name.equals("structtitle")) {
      return content.getStructEntry().getTitle();
    }
    else if (name.equals("structkey")) {
      WGStructEntry entry = content.getStructEntry();
      if (entry != null) {
        return String.valueOf(entry.getStructKey());
      }
      else {
        return null;
      }
    }
    else if (name.equals("itemnames")) {
      return content.getItemNames();
    }
    else if (name.equals("searchscore")) {
        return new Float(content.getSearchScore());
    }
    else if (name.equals("searchexplanation")) {
      return content.getSearchExplanation();
    }
        else if (name.equals("positionpath")) {
            return content.getStructEntry().getPositionPath();
        }
        else if (name.equals("pagepublished")) {
            return content.getStructEntry().getPublished().get(content.getLanguage().getName());
        }
        else if (name.equals("email")) {
            return content.getAuthorEMail();
        }
    else {
      Object result = null;
      String upperName = name.toUpperCase();
      boolean isNoValidMeta = true;

      if (content.getMetaNames().indexOf(upperName) != -1) {
        result = content.getMetaData(upperName);
        isNoValidMeta = false;
      }

      else if (result == null) {
        WGStructEntry structEntry = content.getStructEntry();
        if (structEntry != null) {
          if (structEntry.getMetaNames().indexOf(upperName) != -1) {
            result = structEntry.getMetaData(upperName);
            isNoValidMeta = false;
          }
          if (result == null) {
            WGContentType docType = structEntry.getContentType();
            if (docType != null) {
              if (docType.getMetaNames().indexOf(upperName) != -1) {
                result = docType.getMetaData(upperName);
                isNoValidMeta = false;
              }
            }
          }
        }
      }
      if (isNoValidMeta) {
        this.addwarning("Unknown metadata name: " + name, false);
        return "";
      }
      return result;
    }

  }

  private Object getDatabaseMetaData(String name, String originalName) throws WGAPIException {

    if (name.equals("title")) {
      return this.getdocument().getDatabase().getTitle();
    }
    else if (name.equals("path")) {
      return this.getdocument().getDatabase().getPath();
    }
    else if (name.equals("type")) {
      return this.getdocument().getDatabase().getType();
    }
    else if (name.equals("dbkey")) {
      return this.getdocument().getDatabase().getAttribute(WGACore.DBATTRIB_DBKEY);
    }
    else if (name.startsWith("user")) {
        return getDatabaseUserMetaData(db().getSessionContext().getUserAccess(), name, originalName);
    }
    else if (name.startsWith("original_user")) {
        WGUserAccess userAccess = getoriginaluserdata();
        if (userAccess != null) {
            return getDatabaseUserMetaData(userAccess, name.substring(9), originalName.substring(9));
        }
        else {
            return null;
        }
    }
        else if (name.equals("domain")) {
      return (String) this.getdocument().getDatabase().getAttribute(WGACore.DBATTRIB_DOMAIN);
    }
    else if (name.equals("filecontainers")) {
      return getDesignDocNames(this.getdocument().getDatabase().getFileContainers());
    }
    else if (name.equals("contenttypes")) {
      return getDesignDocNames(this.getdocument().getDatabase().getContentTypes());
    }   
    else if (name.equals("cssjsmodules")) {
      return getDesignDocNames(this.getdocument().getDatabase().getCSSJSModules());
    }
    else if (name.equals("tmlmodules")) {
      return getDesignDocNames(this.getdocument().getDatabase().getTMLModules());
   
    else if (name.equals("areas")) {
      return getDesignDocNames(this.getdocument().getDatabase().getAreas().values());
    }
    else if (name.equals("languages")) {
      return getDesignDocNames(this.getdocument().getDatabase().getLanguages().values());
    }   
    else if (name.equals("defaultlanguage")) {
        return getdocument().getDatabase().getDefaultLanguage();
    }
    else if (name.equals("servername")) {
        return getdocument().getDatabase().getServerName();  
    }
    else {
      this.addwarning("Unknown metadata name: " + name, true);
      return "";
    }

  }

  private Object getDatabaseUserMetaData(WGUserAccess userAccess, String name, String originalName) throws WGAPIException {
     
      // Look if we have detailed user information
      WGUserDetails userDetails = null;
      if (userAccess instanceof WGUserDetails) {
          userDetails  = (WGUserDetails) userAccess;
      }
     
      if (name.equals("username")) {
            return userAccess.getPrimaryName();
        }
      else if (name.equals("useraccess")) {
            return new Integer(userAccess.getAccessLevel());
        }
        else if (name.startsWith("userlabel_") || name.startsWith("useralias_")) {
            if (userDetails != null) {
                int sublinePos = name.indexOf("_");
                String label = originalName.substring(sublinePos + 1);
                return userDetails.getLabeledNames().get(label);
            }
            else {
                return null;
            }
        }
        else if (name.equals("useraliases")) {
            if (userDetails != null) {
                return userDetails.getAliases();
            }
            else {
                return null;
            }
        }
        else if (name.equals("userroles")) {
            if (userDetails != null) {
                return userDetails.getRoles();
            }
            else {
                return null;
            }
        }
        else if (name.equals("usergroups")) {
            if (userDetails != null) {
                return userDetails.getGroups();
            }
            else {
                return null;
            }
        }
        else if (name.equals("useremail")) {
            if (userDetails != null) {
                return userDetails.getEMailAddress();
            }
            else {
                return null;
            }
        }
        else if (name.equals("usermaymovestructs")) {
            return new Boolean(userAccess.mayMoveStructEntries());
        }
        else if (name.equals("usermaydeletedocs")) {
            return new Boolean(userAccess.mayDeleteDocuments());
        }
        else {
          this.addwarning("Unknown metadata name: " + name, true);
            return "";
        }
  }

    private Object getDesignDocNames(Collection containers) throws WGAPIException {
    Iterator designDocs = containers.iterator();
    WGDesignDocument designDoc;
    List designDocNames = new ArrayList();
    while (designDocs.hasNext()) {
      designDoc = (WGDesignDocument) designDocs.next();
      designDocNames.add(designDoc.getName());
    }
    return designDocNames;
  }

  public Object taginfo(String tagId, String name) throws WGAPIException {
   
      BaseTagStatus tag = _designContext.getTag();
    if (tag == null) {
      return null;
    }

    if (tagId == null) {
      this.setLastError("No sourceTag attribute given");
      return null;
    }

    BaseTagStatus refTag = tag.getTagStatusById(tagId);
    if (refTag != null) {
      Object result = refTag.getTagInfo(String.valueOf(name).toLowerCase());
      if (result == null) {
        this.setLastError("Tag " + tagId + " did not provide Info " + name);
      }
      return result;
    }
    else {
        addwarning("Could not find tag for tagid " + tagId, false);
      this.setLastError("Could not find tag for tagid " + tagId);
      return null;
    }
  }

  public String getlasterror() {
    return lastError;
  }

  public void setLastError(String lastError) {
    this.lastError = lastError;
  }

  public boolean isselected() throws WGAPIException {
   
    boolean isSelected = false;
    WGContent pageContent = getmaincontext().content();
    if (pageContent.getDatabase() != this.document.getDatabase()) {
      return false;
    }

    WGContentNavigator navigator = new WGContentNavigator(this.role, new WebTMLLanguageChooser(db(), this));
    navigator.setOnlyPublished(!isbrowserinterface());
    while (pageContent != null) {
      if (pageContent.getStructKey().equals(this.content().getStructKey())) {
        isSelected = true;
        break;
      }

      if (pageContent.hasCompleteRelationships() && !pageContent.getStructEntry().isRoot()) {
        pageContent = navigator.getParentContent(pageContent);
      }
      else {
        pageContent = null;
      }
    }
    return isSelected;
  }

  public boolean haschildren() throws WGAPIException {
    WGContentNavigator navigator = new WGContentNavigator(this.role, new WebTMLLanguageChooser(db(), this));
        return navigator.hasContentChildren(getcontent());
  }

  public boolean hassiblings() throws WGAPIException {
    WGContentNavigator navigator = new WGContentNavigator(this.role, new WebTMLLanguageChooser(db(), this));
        return navigator.getSiblingsCount(getcontent())!=0;
  }


  public boolean isroot() throws WGAPIException {
    return getcontent().isDummy() || getcontent().getStructEntry().isRoot();
  }

  public boolean ismaindocument() throws WGAPIException {
    return (document == getmaincontext().content());
  }

  public boolean isbrowserinterface() {
      BaseTagStatus tag = getDesignContext().getTag();
      if (tag != null) {
          return tag.isBrowserInterface();
      }
      else {
          return false;
      }
  }

  public String contenturl(String mediaKey, String layoutKey) throws UnsupportedEncodingException, WGAPIException {
    return contenturl(mediaKey, layoutKey, false);
  }
    
  public String contenturl() throws UnsupportedEncodingException, WGAPIException {
      return contenturl(null, null, false);
  }
    
  public String contenturl(String mediaKey, String layoutKey, boolean ignoreVirtualLink) throws UnsupportedEncodingException, WGAPIException {
      return getURLBuilder().buildContentURL(this, mediaKey, layoutKey, ignoreVirtualLink);
  }
   
    public String contentdataurl(String mediaKey, String layoutKey) throws ServletException, IOException, WGAPIException {       
        return contentdataurl(mediaKey, layoutKey, false, null);
    }
   
    public String contentdataurl(String mediaKey, String layoutKey, String queryString) throws ServletException, IOException, WGAPIException {       
        return contentdataurl(mediaKey, layoutKey, false, queryString);
    }

   
    public String contentdataurl(String mediaKey, String layoutKey, boolean ignoreVirtualLink, String queryString) throws ServletException, IOException, WGAPIException {
       
        BaseTagStatus tag = _designContext.getTag();
        if (tag ==  null) {
            return null;
        }
       
       
        // retrieve standard contenturl
        String url = contenturl(mediaKey, layoutKey, ignoreVirtualLink);
        // cut off WGPath
        url = url.substring(url.indexOf(_environment.getPublisherURL()) + _environment.getPublisherURL().length());
        // append query string
        if (queryString != null) {
            url = url + "?" + queryString;
        }
       
        // determine contentType (mimeType)
        if (mediaKey == null) {
           
            mediaKey = tag.getMainMediaKey();
        }
        MediaKey key = getwgacore().getMediaKey(mediaKey);       
        String contentType = key.getMimeType();
       
        /** this works on WAS - on tomcat the result is an endless loop        
        // create wrapper for request and response
        RenderServletRequestWrapper req = new RenderServletRequestWrapper(this.getrequest(), url);       
        RenderServletResponseWrapper res = new RenderServletResponseWrapper(this.getresponse());
        **/
        RenderServletRequest req = new RenderServletRequest(this.getrequest(), url);       
        RenderServletResponse res = new RenderServletResponse(this.getresponse());
       
       
        // call include
        this.getrequest().getRequestDispatcher(url).include(req, res);

        // process response
        if (res.isBinary()) {
            byte data[] = res.getBinaryData();
            return createDataURL(data, contentType);
        } else {
            String data = res.getStringData();
            return createDataURL(data, contentType);
        }
    }
   
   
 
  public int getDummy() {
      return 1;
  }

  public String layouturl(String dbKey, String mediaKey, String layoutKey) throws UnsupportedEncodingException, WGException {
      return getURLBuilder().buildLayoutURL(this, resolveDBKey(dbKey), mediaKey, layoutKey);
  }
 
  public String layouturl(String mediaKey, String layoutKey) throws UnsupportedEncodingException, WGException {
      return layouturl(null, mediaKey, layoutKey);
  }

  public void setrole(String role) {
    this.role = role;
  }

  public String getrole() {
    return this.role;
  }

  public void addwarning(String msg, boolean severe) {
      _designContext.addWarning(msg, severe);
  }
   
    public void addwarning(String msg) {
        addwarning(msg, false);
    }
   


  private Object getSessionMetaData(String name) {
   
    if (!getEnvironment().isPageContextAvailable()) {
      this.setLastError("Cannot retrieve session metadata because this script does not run inside a WebTML page");
      return null;
    }

    HttpSession session = gethttpsession();
    if (name.equals("start")) {
      return new Date(session.getCreationTime());
    }
    else if (name.equals("lastaccess")) {
      return new Date(session.getLastAccessedTime());
    }
    else if (name.equals("id")) {
      return session.getId();
    }
    else if (name.equals("language")) {
      return getpreferredlanguage();
    }
    else {
      return null;
    }
  }

  public boolean isnewsession() {
   
    if (!getEnvironment().isPageContextAvailable()) {
      return false;
    }
   
    return gethttpsession().isNew();
  }

  public javax.servlet.http.Cookie[] getcookies() {
   
    if (!_environment.isPageContextAvailable()) {
      return null;
    }
   
    return getrequest().getCookies();
  }

  public javax.servlet.http.HttpServletRequest getrequest() {
   
    if (!_environment.isPageContextAvailable()) {
      return null;
    }
   
    return (javax.servlet.http.HttpServletRequest) _environment.getPageContext().getRequest();
  }

  public boolean istrue(String varname) throws WGAPIException {

    Object value = this.item(varname);

    if (value instanceof Boolean) {
      return ((Boolean) value).booleanValue();
    }
    else if (value instanceof Number) {
      int valueNumber = ((Number) value).intValue();
      if (valueNumber == 1 || valueNumber == -1) {
        return true;
      }
      else {
        return false;
      }
    }
    else if (value instanceof String) {
      return Boolean.valueOf((String) value).booleanValue();
    }
    else {
      return false;
    }

  }
 
  public boolean isdefined(String name) throws WGAPIException {
   
    name = name.toLowerCase();
        TMLPortlet portlet = getportlet();
        Map vars = _environment.getVars();
        Map sessionVars = _environment.getSessionVars();

       
        // Portlet variables
        if (portlet != null && !portlet.isroot()) {
           
            String pName = portlet.getVarPrefix() + name;
           
            // Request variables
            if (vars.containsKey(pName)) {
                return true;
            }

            // Session variables
            if (sessionVars.containsKey(pName)) {
                return true;
            }
           
        }

        // Request variables
    if (vars.containsKey(name)) {
      return true;
    }

    // Session variables
    if (sessionVars.containsKey(name)) {
      return true;
    }

    // Mapped item values
    Object result = this.getItemMappingExpression(name);
    if (result != null) {
      return true;
    }

    // Content items
    return this.document.hasItem(name);

  }

  public boolean isfalse(String varname) throws WGAPIException {
    return !this.istrue(varname);
  }

  public Object option(String option, Object defaultValue) {
   
      BaseTagStatus tag = _designContext.getTag();
    if (tag != null) {
        return tag.getOption(option);
    }
    else {
        return defaultValue;
    }
  }
 
  public Object option(String option) {
      return option(option, null);
  }

  public boolean hasoption(String option){
    return (this.option(option) != null);
  }
 
  public Date dateonly(Date date) {
    return WGUtils.dateOnly(date);
  }
 
  public Date timeonly(Date date) {
    return WGUtils.timeOnly(date);
  }

  @CodeCompletion
  public WGDocument getapiobject() {
    return this.document;
  }


  private Map getVars() {
    return _environment.getVars();
  }

  public Date stringtodate(String text) {

    if (text == null) {
      return null;
    }

    if (text.indexOf(":") == -1) {
      text += " 0:00";
    }

    SimpleDateFormat dateFormat = new SimpleDateFormat();
    dateFormat.setLenient(true);
    return dateFormat.parse(text, new ParsePosition(0));

  }

  @CodeCompletion
  public List createlist() {
    return new ArrayList();
  }
 
  @CodeCompletion
  public List createlist(Object[] objects) {
    return new ArrayList(Arrays.asList(objects));
  }
 
  @CodeCompletion
  public List createlist(String listString, String delimiter) {
    return WGUtils.deserializeCollection(listString, delimiter);
  }

  public int createuserprofile(String name, String passwordthrows WGAPIException {
    return this.createuserprofile((String) this.content().getDatabase().getAttribute(WGACore.DBATTRIB_DOMAIN), name, password);
  }

  public int createuserprofile(String domain, String name, String passwordthrows WGAPIException{
    return createuserprofile(domain, name, password, true);
  }

  public int createuserprofile(String domain, String name, String password, boolean forCurrentUser) throws WGAPIException {
     
      if (!getEnvironment().isPageContextAvailable()) {
          return TMLUserProfile.RC_METHOD_UNAVAILABLE;
      }

    // Get pers db. Ensure that there is one
    if (domain == null || domain.equals("")) {
      return TMLUserProfile.RC_NO_DOMAIN;
    }
    HttpSession session = getEnvironment().getPageContext().getSession();
    if (session == null) {
      return TMLUserProfile.RC_NO_SESSION;
    }

    WGDatabase persDB = getwgacore().openPersonalisationDB(domain, session);
    if (persDB == null) {
      return TMLUserProfile.RC_NOT_PERSONALIZED;
    }

    //  ensure persdb is in correct mode (custom)
    Integer persMode = Integer.valueOf((String) getwgacore().readPublisherOptionOrDefault(getDesignContext().getDesignDB(), WGACore.DBATTRIB_PERSMODE));
    if (persMode.intValue() != Constants.PERSMODE_CUSTOM) {
      return TMLUserProfile.RC_WRONG_PERSMODE;
    }

    // Ensure, there is no profile yet with this name
    WGUserProfile profile = persDB.getUserProfile(name);
    if (profile != null) {
      return TMLUserProfile.RC_PROFILE_EXISTS;
    }

    // Try to create the profile
    try {
      profile = persDB.createUserProfile(name, Constants.PERSMODE_CUSTOM);
    }
    catch (WGException e) {
      this.addwarning("Exception creating user profile: " + e.getMessage(), true);
    }
    if (profile == null) {
      return TMLUserProfile.RC_NOT_CREATABLE;
    }
    TMLUserProfile.prepareNewProfile(profile);

    // Set password eventually
    if (password != null) {
      profile.setMetaData(WGUserProfile.META_PASSWORD, password);
    }

    try {
      profile.save();
    }
    catch (WGAPIException e) {
      this.addwarning("Unable to create user profile: " + e.getMessage(), true);
            return TMLUserProfile.RC_NOT_CREATABLE;
    }

    // Attach to session
    if (forCurrentUser) {
      attachProfileToUser(domain, profile);
    }

    return TMLUserProfile.RC_OK;
  }

  public int assignuserprofile(String name, String passwordthrows WGAPIException {
    return this.assignuserprofile((String) this.content().getDatabase().getAttribute(WGACore.DBATTRIB_DOMAIN), name, password);
  }

  public int assignuserprofile(String domain, String name, String passwordthrows WGAPIException{

      if (!getEnvironment().isPageContextAvailable()) {
            return TMLUserProfile.RC_METHOD_UNAVAILABLE;
        }

    password = (password == null ? "" : password);

    // Get pers db. Ensure that there is one
    if (domain == null || domain.equals("")) {
      return TMLUserProfile.RC_NO_DOMAIN;
    }
    HttpSession session = getEnvironment().getPageContext().getSession();
    if (session == null) {
      return TMLUserProfile.RC_NO_SESSION;
    }
    WGDatabase persDB = getwgacore().openPersonalisationDB(domain, session);
    if (persDB == null) {
      return TMLUserProfile.RC_NOT_PERSONALIZED;
    }

    //  ensure database is in correct mode (custom)
    Integer persMode = Integer.valueOf((String) getwgacore().readPublisherOptionOrDefault(getDesignContext().getDesignDB(), WGACore.DBATTRIB_PERSMODE));
    if (persMode.intValue() != Constants.PERSMODE_CUSTOM) {
      return TMLUserProfile.RC_WRONG_PERSMODE;
    }

    // Try to fetch profile
    WGUserProfile profile = persDB.getUserProfile(name);
    if (profile == null) {
      return TMLUserProfile.RC_NO_PROFILE;
    }

    // Test password
    if (!password.equals(profile.getPassword())) {
      return TMLUserProfile.RC_WRONG_PASSWORD;
    }

    // Attach to session & request and register hit
    attachProfileToUser(domain, profile);
    if (!getDesignContext().getTag().isBrowserInterface()) {
      getwgacore().getDispatcher().registerHit(profile, this.content().getDatabase(), this.content());
    }

    return TMLUserProfile.RC_OK;

  }

  private void attachProfileToUser(String domain, WGUserProfile profile) throws WGAPIException {

    if (!getEnvironment().isPageContextAvailable()) {
      addwarning("Cannot use this method in this TMLScript runtime", false);
      return;
    }

    if (profile != null) {
      gethttpsession().setAttribute(WGPDispatcher.SESSION_PROFILENAME + domain, profile.getName());
    }
    else {
      gethttpsession().removeAttribute(WGPDispatcher.SESSION_PROFILENAME + domain);
    }
  }

  public TMLForm gettmlform() {
   
      TMLForm form = null;
     
      // Use form predefined by environment
    if (_environment != null && _environment.getForm() != null) {
      form = _environment.getForm();
    }

    // Use last defined form on the WebTML request
    if (form == null && getrequest() != null) {
        form = (TMLForm) getrequest().getAttribute(WGACore.ATTRIB_LASTFORM);
        }
       
    return form;

  }

  public TMLForm tmlformbyid(String id) {

    TMLForm form = (TMLForm) getTransientForms().get(id);
    if (form != null) {
      return form;
    }

    form = (TMLForm) getPersistentForms().get(id);
    if (form != null) {
      return form;
    }

    return null;
  }

  private Map getTransientForms() {
        return _environment.getTransientForms();
    }

  @CodeCompletion
    public WGDatabase db(String key) throws WGException {
        WGDatabase db = _environment.fetchDB(resolveDBKey(key));
        if (db != null) {
            return _environment.openDB(db);
        }
       
        return null;
  }
   
    /**
     * Returns the db current in context
     */
    public WGDatabase db() {
        return document.getDatabase();
    }
   
    @CodeCompletion
    public WGDatabase designdb() throws WGException {
        WGDatabase designDB = _designContext.getDesignDB();
        return _environment.openDB(designDB);
    }

    @CodeCompletion
    public WGHierarchicalDatabase hdb(String key) throws WGException {
       
        // Retrieve db via dbkey and wrap as hdb
        WGDatabase db = db(key);
        if (db != null) {
            return WGHierarchicalDatabase.getOrCreateInstance(db);
        }
       
        return null;
   
    }
   
    public WGHierarchicalDatabase hdb() throws WGException {
      return hdb(db().getDbReference());
    }
   
  public int closeuserprofile(String domain) throws WGAPIException {

    HttpSession session = gethttpsession();
    if (session == null) {
      return TMLUserProfile.RC_NO_SESSION;
    }

    TMLUserProfile profile = this.getprofile();
    if (profile == null) {
      return TMLUserProfile.RC_NO_PROFILE;
    }

    Integer mode = Integer.valueOf((String) getwgacore().readPublisherOptionOrDefault(profile.getprofile().getDatabase(), WGACore.DBATTRIB_PERSMODE));
    if (mode.intValue() != Constants.PERSMODE_CUSTOM) {
      return TMLUserProfile.RC_WRONG_PERSMODE;
    }

    attachProfileToUser(domain, null);
    return TMLUserProfile.RC_OK;

  }

  public int closeuserprofile() throws WGAPIException {
    return this.closeuserprofile((String) this.content().getDatabase().getAttribute(WGACore.DBATTRIB_DOMAIN));
  }

  public boolean hasprofile() {
    return (this.getprofile() != null);
  }

  public TMLContext context(WGContent content) throws WGAPIException {
    return getTMLContextForDocument(content);
  }

  @CodeCompletion
  public Mail createmail(String smtpHost, String username, String password) throws UnsupportedEncodingException {
    return new Mail(smtpHost, username, password);
  }
 
  @CodeCompletion
  public Mail createmail() throws TMLException {
    WGDatabase db = getdocument().getDatabase()

      try {
            if (getwgacore().getMailConfig() != null){
                return new Mail(getwgacore().getMailConfig());
            }
            else {
                throw new TMLException("MAIL ERROR: Missing mail configuration.", false);
            }
        }
        catch (UnsupportedEncodingException e) {
            throw new TMLException("MAIL ERROR: Exception creating mail object.", e, false);
        }
     
  }
 

   

  @CodeCompletion
    public ImageScaler createimagescaler(File imageFile) throws ModuleInstantiationException, WGNotSupportedException, IOException {
   
       
        FileInputStream is = new FileInputStream(imageFile);
        ImageScaler scaler = null;
        try {
             scaler = createimagescaler(is);
        }
        finally {
            is.close();
        }
       
        scaler.setSourceFileName(imageFile.getName());
        return scaler;
       
       
    }
   
  @CodeCompletion
    public ImageScaler createimagescaler(InputStream is) throws ModuleInstantiationException, WGNotSupportedException, IOException {

        ImageScaler scaler = ImageScalerFactory.createImageScaler(getwgacore());
        scaler.load(is);
       
        return scaler;
       
       
    }

  public String getpath() throws WGAPIException {

    StringBuffer path = new StringBuffer();
    WGDocument doc = getdocument();
       
    path.append("db:" + doc.getDatabase().getAttribute(WGACore.DBATTRIB_DBKEY));

    switch (doc.getType()) {

      case WGDocument.TYPE_CONTENT :
        if (!getcontent().isDummy()) {
          path.append("/docid:" + getcontent().getContentKey().toString());
        }
        break;

      case WGDocument.TYPE_STRUCTENTRY :
        path.append("/$struct:" + ((WGStructEntry) doc).getStructKey());
        break;

      case WGDocument.TYPE_AREA :
        path.append("/$area:" + ((WGArea) doc).getName());
        break;

      case WGDocument.TYPE_CONTENTTYPE :
        path.append("/$contenttype:" + ((WGContentType) doc).getName());
        break;

      case WGDocument.TYPE_LANGUAGE :
        path.append("/$language:" + ((WGLanguage) doc).getName());
        break;

      case WGDocument.TYPE_TML :
        path.append("/$tml:" + ((WGTMLModule) doc).getName() + "," + ((WGTMLModule) doc).getMediaKey());
        break;

      case WGDocument.TYPE_CSSJS :
        path.append("/$cssjs:" + ((WGCSSJSModule) doc).getName());
        break;

      case WGDocument.TYPE_FILECONTAINER :
        path.append("/$filecontainer:" + ((WGFileContainer) doc).getName());

    }

    return path.toString();

  }

  public void registerForm(TMLForm form, boolean persist) {
      _environment.setForm(form);
  }

  public HttpServletResponse getresponse() {
     
      if (!_environment.isPageContextAvailable()) {
          return null;
      }
     
    return (HttpServletResponse) _environment.getPageContext().getResponse();
  }

  @CodeCompletion
  public void redirectto(String url) throws IOException {

    getrequest().setAttribute(WGACore.ATTRIB_REDIRECT, getresponse().encodeURL(url));
    if (getDesignContext().getTag() instanceof Root.Status) {
        Root.Status status = (Status) getDesignContext().getTag();
        status.result = Collections.singletonList("");
        status.evalBody = false;
    }

  }
 
  public TMLContext getTMLContextForDocument(WGDocument doc) {
      return _environment.getTMLContextForDocument(this, doc);
  }

  public static String createContextKey(WGDocument doc) {
    return doc.getDatabase().getDbReference() + "//" + doc.getDocumentKey().toString();
  }
 
  public Cookie createcookie(String name, String value) {
    return new Cookie(name, value);
  public Cookie createCookie(String name, String value) {
    return new Cookie(name, value);
  }
 
  public Logger getlog() {
    return getwgacore().getLog();
  }
 
 
  public void removevar(String name) throws WGAPIException {
    _environment.getVars().remove(name.toLowerCase());
    if (this.document.getDatabase().hasFeature(WGDatabase.FEATURE_STORESVARS)) {
      this.document.removeItem(name);
    }
  }

  @CodeCompletion
  public WGACore getwgacore() {
      return _environment.getCore();
  }
 
  public HttpSession gethttpsession() {
    if (_environment.isPageContextAvailable()) {
      return _environment.getPageContext().getSession();
    }
    else {
      return null;
    }
   
  }
 
  /**
   * @deprecated
   */
  public void setpreferredlanguage(String lang) {
      addwarning("Method TMLContext.setPreferredLanguage() is deprecated and inoperable since OpenWGA 5.1");
  }
 
  /**
   * Returns the preferred language for the given content context
   * This equals calling {@link #getpreferredlanguage(WGDatabase, boolean)} with the current context database and "true" for the exhaustive parameter
   * @throws WGAPIException
   * @deprecated
   */
  public String getpreferredlanguage() {
      return getpreferredlanguage(db(), true);
  }
 
  /**
   * Determines the preferred language for the given database
   * @param The database for whom the preferred language is determined. It is used to evaluate the available languages and to read it's language behaviour setting
   * @param exhaustive Set to true if the method should try to find a appropriate language even if the pref language was not yet set for the user session
   * @return The preferred language or null if none could be determined
   * @deprecated
   */
  protected String getpreferredlanguage(WGDatabase db, boolean exhaustive) {
        WebTMLLanguageChooser chooser = new WebTMLLanguageChooser(db, this);
        try {
            String lang = chooser.getPreferredLanguage(db);
            if (lang != null) {
                return lang;
            }
            else {
                return getmaincontext().content().getLanguage().getName();
            }
        }
        catch (WGAPIException e) {
            getlog().error("Exception retrieving preferred language for database " + db.getDbReference(), e);
            return null;
          
        }
  }
   
    public Locale getPreferredLanguageLocale() {
       
        String prefLang = getpreferredlanguage();
        if (prefLang == null) {
            return null;
        }
       
        return getwgacore().languageCodeToLocale(prefLang);
       
    }
   
    /**
     * returns a dateFormat for the given pattern
     * if pattern is 'null' a default dateFormat is returned
     * @param pattern - @see java.text.SimpleDateFormat
     * @return DateFormat
     */
    public DateFormat getDateFormat(String pattern) {
       
        // Select language for language dependent date formats
        Locale locale = null;
        WGLanguageChooser chooser = new WebTMLLanguageChooser(db(), this);
        WGLanguage lang = null;
        try {
            lang = chooser.selectDatabaseLanguage(db());
            if (lang != null) {
                locale = lang.getLocale();
            }
        }
        catch (WGAPIException e) {
            getlog().error("Exception selecting language for date format", e);
        }
       
        // Language Fallback(s)
        if (locale == null) {
            locale = this.getPreferredLanguageLocale();
        if (locale == null) {
            locale = Locale.getDefault();
        }
        }
       
        if (pattern == null) {
            return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
        }
       
        // For default patterns
        String lcPattern = pattern.toLowerCase();
        if (lcPattern.endsWith("date") || lcPattern.endsWith("time")) {
            int patternLength;
            if (lcPattern.startsWith("short")) {
                patternLength = DateFormat.SHORT;
            }
            else if (lcPattern.startsWith("medium")) {
                patternLength = DateFormat.MEDIUM;
            }
            else if (lcPattern.startsWith("long")) {
                patternLength = DateFormat.LONG;
            }
            else {
                patternLength = DateFormat.FULL;
            }
           
            if (lcPattern.endsWith("datetime")) {
                return new TextualDateFormat(locale, DateFormat.getDateTimeInstance(patternLength, patternLength, locale));
            }
            else if (lcPattern.endsWith("time")) {
                return new TextualDateFormat(locale, DateFormat.getTimeInstance(patternLength, locale));
            }
            else {
                return new TextualDateFormat(locale, DateFormat.getDateInstance(patternLength, locale));
            }
           
        }
       
        // For custom patterns
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, locale);
        dateFormat.setLenient(false);
        return new TextualDateFormat(locale, dateFormat);
          
            
    }
   
    /**
     * returns a numberFormat for the given pattern
     * if pattern is 'null' a default numberFormat is returned
     * @param pattern - @see java.text.DecimalFormat
     * @return NumberFormat
     */
    public NumberFormat getNumberFormat(String pattern) {
        Locale locale = this.getPreferredLanguageLocale();
       
        if (locale == null) {
            locale = Locale.getDefault();
        }

        if (pattern == null) {
            NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
            numberFormat.setMaximumFractionDigits(Integer.MAX_VALUE);
            numberFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
            return numberFormat;
        }
       
        // For default pattern
        if (pattern.toLowerCase().equals("decimal")) {
            return NumberFormat.getNumberInstance(locale);
        }
       
        // Custom pattern
        return new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
       
       
    }


    @CodeCompletion
    public Date parsedate(String date, String format) throws ParseException {
       
        return this.getDateFormat(format).parse(date);
    }
   
    @CodeCompletion
    public Number parsenumber(String number, String format) throws ParseException {
      return getNumberFormat(format).parse(number);
    }
   
    @CodeCompletion
    public Date createdate() {
        return createdate(true);
    }
   
    @CodeCompletion
    public Date createdate(boolean includeMillis) {
       
        if (includeMillis) {
            return new Date();
        }
        else {
            return new Date(WGUtils.cutoffTimeMillis(System.currentTimeMillis()));
        }
       
    }
   
    public Calendar createcalendar(Date date) {
       
        if (date == null) {
            throw new IllegalArgumentException("Date parameter is null");
        }
       
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        return cal;
       
       
    }
    public Calendar createcalendar() {
      return this.createcalendar(this.createdate());
    }
   
    public void setoption(String name, Object value, String scope) {
       
        BaseTagStatus tag = getDesignContext().getTag();
        if (tag == null) {
            return;
        }
       
        while (tag != null) {
            tag.setOption(name, value, scope);
            if (tag instanceof Root.Status) {
                break;
            }
            tag = tag.getParentTag();
        }
    }
   
    public void setoption(String name, Object value) {
        setoption(name, value, TMLOption.SCOPE_GLOBAL);
    }
   
    public Login createlogin(String username, String password) {
        return new Login(username, password);
    }
   
    public String label(String containerName, String fileName, String key, List params, boolean usePlaceholder) {
        try {
            WGDatabase designDB = designdb();
            return label(designDB, containerName, fileName, key, params, usePlaceholder);
        }
        catch (WGException e) {
           getlog().error("Unable to open design db", e);
           return "(Error retrieving label)";
        }
       
    }
   
    public String label(String containerName, String fileName, String key, List params) {
        return label(containerName, fileName, key, params, true);
    }
   

   
    public String label(WGDatabase designDB, String containerName, String fileName, String key, List params, boolean usePlaceholder) throws WGAPIException {
       
        if (designDB == null) {
            return "(Error retrieving label)";
        }

       
        // Eventually get defaults for label information
        if (containerName == null) {
            containerName = (String) option(Base.OPTION_DEFAULT_LABELCONTAINER + designDB.getDbReference());
            if (containerName == null) {
                containerName = WGAResourceBundleManager.CONTAINER_DEFAULT;
            }
        }
       
        if (fileName == null) {
            fileName = (String) option(Base.OPTION_DEFAULT_LABELFILE + designDB.getDbReference());
            if (fileName == null) {
                fileName = WGAResourceBundleManager.FILE_DEFAULT;
            }
        }
               
        if (key == null) {
            return null;
        }
               
        WGAResourceBundleManager manager = getwgacore().getResourceBundleManager(designDB);
       
        String label = null;
        String forceLanguage = (String) designDB.getAttribute(WGACore.DBATTRIB_FORCE_LABEL_LANGUAGE);
        if (forceLanguage != null) {
            Locale prefLangLocale = WGLanguage.languageNameToLocale(forceLanguage);
            try {
                label = LanguageBehaviourTools.fetchLabelForLanguage(manager, containerName, fileName, key, prefLangLocale);
            }
            catch (IOException e) {
                getlog().error("Exception retrieving label " + containerName + "/" + fileName + "/" + key + " for language " + prefLangLocale.toString() + " from DB " + manager.getDb().getDbReference(), e);
            }
        }
        else {
            LanguageBehaviour langBehaviour = LanguageBehaviourTools.retrieve(designDB);
            label = langBehaviour.webtmlFetchLabel(manager, this, containerName, fileName, key);
        }
    
        // If no label available we return the key prefixed with "#"
        if (label != null) {
            return mergeLabelWithParams(label, params);
        }
        else if (usePlaceholder) {
            return "#" + fileName + "." + key;
        }
        else {
            return null;
        }
       
    }
   
    public String label(WGDatabase designDB, String containerName, String fileName, String key, List params) throws WGAPIException {
        return label(designDB, containerName, fileName, key, params, true);
    }
   
    public String label(String containerName, String fileName, String key) {
        return label(containerName, fileName, key, null);
    }
   
    private String mergeLabelWithParams(String label, List params) {

        // If no labelparam opener in label, we can bypass this operation
        if (label.indexOf(LABELPARAM_OPENER) == -1) {
            return label;
        }
       
        if (params == null) {
            params = new ArrayList();
        }
       
        Object param;
        for (int idx=0; idx < 6; idx++) {
            if (idx < params.size()) {
                param = params.get(idx);
                if (param == null) {
                    param = "";
                }
            }
            else {
                param = "";
            }
            label = WGUtils.strReplace(label, LABELPARAM_OPENER + (idx+1) + LABELPARAM_CLOSER, String.valueOf(param), true);
        }
        return label;
       
    }


    public String label(String fileName, String key, List params) {
        return label(null, fileName, key, params);
    }
   
    public String label(String fileName, String key) {
        return label(null, fileName, key, null);
    }
   
    public String label(String key, List params) {
        return label(null, null, key, params);
    }
   
    public String label(String key) {
        return label(null, null, key, null);
    }

    public boolean haslabel(String key) {
        return (label(null, null, key, null, false) != null);
    }
   
    public boolean haslabel(String fileName, String key) {
        return (label(null, fileName, key, null, false) != null);
    }

    public boolean haslabel(String containerName, String fileName, String key) {
        return (label(containerName, fileName, key, null, false) != null);
    }


    /**
     * @return Returns the webEnvironment.
     */
    public boolean iswebenvironment() {
        return getEnvironment().isWebEnvironment();
    }
   
    /**
     * wrapper for TestCore.assertTrue(...)
     * @param title assertion-title
     * @param category assertion-category
     * @param condition tmlscript-condition to test for true
     */
    @CodeCompletion
    public void asserttrue(String title, String category, String condition) {
        this.getwgacore().getTestCore().assertTrue(title, category, condition, this);
    }
   
    /**
     * wrapper for TestCore.assertEquals(...)
     * @param title assertion-title
     * @param category assertion-category
     * @param obj1 Object1 for compare
     * @param obj2 Object2 for compare
     */
    @CodeCompletion
    public boolean assertequals(String title, String category, Object obj1, Object obj2) {
        return this.getwgacore().getTestCore().assertEquals(title, category, obj1, obj2, this);
    }

    /**
     * wrapper for TestCore.assertTrue(...)
     * @param id of preregistered assertion
     * @param condition tmlscript-condition to test for true
     */
    @CodeCompletion
    public void asserttrue(String id, String condition) {
        this.getwgacore().getTestCore().assertTrue(id, condition, this);
    }
   
    /**
     * wrapper for TestCore.assertEquals(...)
     * @param id of preregistered assertion
     * @param obj1 Object1 for compare
     * @param obj2 Object2 for compare
     */
    @CodeCompletion
    public void assertequals(String id, Object obj1, Object obj2) {
        this.getwgacore().getTestCore().assertEquals(id, obj1, obj2, this);
    }   
   
    /**
     * wrapper for TestCore.registerAssertTrue()
     * @param id unqiue id for the assertion
     * @param title assertion-title
     * @param category assertion-category
     */
    public void registerasserttrue(String id, String title, String category) {
        this.getwgacore().getTestCore().registerAssertTrue(id, title, category);
    }
   

   
    /**
     * wrapper for TestCore.registerAssertEquals()
     * @param id unqiue id for the assertion
     * @param title assertion-title
     * @param category assertion-category
     */
    public void registerassertequals(String id, String title, String category) {
        this.getwgacore().getTestCore().registerAssertEquals(id, title, category);
    }

    /**
     * wrapper for TestCore.assertIsRegisteredOrExecuted()
     * @param id unique id for the assertion
     * @return true/false
     */
    @CodeCompletion
    public boolean assertisregisteredorexecuted(String id) {
        return this.getwgacore().getTestCore().assertIsRegisteredOrExecuted(id);
    }   
   
    /**
     * enable or disable TestCore.assertionDebugMode
     */
    @CodeCompletion
    public void assertiondebug(boolean enabled) {
        this.getwgacore().getTestCore().setDebugAssertions(enabled);
    }
   
    @CodeCompletion
    public boolean isassertiondebug() {
        return this.getwgacore().getTestCore().isDebugAssertions();
    }   
   
   
    @CodeCompletion
    public void changesessionpassword(String domain, String newPassword) {
       
        // Fetch the login info for the current user
        DBLoginInfo loginInfo = (DBLoginInfo) getwgacore().getSessionLogins(gethttpsession()).get(domain);
        if (loginInfo == null) {
            return;
        }
      
        // Change password on login info
        loginInfo.setCredentials(newPassword);
       
        // Change cached password on domain auth module, if it is password-caching
        if (!WGDatabase.SESSIONTOKEN_USER.equals(loginInfo.getUserName())) {
            DomainConfiguration domConfig = getwgacore().getDomainConfig(domain);
            if (domConfig != null && domConfig.getAuthModule() instanceof PasswordCachingAuthenticationModule) {
                PasswordCachingAuthenticationModule module = (PasswordCachingAuthenticationModule) domConfig.getAuthModule();
                module.dropPasswordCache(loginInfo.getUserName());       
    }
        }
       
       
    }
   
    @CodeCompletion
    public void changesessionpassword(String newPassword) throws WGAPIException {
        changesessionpassword((String) meta("db", "domain"), newPassword);
    }
   



    public TMLAction getActionByID(String id, String dbkey) {

        // Default action
        if (id.startsWith("$")) {
            return new TMLAction(id);
        }


        // If tag is present (WebTML-Environment) we can use action registration
        Map actionRegistration = getActionRegistration();
           
        // First try: Search for registered action qualified by design db
        // If there are multiple actions with the same id (from different databases), we need to find the one defined for the current design database first
        Integer actionKey;
        TMLAction action = fetchActionByQualifiedId(id, dbkey, actionRegistration);
        if (action != null) {
            return action;
        }
       
       
        // Second try: Search for module action in the current design db
        try {
           
            // Interpret id as module id
            String moduleId = resolveDesignReference(id);
           
            // If the resolved id differs we will again try to fetch it from registration
            if (!moduleId.equals(id)) {
                action = fetchActionByQualifiedId(id, dbkey, actionRegistration);
                if (action != null) {
                    return null;
                }
            }
           
            action = getModuleActionByID(moduleId, dbkey);
            if (action != null) {
                return action;
            }
        }
        catch (TMLActionException e) {
            addwarning(e.getMessage());
        }
       
       
        // Third try: search for registered action, not qualified by dbkey. We can find actions registered by other DBs that way.
        actionKey = (Integer) actionRegistration.get("ID#" + id.toLowerCase());
        if (actionKey != null) {
            action = (TMLAction) actionRegistration.get(actionKey);
            if (action != null && action.upToDate(this)) {
                return action;
            }
        }

        // No action found
        return null;
    }

    private TMLAction fetchActionByQualifiedId(String id, String dbkey, Map actionRegistration) {
        String qualifiedID = id;
        if (qualifiedID.indexOf("/") == -1) {
            qualifiedID = "ID#" + (dbkey + ACTIONID_DIVIDER + id).toLowerCase();
        }
        TMLAction action = null;
        Integer actionKey = (Integer) actionRegistration.get(qualifiedID);
        if (actionKey != null) {
            TMLAction theAction = (TMLAction) actionRegistration.get(actionKey);
            if (theAction != null && theAction.upToDate(this)) {
                action = theAction;
            }
        }
        return action;
    }
   
    public String getDesignDBKey() {
        return _designContext.getDesignDB().getDbReference();
    }

    public TMLAction getModuleActionByID(String id, String dbKey) throws TMLActionException {
        try {
           
           
            // Determine if there is dbkey information in the id
            List idParts = WGUtils.deserializeCollection(id, "/");
            if (idParts.size() == 2) {
                dbKey = (String) idParts.get(0);
                id = (String) idParts.get(1);
            }
           
            // Get the design db. Either by dbkey in id, by parameter dbkey, by current design db of WebTML or just the current context db
            WGDatabase designDB;
            if (!WGUtils.isEmpty(dbKey)) {
                designDB = db(dbKey);
            }
            else {
                designDB = designdb();
            }
           
            if (designDB == null) {
                throw new TMLActionException("Could not open design db to load tmlscript action module, because it does not exist.");
            }
            if (!designDB.isSessionOpen()) {
                throw new TMLActionException("Could not open design db '" + designDB.getDbReference() + "' to load tmlscript action module, because  you have no access.");
            }
           
            WGCSSJSModule mod = designDB.getCSSJSModule(id, WGScriptModule.CODETYPE_TMLSCRIPT);
            if (mod == null) {
                return null;
            }
           
            TMLAction action =  TMLAction.buildActionFromScriptModule(mod);
            registerAction(action, id, designDB.getDbReference());
            return action;
           
        }
        catch (WGException e) {
           throw new TMLActionException("Could not open design db to load tmlscript action module", e);
        }
    }
   
    @CodeCompletion
    public TMLForm createform(FormInfo formInfo) throws WGAPIException {
       
        TMLForm form = new TMLForm(formInfo, this, getwgacore().getLog());
       _environment.setForm(form);
        return form;
       
    }
   
    @CodeCompletion
    public FormInfo createforminfo(String id) {
        return new FormInfo(id);
    }


    /**
     * Takes a reference name that might be a local name (starting with ":").
     * If it is a local name it will get expanded by the directory name of the currently executed module.
     * If it is not it will just get returned unmodified.
     * @param ref The reference name to expand
     * @param currentModuleRef The name of the currently executed module
     * @return The expanded name
     */
    private static String expandLocalName(String ref, String currentModuleRef) {
       
        if (ref.startsWith("::")) {
            int colonPos = -1;
            if (currentModuleRef != null) {
                colonPos =currentModuleRef.lastIndexOf(":");
            }
            if (colonPos != -1) {
                return currentModuleRef.substring(0, colonPos) + ref.substring(1);
            }
            else {
                return ref.substring(2);
            }
        }
        else {
            return ref;
        }
    }
   
    @CodeCompletion
    public WGResultSet lucenesearch(String phrase, String scope) throws WGQueryException {
        Map params = new HashMap();
       
        scope = scope.toLowerCase();
        if (scope.equals("wga")) {
            params.put(LuceneManager.QUERYOPTION_SEARCHSCOPE, LuceneManager.SEARCHSCOPE_WGA);
        }
        else if (scope.equals("domain")) {
            params.put(LuceneManager.QUERYOPTION_SEARCHSCOPE, LuceneManager.SEARCHSCOPE_DOMAIN)
        }
        else {
            params.put(LuceneManager.QUERYOPTION_SEARCHSCOPE, LuceneManager.SEARCHSCOPE_DB);
        }
       
        return getwgacore().getLuceneManager().search(db(), phrase, params, getrequest());
    }
   
    @CodeCompletion
    public WGResultSet lucenesearch(String phrase) throws WGQueryException {
        return lucenesearch(phrase, "db");
    }
   
    public String fileurl(String containerName, String fileName) throws UnsupportedEncodingException, WGAPIException {
        return fileurl(null, containerName, fileName);
    }
   
    public String fileurl(String dbKey, String containerName, String fileName) throws UnsupportedEncodingException, WGAPIException {
        return getURLBuilder().buildFileURL(this, dbKey, containerName, fileName);
    }
   
    public String fileurl(String fileName) throws UnsupportedEncodingException, WGAPIException {
        return getURLBuilder().buildFileURL(this, null, null, fileName);
    }
   
   
    public String filedataurl(String containerName, String fileName) throws WGAPIException {
        return filedataurl(containerName, fileName, null);
    }
   
    public String filedataurl(String fileName) throws WGAPIException {
        return filedataurl(null, fileName, null);
    }
   
    public String filedataurl(String containerName, String fileName, String contentType) throws WGAPIException {
        return filedataurl(null, containerName, fileName, contentType);
    }
   
    /**
     * creates a RFC2397 data url from the given file
     * @param dbKey
     * @param containerName
     * @param fileName
     * @param contentType
     * @return The url
     * @throws WGAPIException
     */
    public String filedataurl(String dbKey, String containerName, String fileName, String contentType) throws WGAPIException {
       
        // retrieve input stream
        InputStream fileIn = null;
        int fileSize = 0;
        try {
           
        if (containerName == null) {
            // get file from current content
            fileIn = content().getFileData(fileName);
            fileSize = content().getFileSize(fileName);
            if (fileIn == null) {
                addwarning("File '" + fileName + "' is not attached to content '" + content().getContentKey().toString() + "'.");
                return null;
            }
        }
        else {
            // get file from filecontainer
            WGDatabase designDB = null;
                if (dbKey != null) {
                    designDB = db(dbKey);
                }
                else {
                  designDB = designdb();
                }
               
                if (designDB == null) {
                    addwarning("Unknown design db: " + dbKey);
                    return null;
                }
               
                // first try - lookup file container of designDB or explicit given db
                WGDocument container = designDB.getFileContainer(containerName);
                if (container == null) {
                  // second try - lookup file container in current context db
                  container = db().getFileContainer(containerName);
                 
                  if (container == null) {
                    // third try - use container name as key and try to find a content document
                    container = WGPDispatcher.getContentByAnyKey(containerName, db(), new WebTMLLanguageChooser(db(), this), isbrowserinterface());
                  }
                }
               
                if (container != null) {
                fileIn = container.getFileData(fileName);
                fileSize = container.getFileSize(fileName);
                } else {
                  addwarning("No file container or content found for '" + containerName + "'.");
                    return null;
                }
               
                if (fileIn == null) {
                    addwarning("File '" + fileName + "' not found in filecontainer '" + containerName + "'.");
                    return null;
                }               
            }
        }
            catch (WGException e) {
                addwarning("Error opening design db " + getDesignDBKey() + ": " + e.getClass().getName() + " - " + e.getMessage());
                getwgacore().getLog().error("Error opening design db " + getDesignDBKey(), e);
                return null;
            }
       
       
        // Create the byte array to hold the data
        byte[] fileData = new byte[fileSize]
        // read filedata in byte-array
        try {           
            // Read in the bytes
            int offset = 0;
            int numRead = 0;
            while (offset < fileData.length
                   && (numRead=fileIn.read(fileData, offset, fileData.length-offset)) >= 0) {
                offset += numRead;
            }
            // Ensure all the bytes have been read
            if (offset < fileData.length) {
                addwarning("Not all data could be readed from file '" + fileName + "'.");
                return null;
            }
            // close the stream
            fileIn.close();
        } catch (IOException e) {
            addwarning("Unable to read file '" + fileName + "' from filecontainer '" + containerName + "' - " + e.getMessage());
            getwgacore().getLog().error("Unable to read file '" + fileName + "' from filecontainer '" + containerName + "'.", e);
            return null;
        }
       
        if (contentType == null && getEnvironment().isPageContextAvailable()) {
            // try to determine mime type
            contentType = getEnvironment().getPageContext().getServletContext().getMimeType(fileName);           
        }       
        return createDataURL(fileData, contentType);       
    }
   
    /**
     * creates a base64 encoded RFC2396 dataurl
     * @param data
     * @param contentType
     * @return
     */
    private String createDataURL(byte data[], String contentType) {
        StringBuffer url = new StringBuffer();
        url.append("data:");
        if (contentType != null) {
            url.append(contentType);           
        }
        url.append(";base64");
        url.append("," + Base64.encode(data));
        return url.toString();       
    }
   
    /**
     * creates an urlencoded RFC2396 dataurl
     * @param data
     * @return
     * @throws UnsupportedEncodingException
     */
    private String createDataURL(String data, String contentType) throws UnsupportedEncodingException {
        StringBuffer url = new StringBuffer();
        url.append("data:");
        if (contentType != null) {
            url.append(contentType);           
        }
        // RFC2396 defines that data is encoded in US-ASCII 
        url.append("," + URLEncoder.encode(data, "UTF-8"));
        return url.toString();
    }
   
    public void saveprofileonend() {
        if (!iswebenvironment()) {
            return;
        }
       
        TMLUserProfile prof = getprofile();
        if (prof == null) {
            return;
        }
       
        prof.setSavedOnEnd(true);
    }
   
    @CodeCompletion
    public Map createlookuptable() {
        return new HashMap();
    }
   
    public PortletEvent createevent(String name) {
        return new PortletEvent(name);
    }
   
    public String createJavaScriptPortletEvents(String portletKey, boolean skipScriptTags) {       
        HashSet portletEvents = (HashSet) getrequest().getAttribute(TMLPortlet.PORTLET_EVENT_REQUEST_ATTR_PREFIX + portletKey);
        if (portletEvents != null) {
            StringBuffer javaScript = new StringBuffer();
            if (!skipScriptTags) {
                javaScript.append("<script type=\"text/javascript\">");
            }
            Iterator it = portletEvents.iterator();
            while (it.hasNext()) {
                PortletEvent event = (PortletEvent) it.next();               
                javaScript.append("WGA.event.dispatch(" + event.toJavaScriptObject() + ");");
            }
            if (!skipScriptTags) {
                javaScript.append("</script>");
            }
            return javaScript.toString();
        else {
            return null;
        }
       
    }


    public boolean isempty(String itemName) throws WGAPIException {
       
        Object item = item(itemName);
        return isemptyvalue(item);
       
    }


    public boolean isemptyvalue(Object value) {
        if (value == null) {
            return true;
        }
       
        if (value instanceof List) {
            List list = (List) value;
            if (list.size() == 0) {
                return true;
            }
        }
       
        if (value instanceof String) {
            String string = (String) value;
            if (string.trim().equals("")) {
                return true;
            }
           
            // RTF-Editor sets a single <br> to a field when empty
            if (string.trim().equals("<br>")) {
                return true;
            }
        }
       
        return false;
    }
   
    public boolean isfilled(String attValue) throws WGAPIException {
       
        boolean isEditmode = (isbrowserinterface() && content().getStatus().equals(WGContent.STATUS_DRAFT));
        if (!isEditmode) {
            return !isempty(attValue);
        }
        else {
            return true;
        }
       
    }


    public String createJavaScriptPortletRegistration(String portletKey, boolean skipScriptTags) throws WGAPIException {
        // fetch parent keys
        HashSet parentPortletKeys = new HashSet();
        TMLPortlet portlet = this.getportletbykey(portletKey);
        String parentKey = portlet.getparentkey();
        if (parentKey != null) {
            TMLPortlet parentPortlet = portlet.getparentportlet();
            while (parentKey != null && !parentPortlet.isroot() && parentPortlet != null) {
                parentPortletKeys.add(parentPortlet.getportletkey());
                parentKey = parentPortlet.getparentkey();
                parentPortlet = parentPortlet.getparentportlet();               
            }
        }
       
        // create javascript array from parent keys
        String javaScriptParentPortletKeyArray = "new Array(";
        Iterator it = parentPortletKeys.iterator();
        while (it.hasNext()) {
            javaScriptParentPortletKeyArray += "\"" + it.next() + "\"";
            if (it.hasNext()) {
                javaScriptParentPortletKeyArray += ",";
            }
        }
        javaScriptParentPortletKeyArray += ")";
       
        // create javascript block for registration
        StringBuffer javaScript = new StringBuffer();
        if (!skipScriptTags) {
            javaScript.append("<script type=\"text/javascript\">");
        }
        javaScript.append("WGA.portlet.register(\"" + portletKey + "\"," + javaScriptParentPortletKeyArray + ");");
        if (!skipScriptTags) {
            javaScript.append("</script>");
        }
        return javaScript.toString();
    }
   
    @CodeCompletion
    public boolean login(String user, String password, String domain) throws LoginException, WGAPIException {
        return getwgacore().login(user, password, domain, getrequest(), getresponse());
    }
   
    public boolean login(String user, String password) throws LoginException, WGAPIException {
        return login(user, password, (String) db().getAttribute(WGACore.DBATTRIB_DOMAIN));
    }
   
    @CodeCompletion
    public boolean logout(String domain) throws WGAPIException {
        return getwgacore().logout(domain, getrequest().getSession());
    }


   
    @CodeCompletion
    public WGDatabase plugindb(String pluginUniqueName) throws WGException {
        return db(plugindbkey(pluginUniqueName));
    }
   
    @CodeCompletion
    public PluginID pluginid(String pluginUniqueName) throws WGException {
       
        WGAPlugin plugin = getwgacore().getPluginSet().getPluginByUniqueName(pluginUniqueName);
        if (plugin != null) {
            return plugin.getCsConfig().getPluginConfig().getId();
        }
        else {
            return null;
        }

    }
   
    @CodeCompletion
    public String plugindbkey(String pluginUniqueName) {
       
        WGAPlugin plugin = getwgacore().getPluginSet().getPluginByUniqueName(pluginUniqueName);
        if (plugin != null) {
            return plugin.buildDatabaseKey();
        }
        else {
            return null;
        }
       
    }
   
    @CodeCompletion
    public String encode(String encode, Object input) throws FormattingException {
      ObjectFormatter formatter = getwgacore().getEncodingFormatter(encode, this);
      if (formatter != null) {
        return formatter.format(input);
      }
      else {
        addwarning("No encoding formatter registered under encoding key '" + encode + "'");
        return input.toString();
      }     
    }
   
    public String multiencode(String encode, Object input) throws FormattingException {
       
        FormattingChain formatters = new FormattingChain();
        Iterator encoders = WGUtils.deserializeCollection(encode, ",", true).iterator();
        while (encoders.hasNext()) {
            String encoder = (String) encoders.next();
            ObjectFormatter formatter = getwgacore().getEncodingFormatter(encoder, this);
            formatters.addFormatter(formatter);
        }
       
        return formatters.format(input);
       
    }
   
    public WGAURLBuilder getURLBuilder() {
        if (iswebenvironment()) {
            return (WGAURLBuilder) getrequest().getAttribute(WGACore.ATTRIB_URLBUILDER);
        }
        else {
            return new DefaultURLBuilder();
        }
    }
   
    @CodeCompletion
    public Document loadhtml(HttpClient client, String url) throws UnsupportedEncodingException, WGAPIException, IOException, HttpException, SAXException {
       
        if (client == null) {
            client = new HttpClient();
        }
       
        GetMethod homePageMethod = new GetMethod(url);
        int status = client.executeMethod(homePageMethod);
       
        if (homePageMethod.getStatusCode() != 200) {
            throw new HttpException("HTTP Status Code is " + homePageMethod.getStatusCode());
        }
       
        DOMParser parser = new DOMParser();
        parser.setFeature("http://xml.org/sax/features/namespaces", false);
       
        InputSource inputSource;
        if (homePageMethod.getResponseCharSet() != null) {
            Reader reader = new InputStreamReader(homePageMethod.getResponseBodyAsStream(), homePageMethod.getResponseCharSet());
            inputSource = new InputSource(reader);
        }
        else {
            inputSource = new InputSource(homePageMethod.getResponseBodyAsStream());   
        }
       
        parser.parse(inputSource);
        org.w3c.dom.Document w3cDoc = parser.getDocument();
       
        DOMReader xmlReader = new DOMReader();
        return xmlReader.read(w3cDoc);
       
    }
   
    @CodeCompletion
    public Document loadhtml(String url) throws UnsupportedEncodingException, WGAPIException, HttpException, IOException, SAXException {
        return loadhtml(null, url);
    }
   
    @CodeCompletion
    public Document parsehtml(String html) throws SAXException, IOException {
       
        DOMParser parser = new DOMParser();
        parser.parse(new InputSource(new StringReader(html)));
        org.w3c.dom.Document w3cDoc = parser.getDocument();
       
        DOMReader xmlReader = new DOMReader();
        return xmlReader.read(w3cDoc);
       
    }
   
    /**
     * Registers an action for the current Http-Session, if an action with this code is not already registered.
     * Further code about this action object should use the object returned by this method, since that may be
     * a previous registered instance of it with the correct sequence number.
     * @param currentAction The action to register
     * @param id The id of the action. Specify null if the action has no id.
     * @return The action that is registered. Either the action given as parameter, or another one with identical code that already was registered
     */
    public TMLAction registerAction(TMLAction currentAction, String id, String designDB) {
       
        TMLAction tmlAction;
       
        // Check if action registration available. If not, fail silent.
        Map actions = getActionRegistration();
        if (actions == null) {
            return currentAction;
        }
       
        // check if action already exists
        if (!actions.containsKey(currentAction.getKey())) {
            // register new action
            actions.put(currentAction.getKey(), currentAction);
            tmlAction = currentAction; // store new action under tmlAction for further operations
        }
        else {
            // get registered action for further opertations
            tmlAction = (TMLAction) actions.get(currentAction.getKey());
        }
       
        // register action id mapping
        if (id != null) {
            // Map with design db qualifier
            actions.put("ID#" + (designDB + TMLContext.ACTIONID_DIVIDER + id).toLowerCase(), currentAction.getKey());
           
            // Map without design db qualifier
            actions.put("ID#" + id.toLowerCase(), currentAction.getKey());

            currentAction.setID(id.toLowerCase());
        }
        return tmlAction;
    }
   
    protected void removePortletVariables(TMLPortlet portlet) {
       
        String prefix = portlet.getVarPrefix();
       
        // Request variables
        Iterator varsIt = _environment.getVars().keySet().iterator();
        String key;
        while (varsIt.hasNext()) {
            key = (String) varsIt.next();
            if (key.startsWith(prefix)) {
                varsIt.remove();
            }
           
        }

        // Session variables
        Map sessionVars = _environment.getSessionVars();
        synchronized (sessionVars) {
            varsIt = sessionVars.keySet().iterator();
            while (varsIt.hasNext()) {
                key = (String) varsIt.next();
                if (key.startsWith(prefix)) {
                    varsIt.remove();
                }
            }
        }
       
       
    }
 
   
    public String geturlparameter(String name) {
      return getrequest().getParameter(name);
    }
   
  public List geturlparameterlist(String name) {
    String[] values = getrequest().getParameterValues(name);
    List list = new ArrayList();
    if (values != null) {
      for (int i = 0; i < values.length; i++) {
        list.add(values[i]);
      }
    }
    return list;
  }

  public List geturlparameternames() {
    return new ArrayList(getrequest().getParameterMap().keySet());
  }
 
  public void seturlparameterifempty(String name, String value) throws WGIllegalStateException {
    if (getrequest() instanceof WGAFilter.GETRequestWrapper) {
      GETRequestWrapper wrapper = (WGAFilter.GETRequestWrapper) getrequest();             
      wrapper.setParameterIfEmpty(name, value);                   
    } else {
      throw new WGIllegalStateException("method setUrlParameterIfEmtpy() is only supported on GET requests.");
    }
  }
 
  public void seturlparameterifempty(String name, List values) throws WGIllegalStateException {
    if (getrequest() instanceof WGAFilter.GETRequestWrapper) {
      GETRequestWrapper wrapper = (WGAFilter.GETRequestWrapper) getrequest();
      wrapper.setParameterIfEmpty(name, (String[]) values.toArray(new String[values.size()]))
    } else {
      throw new WGIllegalStateException("method setUrlParameterIfEmtpy() is only supported on GET requests.");
    }
  }
 
 
  public boolean isfirstloop() {
     
      BaseTagStatus tag = getDesignContext().getTag();
        if (tag == null) {
            return false;
        }
     
    ForEach.Status targetTag = (ForEach.Status) tag.getAncestorTag(IterationTag.class);
    if (targetTag == null) {
      addwarning("Could not find ancestor iteration tag for method isfirstloop().");
      return false;
    }
    return targetTag.getIterationIndex() == 1;
  }
 
  public boolean islastloop() {
     
      BaseTagStatus tag = getDesignContext().getTag();
        if (tag == null) {
            return false;
        }
     
    ForEach.Status targetTag = (ForEach.Status) tag.getAncestorTag(IterationTag.class);
    if (targetTag == null) {
      addwarning("Could not find ancestor iteration tag for method islastloop().");
      return false;
    }
   
    return targetTag.isLastIteration();
  }
 
  public boolean isfirstloop(String tagId) {
     
      BaseTagStatus tag = getDesignContext().getTag();
        if (tag == null) {
            return false;
        }
         
    IterationTagStatus targetTag = (IterationTagStatus) tag.getTagStatusById(tagId, IterationTagStatus.class);
    if (targetTag == null) {
      addwarning("Could not find iteration tag with id '" + tagId + "'.");
      return false;
    }
    return targetTag.getIterationIndex() == 1;
  }
 
  public boolean islastloop(String tagId) {
    BaseTagStatus tag = getDesignContext().getTag();
    if (tag == null) {
        return false;
    }
   
        IterationTagStatus targetTag = (IterationTagStatus) tag.getTagStatusById(tagId, IterationTagStatus.class);
    if (targetTag == null) {
      addwarning("Could not find iteration tag with id '" + tagId + "'.");
      return false;
    }
    return targetTag.isLastIteration();
 
 

 

 
  public String resolveDBKey(String dbkey) {
     
      if (dbkey == null) {
          return null;
      }
     
      if (dbkey.startsWith("@")) {
          String pluginShortcut = dbkey.substring(1);
          WGDatabase designDB = getDesignContext().getDesignDB();
          if (designDB == null) {
              addwarning("Unable to allocate design database");
              return dbkey;
          }
         
          Map pluginShortcuts = (Map) designDB.getAttribute(WGACore.DBATTRIB_PLUGIN_SHORTCUTS);
          String pluginUniqueName = (String) pluginShortcuts.get(pluginShortcut);
          if (pluginUniqueName != null) {
              String pluginKey = plugindbkey(pluginUniqueName);
              if (pluginKey != null) {
                  return pluginKey;
              }
          }
      }
     
      return dbkey;
     
  }



    /**
   * Ugly duplicate of {@link #pluginid(WGDatabase)}, kept for historical reasons. See B00005E92
   * @param db
   * @return
   */
  public PluginID getpluginid(WGDatabase db) {
      return pluginid(db);
  }
 
  @CodeCompletion
  public PluginID pluginid(WGDatabase db) {
      return (PluginID) db.getAttribute(WGACore.DBATTRIB_PLUGIN_ID);
  }


    public Map getPersistentForms() {
        return _environment.getPersistentForms();
    }


    public TMLDesignContext getDesignContext() {
        return _designContext;
    }
 
   
    public ExpressionResult evaluateExpression(String expression, Map additionalObjects) {
      ExpressionEngine engine = ExpressionEngineFactory.getEngine(ExpressionEngineFactory.ENGINE_TMLSCRIPT);
      return engine.evaluateExpression(expression, this, ExpressionEngine.TYPE_EXPRESSION, additionalObjects);
    }
   
    public ExpressionResult evaluateExpression(String expression) {
      return evaluateExpression(expression, null);
    }
   
    public ExpressionResult evaluateScript(String script, Map additionalObjects) {
      ExpressionEngine engine = ExpressionEngineFactory.getEngine(ExpressionEngineFactory.ENGINE_TMLSCRIPT);
      return engine.evaluateExpression(script, this, ExpressionEngine.TYPE_SCRIPT, additionalObjects);
    }
   
    public ExpressionResult evaluateScript(String script) {
      return evaluateScript(script, null);
    }
   
    @CodeCompletion
    public void waitforauthupdates(WGDatabase db, int timeoutSeconds) throws TMLScriptException {
       
        if (db == null) {
            db = db();
        }
       
        // Collect the CSAuthModules listening to content save events on this database
        List listeners = db.getContentEventListeners();
        List modules = new ArrayList();
        synchronized (listeners) {
            Iterator it = listeners.iterator();
            while (it.hasNext()) {
               WGContentEventListener listener = (WGContentEventListener) it.next();
               if (listener instanceof CSAuthModule) {
                   modules.add(listener);
               }
            }
        }
       
        // Look thru the modules until their currently running update threads have finished
        long timeout = System.currentTimeMillis() + (timeoutSeconds * 1000);
        Map moduleThreads = new HashMap();
        do {
           
            // Idle. Check timeout
            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
            }
            if (System.currentTimeMillis() > timeout) {
                throw new TMLScriptException("Method waitForAuthUpdates() encountered timout of " + timeoutSeconds +  "seconds");
            }
           
            // Iterate modules
            Iterator modIt = modules.iterator();
            while (modIt.hasNext()) {
                CSAuthModule mod = (CSAuthModule) modIt.next();
               
                // Look if a collector runs right now. If not, then this module is thru
                if (mod.getCurrentCollectorThread() == null) {
                    modIt.remove();
                }
               
                // A collection runs right now.
                else {

                    // Retrieve an maybe recorded earlier thread
                    Thread earlierThread = (Thread) moduleThreads.get(mod);
                   
                    // if there is no earlier thread then we just haven't recorded it yet
                    if (earlierThread == null) {
                        moduleThreads.put(mod, mod.getCurrentCollectorThread());
                    }
                   
                    // If there was an earlier thread, we look if it is still the same. If not, the earlier thread is finished and our update most likely thru
                    else if (!earlierThread.equals(mod.getCurrentCollectorThread())) {
                        modIt.remove();
                    }
                   
                }
            }
           
           
        } while (modules.size() > 0);
       
       
    }
   
   
    /**
     * Retrieves a WGA internal system label from the properties files lying under {@link WGACore#SYSTEMLABEL_BASE_PATH} in the language of the current request locale
     * @param systemBundleName Name of the bundle file
     * @param labelKey Key of the label
     * @param params A list of parameters that replace placeholders {1}...{n} in the label
     * @return The label or an empty string if none was found
     */
    public String systemLabel(String systemBundleName, String labelKey, List params) {
        String label;
        PropertyResourceBundle bundle = null;
       
        Locale locale = Locale.getDefault();
        if (iswebenvironment()) {
            locale = getrequest().getLocale();
        }
       
        try{
            bundle = (PropertyResourceBundle)ResourceBundle.getBundle(WGACore.SYSTEMLABEL_BASE_PATH + systemBundleName, locale, this.getClass().getClassLoader());
            label = bundle.getString(labelKey);
           
            if (label != null) {
                return mergeLabelWithParams(label, params);
            }
            else {
                return "";
            }
        }
        catch(java.util.MissingResourceException e){   
            this.addwarning(e.getMessage(), false);
            return "";
        }
       

    }
   
    public String systemLabel(String systemBundleName, String labelKey) {
        return systemLabel(systemBundleName, labelKey, null);
    }


    public static TMLContext createMasterSessionContext(TMLContext context) throws WGAPIException {
        TMLContext masterContext = new TMLContext(context.getdocument(), context.getwgacore(), context.getprofile(), context.gettmlform());
        try {
            masterContext.importEnvironmentData(context);
        }
        catch (TMLException e) {
            context.getlog().error("Error importing TMLScript environment settings", e);
        }
       return masterContext;
    }
   
    public WGUserAccess getoriginaluserdata() {
       
        RootEnvironmentUserData userData = getEnvironment().getRootEnvironmentUserData();
       
        // We have no root environment data = we are in root environment. So we return the current db user access
        if (userData == null) {
            return db().getSessionContext().getUserAccess();
        }
       
        // We return root environment data only if it matches the database currently in context
        if (userData.getDbkey().equals(db().getDbReference())) {
            return userData.getUserAccess();
        }
       
        // We have root environment data, but it does not match the current context db = we have no data for the current db. So return null.
        else {
            return null;
           
        }
       
    }

  public void removetmlform(String formid) {
    _environment.removeForm(formid);   
  }
 
  public void attachscaledimage(WGDocument doc, ImageScaler scaler, String targetFileName) throws IOException, WGAPIException {              
        // Determine final file name
        String finalFileName = null;
        if( targetFileName != null ) {
            finalFileName = targetFileName + scaler.getFormatSuffix();
        }
        else {
            String fileName = scaler.getSourceFileName();
            if (fileName == null) {
                throw new IllegalArgumentException("Unable to determine file name. Please specify as targetFileName.");
            }
           
            String suffix = null;
            if (scaler.getFormat().equals("JPEG")) {
                suffix = ".jpg";
            }
            else if (scaler.getFormat().equals("PNG")) {
                suffix = ".png";
            }
            finalFileName = fileName.substring(0, fileName.lastIndexOf(".")) + suffix;
        }
       
        TemporaryFile targetFile = new TemporaryFile(finalFileName, null, WGFactory.getTempDir());
        targetFile.deleteOnEviction(doc.getDatabase().getSessionContext());
       
        // Write scaled image to target file
        scaler.writeImage(targetFile.getFile());      
           
        // Attach scaled image
        doc.attachFile(targetFile.getFile());                 
    }
 
  public void attachscaledimage(WGDocument doc, ImageScaler scaler) throws IOException, WGAPIException {
        attachscaledimage(doc, scaler, null);
    }
 
  public TMLContext dbContext(WGDatabase dbTarget) throws WGAPIException {
     
      WebTMLLanguageChooser chooser = new WebTMLLanguageChooser(dbTarget, this);
      WGLanguage lang = chooser.selectDatabaseLanguage(dbTarget);
     
      // We want to create a db context even when there is no matching language
      // so we just create dummy content on the source context language
      if (lang == null) {
          lang = dbTarget.getLanguage(content().getLanguage().getName());
      }
     
        WGContent dummyContent = dbTarget.getDummyContent(lang.getName());
        if (dummyContent != null) {
            return getTMLContextForDocument(dummyContent);
        }
        else {
            return null;
        }
  }
 
  public BaseTagStatus gettag() {
      return getDesignContext().getTag();
  }
 
  public List<Warning> getWarnings() {
      return getEnvironment().getWarnings();
  }
 
  public String resolveDesignReference(String ref) {
      return resolveDesignReference(ref, null);
  }
 
  public String resolveDesignReference(String ref, String baseReference) {
     
      if (ref == null) {
          return null;
      }
     
      if (baseReference == null) {
          baseReference = getDesignContext().getBaseReference();
      }
     
      // There may be a dbkey prefix which we must isolate before continuing, append it later on return again
      int slashIdx = ref.indexOf("/");
      String dbkeyPrefix = "";
      if (slashIdx != -1) {
          dbkeyPrefix = ref.substring(0, slashIdx + 1);
          ref = ref.substring(slashIdx + 1);
      }
     
      // Isolate @ flag
      int atIdx = ref.indexOf("@");
      String flag = null;
      if (atIdx != -1) {
          flag = ref.substring(atIdx + 1);
          ref = ref.substring(0, atIdx);
      }
     
      // Handle local references
      ref = TMLContext.expandLocalName(ref, baseReference);
     
      // Determine if we are in an overlay-enabled design
    
      // Special rules for overlay folder/design
      if (baseReference != null && (baseReference.startsWith(OverlayDesignProvider.OVERLAY_PREFIX) || baseReference.equals(OverlayDesignProvider.OVERLAY_FOLDER))) {
         
          // References always go to overlay, unless the "@base" flag is used
          if (!"base".equals(flag) && !ref.startsWith(OverlayDesignProvider.OVERLAY_PREFIX) && !ref.equals(OverlayDesignProvider.OVERLAY_FOLDER)) {
              ref = OverlayDesignProvider.OVERLAY_PREFIX + ref;
          }
         
          // If "@base" flag is used the reference must go outside the overlay (cannot happen normally)
          else if ("base".equals(flag) && ref.startsWith(OverlayDesignProvider.OVERLAY_PREFIX)) {
              ref = ref.substring(OverlayDesignProvider.OVERLAY_PREFIX.length());
          }
      }
     
      return dbkeyPrefix + ref;
  }
 
    public String getScopedString(String str, String scope) {
        return str + WEBTML_SCOPE_DIVIDER + scope;
    }
 
TOP

Related Classes of de.innovationgate.wgpublisher.webtml.utils.TMLContext$ListVarContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.