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