org.jwebsocket.plugins.scripting.app.BaseScriptApp.java Source code

Java tutorial

Introduction

Here is the source code for org.jwebsocket.plugins.scripting.app.BaseScriptApp.java

Source

//   ---------------------------------------------------------------------------
//   jWebSocket - BaseScriptApp for Scripting Plug-in (Community Edition, CE)
//   ---------------------------------------------------------------------------
//   Copyright 2010-2014 Innotrade GmbH (jWebSocket.org)
//   Alexander Schulze, Germany (NRW)
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//   ---------------------------------------------------------------------------
package org.jwebsocket.plugins.scripting.app;

import java.io.File;
import java.security.Permissions;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.jms.Connection;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javolution.util.FastList;
import javolution.util.FastMap;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.jwebsocket.api.IChunkable;
import org.jwebsocket.api.IChunkableDeliveryListener;
import org.jwebsocket.api.IPacketDeliveryListener;
import org.jwebsocket.api.WebSocketConnector;
import org.jwebsocket.api.WebSocketServer;
import org.jwebsocket.config.JWebSocketConfig;
import org.jwebsocket.factory.LocalLoader;
import org.jwebsocket.logging.Logging;
import org.jwebsocket.plugins.scripting.ScriptingPlugIn;
import org.jwebsocket.spring.JWebSocketBeanFactory;
import org.jwebsocket.token.Token;
import org.jwebsocket.token.TokenFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.Assert;

/**
 * The class represents the global "App" object into script applications.
 * Contains abstract methods to be extended by concrete implementations for
 * custom languages like JavaScript or Groovy.
 *
 * @author Rolando Santamaria Maso
 */
abstract public class BaseScriptApp {

    /**
     *
     */
    protected ScriptingPlugIn mPlugIn;
    private final String mAppName;
    private final String mAppPath;
    private final ScriptEngine mScriptApp;
    private final Map<String, List<Object>> mCallbacks = new FastMap<String, List<Object>>().shared();
    private final ScriptAppLogger mLogger;
    private final Logger mLog = Logging.getLogger();
    private final Map<String, Object> mApi = new FastMap<String, Object>().shared();
    private final GenericApplicationContext mBeanFactory = new GenericApplicationContext(
            new DefaultListableBeanFactory());
    private final ServerClient mServerClient;
    private final LocalLoader mClassLoader;
    private final String mJWSHome;
    private final String mNodeId;
    /**
     * String value for the "Connector Started" event. The event is fired when a
     * client started a connection with the server.
     */
    public final static String EVENT_CONNECTOR_STARTED = "connectorStarted";
    /**
     * String value for the "Connector Stopped" event. The event is fired when a
     * client stopped a connection with the server.
     */
    public final static String EVENT_CONNECTOR_STOPPED = "connectorStopped";
    /**
     * String value for the "Engine Started" event. The event is fired when a
     * jWebSocket engine has started.
     */
    public final static String EVENT_ENGINE_STARTED = "engineStarted";
    /**
     * String value for the "Engine Stopped" event. The event is fired when a
     * jWebSocket engine has stopped.
     */
    public final static String EVENT_ENGINE_STOPPED = "engineStopped";
    /**
     * String value for the "Session Started" event. The event is fired when a
     * new client session is created on the server.
     */
    public final static String EVENT_SESSION_STARTED = "sessionStarted";
    /**
     * String value for the "Session Stopped" event. The event is fired when an
     * existing client session is stopped(destroyed) on the server.
     */
    public final static String EVENT_SESSION_STOPPED = "sessionStopped";
    /**
     * String value for the "Logon" event. The event is fired when a client
     * logon.
     */
    public final static String EVENT_LOGON = "logon";
    /**
     * String value for the "Logoff" event. The event is fired when a client
     * logoff.
     */
    public final static String EVENT_LOGOFF = "logoff";
    /**
     * String value for the "Token" event. The event is fired when a token is
     * received from the client to the script application.
     */
    public final static String EVENT_TOKEN = "token";
    /**
     * String value for the "Filter In" event. The event is fired before client
     * tokens arrive to the application controller layer. It is designed to
     * allow pre-filtering.
     */
    public final static String EVENT_FILTER_IN = "filterIn";
    /**
     * String value for the "Filter Out" event. The event is fired before
     * application tokens are sent to the client. It is designed to allow
     * post-filtering.
     */
    public final static String EVENT_FILTER_OUT = "filterOut";
    /**
     * String value for the "System Starting" event. The event is fired when the
     * jWebSocket server system is starting.
     */
    public final static String EVENT_SYSTEM_STARTING = "systemStarting";
    /**
     * String value for the "System Started" event. The event is fired when the
     * jWebSocket server system has started.
     */
    public final static String EVENT_SYSTEM_STARTED = "systemStarted";
    /**
     * String value for the "System Started" event. The event is fired when the
     * jWebSocket server system is stopping.
     */
    public final static String EVENT_SYSTEM_STOPPING = "systemStopping";
    /**
     * String value for the "System Started" event. The event is fired when the
     * jWebSocket server system has stopped.
     */
    public final static String EVENT_SYSTEM_STOPPED = "systemStopped";
    /**
     * String value for the "Before App Reload" event. The event is fired before
     * reaload an script application. Allows to applications to perform
     * operations before to be reloaded.
     */
    public final static String EVENT_BEFORE_APP_RELOAD = "beforeAppReload";
    /**
     * String value for the "App Loaded" event. The event is fired when an
     * script app has been successfully loaded.
     */
    public final static String EVENT_APP_LOADED = "appLoaded";
    /**
     * String value for the "Undeploying" event. The event is fired when an
     * script app is going to be undeployed.
     */
    public final static String EVENT_UNDEPLOYING = "undeploying";

