Package org.openbel.framework.tools.kamstore

Source Code of org.openbel.framework.tools.kamstore.KamManager

/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.tools.kamstore;

import static java.lang.String.format;
import static java.util.Arrays.copyOfRange;
import static org.apache.commons.lang.StringUtils.join;
import static org.openbel.framework.common.BELUtilities.constrainedHashMap;
import static org.openbel.framework.common.Strings.SYSTEM_CONFIG_PATH;
import static org.openbel.framework.common.cfg.SystemConfiguration.getSystemConfiguration;
import static org.openbel.framework.common.enums.ExitCode.GENERAL_FAILURE;
import static org.openbel.framework.core.StandardOptions.ARG_SYSCFG;
import static org.openbel.framework.core.StandardOptions.LONG_OPT_DEBUG;
import static org.openbel.framework.core.StandardOptions.LONG_OPT_SYSCFG;
import static org.openbel.framework.core.StandardOptions.SHORT_OPT_VERBOSE;
import static org.openbel.framework.core.StandardOptions.SHRT_OPT_SYSCFG;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.cli.Option;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.openbel.framework.api.KAMStore;
import org.openbel.framework.api.KAMStoreException;
import org.openbel.framework.api.KAMStoreImpl;
import org.openbel.framework.api.Kam;
import org.openbel.framework.api.internal.KAMCatalogDao;
import org.openbel.framework.api.internal.KAMCatalogDao.KamInfo;
import org.openbel.framework.api.internal.KamDbObject;
import org.openbel.framework.common.BELUtilities;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.SimpleOutput;
import org.openbel.framework.common.cfg.SystemConfiguration;
import org.openbel.framework.common.enums.ExitCode;
import org.openbel.framework.compiler.kam.KAMStoreSchemaService;
import org.openbel.framework.compiler.kam.KAMStoreSchemaServiceImpl;
import org.openbel.framework.core.CommandLineApplication;
import org.openbel.framework.core.df.DBConnection;
import org.openbel.framework.core.df.DatabaseService;
import org.openbel.framework.core.df.DatabaseServiceImpl;
import org.openbel.framework.tools.pkam.DefaultPKAMSerializationService;
import org.openbel.framework.tools.pkam.PKAMSerializationFailure;
import org.openbel.framework.tools.pkam.PKAMSerializationService;
import org.openbel.framework.tools.rdf.RDFExporter;
import org.openbel.framework.tools.xgmml.XGMMLExporter;

public final class KamManager extends CommandLineApplication {

    private static final String KAM_MANAGER_NAME = "Kam Manager";
    private static final String KAM_MANAGER_DESC =
            "Provides utilities to manage the KAM store";

    private static final String LONG_OPT_NO_PRESERVE = "no-preserve";
    private static final String USAGE_NO_PRESERVE =
            " [-f | --force | --no-preserve]";
    private static final String USAGE_PORTABLE_KAM_TYPE =
            " [{-t | --type} {kam | KAM}]";
    private static final String USAGE_TYPE =
            " [{-t | --type} {kam | KAM | rdf | RDF | xgmml | XGMML}]";

    private static final String KAM_EXTENSION = ".kam";
    private static final String XGMML_EXTENSION = ".xgmml";
    private static final String N3_EXTENSION = ".n3";

    // The name of the program that invoked main()
    private final String kamManager;

    // The command option passed to the program
    private Command command;
    private String commandStr;

    // Flags specified by command line options
    private boolean help, verbose, quiet, debug;

    // OpenBEL Framework system configuration to use, either default or from a specified
    // configuration file.
    private final SystemConfiguration sysconfig;

    // Objects used by the various commands.  They are initialized in setUp() and
    // destroyed in teardown().
    private DatabaseService dbservice;
    private DBConnection dbConnection;
    private KAMStore kAMStore;
    private KAMStoreSchemaService kamSchemaService;
    private PKAMSerializationService pkamService;
    private KAMCatalogDao kamCatalogDao;

    /**
     * Static main method to launch the KAM Manager tool.
     *
     * @param args {@link String String[]} the command-line arguments
     */
    public static void main(String[] args) throws Exception {

        KamManager app = new KamManager(args);
        app.run();
    }

