org.sciflex.plugins.synapse.esper.mediators.XMLMediator.java Source code

Java tutorial

Introduction

Here is the source code for org.sciflex.plugins.synapse.esper.mediators.XMLMediator.java

Source

/*
 * SCI-Flex: Flexible Integration of SOA and CEP
 * Copyright (C) 2008, 2009  http://sci-flex.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package org.sciflex.plugins.synapse.esper.mediators;

import java.io.ByteArrayInputStream;
import java.io.File;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.ConfigurationException;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.impl.dom.DOOMAbstractFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.SynapseEnvironment;

import org.sciflex.plugins.synapse.esper.core.activities.MonitoredMediatorActivity;
import org.sciflex.plugins.synapse.esper.core.workflows.MonitoredRequestResponseWorkflow;
import org.sciflex.plugins.synapse.esper.core.util.UniquelyIdentifiableChild;
import org.sciflex.plugins.synapse.esper.core.util.UUIDGenerator;
import org.sciflex.plugins.synapse.esper.mediators.editors.CEPInstanceEditor;
import org.sciflex.plugins.synapse.esper.mediators.helpers.AdminComponentStore;
import org.sciflex.plugins.synapse.esper.mediators.helpers.EPLStatementHelper;
import org.sciflex.plugins.synapse.esper.mediators.helpers.InvokableEPLStatementHelper;
import org.sciflex.plugins.synapse.esper.mediators.monitors.MediatorActivityMonitor;
import org.sciflex.plugins.synapse.esper.mediators.monitors.MediatorStatisticsMonitor;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * Class Mediator which can be used to connect Esper to synapse through its
 * XML communication API. This mediator is designed to be referrenced by the
 * synapse.xml.
 * <p>
 * A sample synapse.xml file is found in the examples folder.
 * @see AxiomMediator
 */
public class XMLMediator implements SynapseEsperMediator {

    /**
     * Log associated with the XML Mediator.
     */
    private static final Log log = LogFactory.getLog(XMLMediator.class);

    /**
     * Trace State.
     */
    private int traceState = 0;

    /**
     * The Instance URI to be used by EPServiceProviderManager.
     * @see com.espertech.esper.client.EPServiceProviderManager
     */
    private String instanceURI = null;

    /**
     * Esper Configuration instance.
     */
    protected Configuration configuration = new Configuration();

    /**
     * Synapse Listener Instance.
     */
    private SynapseListener listener = null;

    /**
     * Helper to handle EPL statements.
     */
    private InvokableEPLStatementHelper eplStatementHelper = null;

    /**
     * Monitors mediator activities.
     */
    private MonitoredMediatorActivity activityMonitor = null;

    /**
     * Monitors mediator statistics.
     */
    private MonitoredRequestResponseWorkflow statMonitor = null;

    /**
     * Admin component store.
     */
    private AdminComponentStore componentStore = null;

    /**
     * Unique Identifier of this object.
     */
    private String uid = null;

    /**
     * The Alias of Mediator
     */
    private String alias = null;

    /**
     * Whether inactive at start
     */
    private boolean inactive = false;

    /**
     * Object used to control access to {@link #getProvider}. Please
     * note that the {@link #mediate} method is calling getProvider()
     * without using this lock, for achieving higher concurrency levels
     * and any change to the outcome of {@link #getProvider} must
     * involve, temporarily stopping the mediator activity. A change to
     * {@link #getProvider} is considered a configuration change.
     */
    private Object providerLock = new Object();

    /**
     * Sets the EventToAddress. Please set listener before setting the
     * EventToAddress.
     * @param uri URI of To Address associated with Event.
     */
    public void setEventToAddress(String uri) {
        if (listener != null)
            listener.setEventToAddress(uri);
        else
            log.error("Listener has not been set");
    }

    /**
     * Sets the Esper Configuration details.
     * @param path Path to configuration file.
     */
    public void setConfiguration(String path) {
        log.debug("Setting configuration " + path);
        try {
            File file = new File(path);
            configuration.configure(file);
            log.info("Setting configuration complete");
        } catch (Exception e) {
            log.error("An error occured while setting the configuration " + e.getMessage());
        }
    }

    /**
     * Sets the Esper Configuration details from an Axiom Element describing
     * the various details.
     * @param config Configuration Axiom Element.
     */
    public void setConfiguration(OMElement config) {
        log.debug("Setting configuration " + config);
        try {
            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
                    .parse(new ByteArrayInputStream(config.toString().getBytes()));
            configuration.configure(doc);
            log.info("Setting configuration complete");
        } catch (Exception e) {
            log.error("An error occured while setting the configuration " + e.getMessage());
        }
    }

    /**
     * Gets the Trace State.
     * @return Trace State.
     */
    public int getTraceState() {
        return traceState;
    }

