org.mule.providers.AbstractConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.providers.AbstractConnector.java

Source

/*
 * Copyright (c) SymphonySoft Limited. All rights reserved.
 * http://www.symphonysoft.com
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE-MULE.txt file.
 */

package org.mule.providers;

import java.beans.ExceptionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mule.MuleManager;
import org.mule.MuleRuntimeException;
import org.mule.config.ThreadingProfile;
import org.mule.config.i18n.Message;
import org.mule.config.i18n.Messages;
import org.mule.impl.AlreadyInitialisedException;
import org.mule.impl.DefaultExceptionStrategy;
import org.mule.impl.internal.events.ConnectionEvent;
import org.mule.management.mbeans.EndpointService;
import org.mule.routing.filters.WildcardFilter;
import org.mule.umo.UMOComponent;
import org.mule.umo.UMOException;
import org.mule.umo.endpoint.UMOEndpoint;
import org.mule.umo.endpoint.UMOEndpointURI;
import org.mule.umo.lifecycle.DisposeException;
import org.mule.umo.lifecycle.Initialisable;
import org.mule.umo.lifecycle.InitialisationException;
import org.mule.umo.manager.UMOServerEvent;
import org.mule.umo.provider.ConnectorException;
import org.mule.umo.provider.UMOConnectable;
import org.mule.umo.provider.UMOConnector;
import org.mule.umo.provider.UMOMessageDispatcher;
import org.mule.umo.provider.UMOMessageDispatcherFactory;
import org.mule.umo.provider.UMOMessageReceiver;
import org.mule.umo.transformer.UMOTransformer;
import org.mule.util.concurrent.WaitableBoolean;

import com.mirth.connect.connectors.vm.VMConnector;

import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;

/**
 * <code>AbstractConnector</code> provides base functionality for all
 * connectors provided with Mule. Connectors are the mechanism used to connect
 * to external systems and protocols in order to send and receive data. <p/> The
 * <code>AbstractConnector</code> provides getter and setter methods for
 * endpoint name, transport name and protocol. It also provides methods to stop
 * and start connecotors and sets up a dispatcher threadpool which allows
 * deriving connectors the possibility to dispatch work to separate threads.
 * This functionality is controlled with the <i> doThreading</i> property on
 * the threadingProfiles for dispachers and receivers.
 * 
 * @author <a href="mailto:ross.mason@symphonysoft.com">Ross Mason</a>
 * @version $Revision: 1.35 $
 */
public abstract class AbstractConnector implements UMOConnector, ExceptionListener, UMOConnectable {
    /**
     * logger used by this class
     */
    protected transient Log logger = LogFactory.getLog(getClass());

    /**
     * Specifies if the endpoint started
     */
    protected AtomicBoolean started = new AtomicBoolean(false);

    /**
     * True once the endpoint has been initialsed
     */
    protected AtomicBoolean initialised = new AtomicBoolean(false);

    /**
     * The name that identifies the endpoint
     */
    protected String name = null;

    /**
     * The exception strategy used by this connector
     */
    protected ExceptionListener exceptionListener = null;

    /**
     * Determines in the connector is alive and well
     */
    protected AtomicBoolean disposed = new AtomicBoolean(false);

    /**
     * Determines in connector has been told to dispose
     */
    protected AtomicBoolean disposing = new AtomicBoolean(false);

    /**
     * Factory used to create dispatchers for this connector
     */
    protected UMOMessageDispatcherFactory dispatcherFactory;

    /**
     * A pool of dispatchers for this connector, the pool is keyed on
     * endpointUri
     */
    protected ConcurrentHashMap dispatchers;

    /**
     * The collection of listeners on this connector. Keyed by entrypoint
     */
    protected ConcurrentHashMap receivers;

    /**
     * Defines the dispatcher threading model
     */
    private ThreadingProfile dispatcherThreadingProfile = null;

    /**
     * Defines the receiver threading model
     */
    private ThreadingProfile receiverThreadingProfile = null;

    /**
     * Determines whether dispatchers should be disposed straight away of after
     * every request or cached
     */
    protected boolean createDispatcherPerRequest = false;

