Package org.knopflerfish.osgi.bundle.bundlerepository

Source Code of org.knopflerfish.osgi.bundle.bundlerepository.ObrCommandGroup$PrintWriterStream

/*
* 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.
*
* Original source: Richard S. Hall (heavy@ungoverned.org)
* KF Console API adaption: Erik Wistrand (wistrand@knopflerfish.org)
*
*/

package org.knopflerfish.osgi.bundle.bundlerepository;

import java.io.*;
import java.util.Dictionary;
import java.util.Hashtable;

import org.osgi.framework.*;
import org.ungoverned.osgi.service.bundlerepository.BundleRecord;
import org.ungoverned.osgi.service.bundlerepository.BundleRepositoryService;

import org.ungoverned.osgi.bundle.bundlerepository.Util;
import org.ungoverned.osgi.bundle.bundlerepository.FileUtil;

import org.knopflerfish.service.console.*;


/**
* Export the following OBR commands as a KF console command group "obr"
*
* <pre>
*  urls [<repository-file-url> ...]
*  list [<string> ...]
*  info <bundle-name>[;<version>] ...
*  deploy [-nodeps] <bundle-name>[;<version>] ... | <bundle-id> ...
*  install [-nodeps] <bundle-name>[;<version>] ...
*  start [-nodeps] <bundle-name>[;<version>] ...
*  update -check
*  update [-nodeps] <bundle-name>[;<version>] ... | <bundle-id> ...
*  source [-x] <local-dir> <bundle-name>[;<version>] ...
* </pre>
*/
public class ObrCommandGroup extends CommandGroupAdapter
{
  private   BundleContext           bc    = null;
  private   BundleRepositoryService brs   = null;
  protected ServiceRegistration     reg   = null;

  public ObrCommandGroup(BundleContext bc) {
    super("obr", "OBR commands");
    this.bc  = bc;

    ServiceReference sr = bc.getServiceReference(BundleRepositoryService.class.getName());

    this.brs = (BundleRepositoryService)bc.getService(sr);

    if(this.brs == null) {
      throw new RuntimeException("BundleRepositoryService must be available");
    }
  }

  public void register() {
    if(reg == null) {
      Hashtable props = new Hashtable();
      props.put("groupName", getGroupName());
      reg = bc.registerService(CommandGroup.class.getName(),
             this,
             props);
    }
  }

  void unregister() {
    if(reg != null) {
      reg.unregister();
      reg = null;
    }
  }

  public final static String USAGE_URLS = "[<url>] ...";
  public final static String [] HELP_URLS = new String [] {
    "List or set repository URLs",
    "<url> repository URL" };

