fr.itinerennes.bundler.cli.GtfsItinerennesBundler.java Source code

Java tutorial

Introduction

Here is the source code for fr.itinerennes.bundler.cli.GtfsItinerennesBundler.java

Source

package fr.itinerennes.bundler.cli;

/*
 * [license]
 * Itinerennes data resources generator
 * ~~~~
 * Copyright (C) 2013 - 2014 Dudie
 * ~~~~
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * [/license]
 */

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import fr.itinerennes.bundler.tasks.framework.AbstractTask;

/**
 * @author Jrmie Huchet
 */
public class GtfsItinerennesBundler {

    /** The event logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger(GtfsItinerennesBundler.class);

    @Option(name = "-k", aliases = "--keolis-api-key", usage = "Keolis API key", required = true, metaVar = "API_KEY")
    private String keolisApiKey;

    @Option(name = "-o", aliases = "--output", usage = "path to the output directory", required = false, metaVar = "OUTPUT")
    private File output;

    @Option(name = "-am", aliases = "--agency-mapping", usage = "agency mapping: '1=2' means agency id '1' will be translated to '2'", required = false, metaVar = "AGENCY_MAPPING")
    private Map<String, String> agencyMapping = new HashMap<String, String>();

    @Option(name = "-t", aliases = "--tasks", usage = "tasks to run", required = false, metaVar = "TASKS")
    private List<String> tasks = new ArrayList<String>();

    @Option(name = "-l", aliases = "--list-tasks", usage = "list available tasks", required = false)
    private boolean listTasks;

    @Option(name = "-h", aliases = "--help", usage = "this help", required = false)
    private boolean help;

    @Argument(usage = "path to the GTFS file", required = true, metaVar = "GTFS")
    private File gtfsFile;

    /**
     * @param args
     */
    public static void main(final String[] args) throws IOException {

        final GtfsItinerennesBundler main = new GtfsItinerennesBundler();
        main.parseCmdLine(args);

        ClassPathXmlApplicationContext bootCtx = null;
        ClassPathXmlApplicationContext ctx = null;
        try {
            LOGGER.info("Initialization...");
            // pre-context dynamically initialize some beans depending on program args
            bootCtx = new ClassPathXmlApplicationContext("classpath:/boot-context.xml");
            main.loadArguments(bootCtx.getBean("programArgs", Properties.class));
            bootCtx.getBean("agencyMapping", Map.class).putAll(main.agencyMapping);

            ctx = new ClassPathXmlApplicationContext(new String[] { "classpath:/application-context.xml" },
                    bootCtx);
            LOGGER.info("Application context initialization finished");

            if (main.listTasks) {
                main.listTasksAndExit(ctx);
            }

            final List<AbstractTask> selectedTasks = main.verifySelectedTasksExists(ctx);
            LOGGER.info("Start tasks execution...");
            main.execute(selectedTasks);
            LOGGER.info("Tasks execution finished");
        } finally {
            IOUtils.closeQuietly(ctx);
            IOUtils.closeQuietly(bootCtx);
        }
    }

    private void loadArguments(final Properties p) {
        for (final Field f : getClass().getDeclaredFields()) {
            if (f.isAnnotationPresent(Option.class) || f.isAnnotationPresent(Argument.class)) {
                try {
                    final String name = String.format("program.args.%s", f.getName());
                    final String value = String.valueOf(f.get(this));
                    p.setProperty(name, value);
                    LOGGER.info("Adding property {}={} to application context", name, value);
                } catch (final Exception e) {
                    throw new RuntimeException("unable to retrieve field values", e);
                }
            }
        }
    }

    private void parseCmdLine(final String[] args) {

        final CmdLineParser parser = new CmdLineParser(this);

        // parse the arguments
        try {
            parser.parseArgument(args);
        } catch (final CmdLineException e) {
            System.err.println(e.getMessage());
            printUsageAndExit(parser, 1);
        }

        // print usage
        if (help) {
            printUsageAndExit(parser, 0);
        }

        // default output folder is current directory
        if (output == null) {
            output = new File(".");
        }

        // ensure output is a directory
        if (output.exists() && output.isFile()) {
            System.err.println(output + " already exists and is a regular file");
            printUsageAndExit(parser, 1);
        } else if (!output.exists()) {
            output.mkdirs();
            LOGGER.info("output will be written to {}", output.toURI());
        }
    }

    private void listTasksAndExit(final ClassPathXmlApplicationContext context) {
        System.out.println("Available tasks:");
        for (final String tName : context.getBeanNamesForType(AbstractTask.class)) {
            System.out.printf(" - %s\n", tName);
        }
        System.exit(0);
    }

    private List<AbstractTask> verifySelectedTasksExists(final ApplicationContext ctx) {
        if (tasks.isEmpty()) {
            tasks.addAll(Arrays.asList(ctx.getBeanNamesForType(AbstractTask.class)));
        }
        final List<AbstractTask> selectedTasks = new ArrayList<AbstractTask>();
        final List<String> missingTasks = new ArrayList<String>();
        for (final String tName : tasks) {
            if (ctx.containsBean(tName)) {
                selectedTasks.add(ctx.getBean(tName, AbstractTask.class));
                LOGGER.info("Added task '{}' in execution queue", tName);
            } else {
                missingTasks.add(tName);
                LOGGER.error("Task '{}' doesn't exist", tName);
            }
        }
        if (!missingTasks.isEmpty()) {
            System.exit(1);
        }
        return selectedTasks;
    }

    private <T extends Runnable> void execute(final Collection<T> tasks) throws IOException {
        // execute tasks
        for (final Runnable t : tasks) {
            LOGGER.info("Running task {}...", t.getClass().getSimpleName());
            t.run();
            LOGGER.info("Task {} finished", t.getClass().getSimpleName());
        }
    }

    private void printUsageAndExit(final CmdLineParser parser, final int status) {

        System.err.println(
                String.format("java %s <GTFS> -k <API_KEY> [-t TASKS] [-o <OUTPUT>] [-am <AGENCY_MAPPING>]",
                        this.getClass().getName()));
        parser.printUsage(System.err);
        System.exit(status);
    }
}