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

weka.core.ClassCache Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This version represents the developer version, the "bleeding edge" of development, you could say. New functionality gets added to this version.

There is a newer version: 3.9.6
Show newest version
/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see .
 */

/**
 * ClassCache.java
 * Copyright (C) 2010-2014 University of Waikato, Hamilton, New Zealand
 */

package weka.core;

import java.io.File;
import java.io.FileFilter;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * A singleton that stores all classes on the classpath.
 * 
 * @author fracpete (fracpete at waikato dot ac dot nz)
 * @version $Revision: 13476 $
 */
public class ClassCache implements RevisionHandler {

  /**
   * For filtering classes.
   * 
   * @author fracpete (fracpete at waikato dot ac dot nz)
   * @version $Revision: 13476 $
   */
  public static class ClassFileFilter implements FileFilter {

    /**
     * Checks whether the file is a class.
     * 
     * @param pathname the file to check
     * @return true if a class file
     */
    @Override
    public boolean accept(File pathname) {
      return pathname.getName().endsWith(".class");
    }
  }

  /**
   * For filtering classes.
   * 
   * @author fracpete (fracpete at waikato dot ac dot nz)
   * @version $Revision: 13476 $
   */
  public static class DirectoryFilter implements FileFilter {

    /**
     * Checks whether the file is a directory.
     * 
     * @param pathname the file to check
     * @return true if a directory
     */
    @Override
    public boolean accept(File pathname) {
      return pathname.isDirectory();
    }
  }

  /** whether to output some debug information. */
  public final static boolean VERBOSE = false;

  /** the key for the default package. */
  public final static String DEFAULT_PACKAGE = "DEFAULT";

  /**
   * for caching all classes on the class path (package-name <-> HashSet
   * with classnames).
   */
  protected Hashtable> m_Cache;

  static {
    // notify if VERBOSE is still on
    if (VERBOSE) {
      System.err.println(ClassCache.class.getName() + ": VERBOSE ON");
    }
  }

  /**
   * Initializes the cache.
   */
  public ClassCache() {
    super();
    initializeNew();
  }

  /**
   * Fixes the classname, turns "/" and "\" into "." and removes ".class".
   * 
   * @param classname the classname to process
   * @return the processed classname
   */
  public static String cleanUp(String classname) {
    String result;

    result = classname;

    if (result.indexOf("/") > -1) {
      result = result.replace("/", ".");
    }
    if (result.indexOf("\\") > -1) {
      result = result.replace("\\", ".");
    }
    if (result.endsWith(".class")) {
      result = result.substring(0, result.length() - 6);
    }

    return result;
  }

  /**
   * Extracts the package name from the (clean) classname.
   * 
   * @param classname the classname to extract the package from
   * @return the package name
   */
  public static String extractPackage(String classname) {
    if (classname.indexOf(".") > -1) {
      return classname.substring(0, classname.lastIndexOf("."));
    } else {
      return DEFAULT_PACKAGE;
    }
  }

  /**
   * Adds the classname to the cache.
   * 
   * @param classname the classname, automatically removes ".class" and turns
   *          "/" or "\" into "."
   * @return true if adding changed the cache
   */
  public boolean add(String classname) {
    String pkgname;
    HashSet names;

    // classname and package
    classname = cleanUp(classname);
    pkgname = extractPackage(classname);

    // add to cache
    if (!m_Cache.containsKey(pkgname)) {
      m_Cache.put(pkgname, new HashSet());
    }
    names = m_Cache.get(pkgname);
    return names.add(classname);
  }

  /**
   * Removes the classname from the cache.
   * 
   * @param classname the classname to remove
   * @return true if the removal changed the cache
   */
  public boolean remove(String classname) {
    String pkgname;
    HashSet names;

    classname = cleanUp(classname);
    pkgname = extractPackage(classname);
    names = m_Cache.get(pkgname);
    if (names != null) {
      return names.remove(classname);
    } else {
      return false;
    }
  }

  /**
   * Fills the class cache with classes in the specified directory.
   * 
   * @param prefix the package prefix so far, null for default package
   * @param dir the directory to search
   */
  protected void initFromDir(String prefix, File dir) {
    File[] files;

    // check classes
    files = dir.listFiles(new ClassFileFilter());
    for (File file : files) {
      if (prefix == null) {
        add(file.getName());
      } else {
        add(prefix + "." + file.getName());
      }
    }

    // descend in directories
    files = dir.listFiles(new DirectoryFilter());
    for (File file : files) {
      if (prefix == null) {
        initFromDir(file.getName(), file);
      } else {
        initFromDir(prefix + "." + file.getName(), file);
      }
    }
  }

  /**
   * Fills the class cache with classes in the specified directory.
   * 
   * @param dir the directory to search
   */
  protected void initFromDir(File dir) {
    if (VERBOSE) {
      System.out.println("Analyzing directory: " + dir);
    }
    initFromDir(null, dir);
  }

