Package com.instantiations.eclipse.shared.installer.operations

Source Code of com.instantiations.eclipse.shared.installer.operations.ScanUnlinkedInstallsOperation$ScanFailedException

package com.instantiations.eclipse.shared.installer.operations;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

import org.eclipse.core.runtime.IStatus;

import com.instantiations.eclipse.shared.installer.BaseProductInstaller;
import com.instantiations.installer.core.InstallOptions;
import com.instantiations.installer.core.model.Context;
import com.instantiations.installer.core.model.InstallOperation;
import com.instantiations.installer.core.model.Installer;
import com.instantiations.installer.internal.core.InstallLog;
import com.instantiations.installer.internal.core.InstallLogEntry;

/**
* Search the specified directory for installations that are not currently linked to any
* Eclipse installation, and place that information into the install options.
* <p>
* Copyright (c) 2006, Instantiations, Inc.<br>
* All Rights Reserved
*
* @author Dan Rubel
*/
public class ScanUnlinkedInstallsOperation extends InstallOperation
{
  public static final String OPTION_UNLINKED_INSTALL_DIRS = "unlinkedInstallDirs";
  private final File rootDir;

  /**
   * Construct a new instance to find unlinked installations
   *
   * @param rootDir the root directory from which to scan
   */
  public ScanUnlinkedInstallsOperation(File rootDir) {
    this.rootDir = rootDir;
  }

  /**
   * Search for unlinked installations
   */
  protected IStatus run(Context installer) {
    InstallOptions options = installer.getOptions();
    if (options.isVerbose())
      System.out.println("Scanning for unlinked installations");
    Collection result = new TreeSet();
    try {
      findUnlinkedDirs(rootDir, installer.getOptions(), result);
    }
    catch (ScanFailedException e) {
      System.out.println("Abort scan for unlinked installations because exception occurred");
      e.printStackTrace();
      result.clear();
    }
    StringBuffer buf = new StringBuffer(result.size() * 40);
    for (Iterator iter = result.iterator(); iter.hasNext();) {
      File installDir = (File) iter.next();
      if (buf.length() > 0)
        buf.append(",");
      buf.append(installDir.getPath());
    }
    options.set(OPTION_UNLINKED_INSTALL_DIRS, buf.toString());
    return super.run(installer);
  }

  public String toString() {
    return "Scanning for unlinked installations...";
  }

  // //////////////////////////////////////////////////////////////////////////
  //
  // Internal
  //
  // //////////////////////////////////////////////////////////////////////////

  /**
   * Find unlinked installation directories that have the specified parent
   *
   * @param dir the directory to scan
   * @param result a collection into which unlinked directories are placed.
   */
  private static void findUnlinkedDirs(File dir, InstallOptions options, Collection result)
    throws ScanFailedException
  {
    if (dir == null || !dir.isDirectory())
      return;
    dir = dir.getAbsoluteFile();
    File[] children = dir.listFiles();
    boolean verbose = options.isVerbose();

    // [author=Dan] Apparently there is an issue with Java 5 reuse of file handles
    // and performing an explicit garbage collect here seems to prevent intermittent
    // "java.io.IOException: The handle is invalid." exceptions that occur when
    // reading existing log files. For more detail, see:
    // http://issues.apache.org/jira/browse/LUCENE-669
    System.gc();

    // Build a list of all Eclipse installations
    Collection eclipseDirs = new HashSet(20);
    if (verbose)
      System.out.println("Scanning " + children.length + " product installations...");
    for (int i = 0; i < children.length; i++) {
      File child = children[i];
      if (verbose)
        System.out.println("  " + child.getPath());
      findEclipseDirs(child, eclipseDirs);
    }
    String[] eclipsePaths = options.getStrings(BaseProductInstaller.OPTION_ALL_ECLIPSES_PATH_LIST);
    if (verbose)
      System.out.println("Including " + eclipsePaths.length
        + " previously identified Eclipse installations in scan");
    for (int i = 0; i < eclipsePaths.length; i++) {
      String eachPath = eclipsePaths[i];
      if (verbose)
        System.out.println("  " + eachPath);
      eclipseDirs.add(new File(eachPath));
    }
    eclipsePaths = options.getStrings(InstallOptions.OPTION_ECLIPSE_PATH_LIST);
    if (verbose)
      System.out.println("Including " + eclipsePaths.length
        + " previously selected Eclipse installations in scan");
    for (int i = 0; i < eclipsePaths.length; i++) {
      String eachPath = eclipsePaths[i];
      if (verbose)
        System.out.println("  " + eachPath);
      eclipseDirs.add(new File(eachPath));
    }
    if (eclipseDirs.size() == 0)
      throw new ScanFailedException("Failed to find any Eclipse installations to scan for links", null);

    // Build a list of linked installation directories
    if (verbose)
      System.out.println("Scanning " + eclipseDirs.size() + " Eclipse installations...");
    Collection linkedInstallDirs = new HashSet(20);
    for (Iterator iter = eclipseDirs.iterator(); iter.hasNext();) {
      File eclipseDir = (File) iter.next();
      if (verbose)
        System.out.println("  " + eclipseDir.getPath());
      findLinkedInstallDirs(eclipseDir, linkedInstallDirs);
    }

    // Determine which install directories are not linked
    for (int i = 0; i < children.length; i++) {
      File child = children[i];
      if (isUnlinkedInstallDir(child, linkedInstallDirs))
        result.add(child);
    }
  }