    /**
     * Gets the ScriptEngine instance associated to the script application.
     *
     * @return
     */
    protected ScriptEngine getScriptApp() {
        return mScriptApp;
    }

    /**
     * Gets the jWebSocket server node id
     *
     * @return
     */
    public String getNodeId() {
        return mNodeId;
    }

    /**
     * Gets the script application events callbacks collection.
     *
     * @return
     */
    protected Map<String, List<Object>> getCallbacks() {
        return mCallbacks;
    }

    /**
     * Gets the script app server internal client instance.
     *
     * @return
     */
    public ServerClient getServerClient() {
        return mServerClient;
    }

    /**
     * Constructor
     *
     * @param aPlugIn The ScriptingPlugIn reference that allows to script
     * applications to get access to the TokenServer instance.
     * @param aAppName The application name (unique value)
     * @param aAppPath The application directory path
     * @param aScriptApp The scripting engine that runs the application
     * @param aClassLoader
     */
    public BaseScriptApp(ScriptingPlugIn aPlugIn, String aAppName, String aAppPath, ScriptEngine aScriptApp,
            LocalLoader aClassLoader) {
        mPlugIn = aPlugIn;
        mAppName = aAppName;
        mAppPath = aAppPath;
        mScriptApp = aScriptApp;
        mLogger = new ScriptAppLogger(mLog, aAppName);
        mServerClient = new ServerClient(this);
        mClassLoader = aClassLoader;
        mNodeId = JWebSocketConfig.getConfig().getNodeId();

        // registering global "AppUtils" resource
        aScriptApp.put("AppUtils", this);

        mJWSHome = JWebSocketConfig.getJWebSocketHome();
    }

    /**
     * Returns the Script App programming language extension.
     *
     * @return
     */
    abstract public String getScriptLanguageExt();

    /**
     * Gets the ScriptEngine instance associated to the script application.
     *
     * @return
     */
    public ScriptEngine getEngine() {
        return mScriptApp;
    }

    /**
     *
     * @return
     */
    public Permissions getPermissions() {
        return mPlugIn.getAppPermissions(mAppName, mAppPath);
    }

    /**
     * Notify an event into the script application.
     *
     * @param aEventName The event name
     * @param aArgs The event arguments
     */
    abstract public void notifyEvent(String aEventName, Object[] aArgs);

