/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.spring;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.MainSupport;
import org.apache.camel.util.IOHelper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* A command line tool for booting up a CamelContext using an optional Spring
* {@link org.springframework.context.ApplicationContext}.
* <p/>
* By placing a file in the {@link #LOCATION_PROPERTIES} directory of any JARs on the classpath,
* allows this Main class to load those additional Spring XML files as Spring
* {@link org.springframework.context.ApplicationContext} to be included.
* <p/>
* Each line in the {@link #LOCATION_PROPERTIES} is a reference to a Spring XML file to include,
* which by default gets loaded from classpath.
*/
@SuppressWarnings("deprecation")
public class Main extends MainSupport {
public static final String LOCATION_PROPERTIES = "META-INF/camel-spring/location.properties";
protected static Main instance;
private static final Charset UTF8 = Charset.forName("UTF-8");
private String applicationContextUri = "META-INF/spring/*.xml";
private String fileApplicationContextUri;
private AbstractApplicationContext applicationContext;
private AbstractApplicationContext parentApplicationContext;
private AbstractApplicationContext additionalApplicationContext;
private String parentApplicationContextUri;
public Main() {
addOption(new ParameterOption("ac", "applicationContext",
"Sets the classpath based spring ApplicationContext", "applicationContext") {
protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
setApplicationContextUri(parameter);
}
});
addOption(new ParameterOption("fa", "fileApplicationContext",
"Sets the filesystem based spring ApplicationContext", "fileApplicationContext") {
protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) {
setFileApplicationContextUri(parameter);
}
});
}
public static void main(String... args) throws Exception {
Main main = new Main();
instance = main;
main.run(args);
}
/**
* Returns the currently executing main
*
* @return the current running instance
*/
public static Main getInstance() {
return instance;
}
// Properties
// -------------------------------------------------------------------------
public AbstractApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(AbstractApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public String getApplicationContextUri() {
return applicationContextUri;
}
public void setApplicationContextUri(String applicationContextUri) {
this.applicationContextUri = applicationContextUri;
}
public String getFileApplicationContextUri() {
return fileApplicationContextUri;
}
public void setFileApplicationContextUri(String fileApplicationContextUri) {
this.fileApplicationContextUri = fileApplicationContextUri;
}
public AbstractApplicationContext getParentApplicationContext() {
if (parentApplicationContext == null) {
if (parentApplicationContextUri != null) {
parentApplicationContext = new ClassPathXmlApplicationContext(parentApplicationContextUri);
parentApplicationContext.start();
}
}
return parentApplicationContext;
}
public void setParentApplicationContext(AbstractApplicationContext parentApplicationContext) {
this.parentApplicationContext = parentApplicationContext;
}
public String getParentApplicationContextUri() {
return parentApplicationContextUri;
}
public void setParentApplicationContextUri(String parentApplicationContextUri) {
this.parentApplicationContextUri = parentApplicationContextUri;
}
// Implementation methods
// -------------------------------------------------------------------------
@Override
protected void doStart() throws Exception {
try {
super.doStart();
if (applicationContext == null) {
applicationContext = createDefaultApplicationContext();
}
// then start any additional after Camel has been started
if (additionalApplicationContext == null) {
additionalApplicationContext = createAdditionalLocationsFromClasspath();
if (additionalApplicationContext != null) {
LOG.debug("Starting Additional ApplicationContext: " + additionalApplicationContext.getId());
additionalApplicationContext.start();
}
}
LOG.debug("Starting Spring ApplicationContext: " + applicationContext.getId());
applicationContext.start();
postProcessContext();
} finally {
if (camelContexts != null && !camelContexts.isEmpty()) {
// if we were veto started then mark as completed
if (getCamelContexts().get(0).isVetoStarted()) {
completed();
}
}
}
}
protected void doStop() throws Exception {
super.doStop();
if (additionalApplicationContext != null) {
LOG.debug("Stopping Additional ApplicationContext: " + additionalApplicationContext.getId());
IOHelper.close(additionalApplicationContext);
}
if (applicationContext != null) {
LOG.debug("Stopping Spring ApplicationContext: " + applicationContext.getId());
IOHelper.close(applicationContext);
}
}
protected ProducerTemplate findOrCreateCamelTemplate() {
String[] names = getApplicationContext().getBeanNamesForType(ProducerTemplate.class);
if (names != null && names.length > 0) {
return getApplicationContext().getBean(names[0], ProducerTemplate.class);
}
if (getCamelContexts().isEmpty()) {
throw new IllegalArgumentException("No CamelContexts are available so cannot create a ProducerTemplate!");
}
return getCamelContexts().get(0).createProducerTemplate();
}
protected AbstractApplicationContext createDefaultApplicationContext() throws IOException {
ApplicationContext parentContext = getParentApplicationContext();
// file based
if (getFileApplicationContextUri() != null) {
String[] args = getFileApplicationContextUri().split(";");
if (parentContext != null) {
return new FileSystemXmlApplicationContext(args, parentContext);
} else {
return new FileSystemXmlApplicationContext(args);
}
}
// default to classpath based
String[] args = getApplicationContextUri().split(";");
if (parentContext != null) {
return new ClassPathXmlApplicationContext(args, parentContext);
} else {
return new ClassPathXmlApplicationContext(args);
}
}
protected Map<String, CamelContext> getCamelContextMap() {
Map<String, SpringCamelContext> map = applicationContext.getBeansOfType(SpringCamelContext.class);
Set<Map.Entry<String, SpringCamelContext>> entries = map.entrySet();
Map<String, CamelContext> answer = new HashMap<String, CamelContext>();
for (Map.Entry<String, SpringCamelContext> entry : entries) {
String name = entry.getKey();
CamelContext camelContext = entry.getValue();
answer.put(name, camelContext);
}
return answer;
}
protected AbstractApplicationContext createAdditionalLocationsFromClasspath() throws IOException {
Set<String> locations = new LinkedHashSet<String>();
findLocations(locations, Main.class.getClassLoader());
if (!locations.isEmpty()) {
LOG.info("Found locations for additional Spring XML files: {}", locations);
String[] locs = locations.toArray(new String[locations.size()]);
return new ClassPathXmlApplicationContext(locs);
} else {
return null;
}
}
protected void findLocations(Set<String> locations, ClassLoader classLoader) throws IOException {
Enumeration<URL> resources = classLoader.getResources(LOCATION_PROPERTIES);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
BufferedReader reader = IOHelper.buffered(new InputStreamReader(url.openStream(), UTF8));
try {
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
line = line.trim();
if (line.startsWith("#") || line.length() == 0) {
continue;
}
locations.add(line);
}
} finally {
IOHelper.close(reader, null, LOG);
}
}
}
}