Package org.codehaus.activemq.broker.impl

Source Code of org.codehaus.activemq.broker.impl.BrokerContainerImpl

/**
*
* Copyright 2004 Protique Ltd
*
* 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.codehaus.activemq.broker.impl;

import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.broker.Broker;
import org.codehaus.activemq.broker.BrokerClient;
import org.codehaus.activemq.broker.BrokerConnector;
import org.codehaus.activemq.broker.BrokerContainer;
import org.codehaus.activemq.capacity.CapacityMonitorEvent;
import org.codehaus.activemq.capacity.CapacityMonitorEventListener;
import org.codehaus.activemq.message.ActiveMQDestination;
import org.codehaus.activemq.message.ActiveMQMessage;
import org.codehaus.activemq.message.ActiveMQXid;
import org.codehaus.activemq.message.ConnectionInfo;
import org.codehaus.activemq.message.ConsumerInfo;
import org.codehaus.activemq.message.DurableUnsubscribe;
import org.codehaus.activemq.message.MessageAck;
import org.codehaus.activemq.message.ProducerInfo;
import org.codehaus.activemq.message.SessionInfo;
import org.codehaus.activemq.service.Service;
import org.codehaus.activemq.store.PersistenceAdapter;

import javax.jms.InvalidClientIDException;
import javax.jms.InvalidDestinationException;
import javax.jms.JMSException;
import javax.jms.JMSSecurityException;
import javax.transaction.xa.XAException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Represents the ActiveMQ JMS Broker which typically has one or many connectors
*
* @version $Revision: 1.19 $
*/
public class BrokerContainerImpl implements BrokerContainer, CapacityMonitorEventListener {
    private static final Log log = LogFactory.getLog(BrokerContainerImpl.class);
    private Broker broker;
    private Map clientIds;
    private Map consumerInfos;
    private Map producerInfos;
    private List connectors;
    private Thread shutdownHook;
    private boolean stopped;

    /**
     * Default Constructor
     *
     * @param brokerName
     */
    public BrokerContainerImpl(String brokerName) {
        this(new DefaultBroker(brokerName));
    }

    public BrokerContainerImpl(String brokerName, PersistenceAdapter persistenceAdapter) {
        this(new DefaultBroker(brokerName, persistenceAdapter));
    }

    /**
     * @param broker
     */
    public BrokerContainerImpl(Broker broker) {
        this.broker = broker;
        this.clientIds = new ConcurrentHashMap();
        this.consumerInfos = new ConcurrentHashMap();
        this.producerInfos = new ConcurrentHashMap();
        this.connectors = new CopyOnWriteArrayList();
        this.broker.addCapacityEventListener(this);
    }

    public List getConnectors() {
        return connectors;
    }

    public void setConnectors(List connectors) {
        this.connectors = connectors;
    }

    /**
     * @return the Broker for the Container
     */
    public Broker getBroker() {
        return broker;
    }

    public PersistenceAdapter getPersistenceAdapter() {
        return broker != null ? broker.getPersistenceAdapter() : null;
    }

    public void setPersistenceAdapter(PersistenceAdapter persistenceAdapter) {
        if (broker == null) {
            throw new IllegalStateException("Cannot set this property as we don't have a broker yet");
        }
        broker.setPersistenceAdapter(persistenceAdapter);
    }

    /**
     * start the Container
     *
     * @throws JMSException
     */
    public void start() throws JMSException {
        log.info("ActiveMQ JMS Message Broker is starting");
        log.info("For help or more information please see: http://activemq.codehaus.org/");
        broker.start();
        addShutdownHook();
        log.info("ActiveMQ JMS Message Broker has started");
    }

    protected void addShutdownHook() {
        shutdownHook = new Thread() {
            public void run() {
                containerShutdown();
            }
        };
        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }

