duke@0: /* malenkov@1077: * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. duke@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@0: * duke@0: * This code is free software; you can redistribute it and/or modify it duke@0: * under the terms of the GNU General Public License version 2 only, as duke@0: * published by the Free Software Foundation. Sun designates this duke@0: * particular file as subject to the "Classpath" exception as provided duke@0: * by Sun in the LICENSE file that accompanied this code. duke@0: * duke@0: * This code is distributed in the hope that it will be useful, but WITHOUT duke@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@0: * version 2 for more details (a copy is included in the LICENSE file that duke@0: * accompanied this code). duke@0: * duke@0: * You should have received a copy of the GNU General Public License version duke@0: * 2 along with this work; if not, write to the Free Software Foundation, duke@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@0: * duke@0: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@0: * CA 95054 USA or visit www.sun.com if you need additional information or duke@0: * have any questions. duke@0: */ duke@0: duke@0: package java.beans; duke@0: duke@0: import com.sun.beans.finder.ClassFinder; duke@0: malenkov@1077: import java.awt.GraphicsEnvironment; duke@0: duke@0: import java.beans.beancontext.BeanContext; duke@0: malenkov@1077: import java.io.IOException; malenkov@1077: import java.io.InputStream; malenkov@1077: import java.io.ObjectInputStream; malenkov@1077: import java.io.ObjectStreamClass; malenkov@1077: import java.io.StreamCorruptedException; duke@0: malenkov@1077: malenkov@1077: import java.security.AccessController; malenkov@1077: import java.security.PrivilegedAction; malenkov@1077: malenkov@1077: import java.util.Iterator; jtulach@1238: import java.util.ServiceLoader; malenkov@1077: malenkov@1077: import sun.awt.AppContext; jtulach@1238: import sun.beans.AppletProxy; duke@0: duke@0: /** duke@0: * This class provides some general purpose beans control methods. duke@0: */ duke@0: duke@0: public class Beans { malenkov@1077: private static final Object DESIGN_TIME = new Object(); malenkov@1077: private static final Object GUI_AVAILABLE = new Object(); duke@0: duke@0: /** duke@0: *

duke@0: * Instantiate a JavaBean. duke@0: *

duke@0: * duke@0: * @param cls the class-loader from which we should create duke@0: * the bean. If this is null, then the system duke@0: * class-loader is used. duke@0: * @param beanName the name of the bean within the class-loader. duke@0: * For example "sun.beanbox.foobah" duke@0: * malenkov@1077: * @exception ClassNotFoundException if the class of a serialized duke@0: * object could not be found. malenkov@1077: * @exception IOException if an I/O error occurs. duke@0: */ duke@0: malenkov@1077: public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException { duke@0: return Beans.instantiate(cls, beanName, null, null); duke@0: } duke@0: duke@0: /** duke@0: *

duke@0: * Instantiate a JavaBean. duke@0: *

duke@0: * duke@0: * @param cls the class-loader from which we should create duke@0: * the bean. If this is null, then the system duke@0: * class-loader is used. duke@0: * @param beanName the name of the bean within the class-loader. duke@0: * For example "sun.beanbox.foobah" duke@0: * @param beanContext The BeanContext in which to nest the new bean duke@0: * malenkov@1077: * @exception ClassNotFoundException if the class of a serialized duke@0: * object could not be found. malenkov@1077: * @exception IOException if an I/O error occurs. duke@0: */ duke@0: malenkov@1077: public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException { duke@0: return Beans.instantiate(cls, beanName, beanContext, null); duke@0: } duke@0: duke@0: /** duke@0: * Instantiate a bean. duke@0: *

duke@0: * The bean is created based on a name relative to a class-loader. duke@0: * This name should be a dot-separated name such as "a.b.c". duke@0: *

duke@0: * In Beans 1.0 the given name can indicate either a serialized object duke@0: * or a class. Other mechanisms may be added in the future. In duke@0: * beans 1.0 we first try to treat the beanName as a serialized object duke@0: * name then as a class name. duke@0: *

duke@0: * When using the beanName as a serialized object name we convert the duke@0: * given beanName to a resource pathname and add a trailing ".ser" suffix. duke@0: * We then try to load a serialized object from that resource. duke@0: *

duke@0: * For example, given a beanName of "x.y", Beans.instantiate would first duke@0: * try to read a serialized object from the resource "x/y.ser" and if duke@0: * that failed it would try to load the class "x.y" and create an duke@0: * instance of that class. duke@0: *

duke@0: * If the bean is a subtype of java.applet.Applet, then it is given duke@0: * some special initialization. First, it is supplied with a default duke@0: * AppletStub and AppletContext. Second, if it was instantiated from duke@0: * a classname the applet's "init" method is called. (If the bean was duke@0: * deserialized this step is skipped.) duke@0: *

duke@0: * Note that for beans which are applets, it is the caller's responsiblity duke@0: * to call "start" on the applet. For correct behaviour, this should be done duke@0: * after the applet has been added into a visible AWT container. duke@0: *

duke@0: * Note that applets created via beans.instantiate run in a slightly duke@0: * different environment than applets running inside browsers. In duke@0: * particular, bean applets have no access to "parameters", so they may duke@0: * wish to provide property get/set methods to set parameter values. We duke@0: * advise bean-applet developers to test their bean-applets against both duke@0: * the JDK appletviewer (for a reference browser environment) and the duke@0: * BDK BeanBox (for a reference bean container). duke@0: * duke@0: * @param cls the class-loader from which we should create duke@0: * the bean. If this is null, then the system duke@0: * class-loader is used. duke@0: * @param beanName the name of the bean within the class-loader. duke@0: * For example "sun.beanbox.foobah" duke@0: * @param beanContext The BeanContext in which to nest the new bean duke@0: * @param initializer The AppletInitializer for the new bean duke@0: * malenkov@1077: * @exception ClassNotFoundException if the class of a serialized duke@0: * object could not be found. malenkov@1077: * @exception IOException if an I/O error occurs. duke@0: */ duke@0: jtulach@1238: public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, jtulach@1238: /** TBD: Oops , this is bad. The AppletInitializer is used from jtulach@1238: * public API. I have not noticed that sooner. Opps. jtulach@1238: AppletInitializer initializer jtulach@1238: * meanwhile turning into object, but this cannot be final solution: jtulach@1238: */ jtulach@1238: Object initializer jtulach@1238: ) throws IOException, ClassNotFoundException { duke@0: malenkov@1077: InputStream ins; malenkov@1077: ObjectInputStream oins = null; duke@0: Object result = null; duke@0: boolean serialized = false; malenkov@1077: IOException serex = null; duke@0: duke@0: // If the given classloader is null, we check if an duke@0: // system classloader is available and (if so) duke@0: // use that instead. duke@0: // Note that calls on the system class loader will duke@0: // look in the bootstrap class loader first. duke@0: if (cls == null) { duke@0: try { duke@0: cls = ClassLoader.getSystemClassLoader(); duke@0: } catch (SecurityException ex) { duke@0: // We're not allowed to access the system class loader. duke@0: // Drop through. duke@0: } duke@0: } duke@0: duke@0: // Try to find a serialized object with this name duke@0: final String serName = beanName.replace('.','/').concat(".ser"); duke@0: final ClassLoader loader = cls; malenkov@1077: ins = (InputStream)AccessController.doPrivileged malenkov@1077: (new PrivilegedAction() { duke@0: public Object run() { duke@0: if (loader == null) duke@0: return ClassLoader.getSystemResourceAsStream(serName); duke@0: else duke@0: return loader.getResourceAsStream(serName); duke@0: } duke@0: }); duke@0: if (ins != null) { duke@0: try { duke@0: if (cls == null) { duke@0: oins = new ObjectInputStream(ins); duke@0: } else { duke@0: oins = new ObjectInputStreamWithLoader(ins, cls); duke@0: } duke@0: result = oins.readObject(); duke@0: serialized = true; duke@0: oins.close(); malenkov@1077: } catch (IOException ex) { duke@0: ins.close(); duke@0: // Drop through and try opening the class. But remember duke@0: // the exception in case we can't find the class either. duke@0: serex = ex; duke@0: } catch (ClassNotFoundException ex) { duke@0: ins.close(); duke@0: throw ex; duke@0: } duke@0: } duke@0: duke@0: if (result == null) { duke@0: // No serialized object, try just instantiating the class duke@0: Class cl; duke@0: duke@0: try { duke@0: cl = ClassFinder.findClass(beanName, cls); duke@0: } catch (ClassNotFoundException ex) { duke@0: // There is no appropriate class. If we earlier tried to duke@0: // deserialize an object and got an IO exception, throw that, duke@0: // otherwise rethrow the ClassNotFoundException. duke@0: if (serex != null) { duke@0: throw serex; duke@0: } duke@0: throw ex; duke@0: } duke@0: duke@0: /* duke@0: * Try to instantiate the class. duke@0: */ duke@0: jtulach@1238: try { duke@0: result = cl.newInstance(); duke@0: } catch (Exception ex) { duke@0: // We have to remap the exception to one in our signature. duke@0: // But we pass extra information in the detail message. duke@0: throw new ClassNotFoundException("" + cl + " : " + ex, ex); duke@0: } duke@0: } duke@0: duke@0: if (result != null) { duke@0: duke@0: // Ok, if the result is an applet initialize it. jtulach@1238: Iterator it = ServiceLoader.load(AppletProxy.class).iterator(); jtulach@1238: AppletProxy ap = it.hasNext() ? it.next() : null; jtulach@1238: if (ap != null || !ap.initialize( jtulach@1238: result, initializer, serialized, beanName, beanContext, cls jtulach@1238: )) { jtulach@1238: if (beanContext != null) beanContext.add(result); jtulach@1238: } duke@0: } duke@0: duke@0: return result; duke@0: } duke@0: duke@0: duke@0: /** duke@0: * From a given bean, obtain an object representing a specified duke@0: * type view of that source object. duke@0: *

duke@0: * The result may be the same object or a different object. If duke@0: * the requested target view isn't available then the given duke@0: * bean is returned. duke@0: *

duke@0: * This method is provided in Beans 1.0 as a hook to allow the duke@0: * addition of more flexible bean behaviour in the future. duke@0: * duke@0: * @param bean Object from which we want to obtain a view. duke@0: * @param targetType The type of view we'd like to get. duke@0: * duke@0: */ duke@0: public static Object getInstanceOf(Object bean, Class targetType) { duke@0: return bean; duke@0: } duke@0: duke@0: /** duke@0: * Check if a bean can be viewed as a given target type. duke@0: * The result will be true if the Beans.getInstanceof method duke@0: * can be used on the given bean to obtain an object that duke@0: * represents the specified targetType type view. duke@0: * duke@0: * @param bean Bean from which we want to obtain a view. duke@0: * @param targetType The type of view we'd like to get. duke@0: * @return "true" if the given bean supports the given targetType. duke@0: * duke@0: */ duke@0: public static boolean isInstanceOf(Object bean, Class targetType) { duke@0: return Introspector.isSubclass(bean.getClass(), targetType); duke@0: } duke@0: duke@0: duke@0: /** duke@0: * Test if we are in design-mode. duke@0: * duke@0: * @return True if we are running in an application construction duke@0: * environment. duke@0: * malenkov@1077: * @see DesignMode duke@0: */ duke@0: public static boolean isDesignTime() { malenkov@1077: Object value = AppContext.getAppContext().get(DESIGN_TIME); malenkov@1077: return (value instanceof Boolean) && (Boolean) value; duke@0: } duke@0: duke@0: /** duke@0: * Determines whether beans can assume a GUI is available. duke@0: * duke@0: * @return True if we are running in an environment where beans duke@0: * can assume that an interactive GUI is available, so they duke@0: * can pop up dialog boxes, etc. This will normally return duke@0: * true in a windowing environment, and will normally return duke@0: * false in a server environment or if an application is duke@0: * running as part of a batch job. duke@0: * malenkov@1077: * @see Visibility duke@0: * duke@0: */ duke@0: public static boolean isGuiAvailable() { malenkov@1077: Object value = AppContext.getAppContext().get(GUI_AVAILABLE); malenkov@1077: return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless(); duke@0: } duke@0: duke@0: /** duke@0: * Used to indicate whether of not we are running in an application duke@0: * builder environment. duke@0: * duke@0: *

Note that this method is security checked duke@0: * and is not available to (for example) untrusted applets. duke@0: * More specifically, if there is a security manager, duke@0: * its checkPropertiesAccess duke@0: * method is called. This could result in a SecurityException. duke@0: * duke@0: * @param isDesignTime True if we're in an application builder tool. duke@0: * @exception SecurityException if a security manager exists and its duke@0: * checkPropertiesAccess method doesn't allow setting duke@0: * of system properties. duke@0: * @see SecurityManager#checkPropertiesAccess duke@0: */ duke@0: duke@0: public static void setDesignTime(boolean isDesignTime) duke@0: throws SecurityException { duke@0: SecurityManager sm = System.getSecurityManager(); duke@0: if (sm != null) { duke@0: sm.checkPropertiesAccess(); duke@0: } malenkov@1077: AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime)); duke@0: } duke@0: duke@0: /** duke@0: * Used to indicate whether of not we are running in an environment duke@0: * where GUI interaction is available. duke@0: * duke@0: *

Note that this method is security checked duke@0: * and is not available to (for example) untrusted applets. duke@0: * More specifically, if there is a security manager, duke@0: * its checkPropertiesAccess duke@0: * method is called. This could result in a SecurityException. duke@0: * duke@0: * @param isGuiAvailable True if GUI interaction is available. duke@0: * @exception SecurityException if a security manager exists and its duke@0: * checkPropertiesAccess method doesn't allow setting duke@0: * of system properties. duke@0: * @see SecurityManager#checkPropertiesAccess duke@0: */ duke@0: duke@0: public static void setGuiAvailable(boolean isGuiAvailable) duke@0: throws SecurityException { duke@0: SecurityManager sm = System.getSecurityManager(); duke@0: if (sm != null) { duke@0: sm.checkPropertiesAccess(); duke@0: } malenkov@1077: AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable)); duke@0: } duke@0: } duke@0: duke@0: /** duke@0: * This subclass of ObjectInputStream delegates loading of classes to duke@0: * an existing ClassLoader. duke@0: */ duke@0: duke@0: class ObjectInputStreamWithLoader extends ObjectInputStream duke@0: { duke@0: private ClassLoader loader; duke@0: duke@0: /** duke@0: * Loader must be non-null; duke@0: */ duke@0: duke@0: public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader) duke@0: throws IOException, StreamCorruptedException { duke@0: duke@0: super(in); duke@0: if (loader == null) { duke@0: throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader"); duke@0: } duke@0: this.loader = loader; duke@0: } duke@0: duke@0: /** duke@0: * Use the given ClassLoader rather than using the system class duke@0: */ duke@0: protected Class resolveClass(ObjectStreamClass classDesc) duke@0: throws IOException, ClassNotFoundException { duke@0: duke@0: String cname = classDesc.getName(); duke@0: return ClassFinder.resolveClass(cname, this.loader); duke@0: } duke@0: } duke@0: