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.HashMap;
020    import java.util.LinkedList;
021    import java.util.Map;
022    import java.util.Set;
023    
024    import javax.xml.bind.JAXBException;
025    
026    import org.apache.camel.CamelContext;
027    import org.apache.camel.ProducerTemplate;
028    import org.apache.camel.spring.handler.CamelNamespaceHandler;
029    import org.apache.camel.util.MainSupport;
030    import org.apache.camel.view.ModelFileGenerator;
031    import org.apache.commons.logging.Log;
032    import org.apache.commons.logging.LogFactory;
033    import org.springframework.context.ApplicationContext;
034    import org.springframework.context.support.AbstractApplicationContext;
035    import org.springframework.context.support.ClassPathXmlApplicationContext;
036    import org.springframework.context.support.FileSystemXmlApplicationContext;
037    
038    /**
039     * A command line tool for booting up a CamelContext using an optional Spring
040     * ApplicationContext
041     *
042     * @version $Revision: 66961 $
043     */
044    public class Main extends MainSupport {
045        private static Main instance;
046    
047        private String applicationContextUri = "META-INF/spring/*.xml";
048        private String fileApplicationContextUri;
049        private AbstractApplicationContext applicationContext;
050        private AbstractApplicationContext parentApplicationContext;
051        private String parentApplicationContextUri;
052    
053        public Main() {
054    
055            addOption(new ParameterOption("ac", "applicationContext",
056                    "Sets the classpath based spring ApplicationContext", "applicationContext") {
057                protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
058                    setApplicationContextUri(parameter);
059                }
060            });
061    
062            addOption(new ParameterOption("fa", "fileApplicationContext",
063                    "Sets the filesystem based spring ApplicationContext", "fileApplicationContext") {
064                protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
065                    setFileApplicationContextUri(parameter);
066                }
067            });
068    
069        }
070        
071        /**
072         * A class for intercepting the hang up signal and do a graceful shutdown of
073         * the Camel.
074         */
075        private class HangupInterceptor extends Thread {
076            Log log = LogFactory.getLog(this.getClass());
077            Main mainInstance;
078    
079            public HangupInterceptor(Main main) {
080                mainInstance = main;
081            }
082    
083            @Override
084            public void run() {
085                log.info("Recieved hang up - stopping the main instance.");
086                try {
087                    mainInstance.stop();
088                } catch (Exception ex) {
089                    log.warn(ex);
090                }
091            }
092        }
093    
094    
095        public static void main(String... args) {
096            Main main = new Main();
097            instance = main;
098            main.enableHangupSupport();
099            main.run(args);
100        }
101    
102        /**
103         * Returns the currently executing main
104         *
105         * @return the current running instance
106         */
107        public static Main getInstance() {
108            return instance;
109        }
110        
111        /**
112         * Enables the hangup support. Gracefully stops by calling stop() on a
113         * Hangup signal.
114         */
115        public void enableHangupSupport() {
116            HangupInterceptor interceptor = new HangupInterceptor(this);
117            Runtime.getRuntime().addShutdownHook(interceptor);
118        }
119    
120        @Override
121        public void enableDebug() {
122            super.enableDebug();
123            setParentApplicationContextUri("/META-INF/services/org/apache/camel/spring/debug.xml");
124        }
125    
126        @Override
127        public void enableTrace() {
128            // TODO
129            super.enableTrace();
130            setParentApplicationContextUri("/META-INF/services/org/apache/camel/spring/trace.xml");
131        }
132    
133        // Properties
134        // -------------------------------------------------------------------------
135        public AbstractApplicationContext getApplicationContext() {
136            return applicationContext;
137        }
138    
139        public void setApplicationContext(AbstractApplicationContext applicationContext) {
140            this.applicationContext = applicationContext;
141        }
142    
143        public String getApplicationContextUri() {
144            return applicationContextUri;
145        }
146    
147        public void setApplicationContextUri(String applicationContextUri) {
148            this.applicationContextUri = applicationContextUri;
149        }
150    
151        public String getFileApplicationContextUri() {
152            return fileApplicationContextUri;
153        }
154    
155        public void setFileApplicationContextUri(String fileApplicationContextUri) {
156            this.fileApplicationContextUri = fileApplicationContextUri;
157        }
158    
159        public AbstractApplicationContext getParentApplicationContext() {
160            if (parentApplicationContext == null) {
161                if (parentApplicationContextUri != null) {
162                    parentApplicationContext = new ClassPathXmlApplicationContext(parentApplicationContextUri);
163                    parentApplicationContext.start();
164                }
165            }
166            return parentApplicationContext;
167        }
168    
169        public void setParentApplicationContext(AbstractApplicationContext parentApplicationContext) {
170            this.parentApplicationContext = parentApplicationContext;
171        }
172    
173        public String getParentApplicationContextUri() {
174            return parentApplicationContextUri;
175        }
176    
177        public void setParentApplicationContextUri(String parentApplicationContextUri) {
178            this.parentApplicationContextUri = parentApplicationContextUri;
179        }
180    
181        // Implementation methods
182        // -------------------------------------------------------------------------
183    
184        @Override
185        protected void doStart() throws Exception {
186            super.doStart();
187            if (applicationContext == null) {
188                applicationContext = createDefaultApplicationContext();
189            }
190            applicationContext.start();
191    
192            postProcessContext();
193        }
194    
195        protected ProducerTemplate findOrCreateCamelTemplate() {
196            String[] names = getApplicationContext().getBeanNamesForType(ProducerTemplate.class);
197            if (names != null && names.length > 0) {
198                return (ProducerTemplate) getApplicationContext().getBean(names[0], ProducerTemplate.class);
199            }
200            for (CamelContext camelContext : getCamelContexts()) {
201                return camelContext.createProducerTemplate();
202            }
203            throw new IllegalArgumentException("No CamelContexts are available so cannot create a ProducerTemplate!");
204        }
205    
206        protected AbstractApplicationContext createDefaultApplicationContext() {
207            // file based
208            if (getFileApplicationContextUri() != null) {
209                String[] args = getFileApplicationContextUri().split(";");
210    
211                ApplicationContext parentContext = getParentApplicationContext();
212                if (parentContext != null) {
213                    return new FileSystemXmlApplicationContext(args, parentContext);
214                } else {
215                    return new FileSystemXmlApplicationContext(args);
216                }
217            }
218            
219            // default to classpath based
220            String[] args = getApplicationContextUri().split(";");
221            ApplicationContext parentContext = getParentApplicationContext();
222            if (parentContext != null) {
223                return new ClassPathXmlApplicationContext(args, parentContext);
224            } else {
225                return new ClassPathXmlApplicationContext(args);
226            }
227        }
228    
229        protected void doStop() throws Exception {
230            LOG.info("Apache Camel terminating");
231    
232            if (applicationContext != null) {
233                applicationContext.close();
234            }
235        }
236    
237        protected Map<String, CamelContext> getCamelContextMap() {
238            Map<String, SpringCamelContext> map = applicationContext.getBeansOfType(SpringCamelContext.class);
239            Set<Map.Entry<String, SpringCamelContext>> entries = map.entrySet();
240            Map<String, CamelContext> answer = new HashMap<String, CamelContext>();
241            for (Map.Entry<String, SpringCamelContext> entry : entries) {
242                String name = entry.getKey();
243                CamelContext camelContext = entry.getValue();
244                answer.put(name, camelContext);
245            }
246            return answer;
247        }
248    
249        protected ModelFileGenerator createModelFileGenerator() throws JAXBException {
250            return new ModelFileGenerator(new CamelNamespaceHandler().getJaxbContext());
251        }
252    }