    /**
     * Stop the Container
     *
     * @throws JMSException
     */
    public synchronized void stop() throws JMSException {
        if (!stopped) {
            log.info("ActiveMQ Message Broker is shutting down");

            try {
                Runtime.getRuntime().removeShutdownHook(shutdownHook);
            }
            catch (Exception e) {
                // Ignore, must be shutting down
            }

            JMSException firstException = null;

            // lets close all the connectors - copying the collection first
            // TODO we might not need to copy the collection, as maybe the List might not
            // throw concurrent modification exception? Couldn't tell from the docs
            // but I don't think it does
            for (Iterator iter = new ArrayList(connectors).iterator(); iter.hasNext();) {
                Service connector = (Service) iter.next();
                try {
                    connector.stop();
                }
                catch (JMSException e) {
                    if (firstException == null) {
                        firstException = e;
                    }
                    log.warn("Could not close connector: " + connector + " due to: " + e, e);
                }
            }
            connectors.clear();

            // lets close all the channels
            // note that this Map implementation does not throw concurrent modification exception
            for (Iterator iter = clientIds.values().iterator(); iter.hasNext();) {
                // should remove clients from parent container?
                BrokerClient client = (BrokerClient) iter.next();
                try {
                    client.stop();
                }
                catch (JMSException e) {
                    if (firstException == null) {
                        firstException = e;
                    }
                    log.warn("Could not close client: " + client + " due to: " + e, e);
                }
            }
            clientIds.clear();

            broker.removeCapacityEventListener(this);
            broker.stop();

            log.info("ActiveMQ JMS Message Broker stopped");

            stopped = true;
            if (firstException != null) {
                throw firstException;
            }
        }
    }

    /**
     * registers a new Connection
     *
     * @param client
     * @param info   infomation about the client-side Connection
     * @throws InvalidClientIDException if the ClientID of the Connection is a duplicate
     */
    public void registerConnection(BrokerClient client, ConnectionInfo info) throws InvalidClientIDException {
        String clientId = info.getClientId();
        if (clientIds.containsKey(clientId)) {
            throw new InvalidClientIDException("Duplicate clientId: " + info);
        }
        log.info("Adding new client: " + clientId + " on transport: " + client.getChannel());
        clientIds.put(clientId, client);
    }

    /**
     * un-registers a Connection
     *
     * @param client
     * @param info   infomation about the client-side Connection
     * @throws JMSException
     */
    public void deregisterConnection(BrokerClient client, ConnectionInfo info) throws JMSException {
        String clientId = client.getClientID();
        if (clientId != null) {
            Object answer = clientIds.remove(clientId);
            if (answer != null) {
                log.info("Removing client: " + clientId + " on transport: " + client.getChannel());
                getBroker().cleanUpClient(client);
            }
            else {
                log.warn("Got duplicate deregisterConnection for client: " + clientId);
            }
        }
        else {
            log.warn("No clientID available for client: " + client);
        }
    }

