Path: blob/master/src/java.desktop/share/classes/java/beans/Beans.java
41152 views
/*1* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.beans;2627import com.sun.beans.finder.ClassFinder;2829import java.applet.Applet;30import java.applet.AppletContext;31import java.applet.AppletStub;32import java.applet.AudioClip;3334import java.awt.Image;3536import java.beans.beancontext.BeanContext;3738import java.io.IOException;39import java.io.InputStream;40import java.io.ObjectInputStream;41import java.io.ObjectStreamClass;42import java.io.StreamCorruptedException;4344import java.lang.reflect.Modifier;4546import java.net.URL;4748import java.util.Enumeration;49import java.util.Hashtable;50import java.util.Iterator;51import java.util.Vector;5253/**54* This class provides some general purpose beans control methods.55*56* @since 1.157*/5859public class Beans {6061/**62* Constructs a {@code Beans}.63*/64public Beans() {}6566/**67* <p>68* Instantiate a JavaBean.69* </p>70* @return a JavaBean71* @param cls the class-loader from which we should create72* the bean. If this is null, then the system73* class-loader is used.74* @param beanName the name of the bean within the class-loader.75* For example "sun.beanbox.foobah"76*77* @exception ClassNotFoundException if the class of a serialized78* object could not be found.79* @exception IOException if an I/O error occurs.80*/8182public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException {83return Beans.instantiate(cls, beanName, null, null);84}8586/**87* <p>88* Instantiate a JavaBean.89* </p>90* @return a JavaBean91*92* @param cls the class-loader from which we should create93* the bean. If this is null, then the system94* class-loader is used.95* @param beanName the name of the bean within the class-loader.96* For example "sun.beanbox.foobah"97* @param beanContext The BeanContext in which to nest the new bean98*99* @exception ClassNotFoundException if the class of a serialized100* object could not be found.101* @exception IOException if an I/O error occurs.102* @since 1.2103*/104@SuppressWarnings("deprecation")105public static Object instantiate(ClassLoader cls, String beanName,106BeanContext beanContext)107throws IOException, ClassNotFoundException {108return Beans.instantiate(cls, beanName, beanContext, null);109}110111/**112* Instantiate a bean.113* <p>114* The bean is created based on a name relative to a class-loader.115* This name should be a dot-separated name such as "a.b.c".116* <p>117* In Beans 1.0 the given name can indicate either a serialized object118* or a class. Other mechanisms may be added in the future. In119* beans 1.0 we first try to treat the beanName as a serialized object120* name then as a class name.121* <p>122* When using the beanName as a serialized object name we convert the123* given beanName to a resource pathname and add a trailing ".ser" suffix.124* We then try to load a serialized object from that resource.125* <p>126* For example, given a beanName of "x.y", Beans.instantiate would first127* try to read a serialized object from the resource "x/y.ser" and if128* that failed it would try to load the class "x.y" and create an129* instance of that class.130* <p>131* If the bean is a subtype of java.applet.Applet, then it is given132* some special initialization. First, it is supplied with a default133* AppletStub and AppletContext. Second, if it was instantiated from134* a classname the applet's "init" method is called. (If the bean was135* deserialized this step is skipped.)136* <p>137* Note that for beans which are applets, it is the caller's responsiblity138* to call "start" on the applet. For correct behaviour, this should be done139* after the applet has been added into a visible AWT container.140* <p>141* Note that applets created via beans.instantiate run in a slightly142* different environment than applets running inside browsers. In143* particular, bean applets have no access to "parameters", so they may144* wish to provide property get/set methods to set parameter values. We145* advise bean-applet developers to test their bean-applets against both146* the JDK appletviewer (for a reference browser environment) and the147* BDK BeanBox (for a reference bean container).148*149* @return a JavaBean150* @param cls the class-loader from which we should create151* the bean. If this is null, then the system152* class-loader is used.153* @param beanName the name of the bean within the class-loader.154* For example "sun.beanbox.foobah"155* @param beanContext The BeanContext in which to nest the new bean156* @param initializer The AppletInitializer for the new bean157*158* @exception ClassNotFoundException if the class of a serialized159* object could not be found.160* @exception IOException if an I/O error occurs.161* @since 1.2162*163* @deprecated It is recommended to use164* {@link #instantiate(ClassLoader, String, BeanContext)},165* because the Applet API is deprecated. See the166* <a href="../../java/applet/package-summary.html"> java.applet package167* documentation</a> for further information.168*/169@Deprecated(since = "9", forRemoval = true)170@SuppressWarnings("removal")171public static Object instantiate(ClassLoader cls, String beanName,172BeanContext beanContext,173AppletInitializer initializer)174throws IOException, ClassNotFoundException {175176InputStream ins;177ObjectInputStream oins = null;178Object result = null;179boolean serialized = false;180IOException serex = null;181182// If the given classloader is null, we check if an183// system classloader is available and (if so)184// use that instead.185// Note that calls on the system class loader will186// look in the bootstrap class loader first.187if (cls == null) {188try {189cls = ClassLoader.getSystemClassLoader();190} catch (SecurityException ex) {191// We're not allowed to access the system class loader.192// Drop through.193}194}195196// Try to find a serialized object with this name197final String serName = beanName.replace('.','/').concat(".ser");198if (cls == null)199ins = ClassLoader.getSystemResourceAsStream(serName);200else201ins = cls.getResourceAsStream(serName);202if (ins != null) {203try {204if (cls == null) {205oins = new ObjectInputStream(ins);206} else {207oins = new ObjectInputStreamWithLoader(ins, cls);208}209result = oins.readObject();210serialized = true;211oins.close();212} catch (IOException ex) {213ins.close();214// Drop through and try opening the class. But remember215// the exception in case we can't find the class either.216serex = ex;217} catch (ClassNotFoundException ex) {218ins.close();219throw ex;220}221}222223if (result == null) {224// No serialized object, try just instantiating the class225Class<?> cl;226227try {228cl = ClassFinder.findClass(beanName, cls);229} catch (ClassNotFoundException ex) {230// There is no appropriate class. If we earlier tried to231// deserialize an object and got an IO exception, throw that,232// otherwise rethrow the ClassNotFoundException.233if (serex != null) {234throw serex;235}236throw ex;237}238239if (!Modifier.isPublic(cl.getModifiers())) {240throw new ClassNotFoundException("" + cl + " : no public access");241}242243/*244* Try to instantiate the class.245*/246247try {248result = cl.newInstance();249} catch (Exception ex) {250// We have to remap the exception to one in our signature.251// But we pass extra information in the detail message.252throw new ClassNotFoundException("" + cl + " : " + ex, ex);253}254}255256if (result != null) {257258// Ok, if the result is an applet initialize it.259260AppletStub stub = null;261262if (result instanceof Applet) {263Applet applet = (Applet) result;264boolean needDummies = initializer == null;265266if (needDummies) {267268// Figure our the codebase and docbase URLs. We do this269// by locating the URL for a known resource, and then270// massaging the URL.271272// First find the "resource name" corresponding to the bean273// itself. So a serialzied bean "a.b.c" would imply a274// resource name of "a/b/c.ser" and a classname of "x.y"275// would imply a resource name of "x/y.class".276277final String resourceName;278279if (serialized) {280// Serialized bean281resourceName = beanName.replace('.','/').concat(".ser");282} else {283// Regular class284resourceName = beanName.replace('.','/').concat(".class");285}286287URL objectUrl = null;288URL codeBase = null;289URL docBase = null;290291// Now get the URL correponding to the resource name.292if (cls == null) {293objectUrl = ClassLoader.getSystemResource(resourceName);294} else295objectUrl = cls.getResource(resourceName);296297// If we found a URL, we try to locate the docbase by taking298// of the final path name component, and the code base by taking299// of the complete resourceName.300// So if we had a resourceName of "a/b/c.class" and we got an301// objectURL of "file://bert/classes/a/b/c.class" then we would302// want to set the codebase to "file://bert/classes/" and the303// docbase to "file://bert/classes/a/b/"304305if (objectUrl != null) {306String s = objectUrl.toExternalForm();307308if (s.endsWith(resourceName)) {309int ix = s.length() - resourceName.length();310codeBase = new URL(s.substring(0,ix));311docBase = codeBase;312313ix = s.lastIndexOf('/');314315if (ix >= 0) {316docBase = new URL(s.substring(0,ix+1));317}318}319}320321// Setup a default context and stub.322BeansAppletContext context = new BeansAppletContext(applet);323324stub = (AppletStub)new BeansAppletStub(applet, context, codeBase, docBase);325applet.setStub(stub);326} else {327initializer.initialize(applet, beanContext);328}329330// now, if there is a BeanContext, add the bean, if applicable.331332if (beanContext != null) {333unsafeBeanContextAdd(beanContext, result);334}335336// If it was deserialized then it was already init-ed.337// Otherwise we need to initialize it.338339if (!serialized) {340// We need to set a reasonable initial size, as many341// applets are unhappy if they are started without342// having been explicitly sized.343applet.setSize(100,100);344applet.init();345}346347if (needDummies) {348((BeansAppletStub)stub).active = true;349} else initializer.activate(applet);350351} else if (beanContext != null) unsafeBeanContextAdd(beanContext, result);352}353354return result;355}356357@SuppressWarnings("unchecked")358private static void unsafeBeanContextAdd(BeanContext beanContext, Object res) {359beanContext.add(res);360}361362/**363* From a given bean, obtain an object representing a specified364* type view of that source object.365* <p>366* The result may be the same object or a different object. If367* the requested target view isn't available then the given368* bean is returned.369* <p>370* This method is provided in Beans 1.0 as a hook to allow the371* addition of more flexible bean behaviour in the future.372*373* @return an object representing a specified type view of the374* source object375* @param bean Object from which we want to obtain a view.376* @param targetType The type of view we'd like to get.377*378*/379public static Object getInstanceOf(Object bean, Class<?> targetType) {380return bean;381}382383/**384* Check if a bean can be viewed as a given target type.385* The result will be true if the Beans.getInstanceof method386* can be used on the given bean to obtain an object that387* represents the specified targetType type view.388*389* @param bean Bean from which we want to obtain a view.390* @param targetType The type of view we'd like to get.391* @return "true" if the given bean supports the given targetType.392*393*/394public static boolean isInstanceOf(Object bean, Class<?> targetType) {395return Introspector.isSubclass(bean.getClass(), targetType);396}397398/**399* Test if we are in design-mode.400*401* @return True if we are running in an application construction402* environment.403*404* @see DesignMode405*/406public static boolean isDesignTime() {407return ThreadGroupContext.getContext().isDesignTime();408}409410/**411* Determines whether beans can assume a GUI is available.412*413* @return True if we are running in an environment where beans414* can assume that an interactive GUI is available, so they415* can pop up dialog boxes, etc. This will normally return416* true in a windowing environment, and will normally return417* false in a server environment or if an application is418* running as part of a batch job.419*420* @see Visibility421*422*/423public static boolean isGuiAvailable() {424return ThreadGroupContext.getContext().isGuiAvailable();425}426427/**428* Used to indicate whether of not we are running in an application429* builder environment.430*431* <p>Note that this method is security checked432* and is not available to (for example) untrusted applets.433* More specifically, if there is a security manager,434* its {@code checkPropertiesAccess}435* method is called. This could result in a SecurityException.436*437* @param isDesignTime True if we're in an application builder tool.438* @exception SecurityException if a security manager exists and its439* {@code checkPropertiesAccess} method doesn't allow setting440* of system properties.441* @see SecurityManager#checkPropertiesAccess442*/443444public static void setDesignTime(boolean isDesignTime)445throws SecurityException {446@SuppressWarnings("removal")447SecurityManager sm = System.getSecurityManager();448if (sm != null) {449sm.checkPropertiesAccess();450}451ThreadGroupContext.getContext().setDesignTime(isDesignTime);452}453454/**455* Used to indicate whether of not we are running in an environment456* where GUI interaction is available.457*458* <p>Note that this method is security checked459* and is not available to (for example) untrusted applets.460* More specifically, if there is a security manager,461* its {@code checkPropertiesAccess}462* method is called. This could result in a SecurityException.463*464* @param isGuiAvailable True if GUI interaction is available.465* @exception SecurityException if a security manager exists and its466* {@code checkPropertiesAccess} method doesn't allow setting467* of system properties.468* @see SecurityManager#checkPropertiesAccess469*/470471public static void setGuiAvailable(boolean isGuiAvailable)472throws SecurityException {473@SuppressWarnings("removal")474SecurityManager sm = System.getSecurityManager();475if (sm != null) {476sm.checkPropertiesAccess();477}478ThreadGroupContext.getContext().setGuiAvailable(isGuiAvailable);479}480}481482/**483* This subclass of ObjectInputStream delegates loading of classes to484* an existing ClassLoader.485*/486487class ObjectInputStreamWithLoader extends ObjectInputStream488{489private ClassLoader loader;490491/**492* Loader must be non-null;493*/494495public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)496throws IOException, StreamCorruptedException {497498super(in);499if (loader == null) {500throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");501}502this.loader = loader;503}504505/**506* Use the given ClassLoader rather than using the system class507*/508@SuppressWarnings("rawtypes")509protected Class resolveClass(ObjectStreamClass classDesc)510throws IOException, ClassNotFoundException {511512String cname = classDesc.getName();513return ClassFinder.resolveClass(cname, this.loader);514}515}516517/**518* Package private support class. This provides a default AppletContext519* for beans which are applets.520*/521@Deprecated(since = "9", forRemoval = true)522@SuppressWarnings("removal")523class BeansAppletContext implements AppletContext {524Applet target;525Hashtable<URL,Object> imageCache = new Hashtable<>();526527BeansAppletContext(Applet target) {528this.target = target;529}530531public AudioClip getAudioClip(URL url) {532// We don't currently support audio clips in the Beans.instantiate533// applet context, unless by some luck there exists a URL content534// class that can generate an AudioClip from the audio URL.535try {536return (AudioClip) url.getContent();537} catch (Exception ex) {538return null;539}540}541542public synchronized Image getImage(URL url) {543Object o = imageCache.get(url);544if (o != null) {545return (Image)o;546}547try {548o = url.getContent();549if (o == null) {550return null;551}552if (o instanceof Image) {553imageCache.put(url, o);554return (Image) o;555}556// Otherwise it must be an ImageProducer.557Image img = target.createImage((java.awt.image.ImageProducer)o);558imageCache.put(url, img);559return img;560561} catch (Exception ex) {562return null;563}564}565566public Applet getApplet(String name) {567return null;568}569570public Enumeration<Applet> getApplets() {571Vector<Applet> applets = new Vector<>();572applets.addElement(target);573return applets.elements();574}575576public void showDocument(URL url) {577// We do nothing.578}579580public void showDocument(URL url, String target) {581// We do nothing.582}583584public void showStatus(String status) {585// We do nothing.586}587588public void setStream(String key, InputStream stream)throws IOException{589// We do nothing.590}591592public InputStream getStream(String key){593// We do nothing.594return null;595}596597public Iterator<String> getStreamKeys(){598// We do nothing.599return null;600}601}602603/**604* Package private support class. This provides an AppletStub605* for beans which are applets.606*/607@Deprecated(since = "9", forRemoval = true)608@SuppressWarnings("removal")609class BeansAppletStub implements AppletStub {610transient boolean active;611transient Applet target;612transient AppletContext context;613transient URL codeBase;614transient URL docBase;615616BeansAppletStub(Applet target,617AppletContext context, URL codeBase,618URL docBase) {619this.target = target;620this.context = context;621this.codeBase = codeBase;622this.docBase = docBase;623}624625public boolean isActive() {626return active;627}628629public URL getDocumentBase() {630// use the root directory of the applet's class-loader631return docBase;632}633634public URL getCodeBase() {635// use the directory where we found the class or serialized object.636return codeBase;637}638639public String getParameter(String name) {640return null;641}642643public AppletContext getAppletContext() {644return context;645}646647public void appletResize(int width, int height) {648// we do nothing.649}650}651652653