    /**
     * Sets the Trace State.
     * @param state Trace State.
     */
    public void setTraceState(int state) {
        traceState = state;
    }

    /**
     * Gets the Alias of Mediator
     * @return Alias of Mediator.
     */
    public String getAlias() {
        return alias;
    }

    /**
     * Sets the Alias of Mediator.
     * @param alias Alias of Mediator.
     */
    public void setAlias(String alias) {
        this.alias = alias;
    }

    /**
     * Sets the Instance URI.
     * @param uri the Instance URI.
     */
    public synchronized void setInstanceURI(String uri) {
        log.debug("Setting Instance URI " + uri);
        if (activityMonitor != null) {
            log.debug("Disabling Mediator Activity");
            activityMonitor.stopMediator();
        }
        synchronized (providerLock) {
            instanceURI = uri;
            if (eplStatementHelper != null) {
                eplStatementHelper.changeProvider(getProvider());
            }
        }
        if (activityMonitor != null) {
            log.debug("Enabling Mediator Activity");
            activityMonitor.startMediator();
        }
    }

    /**
     * Gets the Instance URI.
     * @return the Instance URI.
     */
    public String getInstanceURI() {
        return instanceURI;
    }

    /**
     * Sets associated listener.
     * @param name name of listener class.
     */
    public void setListener(String name) {
        log.debug("Setting listener " + name);
        try {
            Class listenerClass = Class.forName(name);
            if (listenerClass == null) {
                log.error("Invalid Class Name");
                return;
            }
            Object o = listenerClass.newInstance();
            if (o instanceof SynapseListener) {
                listener = (SynapseListener) o;
                log.info("Listener " + name + " was successfully setup");
            } else
                log.error("Setting listener failed");
        } catch (ClassNotFoundException e) {
            log.error("Class " + name + " was not found");
        } catch (Exception e) {
            log.error("Setting listener failed " + e.getMessage());
        }
    }

    /**
     * Sets the EPL Statement. This method is called only at init.
     * Subsequent invocations must be precedeed and followed by
     * disabling and enabling the mediator activity.
     * @param epl the EPL Statement element.
     */
    public void setStatement(OMElement epl) {
        if (listener == null) {
            listener = new SynapseListenerImpl();
        }
        log.debug("Setting EPL statement " + epl);
        String value = epl.getAttributeValue(new QName("value"));
        if (value == null) {
            value = epl.getAttributeValue(new QName("key"));
            if (value == null) {
                log.error("Setting EPL statement failed. Got " + epl);
                return;
            } else {
                log.debug("Setting EPL statment using registry key " + value);
                synchronized (providerLock) {
                    eplStatementHelper = new EPLStatementHelper(EPLStatementHelper.EPLStatementType.INDIRECT, value,
                            getProvider(), listener);
                }
                if (componentStore != null) {
                    componentStore.changeEPLStatementHelper((EPLStatementHelper) eplStatementHelper);
                }
            }
        } else {
            log.debug("Setting EPL statement " + value);
            synchronized (providerLock) {
                eplStatementHelper = new EPLStatementHelper(value, getProvider(), listener);
            }
            if (componentStore != null) {
                componentStore.changeEPLStatementHelper((EPLStatementHelper) eplStatementHelper);
            }
        }
    }

    /**
     * Sets the EPL Statement. This method is called only at init.
     * Subsequent invocations must be precedeed and followed by
     * disabling and enabling the mediator activity.
     * @param epl the EPL Statement.
     */
    public void setStatement(String epl) {
        if (listener == null) {
            listener = new SynapseListenerImpl();
        }
        log.debug("Setting EPL statement " + epl);
        synchronized (providerLock) {
            eplStatementHelper = new EPLStatementHelper(epl, getProvider(), listener);
        }
        if (componentStore != null) {
            componentStore.changeEPLStatementHelper((EPLStatementHelper) eplStatementHelper);
        }
    }

    /**
     * Sets the mediator as inactive at the beginning.
     * @param state whether inactive or not.
     */
    public void setInactive(boolean state) {
        inactive = state;
    }

    /**
     * Gets an EPServiceProvider based on Mediator configuration details.
     * @return EPServiceProvider instance.
     */
    private EPServiceProvider getProvider() {
        try {
            if (instanceURI == null && configuration == null)
                return EPServiceProviderManager.getDefaultProvider();
            else if (instanceURI == null)
                return EPServiceProviderManager.getDefaultProvider(configuration);
            else if (configuration == null)
                return EPServiceProviderManager.getProvider(instanceURI);
            else
                return EPServiceProviderManager.getProvider(instanceURI, configuration);
        } catch (ConfigurationException e) {
            log.error("An error occured while retrieving provider " + e.getMessage());
            return null;
        }
    }

