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;
 | |
|   }
 | |
| }
 |