    /**
     * For better throughput when using TransactedMessageReceivers. This will
     * create an number of receiver threads based on the ThreadingProfile
     * configured fro the receiver. This property is user by transports that
     * support transactions, specifically MessageReceivers that extend the
     * TransactedPollingMessageReceiver.
     */
    protected boolean createMultipleTransactedReceivers = true;

    /**
     * The service descriptor can define a default inbound transformer to be
     * used on an endpoint if no other is set
     */
    protected UMOTransformer defaultInboundTransformer = null;

    /**
     * The service descriptor can define a default outbound transformer to be
     * used on an endpoint if no other is set
     */
    protected UMOTransformer defaultOutboundTransformer = null;

    /**
     * For some connectors such as http, a response transformer is required or
     * where a replyTo needs a trnasformer
     */
    protected UMOTransformer defaultResponseTransformer = null;

    private ConnectionStrategy connectionStrategy;

    protected WaitableBoolean connected = new WaitableBoolean(false);

    protected WaitableBoolean connecting = new WaitableBoolean(false);

    /**
     * keeps arecord of whether the connecter should be started once it is
     * reconnected
     */
    protected WaitableBoolean startedBeforeDisconnect = new WaitableBoolean(false);

    /**
     * Whether to fire message events for every message that is sent or received
     * from this connector
     */
    private boolean enableMessageEvents = false;

    private List supportedProtocols;