    /**
     * Invokes the mediator passing the current message for mediation.
     * @param mc Message Context of the current message.
     * @return returns true if mediation should continue, or false if further 
     * mediation should be aborted.
     */
    public boolean mediate(MessageContext mc) {
        if (activityMonitor != null && !activityMonitor.getIsMediatorActive()) {
            log.warn("Cannot mediate. Mediator is inactive");
            return true;
        }
        long activityStamp = System.currentTimeMillis();
        log.trace("Beginning Mediation");
        // There is no providerLock in place at this point, to enable maximum
        // concurrent use of the mediate method. However, if someone is to
        // acquire a providerLock, that person must ensure that the mediate
        // method is not called.
        EPServiceProvider provider = getProvider();
        if (provider == null) {

            // There should be an error if we couldn't obtain the provider.
            // Therefore, stop mediation

            return false;
        }
        if (componentStore != null) {
            componentStore.invoke(mc);
        }
        eplStatementHelper.invoke(mc);
        // It takes this long to make the request.
        // You will have to setup all the required resources
        // to proceed with the servicing of the request.
        if (statMonitor != null) {
            long ts = System.currentTimeMillis();
            statMonitor.handleRequest(ts - activityStamp);
            activityStamp = ts;
        }
        OMElement bodyElement = null;
        try {
            bodyElement = mc.getEnvelope().getBody().getFirstElement();
        } catch (OMException e) {
            log.warn("An error occured while reading message " + e.getMessage());
            // We don't mind an error while reading a message.
            return true;
        }
        if (bodyElement == null) {
            // FIXME Figure out proper response for null element.
            return true;
        }
        bodyElement.build();

        try {
            String buffer = bodyElement.toStringWithConsume();
            XMLStreamReader xsr = XMLInputFactory.newInstance()
                    .createXMLStreamReader(new ByteArrayInputStream(buffer.getBytes()));
            StAXOMBuilder builder = new StAXOMBuilder(DOOMAbstractFactory.getOMFactory(), xsr);
            OMElement docElement = builder.getDocumentElement();
            if (docElement != null) {
                Node node = (Node) docElement.getParent();
                provider.getEPRuntime().sendEvent(node);
                log.trace("Ending Mediation");
            } else
                log.error("Mediation failed");
        } catch (Exception e) {
            log.error("An error occured while sending Event " + e.getMessage());
        }
        // You have to get here to say the mediator responded.
        // All other returns are failures rather.
        if (statMonitor != null) {
            long ts = System.currentTimeMillis();
            statMonitor.handleResponse(ts - activityStamp);
        }
        return true;
    }

    /**
     * Destruction of Initialized resources.
     */
    public void destroy() {
        if (activityMonitor != null) {
            log.debug("Disabling Mediator Activity");
            activityMonitor.stopMediator();
            activityMonitor = null;
        }
        if (statMonitor != null) {
            log.debug("Disabling Statistics Monitoring");
            statMonitor = null;
        }
        if (componentStore != null) {
            log.debug("Destroying Component Store");
            componentStore.destroy();
        }
    }

    /**
     * Initialization of resources.
     * @param se Synapse Environment passed by configuration.
     */
    public void init(SynapseEnvironment se) {
        // hack to get round lack of init(SynapseEnv) on mediator interface.
        if (listener != null) {
            listener.setSynapseEnvironment(se);
            if (statMonitor == null) {
                log.debug("Enabling Statistics Monitoring");
                statMonitor = new MediatorStatisticsMonitor(this);
            }
            if (activityMonitor == null) {
                log.debug("Enabling Mediator Activity");
                activityMonitor = new MediatorActivityMonitor(this);
                if (!inactive) {
                    activityMonitor.startMediator();
                } else {
                    activityMonitor.startMediator();
                    activityMonitor.stopMediator();
                }
            }
            componentStore = new AdminComponentStore(this);
            componentStore.addUniquelyIdentifiableChild((UniquelyIdentifiableChild) statMonitor);
            componentStore.addUniquelyIdentifiableChild(activityMonitor);
            componentStore.addUniquelyIdentifiableChild(new CEPInstanceEditor(this));
            if (eplStatementHelper != null && eplStatementHelper instanceof EPLStatementHelper) {
                componentStore.changeEPLStatementHelper((EPLStatementHelper) eplStatementHelper);
            }
        } else {
            log.error("Listener has not been set");
        }
    }

    /**
     * Returns the Unique Identifier of the resource.
     *
     * @return the Unique Identifier of the resource.
     */
    public String getUID() {
        if (uid == null) {
            uid = UUIDGenerator.createUUID();
        }
        return uid;
    }

    /**
     * Returns the Type of the resource.
     *
     * @return the Type of the resource.
     */
    public String getType() {
        return XMLMediator.class.getName();
    }
}