    private static String[] withoutKamManagerName(final String[] args) {
        final int length = args.length;
        if (length >= 1 && (
                "KamManager.sh".equals(args[0]) ||
                "KamManager.cmd".equals(args[0]))) {

            return copyOfRange(args, 1, length);
        }
        return args;
    }

    public KamManager(String[] args) {
        super(withoutKamManagerName(args), false);
        if ("KamManager.sh".equals(args[0]) || "KamManager.cmd".equals(args[0])) {
            kamManager = args[0];
        } else {
            kamManager = "KamManager";
        }

        final SimpleOutput reportable = new SimpleOutput();
        reportable.setErrorStream(System.err);
        reportable.setOutputStream(System.out);
        setReportable(reportable);

        printApplicationInfo();

        initializeSystemConfiguration();
        sysconfig = getSystemConfiguration();

        // Determine the command that the user wants to use
        determineCommand();
    }

    private void setUp() throws SQLException, IOException {

        // Setup a database connector to the KAM Store.
        dbservice = new DatabaseServiceImpl();

        if (verbose || debug) {
            reportable.output("Using KAM Store URL: " + sysconfig.getKamURL());
            reportable
                    .output("Using KAM Store User: " + sysconfig.getKamUser());
        }

        dbConnection = dbservice.dbConnection(
                sysconfig.getKamURL(),
                sysconfig.getKamUser(),
                sysconfig.getKamPassword());

        // Connect to the KAM Store. This establishes a connection to the
        // KAM store database and sets up the system to read and process
        // KAMs.
        kAMStore = new KAMStoreImpl(dbConnection);

        // Set up the KAM Store schemas
        kamSchemaService = new KAMStoreSchemaServiceImpl(dbservice);

        // Load the KAM catalog schema, if it doesn't exist (see #88).
        kamSchemaService.setupKAMCatalogSchema();

        if (command == Command.SET_DESCRIPTION || command == Command.RENAME) {
            kamCatalogDao = new KAMCatalogDao(dbConnection,
                    syscfg.getKamCatalogSchema(), syscfg.getKamSchemaPrefix());
        }

        if (command == Command.IMPORT || command == Command.EXPORT) {
            pkamService = new DefaultPKAMSerializationService(
                    dbservice, kamSchemaService);
        }
    }

    private void teardown() {

        // Tears down the KAM store. This removes any cached data and queries
        if (kAMStore != null) {
            kAMStore.teardown();
        }

        // Close the DBConnection
        if (dbConnection != null) {
            try {
                final Connection conn = dbConnection.getConnection();
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                // Do nothing.
            }
        }

        dbservice = null;
        dbConnection = null;
        kAMStore = null;
        kamSchemaService = null;
        pkamService = null;
        kamCatalogDao = null;
    }

