Package bndtools.launcher

Source Code of bndtools.launcher.BundleInstaller$BundleOperationException

/*******************************************************************************
* Copyright (c) 2010 Neil Bartlett.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Neil Bartlett - initial API and implementation
******************************************************************************/
package bndtools.launcher;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.PackageAdmin;

class BundleInstaller implements Runnable {

  private static final String FILE_URI_PREFIX = "file:";

  private static final int NO_START = -1;
    private static final int START = 0;

  private final Logger log = Logger.getLogger("bndtools.launcher");

  private final File propsFile;
  private final BundleContext framework;
  private final Runnable errorCallback;

  private final Map<String, Bundle> locationsMap = new HashMap<String, Bundle>();
  private final Set<Long> startAttempted = new HashSet<Long>();
  private long propsLastUpdated = 0L;



  BundleInstaller(File propsFile, BundleContext framework, Runnable errorCallback) {
    this.propsFile = propsFile;
    this.framework = framework;
        this.errorCallback = errorCallback;

    init();
  }

  private void init() {
    // Get initial bundles
    Bundle[] allBundles = framework.getBundles();
    for (Bundle bundle : allBundles) {
      // Skip the system bundle
      String location = bundle.getLocation();
      if(bundle.getBundleId() != 0 && location != null && location.startsWith(FILE_URI_PREFIX)) {
        locationsMap.put(location, bundle);
      }
    }
    log.log(Level.INFO, "BundleInstaller detected {0} pre-installed bundles with \"file:\" locations.", locationsMap.size());
  }

  public void run() {
    log.info("Bundle installer thread starting...");

    // Enter the main loop
    try {
      while(!Thread.interrupted()) {
        synchronizeBundles();

        // Sleep until next cycle
        Thread.sleep(2000);
      }
    } catch (InterruptedException e) {
      // Allow thread to end
    }
    log.info("Bundle installer thread terminating.");
  }

  void synchronizeBundles() {
    long lastModified = propsFile.lastModified();

    Map<String, Integer> toInstall = new HashMap<String, Integer>();
    List<Bundle> toRemove = new LinkedList<Bundle>();
    int defaultStart = START;

    // Reread bundle list if it has changed;
    if(lastModified > propsLastUpdated) {
        log.fine("Launch properties file has changed");
        propsLastUpdated = lastModified;
      defaultStart = loadBundles(toInstall);

      // Find bundles to uninstall
      for (Iterator<Entry<String, Bundle>> iterator = locationsMap.entrySet().iterator(); iterator.hasNext(); ) {
        Entry<String, Bundle> entry = iterator.next();
        if(!toInstall.containsKey(entry.getKey())) {
          iterator.remove();
          toRemove.add(entry.getValue());
        }
      }

      // Find bundles to install
      for (Iterator<Entry<String, Integer>> iterator = toInstall.entrySet().iterator(); iterator.hasNext(); ) {
        Entry<String, Integer> entry = iterator.next();
        if(locationsMap.containsKey(entry.getKey())) {
          iterator.remove(); // Remaining paths are the new ones
        }
      }
    }

    // Perform the changes
    List<BundleOperationException> errors = new LinkedList<BundleOperationException>();
    performAllChanges(toInstall, toRemove, defaultStart, errors);

    // Report errors
    if(!errors.isEmpty()) {
      log.log(Level.SEVERE, "{0} ERROR(S) OCCURRED", errors.size());
      int i = 0;
      for (BundleOperationException error : errors) {
        String message = MessageFormat.format("{0} BUNDLE {1}: {2}", i++, error.getBundleLocation(), error.getMessage());
        log.log(Level.SEVERE, message, error.getCause());
      }

      if(errorCallback != null)
          errorCallback.run();
    }
  }

  int loadBundles(Map<String, Integer> toInstall) {
      int defaultStart = START;
    try {
      Properties props = new Properties();
      props.load(new FileInputStream(propsFile));

      // Read the default start option
            defaultStart = readStartOptionString(props.getProperty(LauncherConstants.PROP_DEFAULT_START_OPTIONS), START);

      // Add the run bundles
      String bundlesStr = props.getProperty(LauncherConstants.PROP_RUN_BUNDLES);
      if(bundlesStr != null) {
        String[] bundles = bundlesStr.split(",");
        for (String bundleSpec : bundles) {
          String trimmedSpec = bundleSpec.trim();
          if(trimmedSpec.length() > 0) {
              String[] options = trimmedSpec.split(";");
              String bundlePath = options[0];
            String location = FILE_URI_PREFIX + bundlePath;

            int startOption = defaultStart;
            for(int i = 1; i < options.length; i++) {
                if(options[i].startsWith("start=")) {
                    startOption = readStartOptionString(options[i].substring("start=".length()), defaultStart);
                }
            }

            toInstall.put(location, startOption);
          }
        }
      }
    } catch (IOException e) {
      log.log(Level.WARNING, "Error reading launcher properties file {0}.", propsFile.getAbsolutePath());
    }
    return defaultStart;
  }

  int readStartOptionString(String option, int defaultValue) {
      if(LauncherConstants.VALUE_NOSTART.equals(option))
          return NO_START;
        if(LauncherConstants.VALUE_START.equals(option))
            return START;
        if(LauncherConstants.VALUE_START_TRANSIENT.equals(option))
            return Bundle.START_TRANSIENT;
        if(LauncherConstants.VALUE_START_ACTIVATION_POLICY.equals(option))
            return Bundle.START_ACTIVATION_POLICY;
        if(LauncherConstants.VALUE_START_TRANSIENT_ACTIVATION_POLICY.equals(option))
            return Bundle.START_TRANSIENT & Bundle.START_ACTIVATION_POLICY;

        return defaultValue;
  }

