Java tutorial
/** * 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.impl; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import javax.xml.bind.JAXBException; import org.apache.camel.CamelContext; import org.apache.camel.CamelException; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.RouteDefinition; import org.apache.camel.util.ObjectHelper; import org.apache.camel.view.ModelFileGenerator; import org.apache.camel.view.RouteDotGenerator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @version $Revision$ */ public abstract class MainSupport extends ServiceSupport { protected static final Log LOG = LogFactory.getLog(MainSupport.class); protected String dotOutputDir; protected final List<Option> options = new ArrayList<Option>(); protected final CountDownLatch latch = new CountDownLatch(1); protected final AtomicBoolean completed = new AtomicBoolean(false); protected long duration = -1; protected TimeUnit timeUnit = TimeUnit.MILLISECONDS; protected String routesOutputFile; protected boolean aggregateDot; protected boolean trace; protected List<RouteBuilder> routeBuilders = new ArrayList<RouteBuilder>(); protected final List<CamelContext> camelContexts = new ArrayList<CamelContext>(); protected ProducerTemplate camelTemplate; /** * A class for intercepting the hang up signal and do a graceful shutdown of the Camel. */ private final class HangupInterceptor extends Thread { Log log = LogFactory.getLog(this.getClass()); MainSupport mainInstance; public HangupInterceptor(MainSupport main) { mainInstance = main; } @Override public void run() { log.info("Received hang up - stopping the main instance."); try { mainInstance.stop(); } catch (Exception ex) { log.warn(ex); } } } protected MainSupport() { addOption(new Option("h", "help", "Displays the help screen") { protected void doProcess(String arg, LinkedList<String> remainingArgs) { showOptions(); completed(); } }); addOption(new ParameterOption("o", "outdir", "Sets the DOT output directory where the visual representations of the routes are generated", "dot") { protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) { setDotOutputDir(parameter); } }); addOption(new ParameterOption("ad", "aggregate-dot", "Aggregates all routes (in addition to individual route generation) into one context to create one monolithic DOT file for visual representations the entire system.", "aggregate-dot") { protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) { setAggregateDot("true".equals(parameter)); } }); addOption(new ParameterOption("d", "duration", "Sets the time duration that the application will run for, by default in milliseconds. You can use '10s' for 10 seconds etc", "duration") { protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) { String value = parameter.toUpperCase(); if (value.endsWith("S")) { value = value.substring(0, value.length() - 1); setTimeUnit(TimeUnit.SECONDS); } setDuration(Integer.parseInt(value)); } }); addOption(new Option("t", "trace", "Enables tracing") { protected void doProcess(String arg, LinkedList<String> remainingArgs) { enableTrace(); } }); addOption(new ParameterOption("out", "output", "Output all routes to the specified XML file", "filename") { protected void doProcess(String arg, String parameter, LinkedList<String> remainingArgs) { setRoutesOutputFile(parameter); } }); } /** * Runs this process with the given arguments, and will wait until completed, or the JVM terminates. */ public void run() throws Exception { if (!completed.get()) { // if we have an issue starting the propagate exception to caller start(); try { afterStart(); waitUntilCompleted(); beforeStop(); stop(); } catch (Exception e) { // while running then just log errors LOG.error("Failed: " + e, e); } } } /** * Enables the hangup support. Gracefully stops by calling stop() on a * Hangup signal. */ public void enableHangupSupport() { HangupInterceptor interceptor = new HangupInterceptor(this); Runtime.getRuntime().addShutdownHook(interceptor); } /** * Callback to run custom logic after CamelContext has been started */ protected void afterStart() { // noop } /** * Callback to run custom logic before CamelContext is being stopped */ protected void beforeStop() { // noop } /** * Marks this process as being completed */ public void completed() { completed.set(true); latch.countDown(); } /** * Displays the command line options */ public void showOptions() { showOptionsHeader(); for (Option option : options) { System.out.println(option.getInformation()); } } /** * Parses the command line arguments */ public void parseArguments(String[] arguments) { LinkedList<String> args = new LinkedList<String>(Arrays.asList(arguments)); boolean valid = true; while (!args.isEmpty()) { String arg = args.removeFirst(); boolean handled = false; for (Option option : options) { if (option.processOption(arg, args)) { handled = true; break; } } if (!handled) { System.out.println("Unknown option: " + arg); System.out.println(); valid = false; break; } } if (!valid) { showOptions(); completed(); } } public void addOption(Option option) { options.add(option); } public long getDuration() { return duration; } /** * Sets the duration to run the application for in milliseconds until it * should be terminated. Defaults to -1. Any value <= 0 will run forever. */ public void setDuration(long duration) { this.duration = duration; } public TimeUnit getTimeUnit() { return timeUnit; } /** * Sets the time unit duration */ public void setTimeUnit(TimeUnit timeUnit) { this.timeUnit = timeUnit; } public String getDotOutputDir() { return dotOutputDir; } /** * Sets the output directory of the generated DOT Files to show the visual * representation of the routes. A null value disables the dot file * generation */ public void setDotOutputDir(String dotOutputDir) { this.dotOutputDir = dotOutputDir; } public void setAggregateDot(boolean aggregateDot) { this.aggregateDot = aggregateDot; } public boolean isAggregateDot() { return aggregateDot; } public boolean isTrace() { return trace; } public void enableTrace() { this.trace = true; for (CamelContext context : camelContexts) { context.setTracing(true); } } public void setRoutesOutputFile(String routesOutputFile) { this.routesOutputFile = routesOutputFile; } public String getRoutesOutputFile() { return routesOutputFile; } protected void doStop() throws Exception { LOG.info("Apache Camel " + getVersion() + " stopping"); // call completed to properly stop as we count down the waiting latch completed(); } protected void doStart() throws Exception { LOG.info("Apache Camel " + getVersion() + " starting"); } protected void waitUntilCompleted() { while (!completed.get()) { try { if (duration > 0) { TimeUnit unit = getTimeUnit(); LOG.info("Waiting for: " + duration + " " + unit); latch.await(duration, unit); completed.set(true); } else { latch.await(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * Parses the command line arguments then runs the program */ public void run(String[] args) throws Exception { parseArguments(args); run(); } /** * Displays the header message for the command line options */ public void showOptionsHeader() { System.out.println("Apache Camel Runner takes the following options"); System.out.println(); } public List<CamelContext> getCamelContexts() { return camelContexts; } public List<RouteBuilder> getRouteBuilders() { return routeBuilders; } public void setRouteBuilders(List<RouteBuilder> routeBuilders) { this.routeBuilders = routeBuilders; } public List<RouteDefinition> getRouteDefinitions() { List<RouteDefinition> answer = new ArrayList<RouteDefinition>(); for (CamelContext camelContext : camelContexts) { answer.addAll(camelContext.getRouteDefinitions()); } return answer; } /** * Returns a {@link org.apache.camel.ProducerTemplate} from the Spring {@link org.springframework.context.ApplicationContext} instances * or lazily creates a new one dynamically */ public ProducerTemplate getCamelTemplate() throws Exception { if (camelTemplate == null) { camelTemplate = findOrCreateCamelTemplate(); } return camelTemplate; } protected abstract ProducerTemplate findOrCreateCamelTemplate(); protected abstract Map<String, CamelContext> getCamelContextMap(); protected void postProcessContext() throws Exception { Map<String, CamelContext> map = getCamelContextMap(); if (map.size() == 0) { throw new CamelException( "Cannot find any Camel Context from the Application Context. Please check your Application Context setting"); } Set<Map.Entry<String, CamelContext>> entries = map.entrySet(); int size = entries.size(); for (Map.Entry<String, CamelContext> entry : entries) { String name = entry.getKey(); CamelContext camelContext = entry.getValue(); camelContexts.add(camelContext); generateDot(name, camelContext, size); postProcessCamelContext(camelContext); } if (isAggregateDot()) { generateDot("aggregate", aggregateCamelContext(), 1); } if (!"".equals(getRoutesOutputFile())) { outputRoutesToFile(); } } protected void outputRoutesToFile() throws IOException, JAXBException { if (ObjectHelper.isNotEmpty(getRoutesOutputFile())) { LOG.info("Generating routes as XML in the file named: " + getRoutesOutputFile()); ModelFileGenerator generator = createModelFileGenerator(); generator.marshalRoutesUsingJaxb(getRoutesOutputFile(), getRouteDefinitions()); } } protected abstract ModelFileGenerator createModelFileGenerator() throws JAXBException; protected void generateDot(String name, CamelContext camelContext, int size) throws IOException { String outputDir = dotOutputDir; if (ObjectHelper.isNotEmpty(outputDir)) { if (size > 1) { outputDir += "/" + name; } RouteDotGenerator generator = new RouteDotGenerator(outputDir); LOG.info("Generating DOT file for routes: " + outputDir + " for: " + camelContext + " with name: " + name); generator.drawRoutes(camelContext); } } /** * Used for aggregate dot generation, generate a single camel context containing all of the available contexts */ private CamelContext aggregateCamelContext() throws Exception { if (camelContexts.size() == 1) { return camelContexts.get(0); } else { CamelContext answer = new DefaultCamelContext(); for (CamelContext camelContext : camelContexts) { answer.addRouteDefinitions(camelContext.getRouteDefinitions()); } return answer; } } protected void postProcessCamelContext(CamelContext camelContext) throws Exception { for (RouteBuilder routeBuilder : routeBuilders) { camelContext.addRoutes(routeBuilder); } } public void addRouteBuilder(RouteBuilder routeBuilder) { getRouteBuilders().add(routeBuilder); } public abstract class Option { private String abbreviation; private String fullName; private String description; protected Option(String abbreviation, String fullName, String description) { this.abbreviation = "-" + abbreviation; this.fullName = "-" + fullName; this.description = description; } public boolean processOption(String arg, LinkedList<String> remainingArgs) { if (arg.equalsIgnoreCase(abbreviation) || fullName.startsWith(arg)) { doProcess(arg, remainingArgs); return true; } return false; } public String getAbbreviation() { return abbreviation; } public String getDescription() { return description; } public String getFullName() { return fullName; } public String getInformation() { return " " + getAbbreviation() + " or " + getFullName() + " = " + getDescription(); } protected abstract void doProcess(String arg, LinkedList<String> remainingArgs); } public abstract class ParameterOption extends Option { private String parameterName; protected ParameterOption(String abbreviation, String fullName, String description, String parameterName) { super(abbreviation, fullName, description); this.parameterName = parameterName; } protected void doProcess(String arg, LinkedList<String> remainingArgs) { if (remainingArgs.isEmpty()) { System.err.println("Expected fileName for "); showOptions(); completed(); } else { String parameter = remainingArgs.removeFirst(); doProcess(arg, parameter, remainingArgs); } } public String getInformation() { return " " + getAbbreviation() + " or " + getFullName() + " <" + parameterName + "> = " + getDescription(); } protected abstract void doProcess(String arg, String parameter, LinkedList<String> remainingArgs); } }