Package org.ungoverned.osgi.bundle.bundlerepository

Source Code of org.ungoverned.osgi.bundle.bundlerepository.ObrCommandImpl$ParsedCommand

/*
* Oscar Bundle Repository
* Copyright (c) 2004, Richard S. Hall
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the
*     distribution.
*   * Neither the name of the ungoverned.org nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contact: Richard S. Hall (heavy@ungoverned.org)
* Contributor(s):
*
**/
package org.ungoverned.osgi.bundle.bundlerepository;

import java.io.*;
import java.util.StringTokenizer;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.Version;
import org.ungoverned.osgi.service.bundlerepository.BundleRecord;
import org.ungoverned.osgi.service.bundlerepository.BundleRepositoryService;
import org.ungoverned.osgi.service.shell.Command;

public class ObrCommandImpl implements Command
{
    private static final String HELP_CMD = "help";
    private static final String URLS_CMD = "urls";
    private static final String LIST_CMD = "list";
    private static final String INFO_CMD = "info";
    private static final String DEPLOY_CMD = "deploy";
    private static final String INSTALL_CMD = "install";
    private static final String START_CMD = "start";
    private static final String UPDATE_CMD = "update";
    private static final String SOURCE_CMD = "source";

    private static final String NODEPS_SWITCH = "-nodeps";
    private static final String CHECK_SWITCH = "-check";
    private static final String EXTRACT_SWITCH = "-x";

    private BundleContext m_context = null;
    private BundleRepositoryService m_brs = null;

    public ObrCommandImpl(BundleContext context, BundleRepositoryService brs)
    {
        m_context = context;
        m_brs = brs;
    }

    public String getName()
    {
        return "obr";
    }

    public String getUsage()
    {
        return "obr help";
    }

    public String getShortDescription()
    {
        return "Oscar bundle repository.";
    }

    public synchronized void execute(String commandLine, PrintStream out, PrintStream err)
    {
        try
        {
            // Parse the commandLine to get the OBR command.
            StringTokenizer st = new StringTokenizer(commandLine);
            // Ignore the invoking command.
            st.nextToken();
            // Try to get the OBR command, default is HELP command.
            String command = HELP_CMD;
            try
            {
                command = st.nextToken();
            }
            catch (Exception ex)
            {
                // Ignore.
            }

            // Perform the specified command.
            if ((command == null) || (command.equals(HELP_CMD)))
            {
                help(out, st);
            }
            else
            {
                if (command.equals(URLS_CMD))
                {
                    urls(commandLine, command, out, err);
                }
                else if (command.equals(LIST_CMD))
                {
                    list(commandLine, command, out, err);
                }
                else if (command.equals(INFO_CMD))
                {
                    info(commandLine, command, out, err);
                }
                else if (command.equals(DEPLOY_CMD))
                {
                    deploy(commandLine, command, out, err);
                }
                else if (command.equals(INSTALL_CMD) || command.equals(START_CMD))
                {
                    install(commandLine, command, out, err);
                }
                else if (command.equals(UPDATE_CMD))
                {
                    update(commandLine, command, out, err);
                }
                else if (command.equals(SOURCE_CMD))
                {
                    source(commandLine, command, out, err);
                }
                else
                {
                    err.println("Unknown command: " + command);
                }
            }
        }
        catch (InvalidSyntaxException ex)
        {
            err.println("Syntax error: " + ex.getMessage());
        }
        catch (IOException ex)
        {
            err.println("Error: " + ex);
        }
    }

