mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Java
		
	
	
	
package gnu.java.net.loader;
 | 
						|
 | 
						|
import gnu.java.net.IndexListParser;
 | 
						|
 | 
						|
import java.io.IOException;
 | 
						|
import java.net.JarURLConnection;
 | 
						|
import java.net.MalformedURLException;
 | 
						|
import java.net.URL;
 | 
						|
import java.net.URLClassLoader;
 | 
						|
import java.net.URLStreamHandlerFactory;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.LinkedHashMap;
 | 
						|
import java.util.Map;
 | 
						|
import java.util.Set;
 | 
						|
import java.util.StringTokenizer;
 | 
						|
import java.util.jar.Attributes;
 | 
						|
import java.util.jar.JarEntry;
 | 
						|
import java.util.jar.JarFile;
 | 
						|
import java.util.jar.Manifest;
 | 
						|
 | 
						|
/**
 | 
						|
 * A <code>JarURLLoader</code> is a type of <code>URLLoader</code>
 | 
						|
 * only loading from jar url.
 | 
						|
 */
 | 
						|
public final class JarURLLoader extends URLLoader
 | 
						|
{
 | 
						|
  // True if we've initialized -- i.e., tried open the jar file.
 | 
						|
  boolean initialized;
 | 
						|
  // The jar file for this url.
 | 
						|
  JarFile jarfile;
 | 
						|
  // Base jar: url for all resources loaded from jar.
 | 
						|
  final URL baseJarURL;
 | 
						|
  // The "Class-Path" attribute of this Jar's manifest.
 | 
						|
  ArrayList<URLLoader> classPath;
 | 
						|
  // If not null, a mapping from INDEX.LIST for this jar only.
 | 
						|
  // This is a set of all prefixes and top-level files that
 | 
						|
  // ought to be available in this jar.
 | 
						|
  Set indexSet;
 | 
						|
 | 
						|
  // This constructor is used internally.  It purposely does not open
 | 
						|
  // the jar file -- it defers this until later.  This allows us to
 | 
						|
  // implement INDEX.LIST lazy-loading semantics.
 | 
						|
  private JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
 | 
						|
                       URLStreamHandlerFactory factory,
 | 
						|
                       URL baseURL, URL absoluteUrl,
 | 
						|
                       Set indexSet)
 | 
						|
  {
 | 
						|
    super(classloader, cache, factory, baseURL, absoluteUrl);
 | 
						|
 | 
						|
    URL newBaseURL = null;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        // Cache url prefix for all resources in this jar url.
 | 
						|
        String base = baseURL.toExternalForm() + "!/";
 | 
						|
        newBaseURL = new URL("jar", "", -1, base, cache.get(factory, "jar"));
 | 
						|
      }
 | 
						|
    catch (MalformedURLException ignore)
 | 
						|
      {
 | 
						|
        // Ignore.
 | 
						|
      }
 | 
						|
    this.baseJarURL = newBaseURL;
 | 
						|
    this.classPath = null;
 | 
						|
    this.indexSet = indexSet;
 | 
						|
  }
 | 
						|
 | 
						|
  // This constructor is used by URLClassLoader.  It will immediately
 | 
						|
  // try to read the jar file, in case we've found an index or a class-path
 | 
						|
  // setting.  FIXME: it would be nice to defer this as well, but URLClassLoader
 | 
						|
  // makes this hard.
 | 
						|
  public JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
 | 
						|
                      URLStreamHandlerFactory factory,
 | 
						|
                      URL baseURL, URL absoluteUrl)
 | 
						|
  {
 | 
						|
    this(classloader, cache, factory, baseURL, absoluteUrl, null);
 | 
						|
    initialize();
 | 
						|
  }
 | 
						|
 | 
						|
  private void initialize()
 | 
						|
  {
 | 
						|
    JarFile jarfile = null;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        jarfile =
 | 
						|
          ((JarURLConnection) baseJarURL.openConnection()).getJarFile();
 | 
						|
 | 
						|
        Manifest manifest;
 | 
						|
        Attributes attributes;
 | 
						|
        String classPathString;
 | 
						|
 | 
						|
        IndexListParser parser = new IndexListParser(jarfile, baseJarURL,
 | 
						|
                                                     baseURL);
 | 
						|
        LinkedHashMap<URL, Set<String>> indexMap = parser.getHeaders();
 | 
						|
        if (indexMap != null)
 | 
						|
          {
 | 
						|
            // Note that the index also computes
 | 
						|
            // the resulting Class-Path -- there are jars out there
 | 
						|
            // where the index lists some required jars which do
 | 
						|
            // not appear in the Class-Path attribute in the manifest.
 | 
						|
            this.classPath = new ArrayList<URLLoader>();
 | 
						|
            Iterator<Map.Entry<URL, Set<String>>> it = indexMap.entrySet().iterator();
 | 
						|
            while (it.hasNext())
 | 
						|
              {
 | 
						|
                Map.Entry<URL, Set<String>> entry = it.next();
 | 
						|
                URL subURL = entry.getKey();
 | 
						|
                Set<String> prefixes = entry.getValue();
 | 
						|
                if (subURL.equals(baseURL))
 | 
						|
                  this.indexSet = prefixes;
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    JarURLLoader subLoader = new JarURLLoader(classloader,
 | 
						|
                                                              cache,
 | 
						|
                                                              factory, subURL,
 | 
						|
                                                              subURL,
 | 
						|
                                                              prefixes);
 | 
						|
                    // Note that we don't care if the sub-loader itself has an
 | 
						|
                    // index or a class-path -- only the top-level jar
 | 
						|
                    // file gets this treatment; its index should cover
 | 
						|
                    // everything.
 | 
						|
                    this.classPath.add(subLoader);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if ((manifest = jarfile.getManifest()) != null
 | 
						|
                 && (attributes = manifest.getMainAttributes()) != null
 | 
						|
                 && ((classPathString
 | 
						|
                      = attributes.getValue(Attributes.Name.CLASS_PATH))
 | 
						|
                     != null))
 | 
						|
          {
 | 
						|
            this.classPath = new ArrayList<URLLoader>();
 | 
						|
            StringTokenizer st = new StringTokenizer(classPathString, " ");
 | 
						|
            while (st.hasMoreElements ())
 | 
						|
              {
 | 
						|
                String e = st.nextToken ();
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    URL subURL = new URL(baseURL, e);
 | 
						|
                    // We've seen at least one jar file whose Class-Path
 | 
						|
                    // attribute includes the original jar.  If we process
 | 
						|
                    // that normally we end up with infinite recursion.
 | 
						|
                    if (subURL.equals(baseURL))
 | 
						|
                      continue;
 | 
						|
                    JarURLLoader subLoader = new JarURLLoader(classloader,
 | 
						|
                                                              cache, factory,
 | 
						|
                                                              subURL, subURL);
 | 
						|
                    this.classPath.add(subLoader);
 | 
						|
                    ArrayList<URLLoader> extra = subLoader.getClassPath();
 | 
						|
                    if (extra != null)
 | 
						|
                      this.classPath.addAll(extra);
 | 
						|
                  }
 | 
						|
                catch (java.net.MalformedURLException xx)
 | 
						|
                  {
 | 
						|
                    // Give up
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    catch (IOException ioe)
 | 
						|
      {
 | 
						|
        /* ignored */
 | 
						|
      }
 | 
						|
 | 
						|
    this.jarfile = jarfile;
 | 
						|
    this.initialized = true;
 | 
						|
  }
 | 
						|
 | 
						|
  /** get resource with the name "name" in the jar url */
 | 
						|
  public Resource getResource(String name)
 | 
						|
  {
 | 
						|
    if (name.startsWith("/"))
 | 
						|
      name = name.substring(1);
 | 
						|
    if (indexSet != null)
 | 
						|
      {
 | 
						|
        // Trust the index.
 | 
						|
        String basename = name;
 | 
						|
        int offset = basename.lastIndexOf('/');
 | 
						|
        if (offset != -1)
 | 
						|
          basename = basename.substring(0, offset);
 | 
						|
        if (! indexSet.contains(basename))
 | 
						|
          return null;
 | 
						|
        // FIXME: if the index claim to hold the resource, and jar file
 | 
						|
        // doesn't have it, we're supposed to throw an exception.  However,
 | 
						|
        // in our model this is tricky to implement, as another URLLoader from
 | 
						|
        // the same top-level jar may have an overlapping index entry.
 | 
						|
      }
 | 
						|
 | 
						|
    if (! initialized)
 | 
						|
      initialize();
 | 
						|
    if (jarfile == null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    JarEntry je = jarfile.getJarEntry(name);
 | 
						|
    if (je != null)
 | 
						|
      return new JarURLResource(this, name, je);
 | 
						|
    else
 | 
						|
      return null;
 | 
						|
  }
 | 
						|
 | 
						|
  public Manifest getManifest()
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        return (jarfile == null) ? null : jarfile.getManifest();
 | 
						|
      }
 | 
						|
    catch (IOException ioe)
 | 
						|
      {
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public ArrayList<URLLoader> getClassPath()
 | 
						|
  {
 | 
						|
    return classPath;
 | 
						|
  }
 | 
						|
}
 |