    /**
     * Get the application name
     *
     * @return
     */
    public String getName() {
        return mAppName;
    }

    /**
     * Load a Jar into the script app class loader
     *
     * @param aFile
     * @return TRUE if the jar has beeen loaded, FALSE otherwise
     * @throws java.lang.Exception
     */
    public boolean loadJar(String aFile) throws Exception {
        aFile = aFile.replace("${APP_HOME}", mAppPath);
        aFile = aFile.replace("${EXT}", mPlugIn.getExtensionsDirectoryPath() + File.separator);

        return mClassLoader.loadJar(aFile);
    }

    /**
     * Publish and object to be accesed from the client.
     *
     * @param aObjectId The object identifier
     * @param aObject The object to be published
     */
    public void publish(String aObjectId, Object aObject) {
        mApi.put(aObjectId, aObject);
    }

    /**
     * Unpublish an object giving it identifier.
     *
     * @param aObjectId
     */
    public void unpublish(String aObjectId) {
        mApi.remove(aObjectId);
    }

    /**
     * Return TRUE if an object with the giving object identifier is published,
     * FALSE otherwise.
     *
     * @param aObjectId
     * @return
     */
    public boolean isPublished(String aObjectId) {
        return mApi.containsKey(aObjectId);
    }

    /**
     * Get a published object giving the object identifier.
     *
     * @param aObjectId
     * @return
     */
    public Object getPublished(String aObjectId) {
        return mApi.get(aObjectId);
    }

    /**
     * Get the script application root directory path.
     *
     * @return
     */
    public String getPath() {
        return mAppPath;
    }

    /**
     * Get the script application logger.
     *
     * @return
     */
    public ScriptAppLogger getLogger() {
        return mLogger;
    }

    /**
     * Raise an exception with the given message if the boolean expression is
     * FALSE.
     *
     * @param aExpression Boolean expression
     * @param aMessage The exception message
     */
    public void assertTrue(Boolean aExpression, String aMessage) {
        Assert.isTrue(aExpression, aMessage);
    }

    /**
     * Raise an exception with the given message if the Object argument is NULL.
     *
     * @param aObject The object
     * @param aMessage The exception message.
     */
    public void assertNotNull(Object aObject, String aMessage) {
        Assert.notNull(aObject, aMessage);
    }

    /**
     * Import a JavaScript file into the application.
     *
     * @param aFile The JavaScript file path. The string "${APP_HOME}" is
     * replaced by the application root directory path.
     * @throws Exception
     */
    public void importScript(String aFile) throws Exception {
        aFile = aFile.replace("${APP_HOME}", mAppPath);
        aFile = aFile.replace("${EXT}",
                mPlugIn.getExtensionsDirectoryPath() + File.separator + getScriptLanguageExt() + File.separator);

        // add the script extension (example: .js)
        String lScriptPath = aFile + "." + getScriptLanguageExt();
        eval(lScriptPath);
    }

    /**
     * Evaluate an script file into the app script engine.
     *
     * @param aScriptFilePath The script file path to evaluate.
     * @return
     * @throws Exception
     */
    public abstract Object eval(String aScriptFilePath) throws Exception;

    /**
     * Send a token to a given connector.
     *
     * @param aConnector The connector
     * @param aMap The Map representation of the Token
     * @param aFragmentSize The fragment size used to fragment the token. If
     * value is null, the token is not fragmented.
     */
    public void sendToken(WebSocketConnector aConnector, Map aMap, Integer aFragmentSize) {
        // outbound filtering
        notifyEvent(BaseScriptApp.EVENT_FILTER_OUT, new Object[] { aMap, aConnector });

        if (null != aFragmentSize) {
            mPlugIn.sendTokenFragmented(aConnector, toToken(aMap), aFragmentSize);
        } else {
            mPlugIn.sendToken(aConnector, toToken(aMap));
        }
    }

