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