  /**
   * Analyzes the MANIFEST.MF file of a jar whether additional jars are listed
   * in the "Class-Path" key.
   * 
   * @param manifest the manifest to analyze
   */
  protected void initFromManifest(Manifest manifest) {
    if (manifest == null) {
      return;
    }

    Attributes atts;
    String cp;
    String[] parts;

    atts = manifest.getMainAttributes();
    cp = atts.getValue("Class-Path");
    if (cp == null) {
      return;
    }

    parts = cp.split(" ");
    for (String part : parts) {
      if (part.trim().length() == 0) {
        return;
      }
      if (part.toLowerCase().endsWith(".jar")) {
        initFromClasspathPart(part);
      }
    }
  }

  /**
   * Fills the class cache with classes from the specified jar.
   * 
   * @param file the jar to inspect
   */
  protected void initFromJar(File file) {
    JarFile jar;
    JarEntry entry;
    Enumeration enm;

    if (VERBOSE) {
      System.out.println("Analyzing jar: " + file);
    }

    if (!file.exists()) {
      System.out.println("Jar does not exist: " + file);
      return;
    }

    try {
      jar = new JarFile(file);
      enm = jar.entries();
      while (enm.hasMoreElements()) {
        entry = enm.nextElement();
        if (entry.getName().endsWith(".class")) {
          add(entry.getName());
        }
      }
      initFromManifest(jar.getManifest());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Returns all the stored packages.
   * 
   * @return the package names
   */
  public Enumeration packages() {
    return m_Cache.keys();
  }

  /**
   * Returns all the classes for the given package.
   * 
   * @param pkgname the package to get the classes for
   * @return the classes (sorted by name)
   */
  public HashSet getClassnames(String pkgname) {
    if (m_Cache.containsKey(pkgname)) {
      return m_Cache.get(pkgname);
    } else {
      return new HashSet();
    }
  }

  /**
   * Analyzes a part of the classpath.
   * 
   * @param part the part to analyze
   */
  protected void initFromClasspathPart(String part) {
    File file;

    file = null;
    if (part.startsWith("file:")) {
      part = part.replace(" ", "%20");
      try {
        file = new File(new java.net.URI(part));
      } catch (URISyntaxException e) {
        System.err.println("Failed to generate URI: " + part);
        e.printStackTrace();
      }
    } else {
      file = new File(part);
    }
    if (file == null) {
      System.err.println("Skipping: " + part);
      return;
    }

    // find classes
    if (file.isDirectory()) {
      initFromDir(file);
    } else if (file.exists()) {
      initFromJar(file);
    }
  }

  /**
   * Initializes the cache.
   */
  protected void initialize() {
    String part = "";
    URLClassLoader sysLoader;
    URL[] urls;

    m_Cache = new Hashtable>();

    sysLoader = (URLClassLoader) getClass().getClassLoader();
    urls = sysLoader.getURLs();
    for (URL url : urls) {
      part = url.toString();
      if (VERBOSE) {
        System.out.println("Classpath-part: " + part);
      }
      initFromClasspathPart(part);
    }
  }

  protected void initializeNew() {
    m_Cache = new Hashtable>();
    WekaPackageClassLoaderManager wcl = WekaPackageClassLoaderManager.getWekaPackageClassLoaderManager();

    // parent classloader entries...
    URL[] sysOrWekaCP = wcl.getWekaClassloaderClasspathEntries();
    for (URL url : sysOrWekaCP) {
      String part = url.toString();
      if (VERBOSE) {
        System.out.println("Classpath-part: " + part);
      }
      initFromClasspathPart(part);
    }

    // top-level package jar file class entries
    Set classes = wcl.getPackageJarFileClasses();
    for (String cl : classes) {
      add(cl);
    }
  }

  /**
   * Find all classes that have the supplied matchText String in their suffix.
   * 
   * @param matchText the text to match
   * @return an array list of matching fully qualified class names.
   */
  public ArrayList find(String matchText) {
    ArrayList result;
    Enumeration packages;
    Iterator names;
    String name;

    result = new ArrayList();

    packages = m_Cache.keys();
    while (packages.hasMoreElements()) {
      names = m_Cache.get(packages.nextElement()).iterator();
      while (names.hasNext()) {
        name = names.next();
        if (name.contains(matchText)) {
          result.add(name);
        }
      }
    }

    if (result.size() > 1) {
      Collections.sort(result);
    }

    return result;
  }

  /**
   * Returns the revision string.
   * 
   * @return the revision
   */
  @Override
  public String getRevision() {
    return RevisionUtils.extract("$Revision: 13476 $");
  }

  /**
   * For testing only.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    ClassCache cache = new ClassCache();
    Enumeration packages = cache.packages();
    while (packages.hasMoreElements()) {
      String key = packages.nextElement();
      System.out.println(key + ": " + cache.getClassnames(key).size());
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy