Package net.sourceforge.javautil.classloader.source

Source Code of net.sourceforge.javautil.classloader.source.CompositeClassSource$CompositePackageSearchInfo

package net.sourceforge.javautil.classloader.source;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import net.sourceforge.javautil.classloader.impl.ClassInfo;
import net.sourceforge.javautil.classloader.impl.ClassSearchInfo;
import net.sourceforge.javautil.classloader.impl.PackageSearchInfo;
import net.sourceforge.javautil.common.Refreshable;
import net.sourceforge.javautil.common.io.IVirtualArtifact;

/**
* A composite of class sources so they function and can be passed around as one.
*
* @author ponder
* @author $Author: ponderator $
* @version $Id: CompositeClassSource.java 2472 2010-10-24 11:49:51Z ponderator $
*/
public class CompositeClassSource extends ClassSource implements Refreshable {

  private boolean searchedAll = false;
  private boolean sourceAdded = false;
  protected final List<ClassSource> sources = new CopyOnWriteArrayList<ClassSource>();
  private Map<String, CompositePackageSearchInfo> pkgMap = new HashMap<String, CompositePackageSearchInfo>();
 
  public CompositeClassSource() { this("Composite Source"); }
  public CompositeClassSource(String name) { super(name); }
  public CompositeClassSource(ClassSource... sources) { this(); this.add(sources); }
  public CompositeClassSource(List<ClassSource> srcs) { this(); this.add(srcs); }
 
  public void initialize (ClassLoader scl) {
    int size = sources.size();
    for (int s=0; s<size; s++) sources.get(s).initialize(scl);
  }
 
  /**
   * @param <T> The type of class source
   * @param type The type of class sources found in this composite that should be returned
   * @return A collection of class sources of the type specified (may be empty, never null)
   */
  public <T extends ClassSource> List<T> getClassSources (Class<T> type) {
    List<T> sources = new ArrayList<T>();
    Iterator<ClassSource> list = this.sources.iterator();
    while (list.hasNext()) {
      ClassSource src = list.next();
      if (type.isAssignableFrom(src.getClass())) sources.add( (T) src );
    }
    return sources;
  }
 
  /**
   * Add a collection of class sources to this composite.
   *
   * @param srcs The sources to add
   *
   * @see #add(ClassSource...)
   */
  public void add(List<ClassSource> srcs) {
    this.sources.addAll( srcs );
    this.sourceAdded = true;
    this.searchedAll = false;
    this.pkgMap.clear();
  }

  @Override public IVirtualArtifact getVirtualArtifact() { return null; }
 
  /**
   * One or more class sources to add to this composite. This
   * will reset the {@link #searchedAll} flag.
   *
   * @param sources The sources to add
   */
  public void add(ClassSource... sources) {
    this.add(Arrays.asList(sources));
  }
 
  /**
   * Remove a previously {@link #add(ClassSource...)}'ed class source.
   * This will also remove any package information related to the class
   * source.
   *
   * @param src The source to remove
   */
  public void remove(ClassSource src) {
    sources.remove(src);
    Iterator<String> names = pkgMap.keySet().iterator();
    while (names.hasNext()) {
      String key = names.next();
      List<ClassSource> srclist = pkgMap.get(key).sources;
      if (srclist != null && srclist.contains(src)) {
        srclist.remove(src);
        if (srclist.size() == 0) pkgMap.put(key, null);
      }
    }
  }
 
  /**
   * @return The collection of class sources that currently make up this composite
   */
  public List<ClassSource> getSources() {
    return sources;
  }
 
  /**
   * @return Return all the class sources (including the children of children composite's) that are not {@link CompositeClassSource}'s.
   */
  public List<ClassSource> getAllNonCompositeSources () {
    List<ClassSource> sources = new ArrayList<ClassSource>();
    for (int s=0; s<this.sources.size(); s++) {
      ClassSource src = this.sources.get(s);
      if (src instanceof CompositeClassSource) sources.addAll( ((CompositeClassSource)src).getAllNonCompositeSources() );
      else sources.add(src);
    }
    return sources;
  }
 