    /**
     * Registers a MessageConsumer
     *
     * @param client
     * @param info
     * @throws JMSException
     * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
     */
    public void registerMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
        consumerInfos.put(info, client);
        getBroker().addMessageConsumer(client, info);
    }

    /**
     * De-register a MessageConsumer from the Broker
     *
     * @param client
     * @param info
     * @throws JMSException
     */
    public void deregisterMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
        consumerInfos.remove(info);
        getBroker().removeMessageConsumer(client, info);
    }

    /**
     * Registers a MessageProducer
     *
     * @param client
     * @param info
     * @throws JMSException
     * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
     */
    public void registerMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
        ActiveMQDestination dest = info.getDestination();
        if (dest != null && dest.isTemporary()) {
            //check to see if the client that is the target for the temporary destination still exists
            String clientId = ActiveMQDestination.getClientId(dest);
            if (clientId == null) {
                throw new InvalidDestinationException("Destination " + dest.getPhysicalName()
                        + " is a temporary destination with null clientId");
            }
            if (!clientIds.containsKey(clientId)) {
                throw new InvalidDestinationException("Destination " + dest.getPhysicalName()
                        + " is no longer valid because the client " + clientId + " no longer exists");
            }
        }
        producerInfos.put(info, client);
    }

    /**
     * De-register a MessageProducer from the Broker
     *
     * @param client
     * @param info
     * @throws JMSException
     */
    public void deregisterMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
        producerInfos.remove(info);
    }

    /**
     * Register a client-side Session (used for Monitoring)
     *
     * @param client
     * @param info
     * @throws JMSException
     */
    public void registerSession(BrokerClient client, SessionInfo info) throws JMSException {
    }

    /**
     * De-register a client-side Session from the Broker (used for monitoring)
     *
     * @param client
     * @param info
     * @throws JMSException
     */
    public void deregisterSession(BrokerClient client, SessionInfo info) throws JMSException {
    }

    /**
     * Start a transaction from the Client session
     *
     * @param client
     * @param transactionId
     * @throws JMSException
     */
    public void startTransaction(BrokerClient client, String transactionId) throws JMSException {
        getBroker().startTransaction(client, transactionId);
    }

    /**
     * Rollback a transacton
     *
     * @param client
     * @param transactionId
     * @throws JMSException
     */
    public void rollbackTransaction(BrokerClient client, String transactionId) throws JMSException {
        getBroker().rollbackTransaction(client, transactionId);
    }

    /**
     * Commit a transaction
     *
     * @param client
     * @param transactionId
     * @throws JMSException
     */
    public void commitTransaction(BrokerClient client, String transactionId) throws JMSException {
        getBroker().commitTransaction(client, transactionId);
    }

    /**
     * send message with a transaction context
     *
     * @param client
     * @param transactionId
     * @param message
     * @throws JMSException
     */
    public void sendTransactedMessage(BrokerClient client, String transactionId, ActiveMQMessage message)
            throws JMSException {
        getBroker().sendTransactedMessage(client, transactionId, message);
    }

    /**
     * Acknowledge receipt of a message within a transaction context
     *
     * @param client
     * @param transactionId
     * @param ack
     * @throws JMSException
     */
    public void acknowledgeTransactedMessage(BrokerClient client, String transactionId, MessageAck ack)
            throws JMSException {
        getBroker().acknowledgeTransactedMessage(client, transactionId, ack);
    }

    /**
     * Send a non-transacted message to the Broker
     *
     * @param client
     * @param message
     * @throws JMSException
     */
    public void sendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException {
        getBroker().sendMessage(client, message);
    }

    /**
     * Acknowledge reciept of a message
     *
     * @param client
     * @param ack
     * @throws JMSException
     */
    public void acknowledgeMessage(BrokerClient client, MessageAck ack) throws JMSException {
        getBroker().acknowledgeMessage(client, ack);
    }

    /**
     * Command to delete a durable topic subscription
     *
     * @param client
     * @param ds
     * @throws JMSException
     */
    public void durableUnsubscribe(BrokerClient client, DurableUnsubscribe ds) throws JMSException {
        getBroker().deleteSubscription(ds.getClientId(), ds.getSubscriberName());
    }

    /**
     * Start an XA transaction.
     *
     * @param client
     * @param xid
     */
    public void startTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
        getBroker().startTransaction(client, xid);
    }

    /**
     * Gets the prepared XA transactions.
     *
     * @param client
     * @return
     */
    public ActiveMQXid[] getPreparedTransactions(BrokerClient client) throws XAException {
        return getBroker().getPreparedTransactions(client);
    }

    /**
     * Prepare an XA transaction.
     *
     * @param client
     * @param xid
     */
    public int prepareTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
        return getBroker().prepareTransaction(client, xid);
    }

    /**
     * Rollback an XA transaction.
     *
     * @param client
     * @param xid
     */
    public void rollbackTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
        getBroker().rollbackTransaction(client, xid);
    }

    /**
     * Commit an XA transaction.
     *
     * @param client
     * @param xid
     * @param onePhase
     */
    public void commitTransaction(BrokerClient client, ActiveMQXid xid, boolean onePhase) throws XAException {
        getBroker().commitTransaction(client, xid, onePhase);
    }

    public void addConnector(BrokerConnector connector) {
        connectors.add(connector);
    }

    public void removeConnector(BrokerConnector connector) {
        connectors.remove(connector);
    }

    /**
     * Update any message producers about our capacity to handle messages
     *
     * @param event
     */
    public void capacityChanged(CapacityMonitorEvent event) {
        //only send to producers
        for (Iterator i = producerInfos.values().iterator(); i.hasNext();) {
            BrokerClient client = (BrokerClient) i.next();
            client.updateBrokerCapacity(event.getCapacity());
        }
    }

    /**
     * Causes a clean shutdown of the container when the VM is being shut down
     */
    protected void containerShutdown() {
        try {
            stop();
        }
        catch (JMSException e) {
            Exception linkedException = e.getLinkedException();
            if (linkedException != null) {
                log.error("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
            }
            else {
                log.error("Failed to shut down: " + e, e);
            }
        }
        catch (Exception e) {
            log.error("Failed to shut down: " + e, e);
        }
    }
}
TOP

Related Classes of org.codehaus.activemq.broker.impl.BrokerContainerImpl

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.