PackagerCli.java

package esa.bscs.pds4.packager.cli;

import static esa.bscs.pds4.packager.cli.Packager.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.MapPropertySource;

import esa.bscs.pds4.packager.Packager;
import esa.bscs.pds4.packager.config.BaseConfig;
import esa.bscs.pds4.packager.config.DummyValidationConfig;
import esa.bscs.pds4.packager.config.ProfilerConfig;
import esa.bscs.pds4.packager.config.PropertyConfig;
import esa.bscs.pds4.validate.config.ValidationConfig;

public class PackagerCli {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(PackagerCli.class);
            
    private static boolean remoteJarsDownloaded() {
        
        final boolean classifiersAvailable = (ClassLoader.getSystemClassLoader().getResource("META-INF/maven/esa.bscs.pds4/pds4-packager-classifiers/pom.properties") != null);
        final boolean dictionariesAvailable = (ClassLoader.getSystemClassLoader().getResource("META-INF/maven/esa.bscs.pds4-tools.packager/pds4-validate-data/pom.properties") != null);
        
        return classifiersAvailable && dictionariesAvailable;
    }
        
    private static void help(String header) {

        final HelpFormatter helpFormatter = new HelpFormatter();
        
        helpFormatter.setNewLine("\n");
        helpFormatter.printHelp(System.getProperty("app.name") + " -i <input dir> -o <output dir> [-d] [-h] [-l] [-r] [-s] [-v] [-V]", header, getOptions(), null);
    }
    
    public static void main(String[] args) {
        
        Thread.setDefaultUncaughtExceptionHandler(new PackagerErrorHandler());
        
        final StopWatch clock = StopWatch.createStarted();
        final Options cliOptions = getOptions();
        
        try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
            
            final String version = version();
            final CommandLine commandLine = new DefaultParser().parse(cliOptions, args);
            
            // Check if no options or help option
            
            if(commandLine.hasOption("help") || commandLine.getOptions().length == 0) {
                help(null);
                System.exit(0);
            }
            
            // Check if version option
            
            if(commandLine.hasOption("version")) {
                LOGGER.info(version);
                System.exit(0);
            }

            // Check configuration has been retrieved
            
            if(!remoteJarsDownloaded()) {
                LOGGER.error("Could not load packager configuration files. Please run ConfigSynchronizer first.");
                System.exit(1);
            }

            // Check required options 
            
            if(!commandLine.hasOption("input") || !commandLine.hasOption("output")) {
                throw new ParseException("Missing required options: i, o");
            }
            
            // Check which validation configuration should be used
            
            final Class<?> validationConfig = commandLine.hasOption("skip-validation") ? DummyValidationConfig.class : ValidationConfig.class;
            
            if(commandLine.hasOption("skip-validation")) {
                LOGGER.warn("PDS4 product validation disabled.");
            }
            
            // Set naming configuration
            
            final Map<String, Object> cliProperties = new HashMap<>();

            if(commandLine.hasOption("local")) {
                cliProperties.put("packager.config.naming.style", "psa");
            
            } else {
                cliProperties.put("packager.config.naming.style", "bscs");
            }
            
            // Force dictionary stack id if needed
            
            if(commandLine.hasOption("dictionary-stack-id")) {
                final String dictionaryStackId = commandLine.getOptionValue("dictionary-stack-id");
                
                LOGGER.warn("Product validation configuration overridden to use dictionary stack {}", dictionaryStackId);
                
                cliProperties.put("packager.config.dictionary.stack", dictionaryStackId);
            }
                                    
            // Configure spring context 
            
            context.getEnvironment().getPropertySources().addLast(new MapPropertySource("cliProperties", cliProperties));
            context.register(BaseConfig.class, PropertyConfig.class, validationConfig);

            // Check if verbose output selected
            
            if(commandLine.hasOption("verbose")) {
                context.register(ProfilerConfig.class);
            }
            
            // Start application context
            
            context.refresh();
            
            // Check inputs
            
            final File input = new File(commandLine.getOptionValue("input")).getCanonicalFile();
            final File output = new File(commandLine.getOptionValue("output")).getCanonicalFile();
            
            if(!input.isDirectory()) {
                LOGGER.error("Input directory {} is not a directory.", input.getAbsolutePath());
                System.exit(1);
            }
            
            if(!output.isDirectory()) {
                LOGGER.error("Output directory {} is not a directory.", output.getAbsolutePath());
                System.exit(1);
            }
            
            // Check input directory contains PDS4 products
            
            final List<File> labelFiles = new ArrayList<>(FileUtils.listFiles(input, new String[] {"xml", "XML"}, commandLine.hasOption("recursive")));
            
            if(labelFiles.isEmpty()) {
                LOGGER.error("Input directory {} contains no PDS4 products.", input.getAbsolutePath());
                System.exit(1);
            }
            
            // Get packager
            
            final Packager packager = context.getBean(Packager.class);
            
            // Display version info
            
            LOGGER.info(version);
            
            // Call packager
            
            LOGGER.info("Packaging {} PDS4 products found in {}", labelFiles.size(), input.getAbsolutePath());
            
            final File delivery = packager.pack(labelFiles);
            
            // Move delivery to output directory
                        
            FileUtils.moveFile(delivery, new File(output, delivery.getName()));
            
            // Exit successfully
            
            LOGGER.info("Delivery package {} built in {}", delivery.getName(), clock);
            
            System.exit(0);
        
        } catch(ParseException e) {
            
            // If invalid command line arguments print usage help. 
            
            help(e.getMessage());
            
            System.exit(1);
        
        } catch(IOException e) {
            
            // Delivery move to output directory failed
            
            LOGGER.error("Could mot move delivery file to output directory.");
            
            System.exit(1);
        }
    }
}