    private void urls(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException
    {
        // Parse the commandLine.
        StringTokenizer st = new StringTokenizer(commandLine);
        // Ignore the "obr" command.
        st.nextToken();
        // Ignore the "urls" command.
        st.nextToken();

        int count = st.countTokens();
        String[] urls = new String[count];
        for (int i = 0; i < count; i++)
        {
            urls[i] = st.nextToken();
        }

        if (count > 0)
        {
            m_brs.setRepositoryURLs(urls);
        }
        else
        {
            urls = m_brs.getRepositoryURLs();
            if (urls != null)
            {
                for (int i = 0; i < urls.length; i++)
                {
                    out.println(urls[i]);
                }
            }
            else
            {
                out.println("No repository URLs are set.");
            }
        }
    }

    private void list(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException
    {
        // Create a stream tokenizer for the command line string,
        // since the syntax for install/start is more sophisticated.
        StringReader sr = new StringReader(commandLine);
        StreamTokenizer tokenizer = new StreamTokenizer(sr);
        tokenizer.resetSyntax();
        tokenizer.quoteChar('\'');
        tokenizer.quoteChar('\"');
        tokenizer.whitespaceChars('\u0000', '\u0020');
        tokenizer.wordChars('A', 'Z');
        tokenizer.wordChars('a', 'z');
        tokenizer.wordChars('0', '9');
        tokenizer.wordChars('\u00A0', '\u00FF');
        tokenizer.wordChars('.', '.');
        tokenizer.wordChars('-', '-');
        tokenizer.wordChars('_', '_');


        // Ignore the invoking command name and the OBR command.
        int type = tokenizer.nextToken();
        type = tokenizer.nextToken();

        String substr = null;

        for (type = tokenizer.nextToken();
            type != StreamTokenizer.TT_EOF;
            type = tokenizer.nextToken())
        {
            // Add a space in between tokens.
            if (substr == null)
            {
                substr = "";
            }
            else
            {
                substr += " ";
            }

            if ((type == StreamTokenizer.TT_WORD) ||
                (type == '\'') || (type == '"'))
            {
                substr += tokenizer.sval.toLowerCase();
            }
        }

        boolean printed = false;
        for (int i = 0; i < m_brs.getBundleRecordCount(); i++)
        {
            BundleRecord record = m_brs.getBundleRecord(i);
            String name = (String) record.getAttribute(BundleRecord.BUNDLE_NAME);
            if (name != null)
            {
                if ((substr == null) ||
                    (name.toLowerCase().indexOf(substr) >= 0))
                {
                    if (!printed)
                    {
                        printed = true;
                        out.println("");
                    }
                    String version =
                        (String) record.getAttribute(BundleRecord.BUNDLE_VERSION);
                    if (version != null)
                    {
                        out.println(name + " (" + version + ")");
                    }
                    else
                    {
                        out.println(name);
                    }
                }
            }
        }

        if (printed)
        {
            out.println("");
        }
        else
        {
            out.println("No matching bundles.");
        }
    }

    private void info(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException, InvalidSyntaxException
    {
      ParsedCommand pc = parseInfo(commandLine);
      for (int i = 0; (pc != null) && (i < pc.getTargetCount()); i++) {
        out.println("");

        BundleRecord record = null;

        // If there is no version, then try to retrieve by
        // name, but error if there are multiple versions.
        if (pc.getTargetVersion(i) == null) {
          BundleRecord[] records =
            m_brs.getBundleRecords(pc.getTargetName(i));

          if (records.length == 1) {
            record = records[0];
          }
        } else {
          record = m_brs.getBundleRecord(
                                         pc.getTargetName(i),
                                         new Version(pc.getTargetVersion(i)));
        }

        if (record != null) {
          record.printAttributes(out);
        } else {
          err.println("Unknown bundle or amiguous version: "
                      + pc.getTargetName(i));
        }
      }
      out.println("");
    }

    private void deploy(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException, InvalidSyntaxException
    {
        ParsedCommand pc = parseInstallStart(commandLine);
        for (int i = 0; (pc != null) && (i < pc.getTargetCount()); i++)
        {
            // Find either the local bundle or the bundle
            // record so we can get the update location attribute.
            String updateLocation = null;

            // First look for update location locally.
            Bundle bundle =
                findLocalBundle(pc.getTargetName(i), pc.getTargetVersion(i));
            if (bundle != null)
            {
                updateLocation = (String)
                    bundle.getHeaders().get(Constants.BUNDLE_UPDATELOCATION);
            }

            // If update location wasn't found locally, look in repository.
            if (updateLocation == null)
            {
                BundleRecord record =
                    findBundleRecord(pc.getTargetName(i), pc.getTargetVersion(i));
                if (record != null)
                {
                    updateLocation = (String)
                        record.getAttribute(BundleRecord.BUNDLE_UPDATELOCATION);
                }
            }

            if (updateLocation != null)
            {
                m_brs.deployBundle(
                    out, // Output stream.
                    err, // Error stream.
                    updateLocation, // Update location.
                    pc.isResolve(), // Resolve dependencies.
                    false); // Start.
            }
            else
            {
                err.println("Unknown bundle or amiguous version: "
                    + pc.getTargetName(i));
            }
        }
    }

    private void install(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException, InvalidSyntaxException
    {
        // Parse the command line to get all local targets to install.
        ParsedCommand pc = parseInstallStart(commandLine);

        // Loop through each local target and try to find
        // the corresponding bundle record from the repository.
        for (int targetIdx = 0;
            (pc != null) && (targetIdx < pc.getTargetCount());
            targetIdx++)
        {
            // Get the current target's name and version.
            String targetName = pc.getTargetName(targetIdx);
            String targetVersionString = pc.getTargetVersion(targetIdx);

            // Make sure the bundle is not already installed.
            Bundle bundle = findLocalBundle(targetName, targetVersionString);
            if (bundle == null)
            {
                // Find the targets bundle record.
                BundleRecord record = findBundleRecord(targetName, targetVersionString);

                // If we found a record, try to install it.
                if (record != null)
                {
                    m_brs.deployBundle(
                        out, // Output stream.
                        err, // Error stream.
                        (String) record.getAttribute(BundleRecord.BUNDLE_UPDATELOCATION), // Update location.
                        pc.isResolve(), // Resolve dependencies.
                        command.equals(START_CMD)); // Start.
                }
                else
                {
                    err.println("Not in repository: " + targetName);
                }
            }
            else
            {
                err.println("Already installed: " + targetName);
            }
        }
    }

    private void update(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException, InvalidSyntaxException
    {
        // Parse the command line to get all local targets to update.
        ParsedCommand pc = parseUpdate(commandLine);

        if (pc.isCheck())
        {
            updateCheck(out, err);
        }
        else
        {
            // Loop through each local target and try to find
            // the corresponding locally installed bundle.
            for (int targetIdx = 0;
                (pc != null) && (targetIdx < pc.getTargetCount());
                targetIdx++)
            {
                // Get the current target's name and version.
                String targetName = pc.getTargetName(targetIdx);
                String targetVersionString = pc.getTargetVersion(targetIdx);

                // Find corresponding locally installed bundle.
                Bundle bundle = findLocalBundle(targetName, targetVersionString);

                // If we found a locally installed bundle, then
                // try to update it.
                if (bundle != null)
                {
                    m_brs.deployBundle(
                        out, // Output stream.
                        err, // Error stream.
                        (String) bundle.getHeaders().get(Constants.BUNDLE_UPDATELOCATION), // Local bundle to update.
                        pc.isResolve(), // Resolve dependencies.
                        false); // Start.
                }
                else
                {
                    err.println("Not installed: " + targetName);
                }
            }
        }
    }

    private void updateCheck(PrintStream out, PrintStream err)
        throws IOException
    {
      Bundle[] bundles = m_context.getBundles();

      // Loop through each local target and try to find
      // the corresponding locally installed bundle.
      for (int bundleIdx = 0;
           (bundles != null) && (bundleIdx < bundles.length);
           bundleIdx++) {
        // Ignore the system bundle.
        if (bundles[bundleIdx].getBundleId() == 0) {
          continue;
        }

        // Get the local bundle's update location.
        String localLoc = (String)
          bundles[bundleIdx].getHeaders().get(Constants.BUNDLE_UPDATELOCATION);
        if (localLoc == null) {
          // Without an update location, there is no way to
          // check for an update, so ignore the bundle.
          continue;
        }

        // Get the local bundle's version.
        Version localVersion = bundles[bundleIdx].getVersion();

        // Get the matching repository bundle records.
        BundleRecord[] records = m_brs.getBundleRecords((String) bundles[bundleIdx].getHeaders().get(Constants.BUNDLE_NAME));

        // Loop through all records to see if there is an update.
        for (int recordIdx = 0;
             (records != null) && (recordIdx < records.length);
             recordIdx++) {
          String remoteLoc = (String)
            records[recordIdx].getAttribute(BundleRecord.BUNDLE_UPDATELOCATION);
          if (remoteLoc == null) {
            continue;
          }

          // If the update locations are equal, then compare versions.
          if (remoteLoc.equals(localLoc)) {
            String remoteVersionS = (String)
              records[recordIdx].getAttribute(BundleRecord.BUNDLE_VERSION);
            if (remoteVersionS != null) {
              Version remoteVersion = new Version(remoteVersionS);
              int result = remoteVersion.compareTo(localVersion);
              if (result > 0) {
                out.println(records[recordIdx].getAttribute(BundleRecord.BUNDLE_NAME)
                            + " update available.");
                break;
              }
            }
          }
        }
      }
    }

    private void source(
        String commandLine, String command, PrintStream out, PrintStream err)
        throws IOException, InvalidSyntaxException
    {
        // Parse the command line to get all local targets to update.
        ParsedCommand pc = parseSource(commandLine);

        for (int i = 0; i < pc.getTargetCount(); i++)
        {
            BundleRecord record = findBundleRecord(
                pc.getTargetName(i), pc.getTargetVersion(i));
            if (record != null)
            {
                String srcURL = (String)
                    record.getAttribute(BundleRecord.BUNDLE_SOURCEURL);
                if (srcURL != null)
                {
                    FileUtil.downloadSource(
                        out, err, srcURL, pc.getDirectory(), pc.isExtract());
                }
                else
                {
                    err.println("Missing source URL: " + pc.getTargetName(i));
                }
            }
            else
            {
                err.println("Not in repository: " + pc.getTargetName(i));
            }
        }
    }

    private BundleRecord findBundleRecord(String name, String versionString)
    {
      BundleRecord record = null;

      // If there is no version, then try to retrieve by
      // name, but error if there are multiple versions.
      if (versionString == null) {
        BundleRecord[] records =
          m_brs.getBundleRecords(name);
        if (records.length == 1) {
          record = records[0];
        }
      } else {
        record = m_brs.getBundleRecord(name, new Version(versionString));
      }

      return record;
    }

    private Bundle findLocalBundle(String name, String versionString)
    {
      Bundle bundle = null;

      // Get the name only if there is no version, but error
      // if there are multiple matches for the same name.
      if (versionString == null) {
        // Perhaps the target name is a bundle ID and
        // not a name, so try to interpret as a long.
        try {
          bundle = m_context.getBundle(Long.parseLong(name));
        } catch (NumberFormatException ex) {
          // The bundle is not a number, so look for a local
          // bundle with the same name.
          Bundle[] matchingBundles = findLocalBundlesByName(name);

          // If only one matches, then select is.
          if (matchingBundles.length == 1)
            {
              bundle = matchingBundles[0];
            }
        }
      } else {
        // Find the local bundle by name and version.
        bundle = findLocalBundleByVersion(name, new Version(versionString));
      }

      return bundle;
    }

    private Bundle findLocalBundleByVersion(String name, Version version)
    {
      // Get bundles with matching name.
      Bundle[] targets = findLocalBundlesByName(name);

      // Find bundle with matching version.
      if (targets.length > 0) {
        for (int i = 0; i < targets.length; i++) {
          String targetName = (String)
            targets[i].getHeaders().get(BundleRecord.BUNDLE_NAME);
          Version targetVersion = targets[i].getVersion();

          if ((targetName != null) && targetName.equalsIgnoreCase(name) &&
              0==targetVersion.compareTo(version)) {
            return targets[i];
          }
        }
      }

      return null;
    }

    private Bundle[] findLocalBundlesByName(String name)
    {
        // Get local bundles.
        Bundle[] bundles = m_context.getBundles();

        // Find bundles with matching name.
        Bundle[] targets = new Bundle[0];
        for (int i = 0; i < bundles.length; i++)
        {
            String targetName = (String)
                bundles[i].getHeaders().get(BundleRecord.BUNDLE_NAME);
            if (targetName == null)
            {
                targetName = bundles[i].getLocation();
            }
            if ((targetName != null) && targetName.equalsIgnoreCase(name))
            {
                Bundle[] newTargets = new Bundle[targets.length + 1];
                System.arraycopy(targets, 0, newTargets, 0, targets.length);
                newTargets[targets.length] = bundles[i];
                targets = newTargets;
            }
        }

        return targets;
    }

    private ParsedCommand parseInfo(String commandLine)
        throws IOException, InvalidSyntaxException
    {
        // Create a stream tokenizer for the command line string,
        // since the syntax for install/start is more sophisticated.
        StringReader sr = new StringReader(commandLine);
        StreamTokenizer tokenizer = new StreamTokenizer(sr);
        tokenizer.resetSyntax();
        tokenizer.quoteChar('\'');
        tokenizer.quoteChar('\"');
        tokenizer.whitespaceChars('\u0000', '\u0020');
        tokenizer.wordChars('A', 'Z');
        tokenizer.wordChars('a', 'z');
        tokenizer.wordChars('0', '9');
        tokenizer.wordChars('\u00A0', '\u00FF');
        tokenizer.wordChars('.', '.');
        tokenizer.wordChars('-', '-');
        tokenizer.wordChars('_', '_');

        // Ignore the invoking command name and the OBR command.
        int type = tokenizer.nextToken();
        type = tokenizer.nextToken();

        int EOF = 1;
        int SWITCH = 2;
        int TARGET = 4;
        int VERSION = 8;
        int VERSION_VALUE = 16;

        // Construct an install record.
        ParsedCommand pc = new ParsedCommand();
        String currentTargetName = null;

        // The state machine starts by expecting either a
        // SWITCH or a TARGET.
        int expecting = (TARGET);
        while (true)
        {
            // Get the next token type.
            type = tokenizer.nextToken();
            switch (type)
            {
                // EOF received.
                case StreamTokenizer.TT_EOF:
                    // Error if we weren't expecting EOF.
                    if ((expecting & EOF) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Expecting more arguments.", null);
                    }
                    // Add current target if there is one.
                    if (currentTargetName != null)
                    {
                        pc.addTarget(currentTargetName, null);
                    }
                    // Return cleanly.
                    return pc;

                // WORD or quoted WORD received.
                case StreamTokenizer.TT_WORD:
                case '\'':
                case '\"':
                    // If we are expecting a target, the record it.
                    if ((expecting & TARGET) > 0)
                    {
                        // Add current target if there is one.
                        if (currentTargetName != null)
                        {
                            pc.addTarget(currentTargetName, null);
                        }
                        // Set the new target as the current target.
                        currentTargetName = tokenizer.sval;
                        expecting = (EOF | TARGET | VERSION);
                    }
                    else if ((expecting & VERSION_VALUE) > 0)
                    {
                        pc.addTarget(currentTargetName, tokenizer.sval);
                        currentTargetName = null;
                        expecting = (EOF | TARGET);
                    }
                    else
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting '" + tokenizer.sval + "'.", null);
                    }
                    break;

                // Version separator character received.
                case ';':
                    // Error if we weren't expecting the version separator.
                    if ((expecting & VERSION) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting version.", null);
                    }
                    // Otherwise, we will only expect a version value next.
                    expecting = (VERSION_VALUE);
                    break;
            }
        }
    }

    private ParsedCommand parseInstallStart(String commandLine)
        throws IOException, InvalidSyntaxException
    {
        // Create a stream tokenizer for the command line string,
        // since the syntax for install/start is more sophisticated.
        StringReader sr = new StringReader(commandLine);
        StreamTokenizer tokenizer = new StreamTokenizer(sr);
        tokenizer.resetSyntax();
        tokenizer.quoteChar('\'');
        tokenizer.quoteChar('\"');
        tokenizer.whitespaceChars('\u0000', '\u0020');
        tokenizer.wordChars('A', 'Z');
        tokenizer.wordChars('a', 'z');
        tokenizer.wordChars('0', '9');
        tokenizer.wordChars('\u00A0', '\u00FF');
        tokenizer.wordChars('.', '.');
        tokenizer.wordChars('-', '-');
        tokenizer.wordChars('_', '_');

        // Ignore the invoking command name and the OBR command.
        int type = tokenizer.nextToken();
        type = tokenizer.nextToken();

        int EOF = 1;
        int SWITCH = 2;
        int TARGET = 4;
        int VERSION = 8;
        int VERSION_VALUE = 16;

        // Construct an install record.
        ParsedCommand pc = new ParsedCommand();
        String currentTargetName = null;

        // The state machine starts by expecting either a
        // SWITCH or a TARGET.
        int expecting = (SWITCH | TARGET);
        while (true)
        {
            // Get the next token type.
            type = tokenizer.nextToken();
            switch (type)
            {
                // EOF received.
                case StreamTokenizer.TT_EOF:
                    // Error if we weren't expecting EOF.
                    if ((expecting & EOF) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Expecting more arguments.", null);
                    }
                    // Add current target if there is one.
                    if (currentTargetName != null)
                    {
                        pc.addTarget(currentTargetName, null);
                    }
                    // Return cleanly.
                    return pc;

                // WORD or quoted WORD received.
                case StreamTokenizer.TT_WORD:
                case '\'':
                case '\"':
                    // If we are expecting a command SWITCH and the token
                    // equals a command SWITCH, then record it.
                    if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(NODEPS_SWITCH))
                    {
                        pc.setResolve(false);
                        expecting = (EOF | TARGET);
                    }
                    // If we are expecting a target, the record it.
                    else if ((expecting & TARGET) > 0)
                    {
                        // Add current target if there is one.
                        if (currentTargetName != null)
                        {
                            pc.addTarget(currentTargetName, null);
                        }
                        // Set the new target as the current target.
                        currentTargetName = tokenizer.sval;
                        expecting = (EOF | TARGET | VERSION);
                    }
                    else if ((expecting & VERSION_VALUE) > 0)
                    {
                        pc.addTarget(currentTargetName, tokenizer.sval);
                        currentTargetName = null;
                        expecting = (EOF | TARGET);
                    }
                    else
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting '" + tokenizer.sval + "'.", null);
                    }
                    break;

                // Version separator character received.
                case ';':
                    // Error if we weren't expecting the version separator.
                    if ((expecting & VERSION) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting version.", null);
                    }
                    // Otherwise, we will only expect a version value next.
                    expecting = (VERSION_VALUE);
                    break;
            }
        }
    }

    private ParsedCommand parseUpdate(String commandLine)
        throws IOException, InvalidSyntaxException
    {
        // Create a stream tokenizer for the command line string,
        // since the syntax for install/start is more sophisticated.
        StringReader sr = new StringReader(commandLine);
        StreamTokenizer tokenizer = new StreamTokenizer(sr);
        tokenizer.resetSyntax();
        tokenizer.quoteChar('\'');
        tokenizer.quoteChar('\"');
        tokenizer.whitespaceChars('\u0000', '\u0020');
        tokenizer.wordChars('A', 'Z');
        tokenizer.wordChars('a', 'z');
        tokenizer.wordChars('0', '9');
        tokenizer.wordChars('\u00A0', '\u00FF');
        tokenizer.wordChars('.', '.');
        tokenizer.wordChars('-', '-');
        tokenizer.wordChars('_', '_');

        // Ignore the invoking command name and the OBR command.
        int type = tokenizer.nextToken();
        type = tokenizer.nextToken();

        int EOF = 1;
        int SWITCH = 2;
        int TARGET = 4;
        int VERSION = 8;
        int VERSION_VALUE = 16;

        // Construct an install record.
        ParsedCommand pc = new ParsedCommand();
        String currentTargetName = null;

        // The state machine starts by expecting either a
        // SWITCH or a TARGET.
        int expecting = (SWITCH | TARGET);
        while (true)
        {
            // Get the next token type.
            type = tokenizer.nextToken();
            switch (type)
            {
                // EOF received.
                case StreamTokenizer.TT_EOF:
                    // Error if we weren't expecting EOF.
                    if ((expecting & EOF) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Expecting more arguments.", null);
                    }
                    // Add current target if there is one.
                    if (currentTargetName != null)
                    {
                        pc.addTarget(currentTargetName, null);
                    }
                    // Return cleanly.
                    return pc;

                // WORD or quoted WORD received.
                case StreamTokenizer.TT_WORD:
                case '\'':
                case '\"':
                    // If we are expecting a command SWITCH and the token
                    // equals a NODEPS switch, then record it.
                    if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(NODEPS_SWITCH))
                    {
                        pc.setResolve(false);
                        expecting = (EOF | TARGET);
                    }
                    // If we are expecting a command SWITCH and the token
                    // equals a CHECK swithc, then record it.
                    else if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(CHECK_SWITCH))
                    {
                        pc.setCheck(true);
                        expecting = (EOF);
                    }
                    // If we are expecting a target, the record it.
                    else if ((expecting & TARGET) > 0)
                    {
                        // Add current target if there is one.
                        if (currentTargetName != null)
                        {
                            pc.addTarget(currentTargetName, null);
                        }
                        // Set the new target as the current target.
                        currentTargetName = tokenizer.sval;
                        expecting = (EOF | TARGET | VERSION);
                    }
                    else if ((expecting & VERSION_VALUE) > 0)
                    {
                        pc.addTarget(currentTargetName, tokenizer.sval);
                        currentTargetName = null;
                        expecting = (EOF | TARGET);
                    }
                    else
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting '" + tokenizer.sval + "'.", null);
                    }
                    break;

                // Version separator character received.
                case ';':
                    // Error if we weren't expecting the version separator.
                    if ((expecting & VERSION) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting version.", null);
                    }
                    // Otherwise, we will only expect a version value next.
                    expecting = (VERSION_VALUE);
                    break;
            }
        }
    }

