001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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
018package org.apache.activemq.console.command;
019
020import java.net.URI;
021import java.net.URISyntaxException;
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.List;
025import java.util.concurrent.atomic.AtomicInteger;
026
027import org.apache.activemq.broker.BrokerFactory;
028import org.apache.activemq.broker.BrokerService;
029
030public class StartCommand extends AbstractCommand {
031
032    public static final String DEFAULT_CONFIG_URI = "xbean:activemq.xml";
033
034    protected String[] helpFile = new String[] {
035        "Task Usage: Main start [start-options] [uri]",
036        "Description: Creates and starts a broker using a configuration file, or a broker URI.",
037        "",
038        "Start Options:",
039        "    -D<name>=<value>      Define a system property.",
040        "    --version             Display the version information.", 
041        "    -h,-?,--help          Display the start broker help information.",
042        "",
043        "URI:",
044        "",
045        "    XBean based broker configuration:",
046        "",
047        "        Example: Main xbean:file:activemq.xml",
048        "            Loads the xbean configuration file from the current working directory",
049        "        Example: Main xbean:activemq.xml",
050        "            Loads the xbean configuration file from the classpath",
051        "",
052        "    URI Parameter based broker configuration:",
053        "",
054        "        Example: Main broker:(tcp://localhost:61616, tcp://localhost:5000)?useJmx=true",
055        "            Configures the broker with 2 transport connectors and jmx enabled",
056        "        Example: Main broker:(tcp://localhost:61616, network:tcp://localhost:5000)?persistent=false",
057        "            Configures the broker with 1 transport connector, and 1 network connector and persistence disabled",
058        ""
059    };
060
061    private URI configURI;
062    private List<BrokerService> brokers = new ArrayList<BrokerService>(5);
063
064    /**
065     * The default task to start a broker or a group of brokers
066     * 
067     * @param brokerURIs
068     */
069    protected void runTask(List<String> brokerURIs) throws Exception {
070        try {
071            // If no config uri, use default setting
072            if (brokerURIs.isEmpty()) {
073                setConfigUri(new URI(DEFAULT_CONFIG_URI));
074                startBroker(getConfigUri());
075
076                // Set configuration data, if available, which in this case
077                // would be the config URI
078            } else {
079                String strConfigURI;
080
081                while (!brokerURIs.isEmpty()) {
082                    strConfigURI = (String)brokerURIs.remove(0);
083
084                    try {
085                        setConfigUri(new URI(strConfigURI));
086                    } catch (URISyntaxException e) {
087                        context.printException(e);
088                        return;
089                    }
090
091                    startBroker(getConfigUri());
092                }
093            }
094
095            // Prevent the main thread from exiting unless it is terminated
096            // elsewhere
097        } catch (Exception e) {
098            context.printException(new RuntimeException("Failed to execute start task. Reason: " + e, e));
099            throw new Exception(e);
100        }
101        
102        // The broker start up fine.  If this unblocks it's cause they were stopped
103        // and this would occur because of an internal error (like the DB going offline)
104        waitForShutdown();
105    }
106
107    /**
108     * Create and run a broker specified by the given configuration URI
109     * 
110     * @param configURI
111     * @throws Exception
112     */
113    public void startBroker(URI configURI) throws Exception {
114        System.out.println("Loading message broker from: " + configURI);
115        BrokerService broker = BrokerFactory.createBroker(configURI);
116        brokers.add(broker);
117        broker.start();
118    }
119
120    /**
121     * Wait for a shutdown invocation elsewhere
122     * 
123     * @throws Exception
124     */
125    protected void waitForShutdown() throws Exception {
126        final boolean[] shutdown = new boolean[] {
127            false
128        };
129        
130        Runtime.getRuntime().addShutdownHook(new Thread() {
131            public void run() {
132                for (Iterator<BrokerService> i = brokers.iterator(); i.hasNext();) {
133                    try {
134                        BrokerService broker = i.next();
135                        broker.stop();
136                    } catch (Exception e) {
137                    }
138                }
139            }
140        });
141        
142        final AtomicInteger brokerCounter = new AtomicInteger(brokers.size());
143        for (BrokerService bs : brokers) {
144            bs.addShutdownHook(new Runnable() {
145                public void run() {
146                    // When the last broker lets us know he is closed....
147                    if( brokerCounter.decrementAndGet() == 0 ) {
148                        synchronized (shutdown) {
149                            shutdown[0] = true;
150                            shutdown.notify();
151                        }
152                    }
153                }
154            });
155        }
156
157        // Wait for any shutdown event
158        synchronized (shutdown) {
159            while (!shutdown[0]) {
160                try {
161                    shutdown.wait();
162                } catch (InterruptedException e) {
163                }
164            }
165        }
166
167    }
168
169    /**
170     * Sets the current configuration URI used by the start task
171     * 
172     * @param uri
173     */
174    public void setConfigUri(URI uri) {
175        configURI = uri;
176    }
177
178    /**
179     * Gets the current configuration URI used by the start task
180     * 
181     * @return current configuration URI
182     */
183    public URI getConfigUri() {
184        return configURI;
185    }
186
187    /**
188     * Print the help messages for the browse command
189     */
190    protected void printHelp() {
191        context.printHelp(helpFile);
192    }
193
194}