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    package org.apache.camel.spring;
018    
019    import java.util.ArrayList;
020    import java.util.Arrays;
021    import java.util.LinkedList;
022    import java.util.List;
023    import java.util.concurrent.CountDownLatch;
024    import java.util.concurrent.atomic.AtomicBoolean;
025    
026    import org.apache.camel.impl.ServiceSupport;
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    
030    import org.springframework.context.support.AbstractApplicationContext;
031    import org.springframework.context.support.ClassPathXmlApplicationContext;
032    
033    /**
034     * A command line tool for booting up a CamelContext using an optional Spring
035     * ApplicationContext
036     * 
037     * @version $Revision: $
038     */
039    public class Main extends ServiceSupport {
040        private static final Log LOG = LogFactory.getLog(Main.class);
041        private String applicationContextUri = "META-INF/spring/*.xml";
042        private AbstractApplicationContext applicationContext;
043        private List<Option> options = new ArrayList<Option>();
044        private CountDownLatch latch = new CountDownLatch(1);
045        private AtomicBoolean completed = new AtomicBoolean(false);
046    
047        public Main() {
048            addOption(new Option("h", "help", "Displays the help screen") {
049                protected void doProcess(String arg, LinkedList<String> remainingArgs) {
050                    showOptions();
051                    completed();
052                }
053            });
054    
055            addOption(new ParameterOption("a", "applicationContext", "Sets the classpath based pring ApplicationContext", "applicationContext") {
056                protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
057                    setApplicationContextUri(parameter);
058                }
059            });
060        }
061    
062        public static void main(String[] args) {
063            Main main = new Main();
064            main.run(args);
065        }
066    
067        /**
068         * Parses the command line arguments then runs the program
069         */
070        public void run(String[] args) {
071            parseArguments(args);
072            run();
073        }
074    
075        /**
076         * Runs this process with the given arguments
077         */
078        public void run() {
079            if (!completed.get()) {
080                try {
081                    start();
082                    waitUntilCompleted();
083                    stop();
084                } catch (Exception e) {
085                    LOG.error("Failed: " + e, e);
086                }
087            }
088        }
089    
090        /**
091         * Marks this process as being completed
092         */
093        public void completed() {
094            completed.set(true);
095            latch.countDown();
096        }
097    
098        /**
099         * Displays the command line options
100         */
101        public void showOptions() {
102            System.out.println("Apache Camel Runner takes the following options");
103            System.out.println();
104    
105            for (Option option : options) {
106                System.out.println("  " + option.getAbbreviation() + " or " + option.getFullName() + " = " + option.getDescription());
107            }
108        }
109    
110        /**
111         * Parses the commandl ine arguments
112         */
113        public void parseArguments(String[] arguments) {
114            LinkedList<String> args = new LinkedList<String>(Arrays.asList(arguments));
115    
116            boolean valid = true;
117            while (!args.isEmpty()) {
118                String arg = args.removeFirst();
119    
120                boolean handled = false;
121                for (Option option : options) {
122                    if (option.processOption(arg, args)) {
123                        handled = true;
124                        break;
125                    }
126                }
127                if (!handled) {
128                    System.out.println("Unknown option: " + arg);
129                    System.out.println();
130                    valid = false;
131                    break;
132                }
133            }
134            if (!valid) {
135                showOptions();
136                completed();
137            }
138        }
139    
140        public void addOption(Option option) {
141            options.add(option);
142        }
143    
144        public abstract class Option {
145            private String abbreviation;
146            private String fullName;
147            private String description;
148    
149            protected Option(String abbreviation, String fullName, String description) {
150                this.abbreviation = "-" + abbreviation;
151                this.fullName = "-" + fullName;
152                this.description = description;
153            }
154    
155            public boolean processOption(String arg, LinkedList<String> remainingArgs) {
156                if (arg.equalsIgnoreCase(abbreviation) || fullName.startsWith(arg)) {
157                    doProcess(arg, remainingArgs);
158                    return true;
159                }
160                return false;
161            }
162    
163            public String getAbbreviation() {
164                return abbreviation;
165            }
166    
167            public String getDescription() {
168                return description;
169            }
170    
171            public String getFullName() {
172                return fullName;
173            }
174    
175            protected abstract void doProcess(String arg, LinkedList<String> remainingArgs);
176        }
177    
178        public abstract class ParameterOption extends Option {
179            private String parameterName;
180    
181            protected ParameterOption(String abbreviation, String fullName, String description, String parameterName) {
182                super(abbreviation, fullName, description);
183                this.parameterName = parameterName;
184            }
185    
186            protected void doProcess(String arg, LinkedList<String> remainingArgs) {
187                if (remainingArgs.isEmpty()) {
188                    System.err.println("Expected fileName for ");
189                    showOptions();
190                    completed();
191                } else {
192                    String parameter = remainingArgs.removeFirst();
193                    doProcess(arg, parameter, remainingArgs);
194                }
195            }
196    
197            protected abstract void doProcess(String arg, String parameter, LinkedList<String> remainingArgs);
198        }
199    
200        // Properties
201        // -------------------------------------------------------------------------
202        public AbstractApplicationContext getApplicationContext() {
203            return applicationContext;
204        }
205    
206        public void setApplicationContext(AbstractApplicationContext applicationContext) {
207            this.applicationContext = applicationContext;
208        }
209    
210        public String getApplicationContextUri() {
211            return applicationContextUri;
212        }
213    
214        public void setApplicationContextUri(String applicationContextUri) {
215            this.applicationContextUri = applicationContextUri;
216        }
217    
218        // Implementation methods
219        // -------------------------------------------------------------------------
220        protected void doStart() throws Exception {
221            LOG.info("Apache Camel " + getVersion() + " starting");
222            if (applicationContext == null) {
223                applicationContext = createDefaultApplicationContext();
224            }
225            applicationContext.start();
226        }
227    
228        protected AbstractApplicationContext createDefaultApplicationContext() {
229            return new ClassPathXmlApplicationContext(getApplicationContextUri());
230        }
231    
232        protected void doStop() throws Exception {
233            LOG.info("Apache Camel terminating");
234    
235            if (applicationContext != null) {
236                applicationContext.close();
237            }
238        }
239    
240        protected void waitUntilCompleted() {
241            while (!completed.get()) {
242                try {
243                    latch.await();
244                } catch (InterruptedException e) {
245                    // ignore
246                }
247            }
248        }
249    
250        protected String getVersion() {
251            Package aPackage = Package.getPackage("org.apache.camel");
252            if (aPackage != null) {
253                String version = aPackage.getImplementationVersion();
254                if (version == null) {
255                    version = aPackage.getSpecificationVersion();
256                    if (version == null) {
257                        version = "";
258                    }
259                }
260                return version;
261            }
262            return "";
263        }
264    }