  public int cmdUrls(Dictionary opts, Reader in, PrintWriter out, Session session) {
    String[] urls = (String[])opts.get("url");

    if(urls != null && urls.length > 0) {
      brs.setRepositoryURLs(urls);
    } else {
      urls = 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.");
      }
    }
    return 0;
  }

  public final static String USAGE_LIST = "[-l] [<name>]";
  public final static String [] HELP_LIST = new String [] {
    "List contents of repository",
    "-l   -  long format",
    "name -  name (or substring) for bundles to list",
    "        If no name is given, list all bundles.",
  };

  public int cmdList(Dictionary opts, Reader in, PrintWriter out, Session session) {
    String substr = (String)opts.get("name");
    boolean bLong = null != opts.get("-l");

    int nCount = 0;
    int count = brs.getBundleRecordCount();
    if(count == 0) {
      out.println("No bundles in repositories");
    } else {
      if(bLong) {
  out.println("No   Name                Update-location");
      } else {
  out.println("No   Name");
      }
      for (int i = 0; i < brs.getBundleRecordCount(); i++) {
  BundleRecord record = brs.getBundleRecord(i);
  String name = (String) record.getAttribute(BundleRecord.BUNDLE_NAME);
  if (name != null) {
    if ((substr == null) ||
        (name.toLowerCase().indexOf(substr) >= 0))  {
      nCount++;
      String version =
        (String) record.getAttribute(BundleRecord.BUNDLE_VERSION);
      boolean bCit = true; // name.indexOf(" ") != -1;


      StringBuffer sb = new StringBuffer();
      sb.append(" ");
      sb.append(Integer.toString(i + 1));
      pad(sb, 5);
      if(bCit) {
        sb.append("\"");
      }
      if (version != null) {
        sb.append(name + ";" + version);
      } else {
        sb.append(name);
      }
      if(bCit) {
        sb.append("\"");
      }
      if(bLong) {
        sb.append(" ");
        pad(sb, 25);
        sb.append(record.getAttribute(BundleRecord.BUNDLE_UPDATELOCATION));
      }
      out.println(sb.toString());
    }
  }
      }
    }

    if (nCount == 0)      {
      out.println("No matching bundles.");
    }
    return 0;
  }

  static StringBuffer pad(StringBuffer sb, int len) {
    while(sb.length() < len) {
      sb.append(" ");
    }
    return sb;
  }

  public final static String USAGE_INFO = "<name;version> ...";
  public final static String [] HELP_INFO = new String [] {
    "Show bundle info",
    "name - name (or substring) for bundles to list",
    "       if name is an integer, use bundle with",
    "       this index (from obr list)"};

  public int cmdInfo(Dictionary opts, Reader in, PrintWriter outPW, Session session) {
    String[] infos = (String[])opts.get("name;version");

    ParsedCommand pc = parseInfo(infos);
    for (int i = 0; (pc != null) && (i < pc.getTargetCount()); i++) {
      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 =
          brs.getBundleRecords(pc.getTargetName(i));

        if (records.length == 1) {
          record = records[0];
        } else {

        }
      } else {
        record =
          brs.getBundleRecord(pc.getTargetName(i),
                              new Version(pc.getTargetVersion(i)));
      }

      if (record != null) {
        PrintStream outStream = new PrintWriterStream(outPW);

        record.printAttributes(outStream);
      } else {
        outPW.println("Unknown bundle or ambiguous version: "
                      + pc.getTargetName(i));

        for (int j = 0; j < brs.getBundleRecordCount(); j++) {
          BundleRecord r2 = brs.getBundleRecord(j);
          String name    = (String) r2.getAttribute(BundleRecord.BUNDLE_NAME);
          String version = (String) r2.getAttribute(BundleRecord.BUNDLE_VERSION);
          if(name.equals(pc.getTargetName(i))) {
            outPW.println(" \"" + name + ";" + version + "\"");
          }
        }
      }
      outPW.println("");
    }
    return 0;
  }


  public final static String USAGE_DEPLOY = "[-nodeps] <name;version> ...";
  public final static String [] HELP_DEPLOY = new String [] {
    "Deploy bundle(s)",
    "name;version - name (and optional version)"
  };

  public int cmdDeploy(Dictionary opts, Reader in, PrintWriter outPW, Session session) {
    String[] infos = (String[])opts.get("name;version");

    ParsedCommand pc = parseInfo(infos);
    boolean bResolve = (null == opts.get("-nodeps"));

    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) {
  PrintStream outStream = new PrintWriterStream(outPW);

  brs.deployBundle(
         outStream, // Output stream.
         outStream, // Error stream.
         updateLocation, // Update location.
         bResolve, // Resolve dependencies.
         false); // Start.
      } else {
  outPW.println("Unknown bundle or ambiguous version: "
          + pc.getTargetName(i));
  return 1;
      }
    }
    return 0;
  }

  public final static String USAGE_INSTALL = "[-nodeps] <name;version> ...";
  public final static String [] HELP_INSTALL = new String [] {
    "Install bundle",
    "name;version - name and optional version.",
    "               If name starts with '=', use number from obr list",
};

  public int cmdInstall(Dictionary opts, Reader in, PrintWriter out, Session session) {
    return doInstallOrStart(opts, in, out, session, false);
  }

  public final static String USAGE_START = "[-nodeps] <name;version> ...";
  public final static String [] HELP_START = new String [] {
    "Install and start bundle",
    "name;version - name and optional version.",
    "               If name starts with =, use number from obr list",
};

  public int cmdStart(Dictionary opts, Reader in, PrintWriter out, Session session) {
    return doInstallOrStart(opts, in, out, session, true);
  }

  public int doInstallOrStart(Dictionary opts, Reader in, PrintWriter outPW, Session session, boolean bStart) {
    String[] infos = (String[])opts.get("name;version");

    ParsedCommand pc = parseInfo(infos);
    boolean bResolve = (null == opts.get("-nodeps"));


    // 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) {
      PrintStream outStream = new PrintWriterStream(outPW);

      brs.deployBundle(
             outStream, // Output stream.
             outStream, // Error stream.
             (String) record.getAttribute(BundleRecord.BUNDLE_UPDATELOCATION), // Update location.
             bResolve, // Resolve dependencies.
             bStart);
    } else {
      outPW.println("Not in repository: " + targetName);
      return 1;
    }
  } else  {
    outPW.println("Already installed: " + targetName);
  }
      }
    return 0;
  }

  public final static String USAGE_UPDATE = "[-nodeps] [-check] <name;version> ...";
  public final static String [] HELP_UPDATE = new String [] {
    "Update bundle",
    "name;version - name and optional version" };

  public int cmdUpdate(Dictionary opts, Reader in, PrintWriter outPW, Session session) throws IOException {
    String[] infos    = (String[])opts.get("name;version");
    boolean  bCheck   = (null == opts.get("-check"));
    boolean  bResolve = (null == opts.get("-nodeps"));

    ParsedCommand pc  = parseInfo(infos);
    PrintStream   out = new PrintWriterStream(outPW);

    if (bCheck) {
      updateCheck(out, out);
    } 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) {
      brs.deployBundle(
             out, // Output stream.
             out, // Error stream.
             (String) bundle.getHeaders().get(Constants.BUNDLE_UPDATELOCATION), // Local bundle to update.
             bResolve, // Resolve dependencies.
             false); // Start.
    } else {
      outPW.println("Not installed: " + targetName);
    }
  }
    }
    return 0;
  }

  private void updateCheck(PrintStream out, PrintStream err)
    throws IOException
  {
    Bundle[] bundles = bc.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 = 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;
                }
              }
            }
          }
      }
  }

  /*
  public final static String USAGE_SOURCE = "[-x] <localDir> <name;version> ...";
  public final static String [] HELP_SOURCE = new String [] {
    "Get source for a bundle",
    "name;version - name and optional version" };

  public int cmdSource(Dictionary opts, Reader in, PrintWriter outPW, Session session) {
    String[] infos   = (String[])opts.get("name;version");
    String localDir  = (String)opts.get("localDir");
    boolean bExtract = opts.get("-x") != null;

    if(localDir == null) {
      localDir = ".";
    }

    ParsedCommand pc = parseInfo(infos);

    PrintStream out = new PrintWriterStream(outPW);

    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,
            out,
            srcURL,
            localDir,
            bExtract);
    } else {
      outPW.println("Missing source URL: " + pc.getTargetName(i));
      return 1;
    }
  } else {
    outPW.println("Not in repository: " + pc.getTargetName(i));
    return 1;
  }
      }
    return 0;
  }
  */

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

    if(name.startsWith("=")) {
      int id = -1;
      try {
        id = Integer.parseInt(name.substring(1));
        record = brs.getBundleRecord(id - 1);
        if(record != null) {
          System.out.println(id + " " + record.getAttribute(BundleRecord.BUNDLE_UPDATELOCATION));
          return record;
        }
      } catch (Exception ignored) {
      }
    }

    // If there is no version, then try to retrieve by
    // name, but error if there are multiple versions.
    if (versionString == null) {
      BundleRecord[] records =
        brs.getBundleRecords(name);
      if (records.length == 1) {
        record = records[0];
      }
    } else {
      record = 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 = bc.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 = bc.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;
  }


  ParsedCommand parseInfo(String[] infos) {
    ParsedCommand pc = new ParsedCommand();
    for(int i = 0; infos != null && i < infos.length; i++) {
      String name    = infos[i];
      String version = null;
      int ix = infos[i].indexOf(";");
      if(ix != -1) {
  name    = infos[i].substring(0, ix);
  version = infos[i].substring(ix + 1);
      }
      pc.addTarget(name, version);
    }

    return pc;
  }

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

    private String[][] m_targets = new String[0][];

    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;
    }
  }

  /**
   * Wrap a PrintWriter into a PrintStream by overriding all methods.
   */
  public static class PrintWriterStream extends PrintStream {
    PrintWriter pw;
    boolean     bClose = false;

    /**
     * @param pw underlying writer to which all data is send to
     * @param bClose if <tt>true</tt> close the underlying writer
     *               when <tt>PrintWriterStream.close()</tt> is called.
     */
    public PrintWriterStream(PrintWriter pw, boolean bClose) {
      super(new ByteArrayOutputStream()); // This is really a dummy stream
      this.pw     = pw;
      this.bClose = bClose;
    }

    /**
     * Same as <tt>PrintWriterStream(pw, false)</tt>
     */
    public PrintWriterStream(PrintWriter pw) {
      this(pw, false);
    }

    /**
     * Only closes the underlying stream if
     * constructued with the close flag.
     */
    public void close() {
      super.close();
      if(bClose) {
  pw.close();
      }
    }

    /**
     * Write using the trivial, but possibly not always correct translation:
     * <pre>
     *  write((int) byte)
     * </pre>
     */
    public void write(byte[] buf, int off, int len) {
      for(int i = off; i < off + len; i++) {
  write((int)buf[i]);
      }
    }

    public void write(int b) {
      pw.write(b);
    }

    public boolean checkError() {
      return pw.checkError();
    }

    public void flush() {
      pw.flush();
    }

    public void print(boolean b) {
      pw.print(b);
    }

    public void print(char c) {
      pw.print(c);
    }

    public void print(char[] s) {
      pw.print(s);
    }

    public void print(double d) {
      pw.print(d);
    }

    public void print(float f) {
      pw.print(f);
    }

    public void print(int i) {
      pw.print(i);
    }

    public void print(long l) {
      pw.print(l);
    }

    public void print(Object obj) {
      pw.print(obj);
    }

    public void print(String s) {
      pw.print(s);
    }

    public void println() {
      pw.println();
    }

    public void println(boolean x) {
      pw.println(x);
    }

    public void println(char x) {
      pw.println(x);
    }

    public void println(char[] x) {
      pw.println(x);
    }

    public void println(double x) {
      pw.println(x);
    }

    public void println(float x) {
      pw.println(x);
    }

    public void println(int x) {
      pw.println(x);
    }

    public void println(long x) {
      pw.println(x);
    }

    public void println(Object x) {
      pw.println(x);
    }

    public void println(String x) {
      pw.println(x);
    }
  }

}
TOP

Related Classes of org.knopflerfish.osgi.bundle.bundlerepository.ObrCommandGroup$PrintWriterStream

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.