001/* java.beans.Beans 002 Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038package java.beans; 039 040import gnu.java.beans.DummyAppletStub; 041import gnu.java.io.ClassLoaderObjectInputStream; 042 043import java.applet.Applet; 044import java.beans.beancontext.BeanContext; 045import java.io.IOException; 046import java.io.ObjectInputStream; 047import java.net.URL; 048 049/** 050 * <code>Beans</code> provides some helper methods that allow the basic 051 * operations of Bean-ness. 052 * 053 * @author John Keiser 054 * @author Robert Schuster 055 * 056 * @since 1.1 057 * @status updated to 1.4 058 * 059 */ 060public class Beans 061{ 062 static boolean designTime = false; 063 static boolean guiAvailable = true; 064 065 /** 066 * Once again, we have a java.beans class with only 067 * static methods that can be instantiated. When 068 * will the madness end? :) 069 */ 070 public Beans() 071 { 072 // Does intentionally nothing here. 073 } 074 075 /** Creates a bean. 076 * <p>This is a convenience method that calls <code>instantiate(cl, beanName, null, null)</code>.</p> 077 * 078 * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) 079 * @param cl ClassLoader to be used or <code>null</code> for the system classloader. 080 * @param beanName Name of a serialized bean or class name. 081 * @return A newly created bean. 082 * @throws IOException If access of an IO resource failed. 083 * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. 084 */ 085 public static Object instantiate(ClassLoader cl, String beanName) 086 throws IOException, ClassNotFoundException 087 { 088 return instantiate(cl, beanName, null, null); 089 } 090 091 /** Creates a bean. 092 * 093 * <p>This is a convenience method that calls <code>instantiate(cl, beanName, beanContext, null)</code>.</p> 094 * 095 * @see instantiate(ClassLoader, String, BeanContext, AppletInitializer) 096 * @param cl ClassLoader to be used or <code>null</code> for the system classloader. 097 * @param beanName Name of a serialized bean or class name. 098 * @param beanContext Context to which the newly created Bean should be added. 099 * @return A newly created bean. 100 * @throws IOException If access of an IO resource failed. 101 * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. 102 */ 103 public static Object instantiate( 104 ClassLoader cl, 105 String beanName, 106 BeanContext beanContext) 107 throws IOException, ClassNotFoundException 108 { 109 return instantiate(cl, beanName, beanContext, null); 110 } 111 112 /** Instantiates a bean according to Beans 1.0. 113 * 114 * <p>In Beans 1.0 the instantiation scheme is as follows:</p> 115 * <p>The name should be dot-separated (e.g "place.for.beans.myBean") and indicate either a 116 * serialized object or a class name. In the first case all dots in the name are replaced with 117 * slashes ('/') and ".ser" is appended ("place.for.beans.myBean" becomes "place/for/beans/myBean.ser"). 118 * The bean is then loaded as an application or system resource depending on whether a 119 * <code>ClassLoader</code> was provided.</p> 120 * 121 * <p>If no such resource exists or if it contains no bean the name is interpreted as a class name of 122 * which an instance is then created.</p> 123 * 124 * <p>If a <code>BeanContext</code> instance is available the created bean is added to it.</p> 125 * 126 * <p>If the created Bean is an <code>Applet</code> or subclass and an <code>AppletInitializer</code> 127 * instance is available the applet is initialized and afterwards activated using the initializer. Additionally 128 * every instantiated <code>Applet</code> bean is initialized using the {@link Applet.init} method. 129 * Furthermore every applet gets a default <code>AppletStub</code>. The <code>Applet</code>'s 130 * document base is the location of the ".ser" file if it was deserialized or the location of its class 131 * file if it was instantiated.</p> 132 * 133 * <p>A <code>ClassNotFoundException</code> is not only thrown when a class name was unknown 134 * but even when the class has public no-argument constructor 135 * (<code>IllegalAccessException</code> is wrapped) or an exception is thrown while 136 * invoking such a constructor (causing exception is wrapped).</p> 137 * 138 * @param cl ClassLoader to be used or <code>null</code> for the system classloader. 139 * @param beanName Name of a serialized bean or class name. 140 * @param beanContext Context to which the newly created Bean should be added. 141 * @param initializer The AppletInitializer which is used for initializing <code>Applet</code> beans. 142 * @return A newly created bean. 143 * @throws IOException If access of an IO resource failed. 144 * @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class. 145 */ 146 public static Object instantiate( 147 ClassLoader cl, 148 String beanName, 149 BeanContext beanContext, 150 AppletInitializer initializer) 151 throws IOException, ClassNotFoundException 152 { 153 Object bean = null; 154 URL beanLocation = null; 155 URL classLocation = null; 156 157 // Converts bean name into a resource name (eg. "a.b.c" -> "a/b/c"). 158 String resourceName = beanName.replace('.', '/'); 159 160 /* Tries to get an input stream of the Bean, reading it as a system resource 161 * if no ClassLoader is present or as an application resource if a classloader 162 * is given. 163 */ 164 beanLocation = 165 (cl == null) 166 ? ClassLoader.getSystemResource(resourceName + ".ser") 167 : cl.getResource(resourceName + ".ser"); 168 169 // Reads the serialized Bean from the returned URL. 170 if (beanLocation != null) 171 { 172 // Deserializes the bean instance. 173 ObjectInputStream ois = 174 (cl == null) 175 ? new ObjectInputStream(beanLocation.openStream()) 176 : new ClassLoaderObjectInputStream( 177 beanLocation.openStream(), 178 cl); 179 180 bean = ois.readObject(); 181 182 /* Implementation note: The result of ObjectInputStream.readObject() 183 * may have been null at this point (its a valid value to deserialize) 184 * and we explicitly want to try instantiation in such a case 185 * (this is important for compatibility). 186 */ 187 } 188 189 // Instantiates the Bean using reflective instantiation if it has not been created yet. 190 if (bean == null) 191 { 192 // Makes sure that the deserialization was NOT done. 193 beanLocation = null; 194 195 Class beanClass; 196 if (cl == null) 197 { 198 beanClass = Class.forName(beanName); 199 classLocation = 200 ClassLoader.getSystemResource(resourceName + ".class"); 201 } 202 else 203 { 204 beanClass = cl.loadClass(beanName); 205 classLocation = cl.getResource(resourceName + ".class"); 206 } 207 208 // Instantiates and optionally registers the new bean. 209 try 210 { 211 bean = beanClass.newInstance(); 212 } 213 catch(Exception e) { 214 /* Wraps all kinds of Exceptions in a ClassNotFoundException (this behavior 215 * matches with official >= 1.5, this was different for <=1.4) 216 */ 217 throw new ClassNotFoundException(null, e); 218 } 219 } 220 221 /* Applet beans are treated in the following way: 222 * - all AppletS get a default AppletStub 223 * - all AppletS are initialized using the AppletInitializer instance (if it is available) 224 * - as every other Bean Applets are added to a BeanContext if one is available 225 * - each instantiated Applet is initialized using Applet.init() (this is not done for deserialized ones) 226 * - finally AppletS get activated using the AppletInitializerS activate-Method 227 * 228 * The order of operations is important for compatibility. 229 */ 230 Applet applet = null; 231 if (bean instanceof Applet) 232 { 233 // Makes a second instanceof call unneccessary (instanceof is expensive). 234 applet = (Applet) bean; 235 236 /* The AppletStub's code and document base is set as follows: 237 * The code base is always the URL from where the class data originated 238 * (without the package name). 239 * If the Applet was deserialized the document base is the location of 240 * the serialized instance (usually the ".ser" file) otherwise its the URL 241 * from where the class data originated (usually the absolute directory 242 * location of the ".class" file). 243 */ 244 applet.setStub( 245 new DummyAppletStub( 246 applet 247 .getClass() 248 .getProtectionDomain() 249 .getCodeSource() 250 .getLocation(), 251 (beanLocation == null) ? classLocation : beanLocation)); 252 253 // Runs the Applet's initialization using an AppletInitializer. 254 if (initializer != null) 255 { 256 initializer.initialize(applet, beanContext); 257 } 258 } 259 260 // Adds the new bean to its BeanContext. 261 if (beanContext != null) 262 { 263 beanContext.add(bean); 264 } 265 266 if (applet != null) 267 { 268 269 // Initializes an instantiated (not deserialized) Applet using its own method. 270 if (beanLocation == null) 271 { 272 applet.init(); 273 } 274 275 // Runs the Applet's activation using an AppletInitializer. 276 if (initializer != null) 277 { 278 initializer.activate(applet); 279 } 280 } 281 282 return bean; 283 } 284 285 /** 286 * Returns the Bean as a different class type. 287 * This should be used instead of casting to get a new 288 * type view of a Bean, because in the future there may 289 * be new types of Bean, even Beans spanning multiple 290 * Objects. 291 * 292 * @param bean the Bean to cast. 293 * @param newClass the Class to cast it to. 294 * 295 * @return the Bean as a new view, or if the operation 296 * could not be performed, the Bean itself. 297 */ 298 public static Object getInstanceOf(Object bean, Class<?> newClass) 299 { 300 return bean; 301 } 302 303 /** 304 * Determines whether the Bean can be cast to a different 305 * class type. 306 * This should be used instead of instanceof to determine 307 * a Bean's castability, because in the future there may 308 * be new types of Bean, even Beans spanning multiple 309 * Objects. 310 * 311 * @param bean the Bean to cast. 312 * @param newBeanClass the Class to cast it to. 313 * 314 * @return whether the Bean can be cast to the class type 315 * in question. 316 */ 317 public static boolean isInstanceOf(Object bean, Class<?> newBeanClass) 318 { 319 return newBeanClass.isInstance(bean); 320 } 321 322 /** 323 * Returns whether the GUI is available to use. 324 * <p>Defaults to true.</p> 325 * 326 * @return whether the GUI is available to use. 327 */ 328 public static boolean isGuiAvailable() 329 { 330 return guiAvailable; 331 } 332 333 /** 334 * Returns whether it is design time. Design time means 335 * we are in a RAD tool. 336 * <p>Defaults to false.</p> 337 * 338 * @return whether it is design time. 339 */ 340 public static boolean isDesignTime() 341 { 342 return designTime; 343 } 344 345 /** 346 * Sets whether the GUI is available to use. 347 * 348 * @param guiAvailable whether the GUI is available to use. 349 */ 350 public static void setGuiAvailable(boolean guiAvailable) 351 throws SecurityException 352 { 353 Beans.guiAvailable = guiAvailable; 354 } 355 356 /** 357 * Sets whether it is design time. Design time means we 358 * are in a RAD tool. 359 * 360 * @param designTime whether it is design time. 361 */ 362 public static void setDesignTime(boolean designTime) 363 throws SecurityException 364 { 365 Beans.designTime = designTime; 366 } 367 368}