    /**
     * Send a token to a given connector.
     *
     * @param aConnectorId
     * @param aMap The Map representation of the Token
     * @param aFragmentSize The fragment size used to fragment the token. If
     * value is null, the token is not fragmented.
     */
    public void sendToken(String aConnectorId, Map aMap, Integer aFragmentSize) {
        sendToken(mPlugIn.getServer().getConnector(aConnectorId), aMap, aFragmentSize);
    }

    /**
     * Send a token to a given connector.
     *
     * @param aConnector The connector
     * @param aMap The Map representation of the Token
     */
    public void sendToken(WebSocketConnector aConnector, Map aMap) {
        sendToken(aConnector, aMap, null);
    }

    /**
     * Send a token to a given connector with acknowledge callbacks.
     *
     * @param aConnector The connector
     * @param aMap The Map representation of the Token
     * @param aListener The IPacketDeliveryListener implementation callback.
     */
    public void sendToken(WebSocketConnector aConnector, Map aMap, Object aListener) {
        // outbound filtering
        notifyEvent(BaseScriptApp.EVENT_FILTER_OUT, new Object[] { aMap, aConnector });

        mPlugIn.sendTokenInTransaction(aConnector, toToken(aMap),
                (IPacketDeliveryListener) cast(aListener, IPacketDeliveryListener.class));
    }

    /**
     * Send a token to a given connector with acknowledge callbacks.
     *
     * @param aConnectorId
     * @param aMap The Map representation of the Token
     * @param aListener The IPacketDeliveryListener implementation callback.
     */
    public void sendToken(String aConnectorId, Map aMap, Object aListener) {
        sendToken(mPlugIn.getServer().getConnector(aConnectorId), aMap, aListener);
    }

    /**
     * Send a fragmented token to a given connector with acknowledge callbacks.
     *
     * @param aConnector The connector
     * @param aMap The Map representation of the Token
     * @param aFragmentSize The fragmentation size
     * @param aListener The IPacketDeliveryListener implementation callback.
     */
    public void sendToken(WebSocketConnector aConnector, Map aMap, Integer aFragmentSize, Object aListener) {
        // outbound filtering
        notifyEvent(BaseScriptApp.EVENT_FILTER_OUT, new Object[] { aMap, aConnector });

        mPlugIn.sendTokenInTransaction(aConnector, toToken(aMap), aFragmentSize,
                (IPacketDeliveryListener) cast(aListener, IPacketDeliveryListener.class));
    }

    /**
     * Send a fragmented token to a given connector with acknowledge callbacks.
     *
     * @param aConnectorId
     * @param aMap The Map representation of the Token
     * @param aFragmentSize The fragmentation size
     * @param aListener The IPacketDeliveryListener implementation callback.
     */
    public void sendToken(String aConnectorId, Map aMap, Integer aFragmentSize, Object aListener) {
        sendToken(mPlugIn.getServer().getConnector(aConnectorId), aMap, aFragmentSize, aListener);
    }

    /**
     * Send a token to a given connector.
     *
     * @param aConnectorId
     * @param aMap The Map representation of the Token
     */
    public void sendToken(String aConnectorId, Map aMap) {
        sendToken(mPlugIn.getServer().getConnector(aConnectorId), aMap);
    }

    /**
     * Send a chunkable object to a given connector with acknowledge callbacks.
     *
     * @param aConnectorId
     * @param aChunkable The IChunkable implementation object
     */
    public void sendChunkable(String aConnectorId, Object aChunkable) {
        sendChunkable(mPlugIn.getServer().getConnector(aConnectorId), aChunkable);
    }

    /**
     * Send a chunkable object to a given connector with acknowledge callbacks.
     *
     * @param aConnectorId
     * @param aChunkable The IChunkable implementation object
     * @param aListener The IChunkableDeliveryListener implementation callback.
     */
    public void sendChunkable(String aConnectorId, Object aChunkable, Object aListener) {
        sendChunkable(mPlugIn.getServer().getConnector(aConnectorId), aChunkable, aListener);
    }

    /**
     * Send a chunkable object to a given connector with acknowledge callbacks.
     *
     * @param aConnector The connector
     * @param aChunkable The IChunkable implementation object
     */
    public void sendChunkable(WebSocketConnector aConnector, Object aChunkable) {
        mPlugIn.sendChunkable(aConnector, (IChunkable) cast(aChunkable, IChunkable.class));
    }

