All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enhydra.xml.xmlc.commands.options.OptionsParser Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: OptionsParser.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.commands.options;

import java.io.IOException;

import org.enhydra.xml.io.ErrorReporter;
import org.enhydra.xml.io.InputSourceOps;
import org.enhydra.xml.xmlc.XMLCException;
import org.enhydra.xml.xmlc.metadata.MetaData;
import org.enhydra.xml.xmlc.metadata.MetaDataDocument;
import org.xml.sax.InputSource;

// FIXME: The integration of metadata is not as smooth as it should be.
// probably need to be able to parse multiple metadata files and
// then merge them.  Also would be nice to not have this handle
// metadata at all, doing that with a derived class.

// FIXME: this whole approach to parsing options seems to be more complex
// necessary

/**
 * Parse XMLC options, including options files.
 */
public class OptionsParser {
    /*
     * Enabled debug tracing.
     */
    private static final boolean DEBUG = false;

     /*
      * Suffix for metadata and options files.
      */
    static final private String OPT_FILE_SUFFIX = ".xmlc";

    /*
     * Command line arguments and index to next argument.
     */
    private String[] fCommandArgs;
    private int fCommandArgIdx;

    /*
     * Options definition table.
     */
    private OptionSet fOptions;

    /*
     * Used to report errors parsing metadata file.
     */
    private ErrorReporter fErrorReporter;

    /*
     * Ordered list of metadata or options files from cmd line.
     */
    private InputSource[] fMetaDataOptionsFiles;

    /**
     * Track what kind of files we have parsed.
     */
    private boolean fParsedMetaData = false;
    private boolean fParsedOptionsFile = false;

    /**
     * Metadata object being constructed.
     */
    private MetaData fMetaData;

    /**
     * Positional arguments.
     */
    private String[] posArgs;

    /**
     * Check to see if we are at the end of the command line options.
     * Will skip the `--' end of line marker.
     */
    private boolean endOfCmdOptions() {
        if (fCommandArgIdx >= fCommandArgs.length) {
            return true;  // No more args
        }
        if (fCommandArgs[fCommandArgIdx].equals("--")) {
            // End of options marker.
            fCommandArgIdx++;
            return true;
        }
        if (!fCommandArgs[fCommandArgIdx].startsWith("-")) {
            return true;  // No more -options
        }
        return false;
    }

    /**
     * Generate error for invalid options.
     */
    private void invalidOptionError(String name,
                                    InputSource inputSource) throws XMLCException {
        StringBuffer msg = new StringBuffer();
        msg.append("Invalid option \"" + name + "\"");
        if (inputSource != null) { 
            msg.append(" in " + InputSourceOps.getName(inputSource));
        }
        msg.append(", valid options are:\n");
        msg.append(fOptions.getOptionsMsg());
        throw new XMLCException(msg.toString());
    }

    /**
     * Generate error about mixing metadata and options files.
     */
    private void mixedMetaDataOptionsFileError() throws XMLCException {
        throw new XMLCException("command line specifies both metadata and options files, which is not supported.");
    }

    /**
     * Parse a single command line option.
     */
    private void parseCmdOption(boolean parseArguments) throws XMLCException {
        if (DEBUG) {
            System.err.println("parseCmdOption: " + fCommandArgs[fCommandArgIdx]);
        }
        Option option = fOptions.findOption(fCommandArgs[fCommandArgIdx]);
        if (option == null) {
            invalidOptionError(fCommandArgs[fCommandArgIdx], null);
        }
        fCommandArgIdx++;
        int numArgs= option.getNumArgs();
        if (numArgs > (fCommandArgs.length-fCommandArgIdx)) {
            throw new XMLCException("Insufficient number of arguments for option \""
                                    + option.getName() + ": " + option.getHelp());
        }
        if (parseArguments) {
            String[] args = new String[numArgs];
            System.arraycopy(fCommandArgs, fCommandArgIdx, args, 0, numArgs);
            option.parse(args, fErrorReporter, fMetaData);
        }
        fCommandArgIdx += numArgs;
    }

    /**
     * Parse options.  A preparse can be done to find the positional
     * arguments or a full parse to get the option arguments. This is
     * needed to find the positional arguments.
     */
    private void parseOptions(boolean parseArguments) throws XMLCException {
        fCommandArgIdx = 0;
        while (!endOfCmdOptions()) {
            parseCmdOption(parseArguments);
        }
    }

    /**
     * Parse an options file line.
     */
    private void parseOptionsFileEntry(InputSource inputSource,
                                       String[] entry) 
            throws XMLCException {
        Option option = fOptions.findOption(entry[0]);
        if (option == null) {
            invalidOptionError(entry[0], inputSource);
        }
        int numArgs= option.getNumArgs();
        if (entry.length-1 != numArgs) {
            throw new XMLCException("wrong number of arguments for option \""
                                    + option.getName() 
                                    + " in " + InputSourceOps.getName(inputSource)
                                    + ": " + option.getHelp());
        }
        String[] args = new String[entry.length-1];
        System.arraycopy(entry, 1, args, 0, entry.length-1);
        option.parse(args, fErrorReporter, fMetaData);
    }

    /**
     * Parse an options file.
     */
    private void parseOptionsFile(InputSource inputSource)
        throws XMLCException {

        if (fParsedMetaData) {
            mixedMetaDataOptionsFileError();
        }
        fParsedOptionsFile = true;

        OptionFileParser parsedOpts = new OptionFileParser(inputSource);
        String[][] opts = parsedOpts.getOptions();

        for (int idx = 0; idx < opts.length; idx++) {
            parseOptionsFileEntry(inputSource, opts[idx]);
        }
    }

    /**
     * Parse a metadata file.
     */
    private void parseMetaDataFile(InputSource inputSource)
        throws XMLCException {

        if (fParsedOptionsFile) {
            mixedMetaDataOptionsFileError();
        }
        if (fParsedMetaData) {
            throw new XMLCException("Multiple XMLC metadata files specified, which is supported; use document with external entity references instead");
        }
        fParsedMetaData = true;
        MetaDataDocument metaDataDoc
            = MetaDataDocument.parseMetaData(inputSource, fErrorReporter,
                                             null);
        fMetaData = metaDataDoc.getMetaData();
    }

    /**
     * Parse a metadata or options file.
     */
    private void parseMetaDataOptionsFile(InputSource inputSource) 
        throws XMLCException {
        
        // Determine if its a metadata file. If it doesn't look like an
        // XML file, assume its an options file.
        try {
            if (InputSourceOps.isXMLDocument(inputSource)) {
                parseMetaDataFile(inputSource);
            } else {
                parseOptionsFile(inputSource);
            }
        } catch (IOException except) {
            throw new XMLCException("parse of " + inputSource + " failed",
                                    except);
        }
    }

    /**
     * Parse metadata or options files.
     */
    private void parseMetaDataOptionsFiles()
        throws XMLCException {
        // Parse backwards so first one overrides
        for (int idx = fMetaDataOptionsFiles.length-1; idx >= 0; idx--) {
            parseMetaDataOptionsFile(fMetaDataOptionsFiles[idx]);
        }
    }

    /**
     * Parse the positional arguments.
     */
    private void parsePositionalArgs() throws XMLCException {
        // Find *.xmlc metadata or options files.
        int idx;
        int mdCnt = 0;
        for (idx = fCommandArgIdx; 
             (idx < fCommandArgs.length) && fCommandArgs[idx].endsWith(OPT_FILE_SUFFIX);
             idx++) {
            mdCnt++;
        }
        fMetaDataOptionsFiles = new InputSource[mdCnt];
        idx = 0;
        while ((fCommandArgIdx < fCommandArgs.length) 
               && fCommandArgs[fCommandArgIdx].endsWith(OPT_FILE_SUFFIX)) {
            fMetaDataOptionsFiles[idx++] = new InputSource(fCommandArgs[fCommandArgIdx]);
            fCommandArgIdx++;
        }

        // Save the remaining positional arguments.
        int len = fCommandArgs.length-fCommandArgIdx;
        posArgs = new String[len];
        System.arraycopy(fCommandArgs, fCommandArgIdx, posArgs, 0, len);
    }

    /**
     * Constructor.
     *
     * @param optionsSet The set of options to parse, all value are stored in
     * this object.
     * @param errorReporter Use to reporrt metadata parse errors.
     */
    public OptionsParser(OptionSet options,
                         ErrorReporter errorReporter) {
        fOptions = options;
        fErrorReporter = errorReporter;
    }

    /**
     * Parse options.
     *
     * @param args The arguments.
     */
    public void parse(String[] args) throws XMLCException {
        fCommandArgs = args;
        fCommandArgIdx = 0;

        // Must parse once to find the positional arguments.
        parseOptions(false);
        parsePositionalArgs();

        // Create metaData object, if not already created.
        getMetaData();  // creates as side affect

        // Process the option or metadata files.
        parseMetaDataOptionsFiles();
 
        // Parse the command line for real, which will override options files.
        parseOptions(true);
        fMetaData.getDocument().completeModifications();
    }

    /**
     * Get the parsed options.
     */
    public OptionSet getOptions() {
        return fOptions;
    }

    /**
     * Get the metadata object, create if it doesn't exists.
     */
    public MetaData getMetaData() {
        if (fMetaData == null) {
            fMetaData = MetaDataDocument.newInstance().getMetaData();
        }
        return fMetaData;
    }

    /**
     * Get the positional arguments. Options files (.xmlc) will 
     * have been removed.
     */
    public String[] getPositionalArgs() {
        return posArgs;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy