home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / Beans.java < prev    next >
Text File  |  1997-10-01  |  15KB  |  484 lines

  1. /*
  2.  * @(#)Beans.java    1.24 97/01/06  
  3.  * 
  4.  * Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion bdk_beta
  20.  * 
  21.  */
  22.  
  23. package java.beans;
  24.  
  25. import java.io.*;
  26. import java.awt.*;
  27. import java.applet.*;
  28. import java.net.URL;
  29. import java.lang.reflect.Array;
  30.  
  31. /**
  32.  * This class provides some general purpose beans control methods.
  33.  */
  34.  
  35. public class Beans {
  36.  
  37.     /**
  38.      * Instantiate a bean.
  39.      * <p>
  40.      * The bean is created based on a name relative to a class-loader.
  41.      * This name should be a dot-separated name such as "a.b.c".
  42.      * <p>
  43.      * In Beans 1.0 the given name can indicate either a serialized object
  44.      * or a class.  Other mechanisms may be added in the future.  In
  45.      * beans 1.0 we first try to treat the beanName as a serialized object
  46.      * name then as a class name.
  47.      * <p>
  48.      * When using the beanName as a serialized object name we convert the
  49.      * given beanName to a resource pathname and add a trailing ".ser" suffix.
  50.      * We then try to load a serialized object from that resource.
  51.      * <p>
  52.      * For example, given a beanName of "x.y", Beans.instantiate would first
  53.      * try to read a serialized object from the resource "x/y.ser" and if
  54.      * that failed it would try to load the class "x.y" and create an
  55.      * instance of that class.
  56.      * <p>
  57.      * If the bean is a subtype of java.applet.Applet, then it is given
  58.      * some special initialization.  First, it is supplied with a default
  59.      * AppletStub and AppletContext.  Second, if it was instantiated from 
  60.      * a classname the applet's "init" method is called.  (If the bean was
  61.      * deserialized this step is skipped.) 
  62.      * <p>
  63.      * Note that for beans which are applets, it is the caller's responsiblity
  64.      * to call "start" on the applet.  For correct behaviour, this should be done
  65.      * after the applet has been added into a visible AWT container.
  66.      * <p>
  67.      * Note that applets created via beans.instantiate run in a slightly
  68.      * different environment than applets running inside browsers.  In
  69.      * particular, bean applets have no access to "parameters", so they may 
  70.      * wish to provide property get/set methods to set parameter values.  We
  71.      * advise bean-applet developers to test their bean-applets against both
  72.      * the JDK appletviewer (for a reference browser environment) and the
  73.      * BDK BeanBox (for a reference bean container).
  74.      * 
  75.      * @param     classLoader the class-loader from which we should create
  76.      *                       the bean.  If this is null, then the system
  77.      *                        class-loader is used.
  78.      * @param     beanName    the name of the bean within the class-loader.
  79.      *                     For example "sun.beanbox.foobah"
  80.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  81.      *              object could not be found.
  82.      * @exception java.io.IOException if an I/O error occurs.
  83.      */
  84.     public static Object instantiate(ClassLoader cls, String beanName) 
  85.             throws java.io.IOException, ClassNotFoundException {
  86.  
  87.     java.io.InputStream ins;
  88.     java.io.ObjectInputStream oins = null;
  89.     Object result = null;
  90.     boolean serialized = false;
  91.  
  92.     // Try to find a serialized object with this name
  93.     String serName = beanName.replace('.','/').concat(".ser");
  94.     if (cls == null) {
  95.         ins = ClassLoader.getSystemResourceAsStream(serName);
  96.     } else {
  97.         ins  = cls.getResourceAsStream(serName);
  98.     }
  99.     if (ins != null) {
  100.         try {
  101.             if (cls == null) {
  102.             oins = new ObjectInputStream(ins);
  103.             } else {
  104.             oins = new ObjectInputStreamWithLoader(ins, cls);
  105.             }
  106.             result = oins.readObject();
  107.         serialized = true;
  108.             oins.close();
  109.         } catch (java.io.IOException ex) {
  110.         ins.close();
  111.         // For now, drop through and try opening the class.
  112.         // throw ex;
  113.         } catch (ClassNotFoundException ex) {
  114.         ins.close();
  115.         throw ex;
  116.         }
  117.     }
  118.  
  119.     if (result == null) {
  120.         // No serialized object, try just instantiating the class
  121.         Class cl;
  122.         if (cls == null) {
  123.             cl = Class.forName(beanName);
  124.         } else {
  125.             cl = cls.loadClass(beanName);
  126.         }
  127.         try {
  128.             result = cl.newInstance();
  129.         } catch (Exception ex) {
  130.             throw new ClassNotFoundException();
  131.         }
  132.     }
  133.     // Ok, if the result is an applet initialize it.
  134.     if (result != null && result instanceof Applet) {
  135.         Applet applet = (Applet) result;
  136.  
  137.         // Figure our the codebase and docbase URLs.  We do this
  138.         // by locating the URL for a known resource, and then
  139.         // massaging the URL.
  140.  
  141.         // First find the "resource name" corresponding to the bean
  142.         // itself.  So a serialzied bean "a.b.c" would imply a resource
  143.         // name of "a/b/c.ser" and a classname of "x.y" would imply
  144.         // a resource name of "x/y.class".
  145.  
  146.         String resourceName;
  147.         if (serialized) {
  148.         // Serialized bean
  149.         resourceName = beanName.replace('.','/').concat(".ser");
  150.         } else {
  151.         // Regular class
  152.         resourceName = beanName.replace('.','/').concat(".class");
  153.         }
  154.         URL objectUrl = null;
  155.         URL codeBase = null;
  156.         URL docBase = null;
  157.  
  158.         // Now get the URL correponding to the resource name.
  159.         if (cls == null) {
  160.         objectUrl = ClassLoader.getSystemResource(resourceName);
  161.         } else {
  162.         objectUrl = cls.getResource(resourceName);
  163.         }
  164.  
  165.         // If we found a URL, we try to locate the docbase by taking
  166.         // of the final path name component, and the code base by taking
  167.            // of the complete resourceName.
  168.         // So if we had a resourceName of "a/b/c.class" and we got an
  169.         // objectURL of "file://bert/classes/a/b/c.class" then we would
  170.         // want to set the codebase to "file://bert/classes/" and the
  171.         // docbase to "file://bert/classes/a/b/"
  172.  
  173.         if (objectUrl != null) {
  174.         String s = objectUrl.toExternalForm();
  175.         if (s.endsWith(resourceName)) {
  176.               int ix = s.length() - resourceName.length();
  177.             codeBase = new URL(s.substring(0,ix));
  178.             docBase = codeBase;
  179.             ix = s.lastIndexOf('/');
  180.             if (ix >= 0) {
  181.                 docBase = new URL(s.substring(0,ix+1));
  182.             }
  183.         }
  184.         }
  185.                 
  186.         // Setup a default context and stub.
  187.         BeansAppletContext context = new BeansAppletContext(applet);
  188.         BeansAppletStub stub = new BeansAppletStub(applet, context, codeBase, docBase);
  189.         applet.setStub(stub);
  190.  
  191.         // If it was deserialized then it was already init-ed.  Otherwise
  192.         // we need to initialize it.
  193.         if (!serialized) {
  194.         // We need to set a reasonable initial size, as many
  195.         // applets are unhappy if they are started without 
  196.         // having been explicitly sized.
  197.         applet.setSize(100,100);
  198.         applet.init();
  199.         }
  200.         stub.active = true;
  201.     }
  202.     return result;
  203.     }
  204.  
  205.  
  206.     /**
  207.      * From a given bean, obtain an object representing a specified
  208.      * type view of that source object. 
  209.      * <p>
  210.      * The result may be the same object or a different object.  If
  211.      * the requested target view isn't available then the given
  212.      * bean is returned.
  213.      * <p>
  214.      * This method is provided in Beans 1.0 as a hook to allow the
  215.      * addition of more flexible bean behaviour in the future.
  216.      *
  217.      * @param obj  Object from which we want to obtain a view.
  218.      * @param targetType  The type of view we'd like to get.
  219.      *
  220.      */
  221.     public static Object getInstanceOf(Object bean, Class targetType) {
  222.         return bean;
  223.     }
  224.  
  225.     /**
  226.      * Check if a bean can be viewed as a given target type.
  227.      * The result will be true if the Beans.getInstanceof method
  228.      * can be used on the given bean to obtain an object that
  229.      * represents the specified targetType type view.
  230.      *
  231.      * @param bean  Bean from which we want to obtain a view.
  232.      * @param targetType  The type of view we'd like to get.
  233.      * @return "true" if the given bean supports the given targetType.
  234.      */
  235.     public static boolean isInstanceOf(Object bean, Class targetType) {
  236.     return Introspector.isSubclass(bean.getClass(), targetType);
  237.     }
  238.  
  239.  
  240.     /**
  241.      * Test if we are in design-mode.
  242.      *
  243.      * @return  True if we are running in an application construction
  244.      *        environment.
  245.      */
  246.     public static boolean isDesignTime() {
  247.     return designTime;
  248.     }
  249.  
  250.     /**
  251.      * @return  True if we are running in an environment where beans
  252.      *       can assume that an interactive GUI is available, so they 
  253.      *       can pop up dialog boxes, etc.  This will normally return
  254.      *       true in a windowing environment, and will normally return
  255.      *       false in a server environment or if an application is
  256.      *       running as part of a batch job.
  257.      */
  258.     public static boolean isGuiAvailable() {
  259.     return guiAvailable;
  260.     }
  261.  
  262.     /**
  263.      * Used to indicate whether of not we are running in an application
  264.      * builder environment.  Note that this method is security checked
  265.      * and is not available to (for example) untrusted applets.
  266.      *
  267.      * @param isDesignTime  True if we're in an application builder tool.
  268.      */
  269.  
  270.     public static void setDesignTime(boolean isDesignTime)
  271.             throws SecurityException {
  272.     designTime = isDesignTime;
  273.     }
  274.  
  275.     /**
  276.      * Used to indicate whether of not we are running in an environment
  277.      * where GUI interaction is available.  Note that this method is 
  278.      * security checked and is not available to (for example) untrusted
  279.      * applets.
  280.      *
  281.      * @param isGuiAvailable  True if GUI interaction is available.
  282.      */
  283.  
  284.     public static void setGuiAvailable(boolean isGuiAvailable)
  285.             throws SecurityException {
  286.     guiAvailable = isGuiAvailable;
  287.     }
  288.  
  289.  
  290.     private static boolean designTime;
  291.     private static boolean guiAvailable = true;
  292. }
  293.  
  294. /**
  295.  * This subclass of ObjectInputStream delegates loading of classes to
  296.  * an existing ClassLoader.
  297.  */
  298.  
  299. class ObjectInputStreamWithLoader extends ObjectInputStream
  300. {
  301.     private ClassLoader loader;
  302.  
  303.     /**
  304.      * Loader must be non-null;
  305.      */
  306.  
  307.     public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
  308.         throws IOException, StreamCorruptedException {
  309.  
  310.     super(in);
  311.     if (loader == null) {
  312.             throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
  313.     }
  314.     this.loader = loader;
  315.     }
  316.  
  317.     /**
  318.      * Make a primitive array class
  319.      */
  320.  
  321.     private Class primitiveType(char type) {
  322.     switch (type) {
  323.     case 'B': return byte.class;
  324.         case 'C': return char.class;
  325.     case 'D': return double.class;
  326.     case 'F': return float.class;
  327.     case 'I': return int.class;
  328.     case 'J': return long.class;
  329.     case 'S': return short.class;
  330.     case 'Z': return boolean.class;
  331.     default: return null;
  332.     }
  333.     }
  334.  
  335.     /**
  336.      * Use the given ClassLoader rather than using the system class
  337.      */
  338.     protected Class resolveClass(ObjectStreamClass classDesc)
  339.     throws IOException, ClassNotFoundException {
  340.  
  341.     String cname = classDesc.getName();
  342.     if (cname.startsWith("[")) {
  343.         // An array
  344.         Class component;        // component class
  345.         int dcount;            // dimension
  346.         for (dcount=1; cname.charAt(dcount)=='['; dcount++) ;
  347.         if (cname.charAt(dcount) == 'L') {
  348.         component = loader.loadClass(cname.substring(dcount+1,
  349.                                  cname.length()-1));
  350.         } else {
  351.         if (cname.length() != dcount+1) {
  352.             throw new ClassNotFoundException(cname);// malformed
  353.         }
  354.         component = primitiveType(cname.charAt(dcount));
  355.         }
  356.         int dim[] = new int[dcount];
  357.         for (int i=0; i<dcount; i++) {
  358.         dim[i]=0;
  359.         }
  360.         return Array.newInstance(component, dim).getClass();
  361.     } else {
  362.         return loader.loadClass(cname);
  363.     }
  364.     }
  365. }
  366.  
  367. /**
  368.  * Package private support class.  This provides a default AppletContext
  369.  * for beans which are applets.
  370.  */
  371.  
  372. class BeansAppletContext implements AppletContext {
  373.     Applet target;
  374.     java.util.Hashtable imageCache = new java.util.Hashtable();
  375.  
  376.     BeansAppletContext(Applet target) {
  377.         this.target = target;
  378.     }
  379.  
  380.     public AudioClip getAudioClip(URL url) {
  381.     // We don't currently support audio clips in the Beans.instantiate
  382.     // applet context, unless by some luck there exists a URL content
  383.     // class that can generate an AudioClip from the audio URL.
  384.     try {
  385.         return (AudioClip) url.getContent();
  386.       } catch (Exception ex) {
  387.         return null;
  388.     }
  389.     }
  390.  
  391.     public synchronized Image getImage(URL url) {
  392.     Object o = imageCache.get(url);
  393.     if (o != null) {
  394.         return (Image)o;
  395.     }
  396.     try {
  397.         o = url.getContent();
  398.         if (o == null) {
  399.         return null;
  400.         }
  401.         if (o instanceof Image) {
  402.         imageCache.put(url, o);
  403.         return (Image) o;
  404.         }
  405.         // Otherwise it must be an ImageProducer.
  406.         Image img = target.createImage((java.awt.image.ImageProducer)o);
  407.         imageCache.put(url, img);
  408.         return img;
  409.  
  410.       } catch (Exception ex) {
  411.         return null;
  412.     }
  413.     }
  414.  
  415.     public Applet getApplet(String name) {
  416.     return null;
  417.     }
  418.  
  419.     public java.util.Enumeration getApplets() {
  420.     java.util.Vector applets = new java.util.Vector();
  421.     applets.addElement(target);
  422.     return applets.elements();    
  423.     }
  424.  
  425.     public void showDocument(URL url) {
  426.     // We do nothing.
  427.     }
  428.  
  429.     public void showDocument(URL url, String target) {
  430.     // We do nothing.
  431.     }
  432.  
  433.     public void showStatus(String status) {
  434.     // We do nothing.
  435.     }
  436. }
  437.  
  438. /**
  439.  * Package private support class.  This provides an AppletStub
  440.  * for beans which are applets.
  441.  */
  442. class BeansAppletStub implements AppletStub {
  443.     transient boolean active;
  444.     transient Applet target;
  445.     transient AppletContext context;
  446.     transient URL codeBase;
  447.     transient URL docBase;
  448.  
  449.     BeansAppletStub(Applet target,
  450.         AppletContext context, URL codeBase, 
  451.                 URL docBase) {
  452.         this.target = target;
  453.     this.context = context;
  454.     this.codeBase = codeBase;
  455.     this.docBase = docBase;
  456.     }
  457.  
  458.     public boolean isActive() {
  459.     return active;
  460.     }
  461.     
  462.     public URL getDocumentBase() {
  463.     // use the root directory of the applet's class-loader
  464.     return docBase;
  465.     }
  466.  
  467.     public URL getCodeBase() {
  468.     // use the directory where we found the class or serialized object.
  469.     return codeBase;
  470.     }
  471.  
  472.     public String getParameter(String name) {
  473.     return null;
  474.     }
  475.  
  476.     public AppletContext getAppletContext() {
  477.     return context;
  478.     }
  479.  
  480.     public void appletResize(int width, int height) {
  481.     // we do nothing.
  482.     }
  483. }
  484.