    /**
     * Send a chunkable object to a given connector with acknowledge callbacks.
     *
     * @param aConnector The connector
     * @param aChunkable The IChunkable implementation object
     * @param aListener The IChunkableDeliveryListener implementation callback.
     */
    public void sendChunkable(WebSocketConnector aConnector, Object aChunkable, Object aListener) {
        mPlugIn.sendChunkable(aConnector, (IChunkable) cast(aChunkable, IChunkable.class),
                (IChunkableDeliveryListener) cast(aListener, IChunkableDeliveryListener.class));
    }

    /**
     * Cast JavaScript context objects into Java objects
     *
     * @param aObject The object to be casted
     * @param aClass The casting object class
     * @return
     */
    public Object cast(Object aObject, Class aClass) {
        if (aObject.getClass().equals(aClass)) {
            return aObject;
        }

        try {
            // trying to cast first
            return aClass.cast(aObject);
        } catch (Exception lEx) {
        }

        // extracting interface
        return ((Invocable) mScriptApp).getInterface(aObject, aClass);
    }

    /**
     * Get all server connectors (clients).
     *
     * @return
     */
    public Collection<WebSocketConnector> getAllConnectors() {
        return mPlugIn.getServer().selectTokenConnectors().values();
    }

    /**
     * Return TRUE if the given connector has the given authority, FALSE
     * otherwise.
     *
     * @param aConnector The connector
     * @param aAuthority The authority
     * @return
     */
    public boolean hasAuthority(WebSocketConnector aConnector, String aAuthority) {
        return mPlugIn.hasAuthority(aConnector, aAuthority);
    }

    /**
     * Raise an exception if the client does not have the given authority.
     *
     * @param aConnector The connector
     * @param aAuthority The authority
     * @throws Exception
     */
    public void requireAuthority(WebSocketConnector aConnector, String aAuthority) throws Exception {
        if (!mPlugIn.hasAuthority(aConnector, aAuthority)) {
            throw new Exception("Not authorized. Missing required '" + aAuthority + "' authority!");
        }
    }

    /**
     * Raise an exception if the client is not authenticated.
     *
     * @param aConnector The connector
     * @throws Exception
     */
    public void requireAuthenticated(WebSocketConnector aConnector) throws Exception {
        if (!aConnector.getSession().isAuthenticated()) {
            throw new Exception("Not authorized!");
        }
    }

    /**
     * Register a callback for a collection of events.
     *
     * @param aEvents The collection of events
     * @param aFn The callback
     */
    public void on(Collection<String> aEvents, Object aFn) {
        for (String lEventName : aEvents) {
            on(lEventName, aFn);
        }
    }

    /**
     * Register a callback for a certain event.
     *
     * @param aEventName The event name
     * @param aFn The callback
     */
    public void on(String aEventName, Object aFn) {
        if (!mCallbacks.containsKey(aEventName)) {
            mCallbacks.put(aEventName, new FastList<Object>());
        }
        mCallbacks.get(aEventName).add(aFn);
    }

    /**
     * Unregister a callback for a certain event.
     *
     * @param aEventName The event name
     * @param aFn The callback object
     */
    public void un(String aEventName, Object aFn) {
        if (mCallbacks.containsKey(aEventName)) {
            mCallbacks.get(aEventName).remove(aFn);
        }
    }

    /**
     * Create a Token object from a Map instance.
     *
     * @param aMap The Map instance
     * @return
     */
    public Token toToken(Map aMap) {
        return TokenFactory.createToken(aMap);
    }

    /**
     * Create a response Token from a received Token.
     *
     * @param aInToken The incoming Token.
     * @return The response Token
     */
    public Map createResponse(Map aInToken) {
        return mPlugIn.createResponse(toToken(aInToken)).getMap();
    }