  /**
   * Read the "install.log" file for the specified product installation to locate
   * Eclipse installations
   *
   * @param installDir the product installation directory
   * @param result a collection into which Eclipse installation directories are placed.
   */
  private static void findEclipseDirs(File installDir, Collection result) throws ScanFailedException {
    InstallLog log = readLog(installDir);
    if (log == null)
      return;

    // Extract Eclipse installations from the log file

    File eclipseDir;
    for (Iterator iter = log.getEntries().iterator(); iter.hasNext();) {
      InstallLogEntry entry = (InstallLogEntry) iter.next();
      switch (entry.getOperationCode()) {

        case InstallLog.LINK_CREATED_ENTRY :
          int tokenIndex = entry.getArgument().indexOf(InstallLogEntry.LINK_ENTRY_TOKEN);
          if (tokenIndex == -1)
            break;
          File linkFile = new File(entry.getArgument().substring(0, tokenIndex));
          File linksDir = linkFile.getParentFile();
          if (linksDir == null)
            break;
          eclipseDir = linksDir.getParentFile();
          if (eclipseDir == null || !eclipseDir.isDirectory())
            break;
          result.add(eclipseDir.getAbsoluteFile());
          break;

        case InstallLog.ECLIPSE_CONFIG_CLEANED_ENTRY :
          eclipseDir = new File(entry.getArgument());
          if (!eclipseDir.isDirectory())
            break;
          result.add(eclipseDir.getAbsoluteFile());
          break;
      }
    }
  }

  /**
   * Read the log file
   *
   * @param installDir the installation directory containing the log file
   * @return the install log or <code>null</code> if it does not exist or could not be
   *         read
   */
  private static InstallLog readLog(File installDir) throws ScanFailedException {
    // Open the log file

    File logFile = new File(installDir, "install.log");
    if (!logFile.exists())
      return null;
    BufferedReader reader;
    try {
      reader = new BufferedReader(new FileReader(logFile));
    }
    catch (FileNotFoundException e) {
      throw new ScanFailedException("Failed to open log file: " + logFile.getPath(), e);
    }

    // Read the log file

    InstallLog log = new InstallLog();
    try {
      log.read(reader);
    }
    catch (IOException e) {
      throw new ScanFailedException("IOException reading log file: " + logFile.getPath(), e);
    }
    finally {
      try {
        reader.close();
      }
      catch (IOException e) {
        System.out.println("Failed to close log file reader: " + logFile.getPath());
        e.printStackTrace();
      }
    }
    return log;
  }

  /**
   * Scan the "dropins" and "links" directory of the specified installation directory and add all
   * linked install directories to the result collection.
   *
   * @param eclipseDir the Eclipse directory (not <code>null</code>)
   * @param result the collection to which linked install directories are added
   */
  private static void findLinkedInstallDirs(File eclipseDir, Collection result) throws ScanFailedException {
    findLinkedInstallDirs0(new File(eclipseDir, "dropins"), result);
    findLinkedInstallDirs0(new File(eclipseDir, "links"), result);
  }

  private static void findLinkedInstallDirs0(File linksDir, Collection result) throws ScanFailedException {
    if (!linksDir.isDirectory())
      return;
    File[] children = linksDir.listFiles();
    for (int i = 0; i < children.length; i++) {
      File child = children[i];
      if (!child.isFile() || !child.getName().endsWith(".link"))
        continue;
      LineNumberReader reader;
      try {
        reader = new LineNumberReader(new BufferedReader(new FileReader(child)));
      }
      catch (FileNotFoundException e) {
        throw new ScanFailedException("Failed to open link file: " + child.getPath(), e);
      }
      String line;
      try {
        line = reader.readLine();
      }
      catch (IOException e) {
        throw new ScanFailedException("Failed to read link file: " + child.getPath(), e);
      }
      finally {
        try {
          reader.close();
        }
        catch (IOException e) {
          System.out.println("Failed to close link file: " + child.getPath());
          e.printStackTrace();
        }
      }
      if (line == null || !line.startsWith("path="))
        continue;
      File installDir = new File(line.substring(5));
      if (installDir.getName().startsWith("E-"))
        installDir = installDir.getParentFile();
      result.add(installDir);
    }
  }