  @Override public ClassInfo getClassInfo(ClassSearchInfo info) throws ClassNotFoundException {
    String path = info.getClassPath();
    List<ClassSource> srcs = this.checkForPackage(info);
    if (srcs != null) {
      int size = srcs.size();
      for (int s=0; s<size; s++) {
        ClassSource src = srcs.get(s);
        if (src.hasResource(path)) return src.getClassInfo(info);
      }
    }
    throw new ClassNotFoundException(info.getFullClassName());
  }

  @Override public long getLastModified() {
    long lastmodified = -1;
   
    for (int s=0; s<this.sources.size(); s++) {
      ClassSource src = this.sources.get(s);
      if (src.getLastModified() > lastmodified) lastmodified = src.getLastModified();
    }
   
    return lastmodified;
  }
 
  @Override public long getLastModifiedClass() {
    long lastmodified = -1;
   
    for (int s=0; s<this.sources.size(); s++) {
      ClassSource src = this.sources.get(s);
      long lmc = src.getLastModifiedClass();
      if (lmc > lastmodified) lastmodified = lmc;
    }
   
    return lastmodified;
  }
 
  @Override public boolean hasClass(ClassSearchInfo info) {
    List<ClassSource> srcs = this.checkForPackage(info);
    for (int s=0; s<srcs.size(); s++)
      if (srcs.get(s).hasClass(info)) return true;
    return false;
  }

  @Override public synchronized boolean hasPackage(PackageSearchInfo info) {
    return this.checkForPackage(info) != null;
  }

  @Override public boolean hasParentPackage(String packageName) {
    Iterator<String> names = pkgMap.keySet().iterator();
    while (names.hasNext())
      if (names.next().startsWith(packageName)) return true;
    return false;
  }

  @Override public Collection<String> getPackages() {
    if (!this.searchedAll) {
      for (int s=0; s<sources.size(); s++) {
        ClassSource src = sources.get(s);
        Iterator<String> pkgs = src.getPackages().iterator();
        while (pkgs.hasNext()) {
          String name = pkgs.next();
          if (!pkgMap.containsKey(name)) pkgMap.put(name, new CompositePackageSearchInfo());
          CompositePackageSearchInfo info = pkgMap.get(name);
          if (info != null) {
            info.searchedFormally = true;
            if (info.sources == null) info.sources = new ArrayList<ClassSource>();
            if (!info.sources.contains(src)) info.sources.add(src);
          }
        }
      }
    }
    return pkgMap.keySet();
  }
 
  @Override public URL getResource(String resourceName) {
    int size = sources.size();
    for (int s=0; s<size; s++) {
      ClassSource src = sources.get(s);
      if (src.hasResource(resourceName)) return src.getResource(resourceName);
    }
    return null;
  }
 
  /**
   * @param resourceName The resource name to look for in all the sub-sources in this composite
   * @return A list, possibly empty, of resources found that match the name
   * @throws MalformedURLException
   */
  public List<URL> getResources (String resourceName) throws MalformedURLException {
    List<URL> urls = new ArrayList<URL>();
    int size = sources.size();
    for (int s=0; s<size; s++) {
      ClassSource src = sources.get(s);
      if (src instanceof CompositeClassSource) urls.addAll( ((CompositeClassSource)src).getResources(resourceName) );
      else if (src.hasResource(resourceName)) urls.add( src.getResource(resourceName) );
    }
    return urls;
  }
 
  @Override public InputStream getResourceAsStream(String resourceName) {
    for (int s=0; s<sources.size(); s++) {
      if (sources.get(s).hasResource(resourceName)) return sources.get(s).getResourceAsStream(resourceName);
    }
    return null;
  }
 
  @Override public boolean hasResource(String resourceName) {
    int size = sources.size();
    for (int s=0; s<size; s++)
      if (sources.get(s).hasResource(resourceName)) return true;
    return false;
  }
 
  @Override public byte[] loadInternal(ClassSearchInfo info) throws ClassNotFoundException {
    List<ClassSource> possible = this.checkForPackage(info);
    if (possible != null) for (int p=0; p<possible.size(); p++) {
      ClassSource src = possible.get(p);
      if (src.hasResource(info.getClassPath())) return src.loadInternal(info);
    }
    throw new ClassNotFoundException(info.getFullClassName());
  }
 
