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.impl.MainSupport;
028    import org.apache.camel.spring.handler.CamelNamespaceHandler;
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: 792468 $
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        // Properties
119        // -------------------------------------------------------------------------
120        public AbstractApplicationContext getApplicationContext() {
121            return applicationContext;
122        }
123    
124        public void setApplicationContext(AbstractApplicationContext applicationContext) {
125            this.applicationContext = applicationContext;
126        }
127    
128        public String getApplicationContextUri() {
129            return applicationContextUri;
130        }
131    
132        public void setApplicationContextUri(String applicationContextUri) {
133            this.applicationContextUri = applicationContextUri;
134        }
135    
136        public String getFileApplicationContextUri() {
137            return fileApplicationContextUri;
138        }
139    
140        public void setFileApplicationContextUri(String fileApplicationContextUri) {
141            this.fileApplicationContextUri = fileApplicationContextUri;
142        }
143    
144        public AbstractApplicationContext getParentApplicationContext() {
145            if (parentApplicationContext == null) {
146                if (parentApplicationContextUri != null) {
147                    parentApplicationContext = new ClassPathXmlApplicationContext(parentApplicationContextUri);
148                    parentApplicationContext.start();
149                }
150            }
151            return parentApplicationContext;
152        }
153    
154        public void setParentApplicationContext(AbstractApplicationContext parentApplicationContext) {
155            this.parentApplicationContext = parentApplicationContext;
156        }
157    
158        public String getParentApplicationContextUri() {
159            return parentApplicationContextUri;
160        }
161    
162        public void setParentApplicationContextUri(String parentApplicationContextUri) {
163            this.parentApplicationContextUri = parentApplicationContextUri;
164        }
165    
166        // Implementation methods
167        // -------------------------------------------------------------------------
168    
169        @Override
170        protected void doStart() throws Exception {
171            super.doStart();
172            if (applicationContext == null) {
173                applicationContext = createDefaultApplicationContext();
174            }
175            LOG.debug("Starting Spring ApplicationContext: " + applicationContext.getId());
176            applicationContext.start();
177    
178            postProcessContext();
179        }
180    
181        protected void doStop() throws Exception {
182            super.doStop();
183            if (applicationContext != null) {
184                LOG.debug("Stopping Spring ApplicationContext: " + applicationContext.getId());
185                applicationContext.close();
186            }
187        }
188    
189        protected ProducerTemplate findOrCreateCamelTemplate() {
190            String[] names = getApplicationContext().getBeanNamesForType(ProducerTemplate.class);
191            if (names != null && names.length > 0) {
192                return (ProducerTemplate) getApplicationContext().getBean(names[0], ProducerTemplate.class);
193            }
194            if (getCamelContexts().isEmpty()) {
195                throw new IllegalArgumentException("No CamelContexts are available so cannot create a ProducerTemplate!");
196            }
197            return getCamelContexts().get(0).createProducerTemplate();
198        }
199    
200        protected AbstractApplicationContext createDefaultApplicationContext() {
201            // file based
202            if (getFileApplicationContextUri() != null) {
203                String[] args = getFileApplicationContextUri().split(";");
204    
205                ApplicationContext parentContext = getParentApplicationContext();
206                if (parentContext != null) {
207                    return new FileSystemXmlApplicationContext(args, parentContext);
208                } else {
209                    return new FileSystemXmlApplicationContext(args);
210                }
211            }
212    
213            // default to classpath based
214            String[] args = getApplicationContextUri().split(";");
215            ApplicationContext parentContext = getParentApplicationContext();
216            if (parentContext != null) {
217                return new ClassPathXmlApplicationContext(args, parentContext);
218            } else {
219                return new ClassPathXmlApplicationContext(args);
220            }
221        }
222    
223        @SuppressWarnings("unchecked")
224        protected Map<String, CamelContext> getCamelContextMap() {
225            Map<String, SpringCamelContext> map = applicationContext.getBeansOfType(SpringCamelContext.class);
226            Set<Map.Entry<String, SpringCamelContext>> entries = map.entrySet();
227            Map<String, CamelContext> answer = new HashMap<String, CamelContext>();
228            for (Map.Entry<String, SpringCamelContext> entry : entries) {
229                String name = entry.getKey();
230                CamelContext camelContext = entry.getValue();
231                answer.put(name, camelContext);
232            }
233            return answer;
234        }
235    
236        protected ModelFileGenerator createModelFileGenerator() throws JAXBException {
237            return new ModelFileGenerator(new CamelNamespaceHandler().getJaxbContext());
238        }
239    }