2 * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
28 import com.sun.beans.finder.ClassFinder;
30 import java.applet.Applet;
31 import java.applet.AppletContext;
32 import java.applet.AppletStub;
33 import java.applet.AudioClip;
35 import java.awt.GraphicsEnvironment;
36 import java.awt.Image;
38 import java.beans.beancontext.BeanContext;
40 import java.io.IOException;
41 import java.io.InputStream;
42 import java.io.ObjectInputStream;
43 import java.io.ObjectStreamClass;
44 import java.io.StreamCorruptedException;
48 import java.security.AccessController;
49 import java.security.PrivilegedAction;
51 import java.util.Enumeration;
52 import java.util.Hashtable;
53 import java.util.Iterator;
54 import java.util.Vector;
56 import sun.awt.AppContext;
59 * This class provides some general purpose beans control methods.
63 private static final Object DESIGN_TIME = new Object();
64 private static final Object GUI_AVAILABLE = new Object();
68 * Instantiate a JavaBean.
71 * @param cls the class-loader from which we should create
72 * the bean. If this is null, then the system
73 * class-loader is used.
74 * @param beanName the name of the bean within the class-loader.
75 * For example "sun.beanbox.foobah"
77 * @exception ClassNotFoundException if the class of a serialized
78 * object could not be found.
79 * @exception IOException if an I/O error occurs.
82 public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException {
83 return Beans.instantiate(cls, beanName, null, null);
88 * Instantiate a JavaBean.
91 * @param cls the class-loader from which we should create
92 * the bean. If this is null, then the system
93 * class-loader is used.
94 * @param beanName the name of the bean within the class-loader.
95 * For example "sun.beanbox.foobah"
96 * @param beanContext The BeanContext in which to nest the new bean
98 * @exception ClassNotFoundException if the class of a serialized
99 * object could not be found.
100 * @exception IOException if an I/O error occurs.
103 public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException {
104 return Beans.instantiate(cls, beanName, beanContext, null);
108 * Instantiate a bean.
110 * The bean is created based on a name relative to a class-loader.
111 * This name should be a dot-separated name such as "a.b.c".
113 * In Beans 1.0 the given name can indicate either a serialized object
114 * or a class. Other mechanisms may be added in the future. In
115 * beans 1.0 we first try to treat the beanName as a serialized object
116 * name then as a class name.
118 * When using the beanName as a serialized object name we convert the
119 * given beanName to a resource pathname and add a trailing ".ser" suffix.
120 * We then try to load a serialized object from that resource.
122 * For example, given a beanName of "x.y", Beans.instantiate would first
123 * try to read a serialized object from the resource "x/y.ser" and if
124 * that failed it would try to load the class "x.y" and create an
125 * instance of that class.
127 * If the bean is a subtype of java.applet.Applet, then it is given
128 * some special initialization. First, it is supplied with a default
129 * AppletStub and AppletContext. Second, if it was instantiated from
130 * a classname the applet's "init" method is called. (If the bean was
131 * deserialized this step is skipped.)
133 * Note that for beans which are applets, it is the caller's responsiblity
134 * to call "start" on the applet. For correct behaviour, this should be done
135 * after the applet has been added into a visible AWT container.
137 * Note that applets created via beans.instantiate run in a slightly
138 * different environment than applets running inside browsers. In
139 * particular, bean applets have no access to "parameters", so they may
140 * wish to provide property get/set methods to set parameter values. We
141 * advise bean-applet developers to test their bean-applets against both
142 * the JDK appletviewer (for a reference browser environment) and the
143 * BDK BeanBox (for a reference bean container).
145 * @param cls the class-loader from which we should create
146 * the bean. If this is null, then the system
147 * class-loader is used.
148 * @param beanName the name of the bean within the class-loader.
149 * For example "sun.beanbox.foobah"
150 * @param beanContext The BeanContext in which to nest the new bean
151 * @param initializer The AppletInitializer for the new bean
153 * @exception ClassNotFoundException if the class of a serialized
154 * object could not be found.
155 * @exception IOException if an I/O error occurs.
158 public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
159 throws IOException, ClassNotFoundException {
162 ObjectInputStream oins = null;
163 Object result = null;
164 boolean serialized = false;
165 IOException serex = null;
167 // If the given classloader is null, we check if an
168 // system classloader is available and (if so)
170 // Note that calls on the system class loader will
171 // look in the bootstrap class loader first.
174 cls = ClassLoader.getSystemClassLoader();
175 } catch (SecurityException ex) {
176 // We're not allowed to access the system class loader.
181 // Try to find a serialized object with this name
182 final String serName = beanName.replace('.','/').concat(".ser");
183 final ClassLoader loader = cls;
184 ins = (InputStream)AccessController.doPrivileged
185 (new PrivilegedAction() {
186 public Object run() {
188 return ClassLoader.getSystemResourceAsStream(serName);
190 return loader.getResourceAsStream(serName);
196 oins = new ObjectInputStream(ins);
198 oins = new ObjectInputStreamWithLoader(ins, cls);
200 result = oins.readObject();
203 } catch (IOException ex) {
205 // Drop through and try opening the class. But remember
206 // the exception in case we can't find the class either.
208 } catch (ClassNotFoundException ex) {
214 if (result == null) {
215 // No serialized object, try just instantiating the class
219 cl = ClassFinder.findClass(beanName, cls);
220 } catch (ClassNotFoundException ex) {
221 // There is no appropriate class. If we earlier tried to
222 // deserialize an object and got an IO exception, throw that,
223 // otherwise rethrow the ClassNotFoundException.
231 * Try to instantiate the class.
235 result = cl.newInstance();
236 } catch (Exception ex) {
237 // We have to remap the exception to one in our signature.
238 // But we pass extra information in the detail message.
239 throw new ClassNotFoundException("" + cl + " : " + ex, ex);
243 if (result != null) {
245 // Ok, if the result is an applet initialize it.
247 AppletStub stub = null;
249 if (result instanceof Applet) {
250 Applet applet = (Applet) result;
251 boolean needDummies = initializer == null;
255 // Figure our the codebase and docbase URLs. We do this
256 // by locating the URL for a known resource, and then
257 // massaging the URL.
259 // First find the "resource name" corresponding to the bean
260 // itself. So a serialzied bean "a.b.c" would imply a
261 // resource name of "a/b/c.ser" and a classname of "x.y"
262 // would imply a resource name of "x/y.class".
264 final String resourceName;
268 resourceName = beanName.replace('.','/').concat(".ser");
271 resourceName = beanName.replace('.','/').concat(".class");
274 URL objectUrl = null;
278 // Now get the URL correponding to the resource name.
280 final ClassLoader cloader = cls;
282 AccessController.doPrivileged
283 (new PrivilegedAction() {
284 public Object run() {
286 return ClassLoader.getSystemResource
289 return cloader.getResource(resourceName);
293 // If we found a URL, we try to locate the docbase by taking
294 // of the final path name component, and the code base by taking
295 // of the complete resourceName.
296 // So if we had a resourceName of "a/b/c.class" and we got an
297 // objectURL of "file://bert/classes/a/b/c.class" then we would
298 // want to set the codebase to "file://bert/classes/" and the
299 // docbase to "file://bert/classes/a/b/"
301 if (objectUrl != null) {
302 String s = objectUrl.toExternalForm();
304 if (s.endsWith(resourceName)) {
305 int ix = s.length() - resourceName.length();
306 codeBase = new URL(s.substring(0,ix));
309 ix = s.lastIndexOf('/');
312 docBase = new URL(s.substring(0,ix+1));
317 // Setup a default context and stub.
318 BeansAppletContext context = new BeansAppletContext(applet);
320 stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);
321 applet.setStub(stub);
323 initializer.initialize(applet, beanContext);
326 // now, if there is a BeanContext, add the bean, if applicable.
328 if (beanContext != null) {
329 beanContext.add(result);
332 // If it was deserialized then it was already init-ed.
333 // Otherwise we need to initialize it.
336 // We need to set a reasonable initial size, as many
337 // applets are unhappy if they are started without
338 // having been explicitly sized.
339 applet.setSize(100,100);
344 ((BeansAppletStub)stub).active = true;
345 } else initializer.activate(applet);
347 } else if (beanContext != null) beanContext.add(result);
355 * From a given bean, obtain an object representing a specified
356 * type view of that source object.
358 * The result may be the same object or a different object. If
359 * the requested target view isn't available then the given
362 * This method is provided in Beans 1.0 as a hook to allow the
363 * addition of more flexible bean behaviour in the future.
365 * @param bean Object from which we want to obtain a view.
366 * @param targetType The type of view we'd like to get.
369 public static Object getInstanceOf(Object bean, Class<?> targetType) {
374 * Check if a bean can be viewed as a given target type.
375 * The result will be true if the Beans.getInstanceof method
376 * can be used on the given bean to obtain an object that
377 * represents the specified targetType type view.
379 * @param bean Bean from which we want to obtain a view.
380 * @param targetType The type of view we'd like to get.
381 * @return "true" if the given bean supports the given targetType.
384 public static boolean isInstanceOf(Object bean, Class<?> targetType) {
385 return Introspector.isSubclass(bean.getClass(), targetType);
390 * Test if we are in design-mode.
392 * @return True if we are running in an application construction
397 public static boolean isDesignTime() {
398 Object value = AppContext.getAppContext().get(DESIGN_TIME);
399 return (value instanceof Boolean) && (Boolean) value;
403 * Determines whether beans can assume a GUI is available.
405 * @return True if we are running in an environment where beans
406 * can assume that an interactive GUI is available, so they
407 * can pop up dialog boxes, etc. This will normally return
408 * true in a windowing environment, and will normally return
409 * false in a server environment or if an application is
410 * running as part of a batch job.
415 public static boolean isGuiAvailable() {
416 Object value = AppContext.getAppContext().get(GUI_AVAILABLE);
417 return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless();
421 * Used to indicate whether of not we are running in an application
422 * builder environment.
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.
430 * @param isDesignTime True if we're in an application builder tool.
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
437 public static void setDesignTime(boolean isDesignTime)
438 throws SecurityException {
439 SecurityManager sm = System.getSecurityManager();
441 sm.checkPropertiesAccess();
443 AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime));
447 * Used to indicate whether of not we are running in an environment
448 * where GUI interaction is available.
450 * <p>Note that this method is security checked
451 * and is not available to (for example) untrusted applets.
452 * More specifically, if there is a security manager,
453 * its <code>checkPropertiesAccess</code>
454 * method is called. This could result in a SecurityException.
456 * @param isGuiAvailable True if GUI interaction is available.
457 * @exception SecurityException if a security manager exists and its
458 * <code>checkPropertiesAccess</code> method doesn't allow setting
459 * of system properties.
460 * @see SecurityManager#checkPropertiesAccess
463 public static void setGuiAvailable(boolean isGuiAvailable)
464 throws SecurityException {
465 SecurityManager sm = System.getSecurityManager();
467 sm.checkPropertiesAccess();
469 AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable));
474 * This subclass of ObjectInputStream delegates loading of classes to
475 * an existing ClassLoader.
478 class ObjectInputStreamWithLoader extends ObjectInputStream
480 private ClassLoader loader;
483 * Loader must be non-null;
486 public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
487 throws IOException, StreamCorruptedException {
490 if (loader == null) {
491 throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
493 this.loader = loader;
497 * Use the given ClassLoader rather than using the system class
499 protected Class resolveClass(ObjectStreamClass classDesc)
500 throws IOException, ClassNotFoundException {
502 String cname = classDesc.getName();
503 return ClassFinder.resolveClass(cname, this.loader);
508 * Package private support class. This provides a default AppletContext
509 * for beans which are applets.
512 class BeansAppletContext implements AppletContext {
514 Hashtable imageCache = new Hashtable();
516 BeansAppletContext(Applet target) {
517 this.target = target;
520 public AudioClip getAudioClip(URL url) {
521 // We don't currently support audio clips in the Beans.instantiate
522 // applet context, unless by some luck there exists a URL content
523 // class that can generate an AudioClip from the audio URL.
525 return (AudioClip) url.getContent();
526 } catch (Exception ex) {
531 public synchronized Image getImage(URL url) {
532 Object o = imageCache.get(url);
537 o = url.getContent();
541 if (o instanceof Image) {
542 imageCache.put(url, o);
545 // Otherwise it must be an ImageProducer.
546 Image img = target.createImage((java.awt.image.ImageProducer)o);
547 imageCache.put(url, img);
550 } catch (Exception ex) {
555 public Applet getApplet(String name) {
559 public Enumeration getApplets() {
560 Vector applets = new Vector();
561 applets.addElement(target);
562 return applets.elements();
565 public void showDocument(URL url) {
569 public void showDocument(URL url, String target) {
573 public void showStatus(String status) {
577 public void setStream(String key, InputStream stream)throws IOException{
581 public InputStream getStream(String key){
586 public Iterator getStreamKeys(){
593 * Package private support class. This provides an AppletStub
594 * for beans which are applets.
596 class BeansAppletStub implements AppletStub {
597 transient boolean active;
598 transient Applet target;
599 transient AppletContext context;
600 transient URL codeBase;
601 transient URL docBase;
603 BeansAppletStub(Applet target,
604 AppletContext context, URL codeBase,
606 this.target = target;
607 this.context = context;
608 this.codeBase = codeBase;
609 this.docBase = docBase;
612 public boolean isActive() {
616 public URL getDocumentBase() {
617 // use the root directory of the applet's class-loader
621 public URL getCodeBase() {
622 // use the directory where we found the class or serialized object.
626 public String getParameter(String name) {
630 public AppletContext getAppletContext() {
634 public void appletResize(int width, int height) {