  @Override public boolean hasSearchedAll() {
    if (searchedAll) return true;
    int size = sources.size();
    for (int s=0; s<size; s++)
      if (!sources.get(s).hasSearchedAll()) return false;
    return searchedAll = true;
  }
 
  public void refresh () {
    this.searchedAll = false;
    this.pkgMap.clear();
    int size = sources.size();
    for (int s=0; s<size; s++) {
      ClassSource src = sources.get(s);
      if (src instanceof Refreshable) ((Refreshable)src).refresh();
    }
  }
 
  @Override public void cleanup() {
    int size = sources.size();
    for (int s=0; s<size; s++) sources.get(s).cleanup();
  }
 
  @Override public URL getURL() { return null; }
 
  public List<URL> getUrls () {
    List<URL> urls = new ArrayList<URL>();
    int size = sources.size();
    for (int s=0; s<size; s++) {
      ClassSource src = sources.get(s);
      if (src instanceof CompositeClassSource) urls.addAll( ((CompositeClassSource)src).getUrls() );
      else urls.add(src.getURL());
    }
    return urls;
  }
 
  @Override public Collection<String> getResourceNames() {
    List<String> names = new ArrayList<String>();
    int size = sources.size();
    for (int s=0; s<size; s++)
      names.addAll( sources.get(s).getResourceNames() );
    return names;
  }
 
  @Override public Collection<String> getClassNames() {
    List<String> names = new ArrayList<String>();
    int size = sources.size();
    for (int s=0; s<size; s++)
      names.addAll( sources.get(s).getClassNames() );
    return names;
  }
 
  @Override public boolean hasDirectories() {
    int size = sources.size();
    for (int s=0; s<size; s++) if (sources.get(s).hasDirectories()) return true;
    return false;
  }
 
  @Override public List<String> getClassNamesForPackage(PackageSearchInfo info) {
    List<String> classNames = new ArrayList<String>();
    List<ClassSource> srcs = this.getPackageSources(info);
    int size = srcs.size();
    for (int s=0; s<size; s++)
      classNames.addAll(srcs.get(s).getClassNamesForPackage(info));
    return classNames;
  }
 
  /**
   * @param info Package search info
   * @return All the class sources in this composite that have contain the package provided
   */
  public List<ClassSource> getPackageSources (PackageSearchInfo info) {
    this.checkForPackage(info);
    Set<ClassSource> srcs = new LinkedHashSet<ClassSource>();
    List<ClassSource> psrc = pkgMap.get(info.getPackageName()).sources;
    if (psrc != null) {
      int size = psrc.size();
      for (int s=0; s<size; s++) {
        ClassSource src = psrc.get(s);
        if (src instanceof CompositeClassSource) srcs.addAll( ((CompositeClassSource)src).getPackageSources(info) );
        else srcs.add(src);
      }
    }
    return new ArrayList<ClassSource>(srcs);
  }
 
  @Override public boolean isHasBeenModified() {
    int size = sources.size();
    for (int s=0; s<size; s++)
      if (sources.get(s).isHasBeenModified()) { return true; }
    return false;
  }
 
  @Override public boolean isHasClassesBeenModified() {
    int size = sources.size();
    for (int s=0; s<size; s++)
      if (sources.get(s).isHasClassesBeenModified()) { return true; }
    return false;
  }
 
  @Override public ClassSource clone() throws CloneNotSupportedException {
    List<ClassSource> sources = new ArrayList<ClassSource>();
    for (ClassSource source : this.sources) {
      sources.add( source.clone() );
    }
    return new CompositeClassSource(sources);
  }
 
  @Override public synchronized void reload() {
    int size = sources.size();
    for (int s=0; s<size; s++) {
      ClassSource src = sources.get(s);
      if (src.isHasBeenModified()) {
        this.removeFromPackageInfo(src);
        src.reload();
      }
    }
    this.searchedAll = false;
  }
 
  /**
   * @param source The source to look for
   * @return True if any source or sub source in this composite returns true when calling {@link #equals(Object)} on it for the source passed, otherwise false
   */
  public boolean contains (ClassSource source) {
    for (ClassSource src : this.sources) {
      if (src instanceof CompositeClassSource) {
        if (((CompositeClassSource)src).contains(source)) return true;
      } else {
        if (source.equals( src )) return true;
      }
    }
    return false;
  }
 