  /**
   * Determine if the specified installation directory is indeed unlinked
   *
   * @param installDir the installation directory
   * @param linkedInstallDirs the linked installation directories
   * @return <code>true</code> if installDir is unlinked
   */
  private static boolean isUnlinkedInstallDir(File installDir, Collection linkedInstallDirs)
    throws ScanFailedException
  {
    if (installDir == null || !installDir.isDirectory() || linkedInstallDirs.contains(installDir))
      return false;

    // Check for the existing of some known file or directory
    // so that random non-product-install directories are not included in the result

    boolean logFound = false;
    boolean uninstallerFound = false;
    File[] children = installDir.listFiles();
    for (int i = 0; i < children.length; i++) {
      File child = children[i];
      String childName = child.getName();
      if (child.isDirectory()) {
        if (childName.length() == 5 && childName.startsWith("E-"))
          return true;
        if (childName.equals("eclipse")) {

          // Ignore standalone products
          if (new File(child, ".eclipseproduct").exists())
            return false;
          File[] grandChildren = child.listFiles();
          for (int j = 0; j < grandChildren.length; j++) {
            File grandChild = grandChildren[j];
            if (grandChild.getName().endsWith(".exe"))
              return false;
          }

          return true;
        }
      }
      else {

        // Ignore standalone products
        if (childName.equals(".eclipseproduct"))
          return false;
        if (childName.endsWith(".exe"))
          return false;

        if (childName.equals("install.log"))
          logFound = true;
        if (childName.equals("uninstall.jar"))
          uninstallerFound = true;
      }
    }
    if (!logFound || !uninstallerFound)
      return uninstallerFound;

    // If a log was found, but no "eclipse" or "E-#.#" subdirectories
    // then check to see if this is a umbrella install such as WindowTesterPro
    // by checking if any of its subproducts are linked

    InstallLog log = readLog(installDir);
    if (log == null)
      return false;
    for (Iterator iter = log.getEntries().iterator(); iter.hasNext();) {
      InstallLogEntry entry = (InstallLogEntry) iter.next();
      switch (entry.getOperationCode()) {
        case InstallLog.LINK_CREATED_ENTRY :
          int tokenIndex = entry.getArgument().indexOf(InstallLogEntry.LINK_ENTRY_TOKEN);
          if (tokenIndex == -1)
            break;
          File subInstallDir = new File(entry.getArgument().substring(tokenIndex + 1));
          if (subInstallDir.getName().startsWith("E-"))
            subInstallDir = subInstallDir.getParentFile();
          String subInstallName = subInstallDir.getName();
          if (subInstallName.startsWith("Shared_v") || subInstallName.startsWith("CodeProCore_v"))
            break;
          if (linkedInstallDirs.contains(subInstallDir))
            return false;
          break;
      }
    }
    return true;
  }

  // //////////////////////////////////////////////////////////////////////////
  //
  // Internal classes
  //
  // //////////////////////////////////////////////////////////////////////////

  /**
   * Exception used internally to wrapper an IOException and indicate that the scan
   * should not proceed.
   */
  private static final class ScanFailedException extends Exception
  {
    private final Throwable cause;

    public ScanFailedException(String message, Throwable cause) {
      super(message);
      this.cause = cause;
    }

    public void printStackTrace() {
      super.printStackTrace();
      if (cause != null) {
        System.err.println("--- Nested Exception ---");
        cause.printStackTrace();
      }
    }
  }

  // //////////////////////////////////////////////////////////////////////////
  //
  // Main method to generate a list of local unlinked installations for testing purposes
  //
  // //////////////////////////////////////////////////////////////////////////

  /**
   * Test to scan the Instantiations directory for unlinked directories
   */
  public static void main(String[] args) {
    InstallOptions options = new InstallOptions();
    options.setVerbose(true);
    Installer installer = new Installer(options) {
      protected Class getRequiredAdapterType() {
        return null;
      }
    };
   
    File rootDir = new File(args.length > 0 ? args[0] : "/Program Files/Instantiations");

    ScanUnlinkedInstallsOperation op = new ScanUnlinkedInstallsOperation(rootDir);
    long startTime = System.currentTimeMillis();
    op.run(installer);
    long elapseTime = System.currentTimeMillis() - startTime;

    String[] paths = options.getStrings(OPTION_UNLINKED_INSTALL_DIRS);
    System.out.println(paths.length + " unlinked install directories found in " + elapseTime + " milliseconds");
    for (int i = 0; i < paths.length; i++)
      System.out.println("  " + trimmedPath(paths[i], rootDir));
  }

  private static String trimmedPath(File file, File commonDir) {
    return trimmedPath(file.getPath(), commonDir);
  }

  private static String trimmedPath(String path, File commonDir) {
    String prefix = commonDir.getPath();
    if (path.startsWith(prefix))
      path = path.substring(prefix.length());
    return path;
  }
}
TOP

Related Classes of com.instantiations.eclipse.shared.installer.operations.ScanUnlinkedInstallsOperation$ScanFailedException

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.