home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 July / Chip_1998-07_cd.bin / zkuste / JBuilder / BDK / Win / bdk_sep97.exe / _SETUP.1 / JarLoader.java < prev    next >
Encoding:
Java Source  |  1997-09-10  |  8.4 KB  |  314 lines

  1. package sun.beanbox;
  2.  
  3. /**
  4.  * Read the contents of a JAR file.
  5.  *
  6.  */
  7.  
  8. import java.io.*;
  9. import java.util.*;
  10. import java.util.zip.*;
  11. import java.beans.*;
  12. import java.net.*;
  13. import java.awt.*;
  14.  
  15. public class JarLoader {
  16.  
  17.     private static boolean debug = false; // debugging
  18.     private InputStream jarStream; // Jar input stream
  19.     private String jarName;    // name of the jar file
  20.     private SimpleClassLoader loader; // the loader instance
  21.     private static boolean warnedAboutNoBeans;
  22.  
  23.  
  24.     /**
  25.      * Create a JarLoader to read a JAR and to process its contents.
  26.      * Classes and resources are loaded against a single common class
  27.      * loader instance so that things like "adaptor class instantiaton"
  28.      * can work.
  29.      *
  30.      * Loading is started with loadIt()
  31.      */
  32.     public JarLoader(String jarName) throws FileNotFoundException {
  33.     // wil check that this file exists, and that is about it.
  34.     debug("("+jarName+")");
  35.     this.jarName = jarName;
  36.     InputStream is = new FileInputStream(jarName);
  37.     jarStream = new BufferedInputStream(is);
  38.     loader = SimpleClassLoader.ourLoader;
  39.     }
  40.  
  41.     /**
  42.      * get the loader we are using
  43.      */
  44.     public ClassLoader getLoader() {
  45.     return loader;
  46.     }
  47.  
  48.     /*
  49.      * In here for compatibility with older versions of JDK1.1
  50.      */
  51.     private String guessContentTypeFromStream(InputStream is) throws IOException {
  52.     String type;
  53.     type = URLConnection.guessContentTypeFromStream(is);
  54.     // that should be taught about serialized objects.
  55.     
  56.     if (type == null) {
  57.         is.mark(10);
  58.         int c1 = is.read();
  59.         int c2 = is.read();
  60.         int c3 = is.read();
  61.         int c4 = is.read();
  62.         int c5 = is.read();
  63.         int c6 = is.read();
  64.         is.reset();
  65.         if (c1 == 0xAC && c2 == 0xED) {
  66.         type = "application/java-serialized-object";
  67.         }
  68.     }
  69.     return type;
  70.     }
  71.  
  72.     /**
  73.      * Load the classes, resources, etc.
  74.      */
  75.     public JarInfo loadJar() {
  76.     // load all resources.
  77.     // may raise an exception if the file is not a Jar file.
  78.     ZipInputStream zis = null;
  79.     Manifest mf = null;
  80.     Vector classList = new Vector(); // the classes
  81.     Vector serList = new Vector(); // the serialized objects
  82.  
  83.     byte buffer[] = new byte[1024];
  84.  
  85.     try {
  86.         zis = new ZipInputStream(jarStream);
  87.         ZipEntry ent = null;
  88.  
  89.         while ((ent = zis.getNextEntry()) != null) {
  90.  
  91.         String name = ent.getName();
  92.         String type = null;
  93.  
  94.         /* the object we're loading */
  95.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  96.  
  97.         /* NOTE: We don't know the size of an entry until
  98.            we've reached the end of one because of
  99.            compression. This means we can't just do a get size
  100.            and read in the entry. */
  101.  
  102.         for (;;) {
  103.             int len = zis.read(buffer);
  104.             if (len < 0) {
  105.             break;
  106.             }
  107.             baos.write(buffer, 0, len);
  108.         }
  109.  
  110.         byte[] buf = baos.toByteArray();
  111.         int size = buf.length;
  112.         
  113.         if (Manifest.isManifestName(name)) {
  114.             type = "manifest/manifest";
  115.         }
  116.  
  117.         if (type == null) {
  118.             InputStream tmpStream = new ByteArrayInputStream(buf);
  119.             type = guessContentTypeFromStream(tmpStream);
  120.             tmpStream.close();
  121.         }
  122.  
  123.         if (type == null) {
  124.             type = "input-stream/input-stream";
  125.         }
  126.  
  127.         if (type.startsWith("application/java-serialized-object") ||
  128.             type.startsWith("application/x-java-serialized-object")) {
  129.             // Else make the data available as a local stream.
  130.             loader.putLocalResource(name, buf, type);
  131.  
  132.             // Tag it as a serialized object for the bean list.
  133.             String sername = name.substring(0, name.length() - 4);
  134.             sername = sername.replace('/', '.');
  135.             serList.addElement(sername);
  136.  
  137.         } else if (type.startsWith("application/java-vm") ||
  138.                type.startsWith("application/x-java-vm")) {
  139.             /*
  140.              * In JDK1.1, a classloader needs not provide access to the
  141.              * bytecodes of a .class resource.  But it needs to provide
  142.              * a URL for it (e.g. for URL math computation).
  143.              *
  144.              * The bytecodes are kept (and later released) by the
  145.              * SimpleClassLoader instance.
  146.              * Here we just tag the existance of the object.
  147.              */
  148.  
  149.             loader.putClassResource(name, type);
  150.  
  151.             /* remove the .class suffix */
  152.             String classname = name.substring(0, name.length() - 6);
  153.             classname = classname.replace('/', '.');
  154.             loader.defineClassFromBytes(classname, buf);
  155.             classList.addElement(classname);
  156.  
  157.         } else if (type.equals("manifest/manifest")) {
  158.             mf = new Manifest(buf);
  159.  
  160.         } else {
  161.             // Else make the data available as a local stream.
  162.             loader.putLocalResource(name, buf, type);
  163.         }
  164.         }
  165.  
  166.     } catch (IOException e) {
  167.         debug("IOException loading archive: " + e);
  168.         e.printStackTrace();
  169.     } catch (Throwable ex) {
  170.         debug("Caught "+ex+" in loadit()");
  171.         ex.printStackTrace();
  172.     } finally {
  173.         if (zis != null) {
  174.         try {
  175.             zis.close();
  176.         } catch (Exception ex) {
  177.             // ignore
  178.         }
  179.         }
  180.     }
  181.  
  182.     if (! BeanBoxFrame.getDefineOnDemand()) {
  183.         if (! loader.applyDefinitions(classList)) {
  184.         return null;
  185.         }
  186.     }
  187.     JarInfo ji = createJarInfo(classList, serList, mf);
  188.     return ji;
  189.     }
  190.  
  191.     /**
  192.      * Load the JAR file, then apply an action to each bean found
  193.      */
  194.     public static void loadJarDoOnBean(String jarFile, DoOnBean action) {
  195.     JarLoader jl = null;
  196.     try {
  197.         jl = new JarLoader(jarFile);
  198.         if (jl == null) {
  199.         System.err.println("file name passed is not a valid JarFile");
  200.         return;
  201.         }
  202.     } catch (Exception ex) {
  203.         System.err.println("caught an exception while trying to load "+jarFile);
  204.         ex.printStackTrace();
  205.         return;
  206.     }
  207.  
  208.     JarInfo ji = jl.loadJar();
  209.     if (ji == null) {
  210.         System.err.println("JAR file "+jarFile+" did not load properly!");
  211.         System.err.println("Check for error messages possibly regarding");
  212.         System.err.println("problems defining classes");
  213.         return;
  214.     }
  215.     if (ji.getCount() == 0) {
  216.         System.err.println("Jar file "+jarFile+" didn't have any beans!");
  217.         if (!warnedAboutNoBeans) {
  218.         // We only print this explanatory message once.
  219.         warnedAboutNoBeans = true;    
  220.         System.err.println("");
  221.             System.err.println("Each jar file needs to contain a manifest file describing which entries are");
  222.             System.err.println("beans.  You can should provide a suitable manifest when you create the jar.");
  223.         System.err.println("");
  224.         }
  225.     }
  226.     for (int i=0; i<ji.getCount(); i++) {
  227.         String beanName = ji.getName(i);
  228.         BeanInfo bi = ji.getBeanInfo(i);
  229.  
  230.         if (bi == null) {
  231.         // We couldn't load the bean.
  232.         continue;
  233.         }
  234.  
  235.         action.action(ji, bi, beanName);
  236.     }
  237.     }
  238.  
  239.  
  240.     /**
  241.      * Create a JarInfo from a manifest and a class list
  242.      */
  243.  
  244.     private JarInfo createJarInfo(Vector classList,
  245.                   Vector serList,
  246.                   Manifest mf) {
  247.     Hashtable beans;
  248.     Hashtable headersTable = new Hashtable();
  249.     if (mf == null) {
  250.         beans = new Hashtable();
  251.         for (Enumeration keys = classList.elements();
  252.          keys.hasMoreElements(); ) {
  253.         String key = (String) keys.nextElement();
  254.         beans.put(key, new Boolean(false)); // not from serializable
  255.         }
  256.         for (Enumeration keys = serList.elements();
  257.          keys.hasMoreElements(); ) {
  258.         String key = (String) keys.nextElement();
  259.         beans.put(key, new Boolean(true)); // from class definition
  260.         }
  261.     } else {
  262.         beans = new Hashtable();
  263.         for (Enumeration entries = mf.entries();
  264.          entries.hasMoreElements();) {
  265.         MessageHeader mh = (MessageHeader) entries.nextElement();
  266.         String name = mh.findValue("Name");
  267.         String isBean = mh.findValue("Java-Bean");
  268.         if (isBean != null && isBean.equalsIgnoreCase("True")) {
  269.             String beanName;
  270.             boolean fromPrototype = true;
  271.             if (name.endsWith(".class")) {
  272.             fromPrototype = false;
  273.             beanName = name.substring(0, name.length() - 6);
  274.             } else if (name.endsWith(".ser")) {
  275.             beanName = name.substring(0, name.length() - 4);
  276.             } else {
  277.             beanName = name;
  278.             }
  279.             beanName = beanName.replace('/', '.');
  280.             beans.put(beanName, new Boolean(fromPrototype));
  281.             headersTable.put(beanName, mh);
  282.         }
  283.         }
  284.     }
  285.  
  286.     String beanNames[] = new String[beans.size()];
  287.     boolean fromPrototype[] = new boolean[beans.size()];
  288.     MessageHeader headers[] = new MessageHeader[beans.size()];
  289.     Enumeration keys;
  290.     int i;
  291.     for (keys = beans.keys(), i = 0;
  292.          keys.hasMoreElements();
  293.          i++) {
  294.         String key = (String) keys.nextElement();
  295.         beanNames[i] = key;
  296.         fromPrototype[i] = ((Boolean)beans.get(key)).booleanValue();
  297.         headers[i] = (MessageHeader) headersTable.get(key);
  298.     }
  299.  
  300.     return new JarInfo(jarName, loader, beanNames, fromPrototype, headers);
  301.     }
  302.  
  303.  
  304.     /**
  305.      * Debugging stuff
  306.      */
  307.     private static void debug(String msg) {
  308.     if (debug) {
  309.         System.err.println("JarLoader:: "+msg);
  310.     }
  311.     }
  312.  
  313. }
  314.