001    /**
002     *
003     * Copyright 2004 Protique Ltd
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     * http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     *
017     **/
018    
019    package org.activemq.broker.impl;
020    
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Map;
026    import javax.jms.InvalidClientIDException;
027    import javax.jms.InvalidDestinationException;
028    import javax.jms.JMSException;
029    import javax.jms.JMSSecurityException;
030    import javax.transaction.xa.XAException;
031    import org.apache.commons.logging.Log;
032    import org.apache.commons.logging.LogFactory;
033    import org.activemq.ActiveMQConnectionMetaData;
034    import org.activemq.broker.Broker;
035    import org.activemq.broker.BrokerClient;
036    import org.activemq.broker.BrokerConnector;
037    import org.activemq.broker.BrokerContainer;
038    import org.activemq.broker.BrokerContext;
039    import org.activemq.capacity.CapacityMonitorEvent;
040    import org.activemq.capacity.CapacityMonitorEventListener;
041    import org.activemq.io.WireFormat;
042    import org.activemq.io.impl.DefaultWireFormat;
043    import org.activemq.io.util.MemoryBoundedObjectManager;
044    import org.activemq.message.ActiveMQDestination;
045    import org.activemq.message.ActiveMQMessage;
046    import org.activemq.message.ActiveMQXid;
047    import org.activemq.message.ConnectionInfo;
048    import org.activemq.message.ConsumerInfo;
049    import org.activemq.message.DurableUnsubscribe;
050    import org.activemq.message.MessageAck;
051    import org.activemq.message.ProducerInfo;
052    import org.activemq.message.SessionInfo;
053    import org.activemq.security.SecurityAdapter;
054    import org.activemq.service.RedeliveryPolicy;
055    import org.activemq.service.DeadLetterPolicy;
056    import org.activemq.service.Service;
057    import org.activemq.store.PersistenceAdapter;
058    import org.activemq.transport.DiscoveryAgent;
059    import org.activemq.transport.NetworkConnector;
060    import org.activemq.transport.TransportServerChannel;
061    import org.activemq.util.IdGenerator;
062    import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
063    import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
064    import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet;
065    import java.util.Set;
066    
067    /**
068     * Represents the ActiveMQ JMS Broker which typically has one or many connectors
069     *
070     * @version $Revision: 1.1.1.1 $
071     */
072    public class BrokerContainerImpl implements BrokerContainer, CapacityMonitorEventListener {
073        public static final String DISABLE_CLEAN_SHUTDOWN_PROPERTY = "activemq.broker.disable-clean-shutdown";
074        private static final Log log = LogFactory.getLog(BrokerContainerImpl.class);
075        private static final boolean useLoggingForShutdownErrors = false;
076    
077        private BrokerContext context;
078        private Broker broker;
079        private Map clientIds;
080        private Map consumerInfos;
081        private Map producerInfos;
082        private List transportConnectors;
083        private Thread shutdownHook;
084        private boolean stopped;
085        private List networkConnectors;
086        private DiscoveryAgent discoveryAgent;
087        private Map localDiscoveryDetails;
088        private Set remoteClientIds;
089    
090    
091        public BrokerContainerImpl() {
092            this(new IdGenerator().generateId());
093        }
094    
095        public BrokerContainerImpl(String brokerName) {
096            this(brokerName, BrokerContext.getInstance());
097        }
098    
099        public BrokerContainerImpl(String brokerName, MemoryBoundedObjectManager memoryManager) {
100            this(brokerName, BrokerContext.getInstance(), memoryManager);
101        }
102        
103        public BrokerContainerImpl(String brokerName,String clusterName) {
104            this(brokerName, clusterName,BrokerContext.getInstance());
105            
106        }
107    
108        public BrokerContainerImpl(String brokerName, PersistenceAdapter persistenceAdapter) {
109            this(brokerName, persistenceAdapter, BrokerContext.getInstance());
110        }
111    
112        public BrokerContainerImpl(String brokerName, BrokerContext context) {
113            this(new DefaultBroker(brokerName), context);
114        }
115        
116        public BrokerContainerImpl(String brokerName, BrokerContext context, MemoryBoundedObjectManager memoryManager) {
117            this(new DefaultBroker(brokerName,memoryManager), context);
118        }
119        
120        public BrokerContainerImpl(String brokerName, String clusterName, BrokerContext context) {
121            this(new DefaultBroker(brokerName,clusterName), context);
122        }
123        
124        public BrokerContainerImpl(String brokerName, PersistenceAdapter persistenceAdapter, BrokerContext context) {
125            this(new DefaultBroker(brokerName, persistenceAdapter), context);
126        }
127    
128        public BrokerContainerImpl(String brokerName,String clusterName, PersistenceAdapter persistenceAdapter, BrokerContext context) {
129            this(new DefaultBroker(brokerName,clusterName, persistenceAdapter), context);
130        }
131    
132        /**
133         * @param broker
134         */
135        public BrokerContainerImpl(Broker broker, BrokerContext context) {
136            this.broker = broker;
137            this.context = context;
138            this.clientIds = new ConcurrentHashMap();
139            this.consumerInfos = new ConcurrentHashMap();
140            this.producerInfos = new ConcurrentHashMap();
141            this.transportConnectors = new CopyOnWriteArrayList();
142            this.networkConnectors = new CopyOnWriteArrayList();
143            this.remoteClientIds = new CopyOnWriteArraySet();
144            this.broker.addCapacityEventListener(this);
145            if (this.broker instanceof DefaultBroker){
146                ((DefaultBroker)broker).setBrokercontainer(this);
147            }
148            doRegistration(broker.getBrokerName());
149        }
150    
151        /**
152         * start the Container
153         *
154         * @throws JMSException
155         */
156        public void start() throws JMSException {
157            log.info("ActiveMQ "+ActiveMQConnectionMetaData.PROVIDER_VERSION+" JMS Message Broker (" + broker.getBrokerName() + ") is starting");
158            log.info("For help or more information please see: http://www.logicblaze.com");
159            broker.start();
160            addShutdownHook();
161    
162            // TODO we might not need to copy the collections, as maybe the List might not
163            // throw concurrent modification exception? Couldn't tell from the docs
164            // but I don't think it does
165    
166            for (Iterator iter = new ArrayList(networkConnectors).iterator(); iter.hasNext();) {
167                Service connector = (Service) iter.next();
168                connector.start();
169            }
170    
171            for (Iterator iter = new ArrayList(transportConnectors).iterator(); iter.hasNext();) {
172                Service connector = (Service) iter.next();
173                connector.start();
174            }
175    
176            if (discoveryAgent != null) {
177                discoveryAgent.start();
178    
179                localDiscoveryDetails = createLocalDiscoveryDetails();
180                discoveryAgent.registerService(getLocalBrokerName(), localDiscoveryDetails);
181            }
182    
183            log.info("ActiveMQ JMS Message Broker (" + broker.getBrokerName() + ") has started");
184        }
185    
186        /**
187         * Stop the Container
188         *
189         * @throws JMSException
190         */
191        public synchronized void stop() throws JMSException {
192            if (!stopped) {
193                stopped = true;
194    
195                log.info("ActiveMQ Message Broker (" + broker.getBrokerName() + ") is shutting down");
196    
197                context.deregisterContainer(broker.getBrokerName(), this);
198    
199                try {
200                    Runtime.getRuntime().removeShutdownHook(shutdownHook);
201                }
202                catch (Exception e) {
203                    log.debug("Caught exception, must be shutting down: " + e);
204                }
205    
206                JMSException firstException = null;
207                if (discoveryAgent != null) {
208                    try {
209                        discoveryAgent.stop();
210                    } catch (JMSException e) {
211                        firstException = e;
212                        log.warn("Could not close discovery agent: " + discoveryAgent + " due to: " + e, e);
213                    }
214                }
215    
216                for (Iterator iter = new ArrayList(transportConnectors).iterator(); iter.hasNext();) {
217                    Service connector = (Service) iter.next();
218                    try {
219                        connector.stop();
220                    }
221                    catch (JMSException e) {
222                        if (firstException == null) {
223                            firstException = e;
224                        }
225                        log.warn("Could not close transport connector: " + connector + " due to: " + e, e);
226                    }
227                }
228                transportConnectors.clear();
229    
230                for (Iterator iter = new ArrayList(networkConnectors).iterator(); iter.hasNext();) {
231                    Service connector = (Service) iter.next();
232                    try {
233                        connector.stop();
234                    }
235                    catch (JMSException e) {
236                        if (firstException == null) {
237                            firstException = e;
238                        }
239                        log.warn("Could not close network connector: " + connector + " due to: " + e, e);
240                    }
241                }
242                networkConnectors.clear();
243    
244                
245    
246                // lets close all the channels
247                // note that this Map implementation does not throw concurrent modification exception
248                for (Iterator iter = clientIds.values().iterator();iter.hasNext();) {
249                    // should remove clients from parent container?
250                    BrokerClient client = (BrokerClient) iter.next();
251                    if (client != null) {
252                        try {
253                            client.stop();
254                        }
255                        catch (JMSException e) {
256                            if (firstException == null) {
257                                firstException = e;
258                            }
259                            log.warn("Could not close client: " + client + " due to: " + e, e);
260                        }
261                    }
262                }
263                clientIds.clear();
264    
265                broker.removeCapacityEventListener(this);
266                broker.stop();
267    
268                log.info("ActiveMQ JMS Message Broker (" + broker.getBrokerName() + ") stopped");
269    
270                if (firstException != null) {
271                    throw firstException;
272                }
273            }
274        }
275    
276        /**
277         * registers a new Connection
278         *
279         * @param client
280         * @param info   infomation about the client-side Connection
281         * @throws InvalidClientIDException if the ClientID of the Connection is a duplicate
282         */
283            synchronized public void registerConnection(BrokerClient client, ConnectionInfo info) throws JMSException {
284                    String clientId = info.getClientId();
285                    if (clientIds.containsKey(clientId)) {
286                            int timeout = 5000;
287                            log.info("Got duplicate client with id: " + clientId + ". Giving the existing client " + timeout + " millis to prove it's alive.");
288    
289                            // Assert that the existing client is alive
290                            BrokerClient existingClient = (BrokerClient) clientIds.get(clientId);
291                            JMSException ex = null;
292                            boolean isValid = true;
293                            try {
294                                    existingClient.validateConnection(timeout);
295                            } catch (JMSException e) {
296                                    isValid = false;
297                                    ex = e;
298                            }
299                            if (isValid) {
300                                    // The existing client is valid, so kick the new client
301                                    log.info("Client: " + clientId + " on transport: " + existingClient.getChannel()
302                                                    + "' is alive, rejecting new client on transport: " + client.getChannel());
303                                    throw new InvalidClientIDException("Duplicate clientId: " + info);
304                            } else {
305                                    // A transport error occured or the existing client did not
306                                    // respond in time, so kick it and let the new client connect.
307                                    log.info("Replacing client: " + clientId + " on transport: " + existingClient.getChannel() + " ("
308                                                    + ex.getMessage() + ") with client on transport: " + client.getChannel());
309                                    
310                                    // @TODO: Not sure this is the proper way to close the existing client
311                                    existingClient.cleanUp(); 
312                                    existingClient.stop();
313                            }
314    
315                    }
316                    getBroker().addClient(client, info);
317                    log.info("Adding new client: " + clientId + " on transport: " + client.getChannel());
318                    clientIds.put(clientId, client);
319            }
320    
321        /**
322         * un-registers a Connection
323         *
324         * @param client
325         * @param info   infomation about the client-side Connection
326         * @throws JMSException
327         */
328        public void deregisterConnection(BrokerClient client, ConnectionInfo info) throws JMSException {
329            String clientId = client.getClientID();
330            if (clientId != null) {
331                Object answer = clientIds.remove(clientId);
332                if (answer != null) {
333                    log.info("Removing client: " + clientId + " on transport: " + client.getChannel());
334                    getBroker().removeClient(client, info);
335                }
336                else {
337                    log.warn("Got duplicate deregisterConnection for client: " + clientId);
338                }
339            }
340            else {
341                log.warn("No clientID available for client: " + client);
342            }
343        }
344    
345        /**
346         * Registers a MessageConsumer
347         *
348         * @param client
349         * @param info
350         * @throws JMSException
351         * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
352         */
353        public void registerMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
354            consumerInfos.put(info, client);
355            getBroker().addMessageConsumer(client, info);
356        }
357    
358        /**
359         * De-register a MessageConsumer from the Broker
360         *
361         * @param client
362         * @param info
363         * @throws JMSException
364         */
365        public void deregisterMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
366            consumerInfos.remove(info);
367            getBroker().removeMessageConsumer(client, info);
368        }
369    
370        /**
371         * Registers a MessageProducer
372         *
373         * @param client
374         * @param info
375         * @throws JMSException
376         * @throws JMSSecurityException if client authentication fails for the Destination the Consumer applies for
377         */
378        public void registerMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
379            ActiveMQDestination dest = info.getDestination();
380            checkTempDestinationExistance(dest);
381            getBroker().addMessageProducer(client, info);
382    
383            producerInfos.put(info, client);
384        }
385    
386        /**
387         * De-register a MessageProducer from the Broker
388         *
389         * @param client
390         * @param info
391         * @throws JMSException
392         */
393        public void deregisterMessageProducer(BrokerClient client, ProducerInfo info) throws JMSException {
394            getBroker().removeMessageProducer(client, info);
395    
396            producerInfos.remove(info);
397        }
398    
399        /**
400         * Register a client-side Session (used for Monitoring)
401         *
402         * @param client
403         * @param info
404         * @throws JMSException
405         */
406        public void registerSession(BrokerClient client, SessionInfo info) throws JMSException {
407        }
408    
409        /**
410         * De-register a client-side Session from the Broker (used for monitoring)
411         *
412         * @param client
413         * @param info
414         * @throws JMSException
415         */
416        public void deregisterSession(BrokerClient client, SessionInfo info) throws JMSException {
417        }
418    
419        /**
420         * Start a transaction from the Client session
421         *
422         * @param client
423         * @param transactionId
424         * @throws JMSException
425         */
426        public void startTransaction(BrokerClient client, String transactionId) throws JMSException {
427            getBroker().startTransaction(client, transactionId);
428        }
429    
430        /**
431         * Rollback a transacton
432         *
433         * @param client
434         * @param transactionId
435         * @throws JMSException
436         */
437        public void rollbackTransaction(BrokerClient client, String transactionId) throws JMSException {
438            getBroker().rollbackTransaction(client, transactionId);
439        }
440    
441        /**
442         * Commit a transaction
443         *
444         * @param client
445         * @param transactionId
446         * @throws JMSException
447         */
448        public void commitTransaction(BrokerClient client, String transactionId) throws JMSException {
449            getBroker().commitTransaction(client, transactionId);
450        }
451    
452        /**
453         * Send a non-transacted message to the Broker
454         *
455         * @param client
456         * @param message
457         * @throws JMSException
458         */
459        public void sendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException {
460            ActiveMQDestination dest = message.getJMSActiveMQDestination();        
461            checkTempDestinationExistance(dest);
462            broker.sendMessage(client, message);
463        }
464        
465        /**
466         * register a remote clientID
467         * @param remoteClientID
468         */
469        
470        public void registerRemoteClientID(String remoteClientID){
471            remoteClientIds.add(remoteClientID);
472        }
473        
474        /**
475         * deregister a remote clientID
476         * @param remoteClientID
477         */
478        public void deregisterRemoteClientID(String remoteClientID){
479            remoteClientIds.remove(remoteClientID);
480        }
481    
482        /**
483         * @param dest
484         * @throws InvalidDestinationException
485         */
486        private void checkTempDestinationExistance(ActiveMQDestination dest) throws InvalidDestinationException {
487            if (dest != null && dest.isTemporary()) {
488                //check to see if the client that is the target for the temporary destination still exists
489                String clientId = ActiveMQDestination.getClientId(dest);
490                if (clientId == null) {
491                    throw new InvalidDestinationException("Destination " + dest.getPhysicalName()
492                            + " is a temporary destination with null clientId");
493                }
494                if (!clientIds.containsKey(clientId) && !remoteClientIds.contains(clientId)) {
495                    throw new InvalidDestinationException("Destination " + dest.getPhysicalName()
496                            + " is no longer valid because the client " + clientId + " no longer exists");
497                }
498            }
499        }
500    
501        /**
502         * Acknowledge reciept of a message
503         *
504         * @param client
505         * @param ack
506         * @throws JMSException
507         */
508        public void acknowledgeMessage(BrokerClient client, MessageAck ack) throws JMSException {
509            getBroker().acknowledgeMessage(client, ack);
510        }
511    
512        /**
513         * Command to delete a durable topic subscription
514         *
515         * @param client
516         * @param ds
517         * @throws JMSException
518         */
519        public void durableUnsubscribe(BrokerClient client, DurableUnsubscribe ds) throws JMSException {
520            getBroker().deleteSubscription(ds.getClientId(), ds.getSubscriberName());
521        }
522    
523        /**
524         * Start an XA transaction.
525         *
526         * @param client
527         * @param xid
528         */
529        public void startTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
530            getBroker().startTransaction(client, xid);
531        }
532    
533        /**
534         * Gets the prepared XA transactions.
535         *
536         * @param client
537         * @return
538         */
539        public ActiveMQXid[] getPreparedTransactions(BrokerClient client) throws XAException {
540            return getBroker().getPreparedTransactions(client);
541        }
542    
543        /**
544         * Prepare an XA transaction.
545         *
546         * @param client
547         * @param xid
548         */
549        public int prepareTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
550            return getBroker().prepareTransaction(client, xid);
551        }
552    
553        /**
554         * Rollback an XA transaction.
555         *
556         * @param client
557         * @param xid
558         */
559        public void rollbackTransaction(BrokerClient client, ActiveMQXid xid) throws XAException {
560            getBroker().rollbackTransaction(client, xid);
561        }
562    
563        /**
564         * Commit an XA transaction.
565         *
566         * @param client
567         * @param xid
568         * @param onePhase
569         */
570        public void commitTransaction(BrokerClient client, ActiveMQXid xid, boolean onePhase) throws XAException {
571            getBroker().commitTransaction(client, xid, onePhase);
572        }
573    
574    
575        /**
576         * Update any message producers about our capacity to handle messages
577         *
578         * @param event
579         */
580        public void capacityChanged(CapacityMonitorEvent event) {
581            //only send to producers
582            for (Iterator i = producerInfos.values().iterator(); i.hasNext();) {
583                BrokerClient client = (BrokerClient) i.next();
584                client.updateBrokerCapacity(event.getCapacity());
585            }
586        }
587    
588    
589        // Properties
590        //-------------------------------------------------------------------------
591    
592        public List getTransportConnectors() {
593            return transportConnectors;
594        }
595    
596        public void setTransportConnectors(List transportConnectors) {
597            this.transportConnectors = new CopyOnWriteArrayList(transportConnectors);
598        }
599    
600        public void addConnector(BrokerConnector connector) {
601            if( !transportConnectors.contains(connector) ) {
602                transportConnectors.add(connector);
603                if (connector.getServerChannel() != null){
604                    context.registerConnector(connector.getServerChannel().getUrl(), connector);
605                }
606            }
607        }
608    
609        public void removeConnector(BrokerConnector connector) {
610            transportConnectors.remove(connector);
611            if (connector != null && connector.getServerChannel() != null){
612                context.deregisterConnector(connector.getServerChannel().getUrl());
613            }
614        }
615    
616    
617        public void addConnector(String bindAddress) throws JMSException {
618            addConnector(bindAddress, new DefaultWireFormat());
619        }
620    
621        public void addConnector(String bindAddress, WireFormat wireFormat) throws JMSException {
622            addConnector(new BrokerConnectorImpl(this, bindAddress, wireFormat));
623        }
624    
625        public void addConnector(TransportServerChannel transportConnector) {
626            addConnector(new BrokerConnectorImpl(this, transportConnector));
627        }
628    
629        public List getNetworkConnectors() {
630            return networkConnectors;
631        }
632    
633        public void setNetworkConnectors(List networkConnectors) {
634            this.networkConnectors = new CopyOnWriteArrayList(networkConnectors);
635        }
636    
637        public NetworkConnector addNetworkConnector(String uri) throws JMSException {
638            NetworkConnector connector = addNetworkConnector();
639            connector.addNetworkChannel(uri);
640            return connector;
641        }
642    
643        public NetworkConnector addNetworkConnector() {
644            NetworkConnector connector = new NetworkConnector(this);
645            addNetworkConnector(connector);
646            return connector;
647        }
648    
649        public void addNetworkConnector(NetworkConnector connector) {
650            networkConnectors.add(connector);
651        }
652    
653        public void removeNetworkConnector(NetworkConnector connector) {
654            networkConnectors.remove(connector);
655        }
656    
657    
658        public Broker getBroker() {
659            return broker;
660        }
661    
662        public PersistenceAdapter getPersistenceAdapter() {
663            return broker != null ? broker.getPersistenceAdapter() : null;
664        }
665    
666        public void setPersistenceAdapter(PersistenceAdapter persistenceAdapter) {
667            checkBrokerSet();
668            broker.setPersistenceAdapter(persistenceAdapter);
669        }
670    
671        public DiscoveryAgent getDiscoveryAgent() {
672            return discoveryAgent;
673        }
674    
675        public void setDiscoveryAgent(DiscoveryAgent discoveryAgent) {
676            this.discoveryAgent = discoveryAgent;
677        }
678    
679        public SecurityAdapter getSecurityAdapter() {
680            return broker != null ? broker.getSecurityAdapter() : null;
681        }
682    
683        public void setSecurityAdapter(SecurityAdapter securityAdapter) {
684            checkBrokerSet();
685            broker.setSecurityAdapter(securityAdapter);
686        }
687    
688        public RedeliveryPolicy getRedeliveryPolicy() {
689            return broker != null ? broker.getRedeliveryPolicy() : null;
690        }
691    
692        public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) {
693            checkBrokerSet();
694            broker.setRedeliveryPolicy(redeliveryPolicy);
695        }
696    
697        public DeadLetterPolicy getDeadLetterPolicy() {
698            return broker != null ? broker.getDeadLetterPolicy() : null;
699        }
700    
701        public void setDeadLetterPolicy(DeadLetterPolicy deadLetterPolicy) {
702            checkBrokerSet();
703            broker.setDeadLetterPolicy(deadLetterPolicy);
704        }
705    
706        // Implementation methods
707        //-------------------------------------------------------------------------
708    
709        protected void checkBrokerSet() {
710            if (broker == null) {
711                throw new IllegalStateException("Cannot set this property as we don't have a broker yet");
712            }
713        }
714    
715        protected Map createLocalDiscoveryDetails() {
716            Map map = new HashMap();
717            map.put("brokerName", getLocalBrokerName());
718            map.put("connectURL", getLocalConnectionURL());
719            return map;
720        }
721    
722        protected String getLocalBrokerName() {
723            return getBroker().getBrokerName();
724        }
725    
726        protected String getLocalConnectionURL() {
727            StringBuffer buffer = new StringBuffer("reliable:");
728            List list = getTransportConnectors();
729            boolean first = true;
730            for(Iterator iter = list.iterator();iter.hasNext();){
731                BrokerConnector brokerConnector = (BrokerConnector)iter.next();
732                TransportServerChannel connector = brokerConnector.getServerChannel();
733                if(connector!=null){
734                    String url = connector.getUrl();
735                    if(first){
736                        first = false;
737                    }else{
738                        buffer.append(",");
739                    }
740                    buffer.append(url);
741                }
742            }
743            return buffer.toString();
744        }
745    
746        protected void addShutdownHook() {
747            if(System.getProperty(DISABLE_CLEAN_SHUTDOWN_PROPERTY,"false").equals("true"))
748                return;
749            
750            shutdownHook = new Thread("ActiveMQ ShutdownHook") {
751                public void run() {
752                    containerShutdown();
753                }
754            };
755            Runtime.getRuntime().addShutdownHook(shutdownHook);
756        }
757    
758        /**
759         * Causes a clean shutdown of the container when the VM is being shut down
760         */
761        protected void containerShutdown() {
762            try {
763                stop();
764            }
765            catch (JMSException e) {
766                Exception linkedException = e.getLinkedException();
767                if (linkedException != null) {
768                    if (useLoggingForShutdownErrors) {
769                        log.error("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
770                    }
771                    else {
772                        System.err.println("Failed to shut down: " + e + ". Reason: " + linkedException);
773                    }
774                }
775                else {
776                    if (useLoggingForShutdownErrors) {
777                        log.error("Failed to shut down: " + e);
778                    }
779                    else {
780                        System.err.println("Failed to shut down: " + e);
781                    }
782                }
783                if (!useLoggingForShutdownErrors) {
784                    e.printStackTrace(System.err);
785                }
786            }
787            catch (Exception e) {
788                if (useLoggingForShutdownErrors) {
789                    log.error("Failed to shut down: " + e, e);
790                }
791                else {
792                    System.err.println("Failed to shut down: " + e);
793                    e.printStackTrace(System.err);
794                }
795            }
796        }
797        
798        protected void doDeRegistration(String oldName){
799            context.deregisterContainer(oldName,this);
800            context.deregisterContainer("vm://"+oldName,this);
801        }
802        protected void doRegistration(String brokerName){
803           
804            //lets register ourselves with the context
805            context.registerContainer(brokerName, this);
806            //register ourselves for vm:// transports
807            context.registerContainer("vm://" + brokerName, this);
808        }
809    }