    /**
     * Broadcast a Token to a given collection of connectors.
     *
     * @param aConnectors The collection of connectors
     * @param aToken The Token to be broascasted
     */
    public void broadcast(Collection<WebSocketConnector> aConnectors, Map aToken) {
        for (WebSocketConnector aConnector : aConnectors) {
            sendToken(aConnector, aToken);
        }
    }

    /**
     * Broadcast a Token to a given collection of connectors.
     *
     * @param aToken The Token to be broascasted
     */
    public void broadcast(Map aToken) {
        mPlugIn.broadcastToken(null, toToken(aToken));
    }

    /**
     * Create a new instance of a thread-safe Map.
     *
     * @return The thread-safe Map instance.
     */
    public Map newThreadSafeMap() {
        return new FastMap().shared();
    }

    /**
     * Create a new instance of a thread-safe Collection.
     *
     * @return The thread-safe collection instance.
     */
    public Collection newThreadSafeCollection() {
        return new FastList().shared();
    }

    /**
     * Call a method on an application published object.
     *
     * @param aObjectId The published object identifier.
     * @param aMethod The method to be called.
     * @param aArgs The method calling arguments.
     * @return The result of the method execution.
     * @throws Exception
     */
    public abstract Object callMethod(String aObjectId, String aMethod, Collection aArgs) throws Exception;

    /**
     * Get the Spring bean factory instance associated to the given namespace.
     * If 'namespace' argument is null, then the system core bean factory is
     * returned. The system core bean factory is the parent of name-spaced bean
     * factories, so system core beans are visible for every namespaced bean
     * factory.
     *
     * @param aNamespace
     * @return
     */
    private GenericApplicationContext getBeanFactory(String aNamespace) {
        if (null == aNamespace) {
            return JWebSocketBeanFactory.getInstance();
        } else {
            return JWebSocketBeanFactory.getInstance(aNamespace);
        }
    }

    /**
     * Get a bean from the system-core bean factory.
     *
     * @param aBeanId The bean identifier
     * @return
     */
    public Object getBean(String aBeanId) {
        return getBean(aBeanId, null);
    }

    /**
     * Get a bean from the application bean factory.
     *
     * @param aBeanId
     * @return
     */
    public Object getAppBean(String aBeanId) {
        return mBeanFactory.getBean(aBeanId);
    }

    /**
     * Get a bean from a target bean factory.
     *
     * @param aBeanId The bean identifier
     * @param aNamespace The target bean factory namespace
     * @return
     */
    public Object getBean(String aBeanId, String aNamespace) {
        String lBeanPath = (null != aNamespace) ? aNamespace + ":" + aBeanId : aBeanId;

        // checking permission for bean access
        mPlugIn.checkWhiteListedBean(mAppName, lBeanPath);

        return getBeanFactory(aNamespace).getBean(aBeanId);
    }

    /**
     * Get the application bean factory.
     *
     * @return
     */
    public GenericApplicationContext getAppBeanFactory() {
        return mBeanFactory;
    }

    /**
     * Load an Spring IOC XML configuration file into the script application
     * bean factory.
     *
     * @param aFile
     * @throws Exception
     */
    public void loadToAppBeanFactory(String aFile) throws Exception {
        // beans definitions file
        aFile = aFile.replace("${APP_HOME}", mAppPath);

        // creating the XML definitions reader
        XmlBeanDefinitionReader lXmlReader = new XmlBeanDefinitionReader(mBeanFactory);
        lXmlReader.setBeanClassLoader(mClassLoader);

        // path for dtd and xsd files location
        String lBeansDef = FileUtils.readFileToString(new File(aFile));
        lBeansDef = lBeansDef.replace("${JWEBSOCKET_HOME}", mJWSHome);
        lBeansDef = lBeansDef.replace("${APP_HOME}", mAppPath);

        // loading XML definitions file into app bean factory
        lXmlReader.loadBeanDefinitions(new ByteArrayResource(lBeansDef.getBytes()));
    }