    public void run() {
        // Determine the values of the common options (the constructor has already initialized
        // some of the options:  syscfg (from -s/--system-config-file), command and commandStr
        // (from one of the command options), and kamManager (which is always the first
        // argument).
        verbose = hasOption(SHORT_OPT_VERBOSE);
        quiet = !verbose && hasOption("q"); // --verbose supersedes --quiet if both are provided
        debug = hasOption(LONG_OPT_DEBUG);

        final String[] extraArgs =
                getExtraneousArguments().toArray(new String[0]);

        if (help || command == Command.HELP) {
            // The help command requires no extra arguments, although this is not
            // enforced since the user seems to be looking for usage help.
            printHelp(true);

        } else if (command == Command.IMPORT) {
            // The import command requires one or two extra arguments:
            // the KAM file to import and, optionally, the new KAM name.
            checkExtraArguments(extraArgs, 1, 2);

            final String pkamPath = extraArgs[0];
            // check that the indicated PKAM file exists
            final File pkamFile = new File(pkamPath);
            if (!pkamFile.exists()) {
                reportable.error("KAM file does not exist - "
                        + pkamFile.getAbsolutePath());
                bail(ExitCode.GENERAL_FAILURE);
            }

            final String kamName = (extraArgs.length > 1 ? extraArgs[1] : null);
            ExportFormat exportFormat = determineType();
            if (exportFormat == null) {
                exportFormat = inferType(pkamFile);
            }
            if (exportFormat == null) {
                // Assume the default format:  portable KAM
                exportFormat = ExportFormat.PORTABLE_KAM;
            }
            final boolean noPreserve = isNoPreserve();

            runImportCommand(kamName, pkamFile, exportFormat, noPreserve);
            if (!quiet) {
                reportable.output(format("Imported %s file from '%s'.",
                        exportFormat.toString(), pkamPath));
            }

        } else if (command == Command.EXPORT) {
            // The export command uses two extra arguments:
            // the name of the KAM to export and an output file name (which can be
            // a default value if it is not specified).
            checkExtraArguments(extraArgs, 1, 2);
            ExportFormat exportFormat = determineType();
            if (exportFormat == null) {
                // Assume the default format:  portable KAM
                exportFormat = ExportFormat.PORTABLE_KAM;
            }
            final String kamName = extraArgs[0];
            final String outputFilename =
                    (extraArgs.length > 1 ? extraArgs[1] : null);
            final boolean noPreserve = isNoPreserve();
            runExportCommand(kamName, outputFilename, exportFormat,
                    noPreserve);

        } else if (command == Command.SUMMARIZE) {
            // The summarize command requires one extra argument:
            // the name of the KAM to summarize.
            checkExtraArguments(extraArgs, 1);
            final String outputFilename = determineOutputFileName();
            final String kamName = extraArgs[0];
            final boolean noPreserve = isNoPreserve();
            runSummarizeCommand(kamName, outputFilename, noPreserve);

        } else if (command == Command.DELETE) {
            // The delete command requires one extra argument:
            // the name of the KAM to delete.
            checkExtraArguments(extraArgs, 1);
            final String kamName = extraArgs[0];
            runDeleteCommand(kamName);

        } else if (command == Command.LIST) {
            // The list command requires zero extra arguments.
            checkExtraArguments(extraArgs, 0);
            runListCommand();

        } else if (command == Command.SET_DESCRIPTION) {
            // The set-description command requires two extra arguments:
            // the name of the KAM and the new description.
            checkExtraArguments(extraArgs, 2);
            final String kamName = extraArgs[0];
            final String newDescription = extraArgs[1];
            runSetDescriptionCommand(kamName, newDescription);

        } else if (command == Command.RENAME) {
            // The rename command requires two extra arguments:
            // the old KAM name and the new KAM name.
            checkExtraArguments(extraArgs, 2);
            final String oldKamName = extraArgs[0];
            final String newKamName = extraArgs[1];
            final boolean noPreserve = isNoPreserve();
            runRenameCommand(oldKamName, newKamName, noPreserve);

        }
    }

    private void checkExtraArguments(final String[] extraArgs,
            final int expectedNumber) {

        final int extraArgsSize = extraArgs.length;
        if (extraArgsSize != expectedNumber) {
            fatal(format(
                    "`%s --%s` expects %s argument%s but received %s.",
                    kamManager,
                    commandStr,
                    (expectedNumber != 0 ? Integer.toString(expectedNumber)
                            : "no"),
                    (expectedNumber != 1 ? "s" : ""),
                    (extraArgsSize == 0 ? "none" :
                            format("%d:  '%s'", extraArgsSize,
                                    join(extraArgs, "', '")))));
        }
    }

    private void checkExtraArguments(final String[] extraArgs,
            final int minNumber, final int maxNumber) {
        final int extraArgsSize = extraArgs.length;
        if (extraArgsSize < minNumber) {
            fatal(format(
                    "`%s --%s` expects at least %d argument%s but received %s.",
                    kamManager,
                    commandStr,
                    minNumber,
                    (minNumber != 1 ? "s" : ""),
                    (extraArgsSize == 0 ? "none" :
                            format("%d:  '%s'", extraArgsSize,
                                    join(extraArgs, "', '")))));

        } else if (extraArgsSize > maxNumber) {
            fatal(format(
                    "`%s --%s` expects no more than %d argument%s but received %s.",
                    kamManager,
                    commandStr,
                    maxNumber,
                    (maxNumber != 1 ? "s" : ""),
                    (extraArgsSize == 0 ? "none" :
                            format("%d:  '%s'", extraArgsSize,
                                    join(extraArgs, "', '")))));
        }
    }

