home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / beans / Beans.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  19.5 KB  |  641 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)Beans.java    1.49 98/09/24
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.beans;
  16.  
  17. import java.applet.*;
  18.  
  19. import java.awt.*;
  20.  
  21. import java.beans.AppletInitializer;
  22.  
  23. import java.beans.beancontext.BeanContext;
  24.  
  25. import java.io.*;
  26.  
  27. import java.lang.reflect.Constructor;
  28.  
  29. import java.net.URL;
  30. import java.lang.reflect.Array;
  31.  
  32. /**
  33.  * This class provides some general purpose beans control methods.
  34.  */
  35.  
  36. public class Beans {
  37.  
  38.     /**
  39.      * <p>
  40.      * Instantiate a JavaBean.
  41.      * </p>
  42.      *
  43.      * @param     classLoader the class-loader from which we should create
  44.      *                       the bean.  If this is null, then the system
  45.      *                        class-loader is used.
  46.      * @param     beanName    the name of the bean within the class-loader.
  47.      *                     For example "sun.beanbox.foobah"
  48.      *
  49.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  50.      *              object could not be found.
  51.      * @exception java.io.IOException if an I/O error occurs.
  52.      */
  53.  
  54.     public static Object instantiate(ClassLoader cls, String beanName) throws java.io.IOException, ClassNotFoundException {
  55.     return Beans.instantiate(cls, beanName, null, null);
  56.     }
  57.  
  58.     /**
  59.      * <p>
  60.      * Instantiate a JavaBean.
  61.      * </p>
  62.      *
  63.      * @param     classLoader the class-loader from which we should create
  64.      *                       the bean.  If this is null, then the system
  65.      *                        class-loader is used.
  66.      * @param     beanName    the name of the bean within the class-loader.
  67.      *                     For example "sun.beanbox.foobah"
  68.      * @param     beanContext The BeanContext in which to nest the new bean
  69.      *
  70.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  71.      *              object could not be found.
  72.      * @exception java.io.IOException if an I/O error occurs.
  73.      */
  74.  
  75.     public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws java.io.IOException, ClassNotFoundException {
  76.     return Beans.instantiate(cls, beanName, beanContext, null);
  77.     }
  78.  
  79.     /**
  80.      * Instantiate a bean.
  81.      * <p>
  82.      * The bean is created based on a name relative to a class-loader.
  83.      * This name should be a dot-separated name such as "a.b.c".
  84.      * <p>
  85.      * In Beans 1.0 the given name can indicate either a serialized object
  86.      * or a class.  Other mechanisms may be added in the future.  In
  87.      * beans 1.0 we first try to treat the beanName as a serialized object
  88.      * name then as a class name.
  89.      * <p>
  90.      * When using the beanName as a serialized object name we convert the
  91.      * given beanName to a resource pathname and add a trailing ".ser" suffix.
  92.      * We then try to load a serialized object from that resource.
  93.      * <p>
  94.      * For example, given a beanName of "x.y", Beans.instantiate would first
  95.      * try to read a serialized object from the resource "x/y.ser" and if
  96.      * that failed it would try to load the class "x.y" and create an
  97.      * instance of that class.
  98.      * <p>
  99.      * If the bean is a subtype of java.applet.Applet, then it is given
  100.      * some special initialization.  First, it is supplied with a default
  101.      * AppletStub and AppletContext.  Second, if it was instantiated from
  102.      * a classname the applet's "init" method is called.  (If the bean was
  103.      * deserialized this step is skipped.)
  104.      * <p>
  105.      * Note that for beans which are applets, it is the caller's responsiblity
  106.      * to call "start" on the applet.  For correct behaviour, this should be done
  107.      * after the applet has been added into a visible AWT container.
  108.      * <p>
  109.      * Note that applets created via beans.instantiate run in a slightly
  110.      * different environment than applets running inside browsers.  In
  111.      * particular, bean applets have no access to "parameters", so they may
  112.      * wish to provide property get/set methods to set parameter values.  We
  113.      * advise bean-applet developers to test their bean-applets against both
  114.      * the JDK appletviewer (for a reference browser environment) and the
  115.      * BDK BeanBox (for a reference bean container).
  116.      *
  117.      * @param     classLoader the class-loader from which we should create
  118.      *                       the bean.  If this is null, then the system
  119.      *                        class-loader is used.
  120.      * @param     beanName    the name of the bean within the class-loader.
  121.      *                     For example "sun.beanbox.foobah"
  122.      * @param     beanContext The BeanContext in which to nest the new bean
  123.      * @param     initializer The AppletInitializer for the new bean
  124.      *
  125.      * @exception java.lang.ClassNotFoundException if the class of a serialized
  126.      *              object could not be found.
  127.      * @exception java.io.IOException if an I/O error occurs.
  128.      */
  129.  
  130.     public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
  131.             throws java.io.IOException, ClassNotFoundException {
  132.  
  133.     java.io.InputStream ins;
  134.     java.io.ObjectInputStream oins = null;
  135.     Object result = null;
  136.     boolean serialized = false;
  137.     java.io.IOException serex = null;
  138.  
  139.     // If the given classloader is null, we check if an
  140.     // system classloader is available and (if so)
  141.     // use that instead.
  142.     // Note that calls on the system class loader will
  143.     // look in the bootstrap class loader first.
  144.     if (cls == null) {
  145.         try {
  146.             cls = ClassLoader.getSystemClassLoader();
  147.             } catch (SecurityException ex) {
  148.             // We're not allowed to access the system class loader.
  149.             // Drop through.
  150.         }
  151.     }
  152.  
  153.     // Try to find a serialized object with this name
  154.     final String serName = beanName.replace('.','/').concat(".ser");
  155.     final ClassLoader loader = cls;
  156.     ins = (InputStream)java.security.AccessController.doPrivileged
  157.         (new java.security.PrivilegedAction() {
  158.         public Object run() {
  159.             if (loader == null)
  160.             return ClassLoader.getSystemResourceAsStream(serName);
  161.             else
  162.             return loader.getResourceAsStream(serName);
  163.         }
  164.     });
  165.     if (ins != null) {
  166.         try {
  167.             if (cls == null) {
  168.             oins = new ObjectInputStream(ins);
  169.             } else {
  170.             oins = new ObjectInputStreamWithLoader(ins, cls);
  171.             }
  172.             result = oins.readObject();
  173.         serialized = true;
  174.             oins.close();
  175.         } catch (java.io.IOException ex) {
  176.         ins.close();
  177.         // Drop through and try opening the class.  But remember
  178.         // the exception in case we can't find the class either.
  179.         serex = ex;
  180.         } catch (ClassNotFoundException ex) {
  181.         ins.close();
  182.         throw ex;
  183.         }
  184.     }
  185.  
  186.     if (result == null) {
  187.         // No serialized object, try just instantiating the class
  188.         Class cl;
  189.  
  190.         try {
  191.             if (cls == null) {
  192.                 cl = Class.forName(beanName);
  193.             } else {
  194.                 cl = cls.loadClass(beanName);
  195.             }
  196.         } catch (ClassNotFoundException ex) {
  197.         // There is no appropriate class.  If we earlier tried to
  198.         // deserialize an object and got an IO exception, throw that,
  199.         // otherwise rethrow the ClassNotFoundException.
  200.         if (serex != null) {
  201.             throw serex;
  202.         }
  203.         throw ex;
  204.         }
  205.  
  206.         /*
  207.          * Try to instantiate the class.
  208.          */
  209.  
  210.         try {
  211.             result = cl.newInstance();
  212.         } catch (Exception ex) {
  213.         // We have to remap the exception to one in our signature.
  214.         // But we pass extra information in the detail message.
  215.             throw new ClassNotFoundException("" + cl + " : " + ex);
  216.         }
  217.     }
  218.  
  219.     if (result != null) {
  220.  
  221.         // Ok, if the result is an applet initialize it.
  222.  
  223.         AppletStub stub = null;
  224.  
  225.         if (result instanceof Applet) {
  226.             Applet  applet      = (Applet) result;
  227.         boolean needDummies = initializer == null;
  228.  
  229.         if (needDummies) {
  230.  
  231.                 // Figure our the codebase and docbase URLs.  We do this
  232.                 // by locating the URL for a known resource, and then
  233.                 // massaging the URL.
  234.  
  235.                 // First find the "resource name" corresponding to the bean
  236.                 // itself.  So a serialzied bean "a.b.c" would imply a
  237.             // resource name of "a/b/c.ser" and a classname of "x.y"
  238.             // would imply a resource name of "x/y.class".
  239.  
  240.                 final String resourceName;
  241.  
  242.                 if (serialized) {
  243.                 // Serialized bean
  244.                 resourceName = beanName.replace('.','/').concat(".ser");
  245.                 } else {
  246.                 // Regular class
  247.                 resourceName = beanName.replace('.','/').concat(".class");
  248.                 }
  249.  
  250.                 URL objectUrl = null;
  251.                 URL codeBase  = null;
  252.                 URL docBase   = null;
  253.  
  254.                 // Now get the URL correponding to the resource name.
  255.  
  256.             final ClassLoader cloader = cls;
  257.             objectUrl = (URL)
  258.             java.security.AccessController.doPrivileged
  259.             (new java.security.PrivilegedAction() {
  260.                 public Object run() {
  261.                 if (cloader == null)
  262.                     return ClassLoader.getSystemResource
  263.                                 (resourceName);
  264.                 else
  265.                     return cloader.getResource(resourceName);
  266.                 }
  267.             });
  268.  
  269.                 // If we found a URL, we try to locate the docbase by taking
  270.                 // of the final path name component, and the code base by taking
  271.                    // of the complete resourceName.
  272.                 // So if we had a resourceName of "a/b/c.class" and we got an
  273.                 // objectURL of "file://bert/classes/a/b/c.class" then we would
  274.                 // want to set the codebase to "file://bert/classes/" and the
  275.                 // docbase to "file://bert/classes/a/b/"
  276.  
  277.                 if (objectUrl != null) {
  278.                 String s = objectUrl.toExternalForm();
  279.  
  280.                 if (s.endsWith(resourceName)) {
  281.                       int ix   = s.length() - resourceName.length();
  282.                     codeBase = new URL(s.substring(0,ix));
  283.                     docBase  = codeBase;
  284.  
  285.                     ix = s.lastIndexOf('/');
  286.  
  287.                     if (ix >= 0) {
  288.                         docBase = new URL(s.substring(0,ix+1));
  289.                     }
  290.                 }
  291.                 }
  292.  
  293.                 // Setup a default context and stub.
  294.                 BeansAppletContext context = new BeansAppletContext(applet);
  295.  
  296.                 stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);
  297.                 applet.setStub(stub);
  298.         } else {
  299.             initializer.initialize(applet, beanContext);
  300.         }
  301.  
  302.             // now, if there is a BeanContext, add the bean, if applicable.
  303.  
  304.             if (beanContext != null) {
  305.                 beanContext.add(result);
  306.             }
  307.  
  308.         // If it was deserialized then it was already init-ed.
  309.         // Otherwise we need to initialize it.
  310.  
  311.         if (!serialized) {
  312.             // We need to set a reasonable initial size, as many
  313.             // applets are unhappy if they are started without
  314.             // having been explicitly sized.
  315.             applet.setSize(100,100);
  316.             applet.init();
  317.         }
  318.  
  319.         if (needDummies) {
  320.           ((BeansAppletStub)stub).active = true;
  321.          } else initializer.activate(applet);
  322.  
  323.         } else if (beanContext != null) beanContext.add(result);
  324.     }
  325.  
  326.     return result;
  327.     }
  328.  
  329.  
  330.     /**
  331.      * From a given bean, obtain an object representing a specified
  332.      * type view of that source object.
  333.      * <p>
  334.      * The result may be the same object or a different object.  If
  335.      * the requested target view isn't available then the given
  336.      * bean is returned.
  337.      * <p>
  338.      * This method is provided in Beans 1.0 as a hook to allow the
  339.      * addition of more flexible bean behaviour in the future.
  340.      *
  341.      * @param obj  Object from which we want to obtain a view.
  342.      * @param targetType  The type of view we'd like to get.
  343.      *
  344.      */
  345.     public static Object getInstanceOf(Object bean, Class targetType) {
  346.         return bean;
  347.     }
  348.  
  349.     /**
  350.      * Check if a bean can be viewed as a given target type.
  351.      * The result will be true if the Beans.getInstanceof method
  352.      * can be used on the given bean to obtain an object that
  353.      * represents the specified targetType type view.
  354.      *
  355.      * @param bean  Bean from which we want to obtain a view.
  356.      * @param targetType  The type of view we'd like to get.
  357.      * @return "true" if the given bean supports the given targetType.
  358.      *
  359.      */
  360.     public static boolean isInstanceOf(Object bean, Class targetType) {
  361.     return Introspector.isSubclass(bean.getClass(), targetType);
  362.     }
  363.  
  364.  
  365.     /**
  366.      * Test if we are in design-mode.
  367.      *
  368.      * @return  True if we are running in an application construction
  369.      *        environment.
  370.      *
  371.      * @see java.beans.DesignMode
  372.      */
  373.     public static boolean isDesignTime() {
  374.     return designTime;
  375.     }
  376.  
  377.     /**
  378.      * Determines whether beans can assume a GUI is available.
  379.      *
  380.      * @return  True if we are running in an environment where beans
  381.      *       can assume that an interactive GUI is available, so they
  382.      *       can pop up dialog boxes, etc.  This will normally return
  383.      *       true in a windowing environment, and will normally return
  384.      *       false in a server environment or if an application is
  385.      *       running as part of a batch job.
  386.      *
  387.      * @see java.beans.VisibilityState
  388.      *
  389.      */
  390.     public static boolean isGuiAvailable() {
  391.     return guiAvailable;
  392.     }
  393.  
  394.     /**
  395.      * Used to indicate whether of not we are running in an application
  396.      * builder environment.  
  397.      * 
  398.      * <p>Note that this method is security checked
  399.      * and is not available to (for example) untrusted applets.
  400.      * More specifically, if there is a security manager, 
  401.      * its <code>checkPropertiesAccess</code> 
  402.      * method is called. This could result in a SecurityException.
  403.      *
  404.      * @param isDesignTime  True if we're in an application builder tool.
  405.      * @exception  SecurityException  if a security manager exists and its  
  406.      *             <code>checkPropertiesAccess</code> method doesn't allow setting
  407.      *              of system properties.
  408.      * @see SecurityManager#checkPropertiesAccess
  409.      */
  410.  
  411.     public static void setDesignTime(boolean isDesignTime)
  412.             throws SecurityException {
  413.     SecurityManager sm = System.getSecurityManager();
  414.     if (sm != null) {
  415.         sm.checkPropertiesAccess();
  416.     }
  417.     designTime = isDesignTime;
  418.     }
  419.  
  420.     /**
  421.      * Used to indicate whether of not we are running in an environment
  422.      * where GUI interaction is available.  
  423.      * 
  424.      * <p>Note that this method is security checked
  425.      * and is not available to (for example) untrusted applets.
  426.      * More specifically, if there is a security manager, 
  427.      * its <code>checkPropertiesAccess</code> 
  428.      * method is called. This could result in a SecurityException.
  429.      *
  430.      * @param isGuiAvailable  True if GUI interaction is available.
  431.      * @exception  SecurityException  if a security manager exists and its  
  432.      *             <code>checkPropertiesAccess</code> method doesn't allow setting
  433.      *              of system properties.
  434.      * @see SecurityManager#checkPropertiesAccess
  435.      */
  436.  
  437.     public static void setGuiAvailable(boolean isGuiAvailable)
  438.             throws SecurityException {
  439.     SecurityManager sm = System.getSecurityManager();
  440.     if (sm != null) {
  441.         sm.checkPropertiesAccess();
  442.     }
  443.     guiAvailable = isGuiAvailable;
  444.     }
  445.  
  446.  
  447.     private static boolean designTime;
  448.     private static boolean guiAvailable = true;
  449. }
  450.  
  451. /**
  452.  * This subclass of ObjectInputStream delegates loading of classes to
  453.  * an existing ClassLoader.
  454.  */
  455.  
  456. class ObjectInputStreamWithLoader extends ObjectInputStream
  457. {
  458.     private ClassLoader loader;
  459.  
  460.     /**
  461.      * Loader must be non-null;
  462.      */
  463.  
  464.     public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
  465.         throws IOException, StreamCorruptedException {
  466.  
  467.     super(in);
  468.     if (loader == null) {
  469.             throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
  470.     }
  471.     this.loader = loader;
  472.     }
  473.  
  474.     /**
  475.      * Make a primitive array class
  476.      */
  477.  
  478.     private Class primitiveType(char type) {
  479.     switch (type) {
  480.     case 'B': return byte.class;
  481.         case 'C': return char.class;
  482.     case 'D': return double.class;
  483.     case 'F': return float.class;
  484.     case 'I': return int.class;
  485.     case 'J': return long.class;
  486.     case 'S': return short.class;
  487.     case 'Z': return boolean.class;
  488.     default: return null;
  489.     }
  490.     }
  491.  
  492.     /**
  493.      * Use the given ClassLoader rather than using the system class
  494.      */
  495.     protected Class resolveClass(ObjectStreamClass classDesc)
  496.     throws IOException, ClassNotFoundException {
  497.  
  498.     String cname = classDesc.getName();
  499.     if (cname.startsWith("[")) {
  500.         // An array
  501.         Class component;        // component class
  502.         int dcount;            // dimension
  503.         for (dcount=1; cname.charAt(dcount)=='['; dcount++) ;
  504.         if (cname.charAt(dcount) == 'L') {
  505.         component = loader.loadClass(cname.substring(dcount+1,
  506.                                  cname.length()-1));
  507.         } else {
  508.         if (cname.length() != dcount+1) {
  509.             throw new ClassNotFoundException(cname);// malformed
  510.         }
  511.         component = primitiveType(cname.charAt(dcount));
  512.         }
  513.         int dim[] = new int[dcount];
  514.         for (int i=0; i<dcount; i++) {
  515.         dim[i]=0;
  516.         }
  517.         return Array.newInstance(component, dim).getClass();
  518.     } else {
  519.         return loader.loadClass(cname);
  520.     }
  521.     }
  522. }
  523.  
  524. /**
  525.  * Package private support class.  This provides a default AppletContext
  526.  * for beans which are applets.
  527.  */
  528.  
  529. class BeansAppletContext implements AppletContext {
  530.     Applet target;
  531.     java.util.Hashtable imageCache = new java.util.Hashtable();
  532.  
  533.     BeansAppletContext(Applet target) {
  534.         this.target = target;
  535.     }
  536.  
  537.     public AudioClip getAudioClip(URL url) {
  538.     // We don't currently support audio clips in the Beans.instantiate
  539.     // applet context, unless by some luck there exists a URL content
  540.     // class that can generate an AudioClip from the audio URL.
  541.     try {
  542.         return (AudioClip) url.getContent();
  543.       } catch (Exception ex) {
  544.         return null;
  545.     }
  546.     }
  547.  
  548.     public synchronized Image getImage(URL url) {
  549.     Object o = imageCache.get(url);
  550.     if (o != null) {
  551.         return (Image)o;
  552.     }
  553.     try {
  554.         o = url.getContent();
  555.         if (o == null) {
  556.         return null;
  557.         }
  558.         if (o instanceof Image) {
  559.         imageCache.put(url, o);
  560.         return (Image) o;
  561.         }
  562.         // Otherwise it must be an ImageProducer.
  563.         Image img = target.createImage((java.awt.image.ImageProducer)o);
  564.         imageCache.put(url, img);
  565.         return img;
  566.  
  567.       } catch (Exception ex) {
  568.         return null;
  569.     }
  570.     }
  571.  
  572.     public Applet getApplet(String name) {
  573.     return null;
  574.     }
  575.  
  576.     public java.util.Enumeration getApplets() {
  577.     java.util.Vector applets = new java.util.Vector();
  578.     applets.addElement(target);
  579.     return applets.elements();
  580.     }
  581.  
  582.     public void showDocument(URL url) {
  583.     // We do nothing.
  584.     }
  585.  
  586.     public void showDocument(URL url, String target) {
  587.     // We do nothing.
  588.     }
  589.  
  590.     public void showStatus(String status) {
  591.     // We do nothing.
  592.     }
  593. }
  594.  
  595. /**
  596.  * Package private support class.  This provides an AppletStub
  597.  * for beans which are applets.
  598.  */
  599. class BeansAppletStub implements AppletStub {
  600.     transient boolean active;
  601.     transient Applet target;
  602.     transient AppletContext context;
  603.     transient URL codeBase;
  604.     transient URL docBase;
  605.  
  606.     BeansAppletStub(Applet target,
  607.         AppletContext context, URL codeBase,
  608.                 URL docBase) {
  609.         this.target = target;
  610.     this.context = context;
  611.     this.codeBase = codeBase;
  612.     this.docBase = docBase;
  613.     }
  614.  
  615.     public boolean isActive() {
  616.     return active;
  617.     }
  618.  
  619.     public URL getDocumentBase() {
  620.     // use the root directory of the applet's class-loader
  621.     return docBase;
  622.     }
  623.  
  624.     public URL getCodeBase() {
  625.     // use the directory where we found the class or serialized object.
  626.     return codeBase;
  627.     }
  628.  
  629.     public String getParameter(String name) {
  630.     return null;
  631.     }
  632.  
  633.     public AppletContext getAppletContext() {
  634.     return context;
  635.     }
  636.  
  637.     public void appletResize(int width, int height) {
  638.     // we do nothing.
  639.     }
  640. }
  641.