1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/share/classes/java/beans/Beans.java Sat Dec 01 00:00:00 2007 +0000
1.3 @@ -0,0 +1,627 @@
1.4 +/*
1.5 + * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Sun designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Sun in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
1.26 + * have any questions.
1.27 + */
1.28 +
1.29 +package java.beans;
1.30 +
1.31 +import com.sun.beans.finder.ClassFinder;
1.32 +
1.33 +import java.applet.*;
1.34 +
1.35 +import java.awt.*;
1.36 +
1.37 +import java.beans.AppletInitializer;
1.38 +
1.39 +import java.beans.beancontext.BeanContext;
1.40 +
1.41 +import java.io.*;
1.42 +
1.43 +import java.lang.reflect.Constructor;
1.44 +
1.45 +import java.net.URL;
1.46 +import java.lang.reflect.Array;
1.47 +
1.48 +/**
1.49 + * This class provides some general purpose beans control methods.
1.50 + */
1.51 +
1.52 +public class Beans {
1.53 +
1.54 + /**
1.55 + * <p>
1.56 + * Instantiate a JavaBean.
1.57 + * </p>
1.58 + *
1.59 + * @param cls the class-loader from which we should create
1.60 + * the bean. If this is null, then the system
1.61 + * class-loader is used.
1.62 + * @param beanName the name of the bean within the class-loader.
1.63 + * For example "sun.beanbox.foobah"
1.64 + *
1.65 + * @exception java.lang.ClassNotFoundException if the class of a serialized
1.66 + * object could not be found.
1.67 + * @exception java.io.IOException if an I/O error occurs.
1.68 + */
1.69 +
1.70 + public static Object instantiate(ClassLoader cls, String beanName) throws java.io.IOException, ClassNotFoundException {
1.71 + return Beans.instantiate(cls, beanName, null, null);
1.72 + }
1.73 +
1.74 + /**
1.75 + * <p>
1.76 + * Instantiate a JavaBean.
1.77 + * </p>
1.78 + *
1.79 + * @param cls the class-loader from which we should create
1.80 + * the bean. If this is null, then the system
1.81 + * class-loader is used.
1.82 + * @param beanName the name of the bean within the class-loader.
1.83 + * For example "sun.beanbox.foobah"
1.84 + * @param beanContext The BeanContext in which to nest the new bean
1.85 + *
1.86 + * @exception java.lang.ClassNotFoundException if the class of a serialized
1.87 + * object could not be found.
1.88 + * @exception java.io.IOException if an I/O error occurs.
1.89 + */
1.90 +
1.91 + public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws java.io.IOException, ClassNotFoundException {
1.92 + return Beans.instantiate(cls, beanName, beanContext, null);
1.93 + }
1.94 +
1.95 + /**
1.96 + * Instantiate a bean.
1.97 + * <p>
1.98 + * The bean is created based on a name relative to a class-loader.
1.99 + * This name should be a dot-separated name such as "a.b.c".
1.100 + * <p>
1.101 + * In Beans 1.0 the given name can indicate either a serialized object
1.102 + * or a class. Other mechanisms may be added in the future. In
1.103 + * beans 1.0 we first try to treat the beanName as a serialized object
1.104 + * name then as a class name.
1.105 + * <p>
1.106 + * When using the beanName as a serialized object name we convert the
1.107 + * given beanName to a resource pathname and add a trailing ".ser" suffix.
1.108 + * We then try to load a serialized object from that resource.
1.109 + * <p>
1.110 + * For example, given a beanName of "x.y", Beans.instantiate would first
1.111 + * try to read a serialized object from the resource "x/y.ser" and if
1.112 + * that failed it would try to load the class "x.y" and create an
1.113 + * instance of that class.
1.114 + * <p>
1.115 + * If the bean is a subtype of java.applet.Applet, then it is given
1.116 + * some special initialization. First, it is supplied with a default
1.117 + * AppletStub and AppletContext. Second, if it was instantiated from
1.118 + * a classname the applet's "init" method is called. (If the bean was
1.119 + * deserialized this step is skipped.)
1.120 + * <p>
1.121 + * Note that for beans which are applets, it is the caller's responsiblity
1.122 + * to call "start" on the applet. For correct behaviour, this should be done
1.123 + * after the applet has been added into a visible AWT container.
1.124 + * <p>
1.125 + * Note that applets created via beans.instantiate run in a slightly
1.126 + * different environment than applets running inside browsers. In
1.127 + * particular, bean applets have no access to "parameters", so they may
1.128 + * wish to provide property get/set methods to set parameter values. We
1.129 + * advise bean-applet developers to test their bean-applets against both
1.130 + * the JDK appletviewer (for a reference browser environment) and the
1.131 + * BDK BeanBox (for a reference bean container).
1.132 + *
1.133 + * @param cls the class-loader from which we should create
1.134 + * the bean. If this is null, then the system
1.135 + * class-loader is used.
1.136 + * @param beanName the name of the bean within the class-loader.
1.137 + * For example "sun.beanbox.foobah"
1.138 + * @param beanContext The BeanContext in which to nest the new bean
1.139 + * @param initializer The AppletInitializer for the new bean
1.140 + *
1.141 + * @exception java.lang.ClassNotFoundException if the class of a serialized
1.142 + * object could not be found.
1.143 + * @exception java.io.IOException if an I/O error occurs.
1.144 + */
1.145 +
1.146 + public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
1.147 + throws java.io.IOException, ClassNotFoundException {
1.148 +
1.149 + java.io.InputStream ins;
1.150 + java.io.ObjectInputStream oins = null;
1.151 + Object result = null;
1.152 + boolean serialized = false;
1.153 + java.io.IOException serex = null;
1.154 +
1.155 + // If the given classloader is null, we check if an
1.156 + // system classloader is available and (if so)
1.157 + // use that instead.
1.158 + // Note that calls on the system class loader will
1.159 + // look in the bootstrap class loader first.
1.160 + if (cls == null) {
1.161 + try {
1.162 + cls = ClassLoader.getSystemClassLoader();
1.163 + } catch (SecurityException ex) {
1.164 + // We're not allowed to access the system class loader.
1.165 + // Drop through.
1.166 + }
1.167 + }
1.168 +
1.169 + // Try to find a serialized object with this name
1.170 + final String serName = beanName.replace('.','/').concat(".ser");
1.171 + final ClassLoader loader = cls;
1.172 + ins = (InputStream)java.security.AccessController.doPrivileged
1.173 + (new java.security.PrivilegedAction() {
1.174 + public Object run() {
1.175 + if (loader == null)
1.176 + return ClassLoader.getSystemResourceAsStream(serName);
1.177 + else
1.178 + return loader.getResourceAsStream(serName);
1.179 + }
1.180 + });
1.181 + if (ins != null) {
1.182 + try {
1.183 + if (cls == null) {
1.184 + oins = new ObjectInputStream(ins);
1.185 + } else {
1.186 + oins = new ObjectInputStreamWithLoader(ins, cls);
1.187 + }
1.188 + result = oins.readObject();
1.189 + serialized = true;
1.190 + oins.close();
1.191 + } catch (java.io.IOException ex) {
1.192 + ins.close();
1.193 + // Drop through and try opening the class. But remember
1.194 + // the exception in case we can't find the class either.
1.195 + serex = ex;
1.196 + } catch (ClassNotFoundException ex) {
1.197 + ins.close();
1.198 + throw ex;
1.199 + }
1.200 + }
1.201 +
1.202 + if (result == null) {
1.203 + // No serialized object, try just instantiating the class
1.204 + Class cl;
1.205 +
1.206 + try {
1.207 + cl = ClassFinder.findClass(beanName, cls);
1.208 + } catch (ClassNotFoundException ex) {
1.209 + // There is no appropriate class. If we earlier tried to
1.210 + // deserialize an object and got an IO exception, throw that,
1.211 + // otherwise rethrow the ClassNotFoundException.
1.212 + if (serex != null) {
1.213 + throw serex;
1.214 + }
1.215 + throw ex;
1.216 + }
1.217 +
1.218 + /*
1.219 + * Try to instantiate the class.
1.220 + */
1.221 +
1.222 + try {
1.223 + result = cl.newInstance();
1.224 + } catch (Exception ex) {
1.225 + // We have to remap the exception to one in our signature.
1.226 + // But we pass extra information in the detail message.
1.227 + throw new ClassNotFoundException("" + cl + " : " + ex, ex);
1.228 + }
1.229 + }
1.230 +
1.231 + if (result != null) {
1.232 +
1.233 + // Ok, if the result is an applet initialize it.
1.234 +
1.235 + AppletStub stub = null;
1.236 +
1.237 + if (result instanceof Applet) {
1.238 + Applet applet = (Applet) result;
1.239 + boolean needDummies = initializer == null;
1.240 +
1.241 + if (needDummies) {
1.242 +
1.243 + // Figure our the codebase and docbase URLs. We do this
1.244 + // by locating the URL for a known resource, and then
1.245 + // massaging the URL.
1.246 +
1.247 + // First find the "resource name" corresponding to the bean
1.248 + // itself. So a serialzied bean "a.b.c" would imply a
1.249 + // resource name of "a/b/c.ser" and a classname of "x.y"
1.250 + // would imply a resource name of "x/y.class".
1.251 +
1.252 + final String resourceName;
1.253 +
1.254 + if (serialized) {
1.255 + // Serialized bean
1.256 + resourceName = beanName.replace('.','/').concat(".ser");
1.257 + } else {
1.258 + // Regular class
1.259 + resourceName = beanName.replace('.','/').concat(".class");
1.260 + }
1.261 +
1.262 + URL objectUrl = null;
1.263 + URL codeBase = null;
1.264 + URL docBase = null;
1.265 +
1.266 + // Now get the URL correponding to the resource name.
1.267 +
1.268 + final ClassLoader cloader = cls;
1.269 + objectUrl = (URL)
1.270 + java.security.AccessController.doPrivileged
1.271 + (new java.security.PrivilegedAction() {
1.272 + public Object run() {
1.273 + if (cloader == null)
1.274 + return ClassLoader.getSystemResource
1.275 + (resourceName);
1.276 + else
1.277 + return cloader.getResource(resourceName);
1.278 + }
1.279 + });
1.280 +
1.281 + // If we found a URL, we try to locate the docbase by taking
1.282 + // of the final path name component, and the code base by taking
1.283 + // of the complete resourceName.
1.284 + // So if we had a resourceName of "a/b/c.class" and we got an
1.285 + // objectURL of "file://bert/classes/a/b/c.class" then we would
1.286 + // want to set the codebase to "file://bert/classes/" and the
1.287 + // docbase to "file://bert/classes/a/b/"
1.288 +
1.289 + if (objectUrl != null) {
1.290 + String s = objectUrl.toExternalForm();
1.291 +
1.292 + if (s.endsWith(resourceName)) {
1.293 + int ix = s.length() - resourceName.length();
1.294 + codeBase = new URL(s.substring(0,ix));
1.295 + docBase = codeBase;
1.296 +
1.297 + ix = s.lastIndexOf('/');
1.298 +
1.299 + if (ix >= 0) {
1.300 + docBase = new URL(s.substring(0,ix+1));
1.301 + }
1.302 + }
1.303 + }
1.304 +
1.305 + // Setup a default context and stub.
1.306 + BeansAppletContext context = new BeansAppletContext(applet);
1.307 +
1.308 + stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);
1.309 + applet.setStub(stub);
1.310 + } else {
1.311 + initializer.initialize(applet, beanContext);
1.312 + }
1.313 +
1.314 + // now, if there is a BeanContext, add the bean, if applicable.
1.315 +
1.316 + if (beanContext != null) {
1.317 + beanContext.add(result);
1.318 + }
1.319 +
1.320 + // If it was deserialized then it was already init-ed.
1.321 + // Otherwise we need to initialize it.
1.322 +
1.323 + if (!serialized) {
1.324 + // We need to set a reasonable initial size, as many
1.325 + // applets are unhappy if they are started without
1.326 + // having been explicitly sized.
1.327 + applet.setSize(100,100);
1.328 + applet.init();
1.329 + }
1.330 +
1.331 + if (needDummies) {
1.332 + ((BeansAppletStub)stub).active = true;
1.333 + } else initializer.activate(applet);
1.334 +
1.335 + } else if (beanContext != null) beanContext.add(result);
1.336 + }
1.337 +
1.338 + return result;
1.339 + }
1.340 +
1.341 +
1.342 + /**
1.343 + * From a given bean, obtain an object representing a specified
1.344 + * type view of that source object.
1.345 + * <p>
1.346 + * The result may be the same object or a different object. If
1.347 + * the requested target view isn't available then the given
1.348 + * bean is returned.
1.349 + * <p>
1.350 + * This method is provided in Beans 1.0 as a hook to allow the
1.351 + * addition of more flexible bean behaviour in the future.
1.352 + *
1.353 + * @param bean Object from which we want to obtain a view.
1.354 + * @param targetType The type of view we'd like to get.
1.355 + *
1.356 + */
1.357 + public static Object getInstanceOf(Object bean, Class<?> targetType) {
1.358 + return bean;
1.359 + }
1.360 +
1.361 + /**
1.362 + * Check if a bean can be viewed as a given target type.
1.363 + * The result will be true if the Beans.getInstanceof method
1.364 + * can be used on the given bean to obtain an object that
1.365 + * represents the specified targetType type view.
1.366 + *
1.367 + * @param bean Bean from which we want to obtain a view.
1.368 + * @param targetType The type of view we'd like to get.
1.369 + * @return "true" if the given bean supports the given targetType.
1.370 + *
1.371 + */
1.372 + public static boolean isInstanceOf(Object bean, Class<?> targetType) {
1.373 + return Introspector.isSubclass(bean.getClass(), targetType);
1.374 + }
1.375 +
1.376 +
1.377 + /**
1.378 + * Test if we are in design-mode.
1.379 + *
1.380 + * @return True if we are running in an application construction
1.381 + * environment.
1.382 + *
1.383 + * @see java.beans.DesignMode
1.384 + */
1.385 + public static boolean isDesignTime() {
1.386 + return designTime;
1.387 + }
1.388 +
1.389 + /**
1.390 + * Determines whether beans can assume a GUI is available.
1.391 + *
1.392 + * @return True if we are running in an environment where beans
1.393 + * can assume that an interactive GUI is available, so they
1.394 + * can pop up dialog boxes, etc. This will normally return
1.395 + * true in a windowing environment, and will normally return
1.396 + * false in a server environment or if an application is
1.397 + * running as part of a batch job.
1.398 + *
1.399 + * @see java.beans.Visibility
1.400 + *
1.401 + */
1.402 + public static boolean isGuiAvailable() {
1.403 + return guiAvailable;
1.404 + }
1.405 +
1.406 + /**
1.407 + * Used to indicate whether of not we are running in an application
1.408 + * builder environment.
1.409 + *
1.410 + * <p>Note that this method is security checked
1.411 + * and is not available to (for example) untrusted applets.
1.412 + * More specifically, if there is a security manager,
1.413 + * its <code>checkPropertiesAccess</code>
1.414 + * method is called. This could result in a SecurityException.
1.415 + *
1.416 + * @param isDesignTime True if we're in an application builder tool.
1.417 + * @exception SecurityException if a security manager exists and its
1.418 + * <code>checkPropertiesAccess</code> method doesn't allow setting
1.419 + * of system properties.
1.420 + * @see SecurityManager#checkPropertiesAccess
1.421 + */
1.422 +
1.423 + public static void setDesignTime(boolean isDesignTime)
1.424 + throws SecurityException {
1.425 + SecurityManager sm = System.getSecurityManager();
1.426 + if (sm != null) {
1.427 + sm.checkPropertiesAccess();
1.428 + }
1.429 + designTime = isDesignTime;
1.430 + }
1.431 +
1.432 + /**
1.433 + * Used to indicate whether of not we are running in an environment
1.434 + * where GUI interaction is available.
1.435 + *
1.436 + * <p>Note that this method is security checked
1.437 + * and is not available to (for example) untrusted applets.
1.438 + * More specifically, if there is a security manager,
1.439 + * its <code>checkPropertiesAccess</code>
1.440 + * method is called. This could result in a SecurityException.
1.441 + *
1.442 + * @param isGuiAvailable True if GUI interaction is available.
1.443 + * @exception SecurityException if a security manager exists and its
1.444 + * <code>checkPropertiesAccess</code> method doesn't allow setting
1.445 + * of system properties.
1.446 + * @see SecurityManager#checkPropertiesAccess
1.447 + */
1.448 +
1.449 + public static void setGuiAvailable(boolean isGuiAvailable)
1.450 + throws SecurityException {
1.451 + SecurityManager sm = System.getSecurityManager();
1.452 + if (sm != null) {
1.453 + sm.checkPropertiesAccess();
1.454 + }
1.455 + guiAvailable = isGuiAvailable;
1.456 + }
1.457 +
1.458 +
1.459 + private static boolean designTime;
1.460 + private static boolean guiAvailable;
1.461 + static {
1.462 + guiAvailable = !GraphicsEnvironment.isHeadless();
1.463 + }
1.464 +}
1.465 +
1.466 +/**
1.467 + * This subclass of ObjectInputStream delegates loading of classes to
1.468 + * an existing ClassLoader.
1.469 + */
1.470 +
1.471 +class ObjectInputStreamWithLoader extends ObjectInputStream
1.472 +{
1.473 + private ClassLoader loader;
1.474 +
1.475 + /**
1.476 + * Loader must be non-null;
1.477 + */
1.478 +
1.479 + public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
1.480 + throws IOException, StreamCorruptedException {
1.481 +
1.482 + super(in);
1.483 + if (loader == null) {
1.484 + throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
1.485 + }
1.486 + this.loader = loader;
1.487 + }
1.488 +
1.489 + /**
1.490 + * Use the given ClassLoader rather than using the system class
1.491 + */
1.492 + protected Class resolveClass(ObjectStreamClass classDesc)
1.493 + throws IOException, ClassNotFoundException {
1.494 +
1.495 + String cname = classDesc.getName();
1.496 + return ClassFinder.resolveClass(cname, this.loader);
1.497 + }
1.498 +}
1.499 +
1.500 +/**
1.501 + * Package private support class. This provides a default AppletContext
1.502 + * for beans which are applets.
1.503 + */
1.504 +
1.505 +class BeansAppletContext implements AppletContext {
1.506 + Applet target;
1.507 + java.util.Hashtable imageCache = new java.util.Hashtable();
1.508 +
1.509 + BeansAppletContext(Applet target) {
1.510 + this.target = target;
1.511 + }
1.512 +
1.513 + public AudioClip getAudioClip(URL url) {
1.514 + // We don't currently support audio clips in the Beans.instantiate
1.515 + // applet context, unless by some luck there exists a URL content
1.516 + // class that can generate an AudioClip from the audio URL.
1.517 + try {
1.518 + return (AudioClip) url.getContent();
1.519 + } catch (Exception ex) {
1.520 + return null;
1.521 + }
1.522 + }
1.523 +
1.524 + public synchronized Image getImage(URL url) {
1.525 + Object o = imageCache.get(url);
1.526 + if (o != null) {
1.527 + return (Image)o;
1.528 + }
1.529 + try {
1.530 + o = url.getContent();
1.531 + if (o == null) {
1.532 + return null;
1.533 + }
1.534 + if (o instanceof Image) {
1.535 + imageCache.put(url, o);
1.536 + return (Image) o;
1.537 + }
1.538 + // Otherwise it must be an ImageProducer.
1.539 + Image img = target.createImage((java.awt.image.ImageProducer)o);
1.540 + imageCache.put(url, img);
1.541 + return img;
1.542 +
1.543 + } catch (Exception ex) {
1.544 + return null;
1.545 + }
1.546 + }
1.547 +
1.548 + public Applet getApplet(String name) {
1.549 + return null;
1.550 + }
1.551 +
1.552 + public java.util.Enumeration getApplets() {
1.553 + java.util.Vector applets = new java.util.Vector();
1.554 + applets.addElement(target);
1.555 + return applets.elements();
1.556 + }
1.557 +
1.558 + public void showDocument(URL url) {
1.559 + // We do nothing.
1.560 + }
1.561 +
1.562 + public void showDocument(URL url, String target) {
1.563 + // We do nothing.
1.564 + }
1.565 +
1.566 + public void showStatus(String status) {
1.567 + // We do nothing.
1.568 + }
1.569 +
1.570 + public void setStream(String key, InputStream stream)throws IOException{
1.571 + // We do nothing.
1.572 + }
1.573 +
1.574 + public InputStream getStream(String key){
1.575 + // We do nothing.
1.576 + return null;
1.577 + }
1.578 +
1.579 + public java.util.Iterator getStreamKeys(){
1.580 + // We do nothing.
1.581 + return null;
1.582 + }
1.583 +}
1.584 +
1.585 +/**
1.586 + * Package private support class. This provides an AppletStub
1.587 + * for beans which are applets.
1.588 + */
1.589 +class BeansAppletStub implements AppletStub {
1.590 + transient boolean active;
1.591 + transient Applet target;
1.592 + transient AppletContext context;
1.593 + transient URL codeBase;
1.594 + transient URL docBase;
1.595 +
1.596 + BeansAppletStub(Applet target,
1.597 + AppletContext context, URL codeBase,
1.598 + URL docBase) {
1.599 + this.target = target;
1.600 + this.context = context;
1.601 + this.codeBase = codeBase;
1.602 + this.docBase = docBase;
1.603 + }
1.604 +
1.605 + public boolean isActive() {
1.606 + return active;
1.607 + }
1.608 +
1.609 + public URL getDocumentBase() {
1.610 + // use the root directory of the applet's class-loader
1.611 + return docBase;
1.612 + }
1.613 +
1.614 + public URL getCodeBase() {
1.615 + // use the directory where we found the class or serialized object.
1.616 + return codeBase;
1.617 + }
1.618 +
1.619 + public String getParameter(String name) {
1.620 + return null;
1.621 + }
1.622 +
1.623 + public AppletContext getAppletContext() {
1.624 + return context;
1.625 + }
1.626 +
1.627 + public void appletResize(int width, int height) {
1.628 + // we do nothing.
1.629 + }
1.630 +}