    private ParsedCommand parseSource(String commandLine)
        throws IOException, InvalidSyntaxException
    {
        // Create a stream tokenizer for the command line string,
        // since the syntax for install/start is more sophisticated.
        StringReader sr = new StringReader(commandLine);
        StreamTokenizer tokenizer = new StreamTokenizer(sr);
        tokenizer.resetSyntax();
        tokenizer.quoteChar('\'');
        tokenizer.quoteChar('\"');
        tokenizer.whitespaceChars('\u0000', '\u0020');
        tokenizer.wordChars('A', 'Z');
        tokenizer.wordChars('a', 'z');
        tokenizer.wordChars('0', '9');
        tokenizer.wordChars('\u00A0', '\u00FF');
        tokenizer.wordChars('.', '.');
        tokenizer.wordChars('-', '-');
        tokenizer.wordChars('_', '_');
        tokenizer.wordChars('/', '/');

        // Ignore the invoking command name and the OBR command.
        int type = tokenizer.nextToken();
        type = tokenizer.nextToken();

        int EOF = 1;
        int SWITCH = 2;
        int DIRECTORY = 4;
        int TARGET = 8;
        int VERSION = 16;
        int VERSION_VALUE = 32;

        // Construct an install record.
        ParsedCommand pc = new ParsedCommand();
        String currentTargetName = null;

        // The state machine starts by expecting either a
        // SWITCH or a DIRECTORY.
        int expecting = (SWITCH | DIRECTORY);
        while (true)
        {
            // Get the next token type.
            type = tokenizer.nextToken();
            switch (type)
            {
                // EOF received.
                case StreamTokenizer.TT_EOF:
                    // Error if we weren't expecting EOF.
                    if ((expecting & EOF) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Expecting more arguments.", null);
                    }
                    // Add current target if there is one.
                    if (currentTargetName != null)
                    {
                        pc.addTarget(currentTargetName, null);
                    }
                    // Return cleanly.
                    return pc;

                // WORD or quoted WORD received.
                case StreamTokenizer.TT_WORD:
                case '\'':
                case '\"':
                    // If we are expecting a command SWITCH and the token
                    // equals a command SWITCH, then record it.
                    if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(EXTRACT_SWITCH))
                    {
                        pc.setExtract(true);
                        expecting = (DIRECTORY);
                    }
                    // If we are expecting a directory, the record it.
                    else if ((expecting & DIRECTORY) > 0)
                    {
                        // Set the directory for the command.
                        pc.setDirectory(tokenizer.sval);
                        expecting = (TARGET);
                    }
                    // If we are expecting a target, the record it.
                    else if ((expecting & TARGET) > 0)
                    {
                        // Add current target if there is one.
                        if (currentTargetName != null)
                        {
                            pc.addTarget(currentTargetName, null);
                        }
                        // Set the new target as the current target.
                        currentTargetName = tokenizer.sval;
                        expecting = (EOF | TARGET | VERSION);
                    }
                    else if ((expecting & VERSION_VALUE) > 0)
                    {
                        pc.addTarget(currentTargetName, tokenizer.sval);
                        currentTargetName = null;
                        expecting = (EOF | TARGET);
                    }
                    else
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting '" + tokenizer.sval + "'.", null);
                    }
                    break;

                // Version separator character received.
                case ';':
                    // Error if we weren't expecting the version separator.
                    if ((expecting & VERSION) == 0)
                    {
                        throw new InvalidSyntaxException(
                            "Not expecting version.", null);
                    }
                    // Otherwise, we will only expect a version value next.
                    expecting = (VERSION_VALUE);
                    break;
            }
        }
    }

    private void help(PrintStream out, StringTokenizer st)
    {
        String command = HELP_CMD;
        if (st.hasMoreTokens())
        {
            command = st.nextToken();
        }
        if (command.equals(URLS_CMD))
        {
            out.println("");
            out.println("obr " + URLS_CMD + " [<repository-file-url> ...]");
            out.println("");
            out.println(
                "This command gets or sets the URLs to the repository files\n" +                "used by OBR. Specify no arguments to get the current repository\n" +
                "URLs or specify a space-delimited list of URLs to change the\n" +
                "URLs. Each URL should point to a file containing meta-data about\n" +                "available bundles in XML format.");
            out.println("");
        }
        else if (command.equals(LIST_CMD))
        {
            out.println("");
            out.println("obr " + LIST_CMD + " [<string> ...]");
            out.println("");
            out.println(
                "This command lists bundles available in the bundle repository.\n" +
                "If no arguments are specified, then all available bundles are\n" +
                "listed, otherwise any arguments are concatenated with spaces\n" +
                "and used as a substring filter on the bundle names.");
            out.println("");
        }
        else if (command.equals(INFO_CMD))
        {
            out.println("");
            out.println("obr " + INFO_CMD
                + " <bundle-name>[;<version>] ...");
            out.println("");
            out.println(
                "This command displays the meta-data for the specified bundles.\n" +
                "If a bundle's name contains spaces, then it must be surrounded\n" +
                "by quotes. It is also possible to specify a precise version\n" +
                "if more than one version exists, such as:\n" +
                "\n" +
                "    obr info \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "The above example retrieves the meta-data for version \"1.0.0\"\n" +
                "of the bundle named \"Bundle Repository\".");
            out.println("");
        }
        else if (command.equals(DEPLOY_CMD))
        {
            out.println("");
            out.println("obr " + DEPLOY_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ... | <bundle-id> ...");
            out.println("");
            out.println(
                "This command tries to install or update the specified bundles\n" +
                "and all of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch\n" +
                "to ignore dependencies. You can specify either the bundle name or\n" +
                "the bundle identifier. If a bundle's name contains spaces, then\n" +
                "it must be surrounded by quotes. It is also possible to specify a\n" +                "precise version if more than one version exists, such as:\n" +
                "\n" +
                "    obr deploy \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "For the above example, if version \"1.0.0\" of \"Bundle Repository\" is\n" +
                "already installed locally, then the command will attempt to update it\n" +
                "and all of its dependencies; otherwise, the command will install it\n" +
                "and all of its dependencies.");
            out.println("");
        }
        else if (command.equals(INSTALL_CMD))
        {
            out.println("");
            out.println("obr " + INSTALL_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ...");
            out.println("");
            out.println(
                "This command installs the specified bundles and all of their\n" +
                "dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch to ignore\n" +
                "dependencies. If a bundle's name contains spaces, then it\n" +
                "must be surrounded by quotes. If a specified bundle is already\n" +                "installed, then this command has no effect. It is also possible\n" +                "to specify a precise version if more than one version exists,\n" +                "such as:\n" +
                "\n" +
                "    obr install \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "The above example installs version \"1.0.0\" of the bundle\n" +
                "named \"Bundle Repository\" and its dependencies. ");
            out.println("");
        }
        else if (command.equals(START_CMD))
        {
            out.println("");
            out.println("obr " + START_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ...");
            out.println("");
            out.println(
                "This command installs and starts the specified bundles and all\n" +
                "of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch to\n" +
                "ignore dependencies. If a bundle's name contains spaces, then\n" +
                "it must be surrounded by quotes. If a specified bundle is already\n" +                "installed, then this command has no effect. It is also possible\n" +                "to specify a precise version if more than one version exists,\n" +                "such as:\n" +
                "\n" +
                "    obr start \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "The above example installs and starts version \"1.0.0\" of the\n" +
                "bundle named \"Bundle Repository\" and its dependencies.");
            out.println("");
        }
        else if (command.equals(UPDATE_CMD))
        {
            out.println("");
            out.println("obr " + UPDATE_CMD + " " + CHECK_SWITCH);
            out.println("");
            out.println("obr " + UPDATE_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ... | <bundle-id> ...");
            out.println("");
            out.println(
                "The first form of the command above checks for available updates\n" +                "and the second updates the specified locally installed bundles\n" +
                "and all of their dependencies by default; use the \"" + NODEPS_SWITCH + "\" switch\n" +
                "to ignore dependencies. You can specify either the bundle name or\n" +
                "the bundle identifier. If a bundle's name contains spaces, then\n" +
                "it must be surrounded by quotes. If a specified bundle is not\n" +                "already installed, then this command has no effect. It is also\n" +                "possible to specify a precise version if more than one version\n" +                "exists, such as:\n" +
                "\n" +
                "    obr update \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "The above example updates version \"1.0.0\" of the bundle named\n" +
                "\"Bundle Repository\" and its dependencies. The update command may\n" +
                "install new bundles if the updated bundles have new dependencies.");
            out.println("");
        }
        else if (command.equals(SOURCE_CMD))
        {
            out.println("");
            out.println("obr " + SOURCE_CMD
                + " [" + EXTRACT_SWITCH
                + "] <local-dir> <bundle-name>[;<version>] ...");
            out.println("");
            out.println(
                "This command retrieves the source archives of the specified\n" +
                "bundles and saves them to the specified local directory; use\n" +
                "the \"" + EXTRACT_SWITCH + "\" switch to automatically extract the source archives.\n" +
                "If a bundle name contains spaces, then it must be surrounded\n" +
                "by quotes. It is also possible to specify a precise version if\n" +                "more than one version exists, such as:\n" +
                "\n" +
                "    obr source /home/rickhall/tmp \"Bundle Repository\";1.0.0\n" +
                "\n" +
                "The above example retrieves the source archive of version \"1.0.0\"\n" +
                "of the bundle named \"Bundle Repository\" and saves it to the\n" +
                "specified local directory.");
            out.println("");
        }
        else
        {
            out.println("obr " + HELP_CMD
                + " [" + URLS_CMD + " | " + LIST_CMD
                + " | " + INFO_CMD + " | " + INSTALL_CMD
                + " | " + DEPLOY_CMD + " | " + START_CMD
                + " | " + UPDATE_CMD + " | " + SOURCE_CMD + "]");
            out.println("obr " + URLS_CMD + " [<repository-file-url> ...]");
            out.println("obr " + LIST_CMD + " [<string> ...]");
            out.println("obr " + INFO_CMD
                + " <bundle-name>[;<version>] ...");
            out.println("obr " + DEPLOY_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ... | <bundle-id> ...");
            out.println("obr " + INSTALL_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ...");
            out.println("obr " + START_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ...");
            out.println("obr " + UPDATE_CMD + " " + CHECK_SWITCH);
            out.println("obr " + UPDATE_CMD
                + " [" + NODEPS_SWITCH
                + "] <bundle-name>[;<version>] ... | <bundle-id> ...");
            out.println("obr " + SOURCE_CMD
                + " [" + EXTRACT_SWITCH
                + "] <local-dir> <bundle-name>[;<version>] ...");
        }
    }

    private static class ParsedCommand
    {
        private static final int NAME_IDX = 0;
        private static final int VERSION_IDX = 1;

        private boolean m_isResolve = true;
        private boolean m_isCheck = false;
        private boolean m_isExtract = false;
        private String m_dir = null;
        private String[][] m_targets = new String[0][];

        public boolean isResolve()
        {
            return m_isResolve;
        }

        public void setResolve(boolean b)
        {
            m_isResolve = b;
        }

        public boolean isCheck()
        {
            return m_isCheck;
        }

        public void setCheck(boolean b)
        {
            m_isCheck = b;
        }

        public boolean isExtract()
        {
            return m_isExtract;
        }

        public void setExtract(boolean b)
        {
            m_isExtract = b;
        }

        public String getDirectory()
        {
            return m_dir;
        }

        public void setDirectory(String s)
        {
            m_dir = s;
        }

        public int getTargetCount()
        {
            return m_targets.length;
        }

        public String getTargetName(int i)
        {
            if ((i < 0) || (i >= getTargetCount()))
            {
                return null;
            }
            return m_targets[i][NAME_IDX];
        }

        public String getTargetVersion(int i)
        {
            if ((i < 0) || (i >= getTargetCount()))
            {
                return null;
            }
            return m_targets[i][VERSION_IDX];
        }

        public void addTarget(String name, String version)
        {
            String[][] newTargets = new String[m_targets.length + 1][];
            System.arraycopy(m_targets, 0, newTargets, 0, m_targets.length);
            newTargets[m_targets.length] = new String[] { name, version };
            m_targets = newTargets;
        }
    }
}
TOP

Related Classes of org.ungoverned.osgi.bundle.bundlerepository.ObrCommandImpl$ParsedCommand

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.