    /*
     * The following methods determine values for certain command line options:
     */

    /**
     * Initializes the member variables command, commandStr, and help, according to the command
     * option specified by the user in the command line.
     */
    private void determineCommand() {
        command = null;
        commandStr = null;

        boolean tooManyCommands = false;
        for (Command c : Command.values()) {
            final String alias = c.getAlias();
            if (hasOption(alias)) {
                if (c == Command.HELP) {
                    // `--help` can be a command or just a long option for another command.
                    help = true;
                } else if (command == null) {
                    // Found a command option
                    command = c;
                    commandStr = alias;
                } else {
                    tooManyCommands = true;
                }
            }
        }

        if (tooManyCommands) {
            command = null;
            commandStr = null;

            if (!help) {
                reportable.error(format(
                        "You must specify only one command (%s).%n",
                        showCommandAliases()));
                printHelp(true);
            }
        }
        if (help && command == null) {
            // `--help` is considered as the command if no other command is provided.
            command = Command.HELP;
            commandStr = command.getAlias();

        } else if (command == null) {
          // Print usage if no commands were specified
          printUsage();
          reportable.error("\n");
            reportable
                    .error("No command option given. Please specify one of:  "
                            + showCommandAliases());
            end();
        }
    }

    /**
     * Converts the -t/--type argument to an ExportFormat.
     * @return
     */
    private ExportFormat determineType() {
        ExportFormat exportFormat = null;
        if (hasOption("t")) {
            final String value = getOptionValue("t");
            exportFormat = ExportFormat.getFormatByLabel(value);
            if (exportFormat == null) {
                reportable.error(format(
                        "The KAM file format '%s' is not valid.%n", value));
                printHelp(true);
            }
        }
        return exportFormat;
    }

    /**
     * If {@link determineType} returns {@code null} then this function may be able to determine
     * an appropriate type of KAM file from its file extension.
     * @param file
     * @return
     */
    private static ExportFormat inferType(final File file) {
        final int index = file.getName().lastIndexOf(".");
        if (index == -1) {
            return null;
        }

        final String extension = file.getName().substring(index);
        if (extension.equals(KAM_EXTENSION)) {
            return ExportFormat.PORTABLE_KAM;
        } else if (extension.equals(XGMML_EXTENSION)) {
            return ExportFormat.XGMML;
        } else if (extension.equals(N3_EXTENSION)) {
            return ExportFormat.RDF;
        } else {
            return null;
        }
    }

    /**
     * Gets the -o/--output-file option.
     * @return
     */
    private String determineOutputFileName() {
        return (hasOption("o") ? getOptionValue("o") : null);
    }

    /**
     * Determines whether -f/--force/--no-preserve was specified on the command line.
     * @return
     */
    private boolean isNoPreserve() {
        return hasOption("f") || hasOption(LONG_OPT_NO_PRESERVE);
    }

    /*
     * The following methods are responsible for performing one of the commands.  They all:
     * <ol>
     * <li>throw no exceptions, and therefore report their own error messages</li>
     * <li>take the values of the related command line options as method arguments (except for common options)</li>
     * <li>may utilize the services provided by those objects initialized in {@link setUp} and destroyed in {@link teardown}, and</li>
     * <li>call {@link setUp} and {@link teardown} before and after performing the command.</li>
     * </ol>
     */

    private void runImportCommand(final String kamName, final File pkamFile,
            final ExportFormat exportFormat,
            final boolean noPreserve) {

        if (exportFormat != ExportFormat.PORTABLE_KAM) {
            fatal(format(
                    "`%s --%s` only supports the portable KAM file format.",
                    kamManager, commandStr));
        }

        final String pkamPath = pkamFile.getAbsolutePath();
        try {
            setUp();

            // find KAM by name and see if validate preserve option
            if (kamName != null) {
                List<KamInfo> kamInfos = kAMStore.getCatalog();
                for (KamInfo kamInfo : kamInfos) {
                    if (kamName.equals(kamInfo.getName()) && !noPreserve) {
                        teardown();
                        fatal("KAM cannot be overridden, specify --"
                                + LONG_OPT_NO_PRESERVE + " to override");
                    }
                }
            }

            pkamService.deserializeKAM(kamName, pkamPath, noPreserve);
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (PKAMSerializationFailure e) {
            teardown();
            bailOnException(e);
        } catch (IllegalStateException e) {
            // FIXME Hack to catch noPreserve check error thrown from DefaultPKAMSerializationService
            teardown();
            fatal("KAM cannot be overridden, specify --" + LONG_OPT_NO_PRESERVE
                    + " to override");
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    private void runExportCommand(final String kamName, String outputFilename,
            final ExportFormat exportFormat,
            final boolean noPreserve) {
        if (kamName == null) {
            return;
        }
        final Kam kam;

        try {
            setUp();
            kam = kAMStore.getKam(kamName);

            // establish a default if output path is not set
            if (outputFilename == null) {
                outputFilename =
                        kam.getKamInfo().getName()
                                + defaultExtension(exportFormat);
            }

            if (!noPreserve && new File(outputFilename).exists()) {
                teardown();
                fatal("File '" + outputFilename + "' exists, specify --"
                        + LONG_OPT_NO_PRESERVE + " to override.");
            }

            final String formatString;
            if (exportFormat == ExportFormat.XGMML) {
                formatString = "XGMML";
                XGMMLExporter.exportKam(kam, kAMStore, outputFilename);
            } else if (exportFormat == ExportFormat.RDF) {
                formatString = "RDF";
                RDFExporter.exportRdf(kam, kAMStore.getKamInfo(kamName),
                        kAMStore, outputFilename);
            } else if (exportFormat == ExportFormat.PORTABLE_KAM) {
                formatString = "portable";
                pkamService.serializeKAM(kamName, outputFilename);
            } else {
                throw new UnsupportedOperationException(exportFormat.toString()
                        + " is not supported.");
            }

            if (!quiet) {
                reportable.output(format(
                        "Exported '%s' KAM to %s format in '%s'.",
                        kam.getKamInfo().getName(), formatString,
                        outputFilename));
            }
        } catch (PKAMSerializationFailure e) {
            reportable.error(e.getUserFacingMessage());
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } catch (InvalidArgument e) {
            teardown();
            bailOnException(e);
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    private static String defaultExtension(final ExportFormat type) {
        switch (type) {
        case PORTABLE_KAM:
            return KAM_EXTENSION;
        case XGMML:
            return XGMML_EXTENSION;
        case RDF:
            return N3_EXTENSION;
        }
        throw new UnsupportedOperationException(type.toString()
                + " is not supported.");
    }

    private void runSummarizeCommand(final String kamName,
            final String outputFilename, final boolean noPreserve) {

        KamSummaryXHTMLWriter xhtmlWriter = null;
        try {
            setUp();

            xhtmlWriter = createOutputFileWriter(outputFilename, noPreserve);
            Kam kam;
            if (kamName != null) {
                // Look up the requested KAM and summarize.
                kam = kAMStore.getKam(kamName);
                KamSummarizer summarizer = new KamSummarizer(reportable);
                KamSummary summary = KamSummarizer.summarizeKam(kAMStore, kam);
                summarizer.printKamSummary(kAMStore, summary);
                if (xhtmlWriter != null) {
                    xhtmlWriter.write(summary);
                }
            }
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } catch (InvalidArgument e) {
            teardown();
            bailOnException(e);
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
            if (xhtmlWriter != null) {
                try {
                    xhtmlWriter.close();
                } catch (IOException e) {
                    teardown();
                    bailOnException(e);
                }
            }
        }
    }

    private KamSummaryXHTMLWriter createOutputFileWriter(String outputFilename,
            final boolean noPreserve) throws IOException {
        FileWriter writer = null;
        KamSummaryXHTMLWriter xhtmlWriter = null;

        if (verbose || debug) {
            reportable.output("Creating output file: " + outputFilename);
        }
        if (!StringUtils.isBlank(outputFilename)) {
            File outputFile = new File(outputFilename);
            if (!outputFile.exists() || noPreserve) {
                writer = new FileWriter(outputFile);
                xhtmlWriter = new KamSummaryXHTMLWriter(writer);
                xhtmlWriter.open();
            } else {
                reportable
                        .warning(format(
                                "Output file already exist: %s, specify --%s option to overwrite.",
                                outputFilename, LONG_OPT_NO_PRESERVE));
            }
        }

        return xhtmlWriter;
    }

    private void runDeleteCommand(final String kamName) {
        try {
            setUp();

            KamInfo kamInfo = kAMStore.getKamInfo(kamName);
            if (kamInfo != null) {
                deleteKam(kamInfo, quiet);
            } else {
                reportable.warning("No KAM named '" + kamName
                        + "' exists in the catalog.");
            }
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    private void deleteKam(final KamInfo kamInfo, final boolean quiet)
            throws SQLException, IOException {
        final String kamName = kamInfo.getName();
        kamSchemaService.deleteFromKAMCatalog(kamName);
        final String schemaName = kamInfo.getSchemaName();
        boolean deletedSchema =
                kamSchemaService.deleteKAMStoreSchema(dbConnection, schemaName);
        if (deletedSchema && !quiet) {
            reportable.output("The KAM named '" + kamName
                    + "' has been removed.");
        } else if (!deletedSchema) {
            reportable
                    .warning("The KAM data was truncated, but the database schema '"
                            + schemaName
                            + "' still exists. The schema deletion must be handled separately in dba-managed configurations.");
        }
    }

    private void runListCommand() {
        try {
            setUp();

            final List<KamInfo> kamInfos = kAMStore.getCatalog();
            // Get a list of all the KAMs available in the KAM store
            reportable.output("Available KAMs:");
            reportable.output("\tName\tLast Compiled\tSchema Name");
            reportable.output("\t------\t-------------\t-----------");
            for (KamInfo kamInfo : kamInfos) {
                KamDbObject kamDb = kamInfo.getKamDbObject();
                reportable.output(format("\t%s\t%s\t%s",
                        kamDb.getName(), kamDb.getLastCompiled(),
                        kamDb.getSchemaName()));
            }
            reportable.output("\n");
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    private void runSetDescriptionCommand(final String kamName,
            final String newDescription) {
        try {
            setUp();

            final KamInfo kamInfo = kAMStore.getKamInfo(kamName);
            if (kamInfo != null) {
                if (!BELUtilities.equals(kamInfo.getDescription(),
                        newDescription)) {
                    final KamDbObject updated =
                            new KamDbObject(kamInfo.getId(), kamInfo.getName(),
                                    newDescription, kamInfo.getLastCompiled(),
                                    kamInfo.getSchemaName());
                    kamCatalogDao.saveToCatalog(updated);
                }
            } else {
                reportable.warning("No KAM named '" + kamName
                        + "' exists in the catalog.");
            }
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    private void runRenameCommand(final String oldKamName,
            final String newKamName, final boolean noPreserve) {
        if (BELUtilities.equals(oldKamName, newKamName)) {
            return;
        }

        try {
            setUp();

            final KamInfo kamInfo = kAMStore.getKamInfo(oldKamName);
            if (kamInfo != null) {
                final KamInfo kamInfo2 = kAMStore.getKamInfo(newKamName);
                if (kamInfo2 != null) {
                    if (noPreserve) {
                        deleteKam(kamInfo2, true);
                    } else {
                        teardown();
                        fatal(format(
                                "A KAM named '%s' already exists in the KAM store. Specify --%s to override.",
                                newKamName, LONG_OPT_NO_PRESERVE));
                    }
                }
                final KamDbObject updated =
                        new KamDbObject(kamInfo.getId(), newKamName,
                                kamInfo.getDescription(),
                                kamInfo.getLastCompiled(),
                                kamInfo.getSchemaName());
                kamCatalogDao.saveToCatalog(updated);
            } else {
                reportable.warning("No KAM named '" + oldKamName
                        + "' exists in the catalog.");
            }
        } catch (SQLException e) {
            teardown();
            bailOnException(e);
        } catch (KAMStoreException e) {
            teardown();
            bailOnException(e);
        } catch (IOException e) {
            teardown();
            bailOnException(e);
        } finally {
            teardown();
        }
    }

    /*
     * The following are utility methods used for usage and error messages:
     */

    private static String showCommandAliases() {
        final Command[] commands = Command.values();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < commands.length; ++i) {
            if (i != 0) {
                sb.append(", ");
                if (i == commands.length - 1) {
                    sb.append("or ");
                }
            }
            sb.append("`--");
            sb.append(commands[i].getAlias());
            sb.append("`");
        }
        return sb.toString();
    }

    private void bailOnException(final Exception e) {
        final Throwable cause = ExceptionUtils.getRootCause(e);
        reportable.error("Unable to run " + KAM_MANAGER_NAME);
        reportable.error("Reason: "
                + (cause == null ? e.getMessage() : cause.getMessage()));
        if (debug) {
            e.printStackTrace(reportable.errorStream());
        }
        bail(GENERAL_FAILURE);
    }

    /*
     * The following are overrides of {@link org.openbel.framework.clf.CommandLineApplication CommandLineApplication}'s methods:
     */

    @Override
    public String getApplicationName() {
        return KAM_MANAGER_NAME;
    }

    @Override
    public String getApplicationShortName() {
        return KAM_MANAGER_NAME;
    }

    @Override
    public String getApplicationDescription() {
        return KAM_MANAGER_DESC;
    }

    @Override
    public String getUsage() {
        final StringBuilder bldr = new StringBuilder();

        if (command == null || command == Command.HELP) {
            bldr.append(" {");
            final Command[] commands = Command.values();
            for (int i = 0; i < commands.length; ++i) {
                if (commands[i] != Command.HELP) {
                    if (i != 0) {
                        bldr.append(" | ");
                    }
                    bldr.append("--").append(commands[i].getAlias());
                }
            }
            bldr.append("}");

        } else {
            bldr.append(" --").append(commandStr);

            if (command == Command.IMPORT) {
                bldr.append(" <exported KAM file> [<new KAM name>]")
                        .append(USAGE_NO_PRESERVE)
                        .append(USAGE_PORTABLE_KAM_TYPE);
            } else if (command == Command.EXPORT) {
                bldr.append(" <KAM name> [<output file name>]")
                        .append(USAGE_NO_PRESERVE).append(USAGE_TYPE);
            } else if (command == Command.SUMMARIZE
                    || command == Command.DELETE) {
                bldr.append(" <KAM name>");
            } else if (command == Command.SET_DESCRIPTION) {
                bldr.append(" <KAM name> <new description>");
            } else if (command == Command.RENAME) {
                bldr.append(" <old KAM name> <new KAM name>").append(
                        USAGE_NO_PRESERVE);
            }
        }

        bldr.append(" [-h | --help] [-v | --verbose] [-q | --quiet] [--debug] [{-s | --system-config-file} <OpenBEL Framework configuration file>]");

        return bldr.toString();
    }

    private static EnumMap<Command, String> commandToUsageHelp =
            new EnumMap<Command, String>(Command.class);
    static {
        commandToUsageHelp.put(Command.DELETE,
                "Deletes a KAM from the KAM store.");
        commandToUsageHelp.put(Command.EXPORT, "Exports a KAM to a file.");
        commandToUsageHelp.put(Command.IMPORT,
                "Imports a KAM from a file to a KAM store.");
        commandToUsageHelp.put(Command.LIST, "Lists the KAMs in a KAM store.");
        commandToUsageHelp.put(Command.RENAME, "Changes the name of a KAM.");
        commandToUsageHelp.put(Command.SET_DESCRIPTION,
                "Changes the description of a KAM.");
        commandToUsageHelp.put(Command.SUMMARIZE,
                "Prints summary information for a KAM.");
    }

    @Override
    public List<Option> getCommandLineOptions() {
        List<Option> options = new LinkedList<Option>();

        // Add the long options that serve as the commands
        for (Command c : Command.values()) {
            if (c != Command.HELP) {
                options.add(new Option(null, c.getAlias(), false,
                        "The " + c.getAlias() + " command. "
                                + commandToUsageHelp.get(c)));
            }
        }

        // -f/--force/--no-preserve used for the import, export, and rename commands
        final String noPreserveHelp =
                "Optional.  Used with the summarize or export commands, if a file with the same name "
                        +
                        "as the output file already exists then it will be overwritten. "
                        +
                        "If used with the import command, if a KAM with the same name as "
                        +
                        "being imported already exists in the KAM store, it will be "
                        +
                        "overwritten.  If used with the rename command, if the new name for a KAM "
                        +
                        "is also the name of another KAM in the KAM store, then that KAM "
                        +
                        "will be overwritten.\n"
                        +
                        "The default is always to preserve the existing file or KAM and "
                        +
                        "generate a warning.";
        options.add(new Option("f", "force", false,
                "Identical to --no-preserve."));
        options.add(new Option(null, LONG_OPT_NO_PRESERVE, false,
                noPreserveHelp));

        // -o/--output-file used to set the file to output XHTML output (for the
        // summarize command, for example)
        final String outputFileHelp =
                "Optional.  If present, it indicates the name of the output file "
                        +
                        "to write the summary to.  The file will be written as XHTML.";
        options.add(new Option("o", "output-file", true, outputFileHelp));

        // -t/--type used for the import and export commands
        final String typeHelp =
                "With the import command, this option specifies the format of the imported KAM file. "
                        +
                        "By default, "
                        + getApplicationShortName()
                        + " infers the format of the KAM file by "
                        +
                        "its extension ("
                        + KAM_EXTENSION
                        + ", "
                        + XGMML_EXTENSION
                        + ", or "
                        + N3_EXTENSION
                        + ").\n"
                        +
                        "With the export command, this option specifies the type of export file to generate. "
                        +
                        "If XGMML the KAM will be exported in XGMML format.  If RDF "
                        +
                        "the KAM will be exported as an RDF using N3 format.  If KAM "
                        +
                        "is specified, the KAM will be exported in a portable binary "
                        +
                        "format that can be subsequently imported to another KAM store "
                        +
                        "using the "
                        + getApplicationShortName()
                        + " import command. The default is to export to " +
                        "a portable KAM format.";
        options.add(new Option("t", "type", true, typeHelp));

        // Add the options common to all commands:

        options.add(new Option(
                "q",
                "quiet",
                false,
                "Enables quiet mode. This mode outputs very little additional information "
                        +
                        "as the application runs.\n" +
                        "The default is to disable quiet mode."));

        final Option sOpt = new Option(SHRT_OPT_SYSCFG, LONG_OPT_SYSCFG, true,
                SYSTEM_CONFIG_PATH);
        sOpt.setArgName(ARG_SYSCFG);
        options.add(sOpt);

        // The base class CommandLineApplication will add the --debug, -h/--help,
        // and -v/--verbose options.

        return options;
    }

    /*
     * The following are the Command and ExportFormat enums:
     */

    private static enum Command {
        IMPORT("import"),
        EXPORT("export"),
        SUMMARIZE("summarize"),
        DELETE("delete"),
        LIST("list"),
        SET_DESCRIPTION("set-description"),
        RENAME("rename"),
        HELP("help");

        private static final Map<String, Command> aliasToCommand;
        static {
            aliasToCommand = constrainedHashMap(values().length);
            for (Command command : values()) {
                aliasToCommand.put(command.alias, command);
            }
        }

        private String alias;

        private Command(String alias) {
            this.alias = alias;
        }

        public String getAlias() {
            return alias;
        }
    }

    /**
     * ExportFormat represents the supported export formats.
     */
    public static enum ExportFormat {
        XGMML("xgmml", "XGMML"),
        RDF("rdf", "RDF"),
        PORTABLE_KAM("kam", "KAM");

        private static final Map<String, ExportFormat> STRINGTOENUM;
        static {
            STRINGTOENUM = constrainedHashMap(values().length);
            for (ExportFormat exportFormat : values()) {
                for (String label : exportFormat.labels) {
                    STRINGTOENUM.put(label, exportFormat);
                }
            }
        }

        private final String[] labels;

        private ExportFormat(final String... labels) {
            this.labels = labels;
        }

        @Override
        public String toString() {
            switch (this) {
            case XGMML:
                return "XGMML";
            case RDF:
                return "RDF";
            case PORTABLE_KAM:
                return "Portable KAM";
            default:
                throw new UnsupportedOperationException(
                        "ExportFormat." + name()
                                + ".toString() is not supported.");
            }
        }

        public static ExportFormat getFormatByLabel(final String label) {
            return STRINGTOENUM.get(label);
        }
    }
}
TOP

Related Classes of org.openbel.framework.tools.kamstore.KamManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.