  private static class BundleOperationException extends Exception {
    private static final long serialVersionUID = 1L;
    final String bundleLocation;

    public BundleOperationException(String bundleLocation, String message, Throwable cause) {
      super(message, cause);
      this.bundleLocation = bundleLocation;
    }
    public String getBundleLocation() {
      return bundleLocation;
    }
  }

  void performAllChanges(Map<String, Integer> toInstall, Collection<? extends Bundle> toRemove, int defaultStart, Collection<? super BundleOperationException> errors) {
    assert errors != null : "errors must not be null";

    // Uninstall
    if(toRemove != null)
      performUninstalls(toRemove, errors);

    // Updates
    performUpdates(errors);

    // Install
    if(toInstall != null) {
      performInstalls(toInstall.keySet(), errors);
    }

    // Resolve bundles
    ServiceReference pkgAdmRef = framework.getServiceReference(PackageAdmin.class.getName());
    if(pkgAdmRef != null) {
      PackageAdmin pkgAdm = (PackageAdmin) framework.getService(pkgAdmRef);
      if(pkgAdm != null) {
        try {
          pkgAdm.resolveBundles(null);
        } finally {
          framework.ungetService(pkgAdmRef);
        }
      }
    }

    // Start
    performStarts(defaultStart, toInstall, errors);
  }

  void performUninstalls(Collection<? extends Bundle> toRemove, Collection<? super BundleOperationException> errors) {
    assert toRemove != null : "toRemove must not be null";
    assert errors != null : "errors must not be null";
    for (Bundle bundle : toRemove) {
      try {
        if(bundle.getState() != Bundle.UNINSTALLED) {
          log.log(Level.FINE, "Uninstalling bundle {0}", bundle.getLocation());
          startAttempted.remove(bundle.getBundleId());
          bundle.uninstall();
        } else {
          errors.add(new BundleOperationException(bundle.getLocation(), "Bundle is already uninstalled", null));
        }
      } catch (BundleException e) {
        errors.add(new BundleOperationException(bundle.getLocation(), "Error uninstalling bundle", e));
      }
    }
  }

  void performUpdates(Collection<? super BundleOperationException> errors) {
    for(Iterator<Entry<String, Bundle>> iterator = locationsMap.entrySet().iterator(); iterator.hasNext(); ) {
      Entry<String, Bundle> entry = iterator.next();

      String location = entry.getKey();
      Bundle bundle = entry.getValue();

      File bundleFile;
      if(location.startsWith(FILE_URI_PREFIX)) {
        bundleFile = new File(location.substring(FILE_URI_PREFIX.length()));
      } else {
        bundleFile = new File(location);
      }

      if(!bundleFile.isFile() && !bundleFile.isDirectory()) {
        // Bundle file has been deleted => uninstall it
        try {
          log.log(Level.FINE, "Uninstalling bundle {0}.", bundle.getLocation());
          startAttempted.remove(bundle.getBundleId());
          bundle.uninstall();
        } catch (BundleException e) {
          errors.add(new BundleOperationException(bundle.getLocation(), "Error uninstalling bundle.", e));
        }
      } else {
        if(bundle.getLastModified() < bundleFile.lastModified()) {
          try {
            log.log(Level.FINE, "Updating bundle {0}.", bundle.getLocation());
            startAttempted.remove(bundle.getBundleId());
            bundle.update(new FileInputStream(bundleFile));
          } catch (FileNotFoundException e) {
            errors.add(new BundleOperationException(bundle.getLocation(), "Error updating bundle, its bundle file may have been deleted.", e));
          } catch (BundleException e) {
            errors.add(new BundleOperationException(bundle.getLocation(), "Error updating bundle.", e));
          }
        }
      }
    }
  }

  Collection<Bundle> performInstalls(Collection<? extends String> toInstall, Collection<? super BundleOperationException> errors) {
    assert toInstall != null : "toInstall must not be null";
    assert errors != null : "errors must not be null";

    Collection<Bundle> installed = new LinkedList<Bundle>();
    for (String location : toInstall) {
      Bundle bundle = null;

      // Install it
      try {
        log.log(Level.FINE, "Installing bundle {0}", location);
        bundle = framework.installBundle(location);
        startAttempted.remove(bundle.getBundleId());

        locationsMap.put(location, bundle);
        installed.add(bundle);
      } catch (BundleException e) {
        errors.add(new BundleOperationException(location, "Error installing bundle.", e));
      }
    }

    return installed;
  }

  void performStarts(int defaultStart, Map<String, Integer> startOptions, Collection<? super BundleOperationException> errors) {
    assert errors != null : "errors must not be null";
    for (Bundle bundle : locationsMap.values()) {
      // Don't keep trying to start a bundle that have already attempted to start
      if(startAttempted.contains(bundle.getBundleId()))
        continue;

      // Skip fragments
      if(bundle.getHeaders().get(org.osgi.framework.Constants.FRAGMENT_HOST) != null)
        continue;

      try {
          Integer startOptionObj = startOptions.get(bundle.getLocation());
          int startOption = startOptionObj != null
              ? startOptionObj.intValue()
              : defaultStart;

          if(startOption != -1) {
              log.log(Level.FINE, "Starting bundle {0}", bundle.getLocation());
              startAttempted.add(bundle.getBundleId());
              bundle.start(startOption);
          }
      } catch (BundleException e) {
        errors.add(new BundleOperationException(bundle.getLocation(), "Error starting bundle.", e));
      } catch (IllegalStateException e) {
          errors.add(new BundleOperationException(bundle.getLocation(), "Error starting bundle", e));
      }
    }
  }
}
TOP

Related Classes of bndtools.launcher.BundleInstaller$BundleOperationException

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.