    public AbstractConnector() {
        // make sure we always have an exception strategy
        exceptionListener = new DefaultExceptionStrategy();
        dispatchers = new ConcurrentHashMap();
        receivers = new ConcurrentHashMap();
        connectionStrategy = MuleManager.getConfiguration().getConnectionStrategy();
        enableMessageEvents = MuleManager.getConfiguration().isEnableMessageEvents();
        supportedProtocols = new ArrayList();
        // Always add the default protocol
        supportedProtocols.add(getProtocol().toLowerCase());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.providers.UMOConnector#getName()
     */
    public String getName() {
        return name;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.providers.UMOConnector#setName(java.lang.String)
     */
    public void setName(String newName) {
        if (newName == null) {
            throw new IllegalArgumentException("Connector name cannot be null");
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Set UMOConnector name to: " + newName);
        }
        name = newName;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.providers.UMOConnector#create(java.util.HashMap)
     */
    public final synchronized void initialise() throws InitialisationException {
        if (initialised.get()) {
            throw new AlreadyInitialisedException("Connector '" + getName() + "'", this);
        }
        if (logger.isInfoEnabled()) {
            logger.info("Initialising " + getClass().getName());
        }
        if (exceptionListener instanceof Initialisable) {
            ((Initialisable) exceptionListener).initialise();
        }

        doInitialise();
        initialised.set(true);
    }

    public abstract String getProtocol();

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#start()
     */
    public final void startConnector() throws UMOException {
        if (isDisposed()) {
            throw new ConnectorException(new Message(Messages.CANT_START_DISPOSED_CONNECTOR), this);
        }
        if (!started.get()) {
            if (!isConnected()) {
                getConnectionStrategy().connect(this);
            }
            if (logger.isInfoEnabled()) {
                logger.info("Starting Connector: " + getClass().getName());
            }
            doStart();
            for (Iterator iterator = receivers.values().iterator(); iterator.hasNext();) {
                AbstractMessageReceiver amr = (AbstractMessageReceiver) iterator.next();
                if (logger.isDebugEnabled()) {
                    logger.debug("Starting receiver on endpoint: " + amr.getEndpoint().getEndpointURI());
                }
                amr.start();
            }
            started.set(true);
            if (logger.isInfoEnabled()) {
                logger.info("Connector: " + getClass().getName() + " has been started");
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#isStarted()
     */
    public boolean isStarted() {
        return started.get();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#stop()
     */
    public final void stopConnector() throws UMOException {
        if (isDisposed()) {
            return; // throw new MuleException("Cannot stop a connector once it
            // has been disposing");
        }
        if (started.get()) {
            if (logger.isInfoEnabled()) {
                logger.info("Stopping Connector: " + getClass().getName());
            }
            doStop();
            for (Iterator iterator = receivers.values().iterator(); iterator.hasNext();) {
                UMOMessageReceiver mr = (UMOMessageReceiver) iterator.next();
                if (logger.isDebugEnabled()) {
                    logger.debug("Stopping receiver on endpoint: " + mr.getEndpoint().getEndpointURI());
                }
                mr.stop();
            }
            started.set(false);
            if (isConnected()) {
                try {
                    disconnect();
                } catch (Exception e) {
                    logger.error("Failed to disconnect: " + e.getMessage(), e);
                }
            }
            if (logger.isInfoEnabled()) {
                logger.info("Connector " + getClass().getName() + " has been stopped");
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#shutdown()
     */
    public final synchronized void dispose() {
        disposing.set(true);
        if (logger.isInfoEnabled()) {
            logger.info("Disposing Connector: " + getClass().getName());
            logger.debug("Disposing Receivers");
        }
        disposeReceivers();
        disposeDispatchers();

        doDispose();
        disposed.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Connector " + getClass().getName() + " has been disposed.");
        }

        receivers = null;
        dispatchers = null;
    }

    protected void disposeReceivers() {
        if (receivers != null) {
            Map.Entry entry;
            for (Iterator iterator = receivers.entrySet().iterator(); iterator.hasNext();) {
                entry = (Map.Entry) iterator.next();
                try {
                    destroyReceiver(((UMOMessageReceiver) entry.getValue()), null);
                } catch (Exception e) {
                    logger.error("Failed to destroy receiver: " + e.getMessage(), e);
                }
                receivers.remove(entry.getKey());

            }
            logger.debug("Receivers Disposed");
        }
    }

    protected void disposeDispatchers() {
        if (dispatchers != null) {
            // Map.Entry entry;
            logger.debug("Disposing Dispatchers");
            for (Iterator iterator = dispatchers.values().iterator(); iterator.hasNext();) {
                UMOMessageDispatcher umoMessageDispatcher = (UMOMessageDispatcher) iterator.next();
                umoMessageDispatcher.dispose();
            }
            dispatchers.clear();
            logger.debug("Dispatchers Disposed");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#isAlive()
     */
    public boolean isDisposed() {
        return disposed.get();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.umo.provider.UMOConnector#handleException(java.lang.Object,
     *      java.lang.Throwable)
     */
    public void handleException(Exception exception) {
        if (exceptionListener == null) {
            throw new MuleRuntimeException(
                    new Message(Messages.EXCEPTION_ON_CONNECTOR_X_NO_EXCEPTION_LISTENER, getName()), exception);
        } else {
            exceptionListener.exceptionThrown(exception);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.mule.util.ExceptionListener#onException(java.lang.Throwable)
     */
    public void exceptionThrown(Exception e) {
        handleException(e);
    }

    /**
     * @return the ExceptionStrategy for this endpoint
     * @see ExceptionListener
     */
    public ExceptionListener getExceptionListener() {
        return exceptionListener;
    }

    /**
     * @param listener
     *            the ExceptionStrategy to use with this endpoint
     * @see ExceptionListener
     */
    public void setExceptionListener(ExceptionListener listener) {
        exceptionListener = listener;
    }

    /**
     * @return Returns the dispatcherFactory.
     */
    public UMOMessageDispatcherFactory getDispatcherFactory() {
        return dispatcherFactory;
    }

    /**
     * @param dispatcerFactory
     *            The dispatcherFactory to set.
     */
    public void setDispatcherFactory(UMOMessageDispatcherFactory dispatcerFactory) {
        this.dispatcherFactory = dispatcerFactory;
    }

    public synchronized UMOMessageDispatcher getDispatcher(String endpoint) throws UMOException {
        checkDisposed();
        UMOMessageDispatcher dispatcher = null;
        if (endpoint == null || "".equals(endpoint)) {
            endpoint = "ANY";
        }
        if ("ANY".equals(endpoint) && dispatchers.size() > 0) {
            Map.Entry entry;
            for (Iterator iterator = dispatchers.entrySet().iterator(); iterator.hasNext();) {
                entry = (Map.Entry) iterator.next();
                if (((UMOMessageDispatcher) entry.getValue()).isDisposed()) {
                    dispatchers.remove(entry.getKey());
                } else {
                    dispatcher = (UMOMessageDispatcher) entry.getValue();
                    break;
                }
            }
        } else {
            if (dispatchers == null) {
                throw new NullPointerException("Dispatchers are null for connector: " + name);
            }
            dispatcher = (UMOMessageDispatcher) dispatchers.get(endpoint);
            if (dispatcher != null && dispatcher.isDisposed()) {
                dispatchers.values().remove(dispatcher);
                dispatcher = null;
            }
        }

        if (dispatcher == null) {
            dispatcher = createDispatcher();
            dispatchers.put(endpoint, dispatcher);
        }
        return dispatcher;
    }

    protected void checkDisposed() throws DisposeException {
        if (isDisposed()) {
            throw new DisposeException(new Message(Messages.CANT_START_DISPOSED_CONNECTOR), this);
        }
    }

    protected UMOMessageDispatcher createDispatcher() throws UMOException {
        if (dispatcherFactory == null) {
            throw new ConnectorException(new Message(Messages.CONNECTOR_NOT_STARTED, name), this);
        }
        UMOMessageDispatcher dispatcher = dispatcherFactory.create(this);
        return dispatcher;
    }

    public UMOMessageReceiver registerListener(UMOComponent component, UMOEndpoint endpoint) throws Exception {
        if (endpoint == null || component == null) {
            throw new IllegalArgumentException(
                    "The endpoint and component cannot be null when registering a listener");
        }

        UMOEndpointURI endpointUri = endpoint.getEndpointURI();
        if (endpointUri == null) {
            throw new ConnectorException(new Message(Messages.ENDPOINT_NULL_FOR_LISTENER), this);
        }
        logger.info("registering listener: " + component.getDescriptor().getName() + " on endpointUri: "
                + endpointUri.toString());

        UMOMessageReceiver receiver = getReceiver(component, endpoint);

        if (receiver != null) {
            if (!(this instanceof VMConnector)) {
                throw new ConnectorException(new Message(Messages.LISTENER_ALREADY_REGISTERED, endpointUri), this);
            }
        } else {
            receiver = createReceiver(component, endpoint);
            receivers.put(getReceiverKey(component, endpoint), receiver);
        }

        if (started.get() && endpoint.getInitialState().equals(UMOEndpoint.INITIAL_STATE_STARTED)) {
            ((AbstractMessageReceiver) receiver).start();
        }
        return receiver;
    }

    /**
     * The method determines the key used to store the receiver against.
     * 
     * @param component
     *            the component for which the endpoint is being registered
     * @param endpoint
     *            the endpoint being registered for the component
     * @return the key to store the newly created receiver against
     */
    protected Object getReceiverKey(UMOComponent component, UMOEndpoint endpoint) {
        if (endpoint.getEndpointURI().getFilterAddress() != null) {
            return endpoint.getEndpointURI().getFilterAddress();
        } else {
            return endpoint.getEndpointURI().getAddress();
        }
    }

    public final void unregisterListener(UMOComponent component, UMOEndpoint endpoint) throws Exception {
        if (endpoint == null || component == null || endpoint.getEndpointURI() == null) {
            throw new IllegalArgumentException(
                    "The endpoint and component and endpointUri cannot be null when you unregister a listener");
        }

        if (this instanceof VMConnector) {
            UMOMessageReceiver receiver = (UMOMessageReceiver) receivers.get(getReceiverKey(component, endpoint));
            if (receiver != null) { // check if the receiver wasn't initialized (only happens if channel initial state is stopped and was never started)
                receiver.stop();
            }
        } else {
            UMOEndpointURI endpointUri = endpoint.getEndpointURI();
            if (logger.isInfoEnabled()) {
                logger.info("removing listener on endpointUri: " + endpointUri);
            }

            UMOMessageReceiver receiver = (UMOMessageReceiver) receivers
                    .remove(getReceiverKey(component, endpoint));
            if (receiver != null) {
                destroyReceiver(receiver, endpoint);
                receiver.dispose();
            }
        }
    }

    public void startDispatchers(UMOComponent component, UMOEndpoint endpoint) throws UMOException {

    }

    public void stopDispatchers(UMOComponent component, UMOEndpoint endpoint) throws UMOException {

    }

    public ThreadingProfile getDispatcherThreadingProfile() {
        if (dispatcherThreadingProfile == null) {
            dispatcherThreadingProfile = MuleManager.getConfiguration().getMessageDispatcherThreadingProfile();

        }
        return dispatcherThreadingProfile;
    }

    public void setDispatcherThreadingProfile(ThreadingProfile dispatcherThreadingProfile) {
        this.dispatcherThreadingProfile = dispatcherThreadingProfile;
    }

    public ThreadingProfile getReceiverThreadingProfile() {
        if (receiverThreadingProfile == null) {
            receiverThreadingProfile = MuleManager.getConfiguration().getMessageReceiverThreadingProfile();
        }
        return receiverThreadingProfile;
    }

    public void setReceiverThreadingProfile(ThreadingProfile receiverThreadingProfile) {
        this.receiverThreadingProfile = receiverThreadingProfile;
    }

    public abstract UMOMessageReceiver createReceiver(UMOComponent component, UMOEndpoint endpoint)
            throws Exception;

    public void destroyReceiver(UMOMessageReceiver receiver, UMOEndpoint endpoint) throws Exception {
        receiver.dispose();
    }

    /**
     * Template method to perform any work when starting the connectoe
     * 
     * @throws UMOException
     *             if the method fails
     */
    protected void doStart() throws UMOException {
    }

    /**
     * Template method to perform any work when stopping the connectoe
     * 
     * @throws UMOException
     *             if the method fails
     */
    protected void doStop() throws UMOException {
    }

    /**
     * Template method to perform any work when destroying the connectoe
     * 
     */
    protected void doDispose() {
        try {
            stopConnector();
        } catch (UMOException e) {
            logger.warn("Failed to stop during shutdown: " + e.getMessage(), e);
        }
    }

    public void doInitialise() throws InitialisationException {
    }

    public UMOTransformer getDefaultInboundTransformer() {
        if (defaultInboundTransformer != null) {
            try {
                return (UMOTransformer) defaultInboundTransformer.clone();
            } catch (CloneNotSupportedException e) {
                logger.error("Failed to clone default Inbound transformer");
                return null;
            }
        } else {
            return null;
        }
    }

    public void setDefaultInboundTransformer(UMOTransformer defaultInboundTransformer) {
        this.defaultInboundTransformer = defaultInboundTransformer;
    }

    public UMOTransformer getDefaultResponseTransformer() {
        if (defaultResponseTransformer != null) {
            try {
                return (UMOTransformer) defaultResponseTransformer.clone();
            } catch (CloneNotSupportedException e) {
                logger.error("Failed to clone default Outbound transformer");
                return null;
            }
        } else {
            return null;
        }
    }

    public UMOTransformer getDefaultOutboundTransformer() {
        if (defaultOutboundTransformer != null) {
            try {
                return (UMOTransformer) defaultOutboundTransformer.clone();
            } catch (CloneNotSupportedException e) {
                logger.error("Failed to clone default Outbound transformer");
                return null;
            }
        } else {
            return null;
        }
    }

    public void setDefaultOutboundTransformer(UMOTransformer defaultOutboundTransformer) {
        this.defaultOutboundTransformer = defaultOutboundTransformer;
    }

    public void setDefaultResponseTransformer(UMOTransformer defaultResponseTransformer) {
        this.defaultResponseTransformer = defaultResponseTransformer;
    }

    public ReplyToHandler getReplyToHandler() {
        return new DefaultReplyToHandler(defaultResponseTransformer);
    }

    public Map getDispatchers() {
        return dispatchers;
    }

    /**
     * Fires a server event to all registered
     * {@link org.mule.impl.internal.events.CustomEventListener} eventManager.
     * 
     * @param event
     *            the event to fire. This must be of type
     *            {@link org.mule.impl.internal.events.CustomEvent} otherwise an
     *            exception will be thrown.
     * @throws UnsupportedOperationException
     *             if the event fired is not a
     *             {@link org.mule.impl.internal.events.CustomEvent}
     */
    public void fireEvent(UMOServerEvent event) {
        MuleManager.getInstance().fireEvent(event);
        // if(event instanceof CustomEvent) {
        // if(eventManager!=null) {
        // eventManager.fireEvent(event);
        // } else if(logger.isDebugEnabled()) {
        // logger.debug("Event Manager is not enabled, ignoring event: " +
        // event);
        // }
        // } else {
        // throw new UnsupportedOperationException(new
        // Message(Messages.ONLY_CUSTOM_EVENTS_CAN_BE_FIRED).getMessage());
        // }
    }

    public ConnectionStrategy getConnectionStrategy() {
        // not happy with this but each receiver needs its own instance
        // of the connection strategy and using a factory just introduces extra
        // implementation
        try {
            return (ConnectionStrategy) BeanUtils.cloneBean(connectionStrategy);
        } catch (Exception e) {
            throw new MuleRuntimeException(new Message(Messages.FAILED_TO_CLONE_X, "connectionStrategy"), e);
        }
    }

    public void setConnectionStrategy(ConnectionStrategy connectionStrategy) {
        this.connectionStrategy = connectionStrategy;
    }

    public List getEndpointMBeans() {
        // for now only return receiver endpoints as those are the ones we can
        // control
        // in terms of connecting/disconnecting
        List beans = new ArrayList(receivers.size());
        for (Iterator iterator = receivers.values().iterator(); iterator.hasNext();) {
            UMOMessageReceiver receiver = (UMOMessageReceiver) iterator.next();
            beans.add(new EndpointService(receiver));
        }
        return beans;
    }

    public boolean isDisposing() {
        return disposing.get();
    }

    public boolean isRemoteSyncEnabled() {
        return false;
    }

    public AbstractMessageReceiver getReceiver(UMOComponent component, UMOEndpoint endpoint) {
        return (AbstractMessageReceiver) receivers.get(getReceiverKey(component, endpoint));
    }

    public Map getReceivers() {
        return Collections.unmodifiableMap(receivers);
    }

    public AbstractMessageReceiver getReceiver(String key) {
        return (AbstractMessageReceiver) receivers.get(key);
    }

    public AbstractMessageReceiver[] getReceivers(String wildcardExpression) {

        List temp = new ArrayList();
        WildcardFilter filter = new WildcardFilter(wildcardExpression);
        for (Iterator iterator = receivers.keySet().iterator(); iterator.hasNext();) {
            Object o = iterator.next();
            if (filter.accept(o)) {
                temp.add(receivers.get(o));
            }
        }
        AbstractMessageReceiver[] result = new AbstractMessageReceiver[temp.size()];
        return (AbstractMessageReceiver[]) temp.toArray(result);
    }

    public void connect() throws Exception {
        if (connected.get()) {
            return;
        }

        if (connecting.commit(false, true)) {
            connectionStrategy.connect(this);
            logger.info("Connected: " + getConnectionDescription());
            return;
        }

        try {
            doConnect();
            fireEvent(new ConnectionEvent(this, getConnectEventId(), ConnectionEvent.CONNECTION_CONNECTED));
        } catch (Exception e) {
            fireEvent(new ConnectionEvent(this, getConnectEventId(), ConnectionEvent.CONNECTION_FAILED));
            if (e instanceof ConnectException) {
                throw (ConnectException) e;
            } else {
                throw new ConnectException(e, this);
            }
        }
        connected.set(true);
        connecting.set(false);
        if (startedBeforeDisconnect.get()) {
            startConnector();
        }
    }

    public void disconnect() throws Exception {
        startedBeforeDisconnect.set(isStarted());
        fireEvent(new ConnectionEvent(this, getConnectEventId(), ConnectionEvent.CONNECTION_DISCONNECTED));
        connected.set(false);
        doDisconnect();
        stopConnector();
        logger.info("Disconnected: " + getConnectionDescription());
    }

    public String getConnectionDescription() {
        return toString();
    }

    public boolean isConnected() {
        return connected.get();
    }

    /**
     * Template method where any connections should be made for the connector
     * 
     * @throws Exception
     */
    public void doConnect() throws Exception {

    }

    /**
     * Template method where any connected resources used by the connector
     * should be disconnected
     * 
     * @throws Exception
     */
    public void doDisconnect() throws Exception {

    }

    /**
     * The resource id used when firing ConnectEvents from this connector
     * 
     * @return the resource id used when firing ConnectEvents from this
     *         connector
     */
    protected String getConnectEventId() {
        return getName();
    }

    /**
     * controls whether dispatchers or cached or created per request Note that
     * if an exception occurs in the Dispatcher it is automatically disposed of
     * and a new one is created for the next request. This allows dispatchers to
     * recover from loss of connection and other faults.
     * 
     * @param createDispatcherPerRequest
     *            whether a new dispatcher is created for every request or not
     */
    public void setCreateDispatcherPerRequest(boolean createDispatcherPerRequest) {
        this.createDispatcherPerRequest = createDispatcherPerRequest;
    }

    /**
     * controls whether dispatchers or cached or created per request Note that
     * if an exception occurs in the Dispatcher it is automatically disposed of
     * and a new one is created for the next request. This allows dispatchers to
     * recover from loss of connection and other faults.
     * 
     * @return true if a anew dispatcher is created for every request
     */
    public boolean isCreateDispatcherPerRequest() {
        return createDispatcherPerRequest;
    }

    /**
     * For better throughput when using TransactedMessageReceivers. This will
     * create an number of receiver threads based on the ThreadingProfile
     * configured fro the receiver. This property is user by transports that
     * support transactions, specifically MessageReceivers that extend the
     * TransactedPollingMessageReceiver.
     * 
     * @return true if multiple receiver threads will be created for receivers
     *         on this connection
     */
    public boolean isCreateMultipleTransactedReceivers() {
        return createMultipleTransactedReceivers;
    }

    /**
     * For better throughput when using TransactedMessageReceivers. This will
     * create an number of receiver threads based on the ThreadingProfile
     * configured fro the receiver. This property is user by transports that
     * support transactions, specifically MessageReceivers that extend the
     * TransactedPollingMessageReceiver.
     * 
     * @param createMultipleTransactedReceivers
     *            true if multiple receiver threads will be created for
     *            receivers on this connection
     */
    public void setCreateMultipleTransactedReceivers(boolean createMultipleTransactedReceivers) {
        this.createMultipleTransactedReceivers = createMultipleTransactedReceivers;
    }

    /**
     * Whether to fire message events for every message that is sent or received
     * from this connector
     * 
     * @return
     */
    public boolean isEnableMessageEvents() {
        return enableMessageEvents;
    }

    /**
     * Whether to fire message events for every message that is sent or received
     * from this connector
     * 
     * @param enableMessageEvents
     */
    public void setEnableMessageEvents(boolean enableMessageEvents) {
        this.enableMessageEvents = enableMessageEvents;
    }

    /**
     * Registers other protocols 'understood' by this connector. These must
     * contain scheme meta info. Any protocol registered must begin with the
     * protocol of this connector, i.e. If the connector is axis the protocol
     * for jms over axis will be axis:jms. Here, 'axis' is the scheme meta info
     * and 'jms' is the protocol. If the protocol argument does not start with
     * the connector's protocol, it will be appended.
     * 
     * @param protocol
     *            the supported protocol to register
     */
    public void registerSupportedProtocol(String protocol) {
        protocol = protocol.toLowerCase();
        if (protocol.startsWith(getProtocol().toLowerCase())) {
            supportedProtocols.add(protocol);
        } else {
            supportedProtocols.add(getProtocol().toLowerCase() + ":" + protocol);
        }
    }

    /**
     * @return true if the protocol is supported by this connector.
     */
    public boolean supportsProtocol(String protocol) {
        return supportedProtocols.contains(protocol.toLowerCase());
    }
}