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