    /**
     * Get a JMS Manager instance using default configuration.
     *
     * @return
     * @throws java.lang.Exception
     */
    public JMSManagerAbstraction getJMSManager() throws Exception {
        JMSManagerAbstraction lAbstraction = new JMSManagerAbstraction(this);
        lAbstraction.setDefaultDestination(mPlugIn.getServer().getJMSManager().getDefaultDestination());

        return lAbstraction;
    }

    /**
     * Get a JMS Manager instance indicating transaction support.
     *
     * @param aUseTransaction If TRUE, JMS session instance will support
     * transactions.
     * @return
     * @throws java.lang.Exception
     */
    public JMSManagerAbstraction getJMSManager(boolean aUseTransaction) throws Exception {
        JMSManagerAbstraction lAbstraction = new JMSManagerAbstraction(this, aUseTransaction);
        lAbstraction.setDefaultDestination(mPlugIn.getServer().getJMSManager().getDefaultDestination());

        return lAbstraction;
    }

    /**
     * Get a JMS Manager instance indicating transaction support setting and
     * passing the JMS connection instance.
     *
     * @param aUseTransaction If TRUE, JMS session instance will support
     * transactions.
     * @param aConn The JMS connection instance to be used.
     * @return
     * @throws java.lang.Exception
     */
    public JMSManagerAbstraction getJMSManager(boolean aUseTransaction, Connection aConn) throws Exception {
        JMSManagerAbstraction lAbstraction = new JMSManagerAbstraction(this, aUseTransaction, aConn);
        lAbstraction.setDefaultDestination(mPlugIn.getServer().getJMSManager().getDefaultDestination());

        return lAbstraction;
    }

    /**
     * Get a JMS Manager instance indicating transaction support setting and
     * passing the JMS connection instance.
     *
     * @param aUseTransaction If TRUE, JMS session instance will support
     * transactions.
     * @param aConn The JMS connection instance to be used.
     * @param aDefaultDestination The default destination
     * @return
     */
    public JMSManagerAbstraction getJMSManager(boolean aUseTransaction, Connection aConn,
            String aDefaultDestination) {
        JMSManagerAbstraction lAbstraction = new JMSManagerAbstraction(this, aUseTransaction, aConn,
                aDefaultDestination);

        return lAbstraction;
    }

    /**
     * Get the application version.
     *
     * @return
     * @throws Exception
     */
    public abstract String getVersion() throws Exception;

    /**
     * Get the application description.
     *
     * @return
     * @throws Exception
     */
    public abstract String getDescription() throws Exception;

    /**
     * Get the application client API
     *
     * @return
     * @throws Exception
     */
    public abstract Map getClientAPI() throws Exception;

    /**
     * Get system property. May require sandbox permission.
     *
     * @param aPropertyName
     * @return
     */
    public String getSystemProperty(String aPropertyName) {
        return System.getProperty(aPropertyName);
    }

    /**
     * Set a system property. May require sandbox permission.
     *
     * @param aPropertyName
     * @param aValue
     * @return
     */
    public String setSystemProperty(String aPropertyName, String aValue) {
        return System.setProperty(aPropertyName, aValue);
    }

    /**
     * Get the WebSocketServer instance that holds the scripting plug-in
     *
     * @return
     */
    public WebSocketServer getWebSocketServer() {
        return mPlugIn.getServer();
    }

    /**
     * Call invoke method on a target plug-in
     *
     * @param aPlugInId
     * @param aConnector
     * @param aToken
     * @return
     */
    public Token invokePlugIn(String aPlugInId, WebSocketConnector aConnector, Map aToken) {
        return mPlugIn.invokePlugIn(aPlugInId, aConnector, toToken(aToken));
    }

    /**
     * Call invoke method on a target plug-in
     *
     * @param aPlugInId
     * @param aConnector
     * @param aToken
     * @return
     */
    public Token invokePlugIn(String aPlugInId, WebSocketConnector aConnector, Token aToken) {
        return mPlugIn.invokePlugIn(aPlugInId, aConnector, aToken);
    }

    /**
     * Return TRUE if the jWebSocket cluster is active, FALSE otherwise
     *
     * @return
     */
    public boolean isClusterEnabled() {
        return mPlugIn.isClusterEnabled();
    }
}