  /**
   * Facility method, remove all cached package information related
   * to a particular class source.
   *
   * @param src The source for which package information should be removed
   */
  private void removeFromPackageInfo (ClassSource src) {
    List<String> pkgs = new ArrayList<String>(this.pkgMap.keySet());
    int size = pkgs.size();
    for (int k=0; k<size; k++) {
      CompositePackageSearchInfo info = pkgMap.get(pkgs.get(k));
      if (info != null && info.sources != null) {
        info.sources.remove(src);
        info.searchedFormally = false;
      }
    }
  }
 
  @Override public boolean hasParentResource(String parentResource) {
    int size = sources.size();
    for (int s=0; s<size; s++)
      if (sources.get(s).hasParentResource(parentResource)) return true;
    return false;
  }
 
  @Override public ClassInfo getIfHasClass(ClassSearchInfo info) throws ClassNotFoundException {
    List<ClassSource> srcs = this.getPackageSources(info);
    int size = srcs.size();
    for (int i=0; i<size; i++) {
      ClassSource src = srcs.get(i);
      ClassInfo cinfo = src.getIfHasClass(info);
      if (cinfo != null) return cinfo;
    }
    return null;
  }
 
  /**
   * This will perform progressive scans (on each invocation) in relation to direct package
   * requests, only searching what is necessary till finding what is requested and registering
   * what is found on the way, thus striking a balance between doing a full pre-scan (which could
   * take a long time) and caching what is found while searching for other things.
   *
   * @param pinfo The package search information
   * @return A list of class sources that contain the package provided
   */
  protected List<ClassSource> checkForPackage (PackageSearchInfo pinfo) {
    CompositePackageSearchInfo info = pkgMap.get(pinfo.getPackageName());
    if (info == null && "".equals(pinfo.getPackageName())) {
      pkgMap.put("", info = new CompositePackageSearchInfo());
      info.searchedFormally = true;
      info.sources = new ArrayList<ClassSource>();
      info.sources.addAll(sources);
    } else if (info == null || (info != null && !info.searchedFormally)) {
      String path = pinfo.getPackagePath();
      pkgMap.put(pinfo.getPackageName(), info = new CompositePackageSearchInfo());
      info.searchedFormally = true;
      int size = sources.size();
      for (int s=0; s<size; s++) {
        ClassSource src = sources.get(s);
        if (src.hasParentResource(path)) {
          if (info.sources == null) info.sources = new ArrayList<ClassSource>();
          if (!info.sources.contains(src)) info.sources.add(src);
        }
      }
      if (info.sources != null) {
        for (int p=0; p<pinfo.getPackages().size(); p++) {
          String pkg = pinfo.getPackages().get(p);
          CompositePackageSearchInfo ppinfo = pkgMap.get(pkg);
          if (ppinfo == null) {
            pkgMap.put(pkg, ppinfo = new CompositePackageSearchInfo());
            ppinfo.sources = new ArrayList<ClassSource>();
          }
          if (ppinfo.sources == null) ppinfo.sources = new ArrayList<ClassSource>();
          ppinfo.sources.addAll(info.sources);
        }
      }
    }
    return pkgMap.get(pinfo.getPackageName()).sources;
  }
 
  /**
   * A composite specifically for holding state related to packages and
   * a collection of class sources.
   *
   * @author elponderador
   * @author $Author: ponderator $
   * @version $Id: CompositeClassSource.java 2472 2010-10-24 11:49:51Z ponderator $
   */
  private class CompositePackageSearchInfo {
   
    /**
     * Whether this package has been searched formally, due to a direct
     * request involving the specific package, not parent packages in an
     * unrelated request.
     */
    boolean searchedFormally = false;
   
    /**
     * The class sources that have been previously related to this package after a scan.
     */
    List<ClassSource> sources = null;
   
  }
 
}
TOP

Related Classes of net.sourceforge.javautil.classloader.source.CompositeClassSource$CompositePackageSearchInfo

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.