src/share/classes/java/beans/Beans.java
author Jaroslav Tulach <jtulach@netbeans.org>
Wed, 17 Jun 2009 14:45:59 +0200
changeset 1239 0b5692417910
parent 1238 57914fd9382f
child 1240 4b353465cd30
permissions -rw-r--r--
Returning back the right type of the static method - now the Beans class cannot be compiled without applet module around
duke@0
     1
/*
malenkov@1077
     2
 * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
duke@0
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0
     4
 *
duke@0
     5
 * This code is free software; you can redistribute it and/or modify it
duke@0
     6
 * under the terms of the GNU General Public License version 2 only, as
duke@0
     7
 * published by the Free Software Foundation.  Sun designates this
duke@0
     8
 * particular file as subject to the "Classpath" exception as provided
duke@0
     9
 * by Sun in the LICENSE file that accompanied this code.
duke@0
    10
 *
duke@0
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
duke@0
    14
 * version 2 for more details (a copy is included in the LICENSE file that
duke@0
    15
 * accompanied this code).
duke@0
    16
 *
duke@0
    17
 * You should have received a copy of the GNU General Public License version
duke@0
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0
    20
 *
duke@0
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@0
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@0
    23
 * have any questions.
duke@0
    24
 */
duke@0
    25
duke@0
    26
package java.beans;
duke@0
    27
duke@0
    28
import com.sun.beans.finder.ClassFinder;
duke@0
    29
malenkov@1077
    30
import java.awt.GraphicsEnvironment;
duke@0
    31
duke@0
    32
import java.beans.beancontext.BeanContext;
duke@0
    33
malenkov@1077
    34
import java.io.IOException;
malenkov@1077
    35
import java.io.InputStream;
malenkov@1077
    36
import java.io.ObjectInputStream;
malenkov@1077
    37
import java.io.ObjectStreamClass;
malenkov@1077
    38
import java.io.StreamCorruptedException;
duke@0
    39
malenkov@1077
    40
malenkov@1077
    41
import java.security.AccessController;
malenkov@1077
    42
import java.security.PrivilegedAction;
malenkov@1077
    43
malenkov@1077
    44
import java.util.Iterator;
jtulach@1238
    45
import java.util.ServiceLoader;
malenkov@1077
    46
malenkov@1077
    47
import sun.awt.AppContext;
jtulach@1238
    48
import sun.beans.AppletProxy;
duke@0
    49
duke@0
    50
/**
duke@0
    51
 * This class provides some general purpose beans control methods.
duke@0
    52
 */
duke@0
    53
duke@0
    54
public class Beans {
malenkov@1077
    55
    private static final Object DESIGN_TIME = new Object();
malenkov@1077
    56
    private static final Object GUI_AVAILABLE = new Object();
duke@0
    57
duke@0
    58
    /**
duke@0
    59
     * <p>
duke@0
    60
     * Instantiate a JavaBean.
duke@0
    61
     * </p>
duke@0
    62
     *
duke@0
    63
     * @param     cls         the class-loader from which we should create
duke@0
    64
     *                        the bean.  If this is null, then the system
duke@0
    65
     *                        class-loader is used.
duke@0
    66
     * @param     beanName    the name of the bean within the class-loader.
duke@0
    67
     *                        For example "sun.beanbox.foobah"
duke@0
    68
     *
malenkov@1077
    69
     * @exception ClassNotFoundException if the class of a serialized
duke@0
    70
     *              object could not be found.
malenkov@1077
    71
     * @exception IOException if an I/O error occurs.
duke@0
    72
     */
duke@0
    73
malenkov@1077
    74
    public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException {
duke@0
    75
        return Beans.instantiate(cls, beanName, null, null);
duke@0
    76
    }
duke@0
    77
duke@0
    78
    /**
duke@0
    79
     * <p>
duke@0
    80
     * Instantiate a JavaBean.
duke@0
    81
     * </p>
duke@0
    82
     *
duke@0
    83
     * @param     cls         the class-loader from which we should create
duke@0
    84
     *                        the bean.  If this is null, then the system
duke@0
    85
     *                        class-loader is used.
duke@0
    86
     * @param     beanName    the name of the bean within the class-loader.
duke@0
    87
     *                        For example "sun.beanbox.foobah"
duke@0
    88
     * @param     beanContext The BeanContext in which to nest the new bean
duke@0
    89
     *
malenkov@1077
    90
     * @exception ClassNotFoundException if the class of a serialized
duke@0
    91
     *              object could not be found.
malenkov@1077
    92
     * @exception IOException if an I/O error occurs.
duke@0
    93
     */
duke@0
    94
malenkov@1077
    95
    public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException {
duke@0
    96
        return Beans.instantiate(cls, beanName, beanContext, null);
duke@0
    97
    }
duke@0
    98
duke@0
    99
    /**
duke@0
   100
     * Instantiate a bean.
duke@0
   101
     * <p>
duke@0
   102
     * The bean is created based on a name relative to a class-loader.
duke@0
   103
     * This name should be a dot-separated name such as "a.b.c".
duke@0
   104
     * <p>
duke@0
   105
     * In Beans 1.0 the given name can indicate either a serialized object
duke@0
   106
     * or a class.  Other mechanisms may be added in the future.  In
duke@0
   107
     * beans 1.0 we first try to treat the beanName as a serialized object
duke@0
   108
     * name then as a class name.
duke@0
   109
     * <p>
duke@0
   110
     * When using the beanName as a serialized object name we convert the
duke@0
   111
     * given beanName to a resource pathname and add a trailing ".ser" suffix.
duke@0
   112
     * We then try to load a serialized object from that resource.
duke@0
   113
     * <p>
duke@0
   114
     * For example, given a beanName of "x.y", Beans.instantiate would first
duke@0
   115
     * try to read a serialized object from the resource "x/y.ser" and if
duke@0
   116
     * that failed it would try to load the class "x.y" and create an
duke@0
   117
     * instance of that class.
duke@0
   118
     * <p>
duke@0
   119
     * If the bean is a subtype of java.applet.Applet, then it is given
duke@0
   120
     * some special initialization.  First, it is supplied with a default
duke@0
   121
     * AppletStub and AppletContext.  Second, if it was instantiated from
duke@0
   122
     * a classname the applet's "init" method is called.  (If the bean was
duke@0
   123
     * deserialized this step is skipped.)
duke@0
   124
     * <p>
duke@0
   125
     * Note that for beans which are applets, it is the caller's responsiblity
duke@0
   126
     * to call "start" on the applet.  For correct behaviour, this should be done
duke@0
   127
     * after the applet has been added into a visible AWT container.
duke@0
   128
     * <p>
duke@0
   129
     * Note that applets created via beans.instantiate run in a slightly
duke@0
   130
     * different environment than applets running inside browsers.  In
duke@0
   131
     * particular, bean applets have no access to "parameters", so they may
duke@0
   132
     * wish to provide property get/set methods to set parameter values.  We
duke@0
   133
     * advise bean-applet developers to test their bean-applets against both
duke@0
   134
     * the JDK appletviewer (for a reference browser environment) and the
duke@0
   135
     * BDK BeanBox (for a reference bean container).
duke@0
   136
     *
duke@0
   137
     * @param     cls         the class-loader from which we should create
duke@0
   138
     *                        the bean.  If this is null, then the system
duke@0
   139
     *                        class-loader is used.
duke@0
   140
     * @param     beanName    the name of the bean within the class-loader.
duke@0
   141
     *                        For example "sun.beanbox.foobah"
duke@0
   142
     * @param     beanContext The BeanContext in which to nest the new bean
duke@0
   143
     * @param     initializer The AppletInitializer for the new bean
duke@0
   144
     *
malenkov@1077
   145
     * @exception ClassNotFoundException if the class of a serialized
duke@0
   146
     *              object could not be found.
malenkov@1077
   147
     * @exception IOException if an I/O error occurs.
duke@0
   148
     */
duke@0
   149
jtulach@1239
   150
    public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
jtulach@1239
   151
                        throws IOException, ClassNotFoundException {
duke@0
   152
malenkov@1077
   153
        InputStream ins;
malenkov@1077
   154
        ObjectInputStream oins = null;
duke@0
   155
        Object result = null;
duke@0
   156
        boolean serialized = false;
malenkov@1077
   157
        IOException serex = null;
duke@0
   158
duke@0
   159
        // If the given classloader is null, we check if an
duke@0
   160
        // system classloader is available and (if so)
duke@0
   161
        // use that instead.
duke@0
   162
        // Note that calls on the system class loader will
duke@0
   163
        // look in the bootstrap class loader first.
duke@0
   164
        if (cls == null) {
duke@0
   165
            try {
duke@0
   166
                cls = ClassLoader.getSystemClassLoader();
duke@0
   167
            } catch (SecurityException ex) {
duke@0
   168
                // We're not allowed to access the system class loader.
duke@0
   169
                // Drop through.
duke@0
   170
            }
duke@0
   171
        }
duke@0
   172
duke@0
   173
        // Try to find a serialized object with this name
duke@0
   174
        final String serName = beanName.replace('.','/').concat(".ser");
duke@0
   175
        final ClassLoader loader = cls;
malenkov@1077
   176
        ins = (InputStream)AccessController.doPrivileged
malenkov@1077
   177
            (new PrivilegedAction() {
duke@0
   178
                public Object run() {
duke@0
   179
                    if (loader == null)
duke@0
   180
                        return ClassLoader.getSystemResourceAsStream(serName);
duke@0
   181
                    else
duke@0
   182
                        return loader.getResourceAsStream(serName);
duke@0
   183
                }
duke@0
   184
        });
duke@0
   185
        if (ins != null) {
duke@0
   186
            try {
duke@0
   187
                if (cls == null) {
duke@0
   188
                    oins = new ObjectInputStream(ins);
duke@0
   189
                } else {
duke@0
   190
                    oins = new ObjectInputStreamWithLoader(ins, cls);
duke@0
   191
                }
duke@0
   192
                result = oins.readObject();
duke@0
   193
                serialized = true;
duke@0
   194
                oins.close();
malenkov@1077
   195
            } catch (IOException ex) {
duke@0
   196
                ins.close();
duke@0
   197
                // Drop through and try opening the class.  But remember
duke@0
   198
                // the exception in case we can't find the class either.
duke@0
   199
                serex = ex;
duke@0
   200
            } catch (ClassNotFoundException ex) {
duke@0
   201
                ins.close();
duke@0
   202
                throw ex;
duke@0
   203
            }
duke@0
   204
        }
duke@0
   205
duke@0
   206
        if (result == null) {
duke@0
   207
            // No serialized object, try just instantiating the class
duke@0
   208
            Class cl;
duke@0
   209
duke@0
   210
            try {
duke@0
   211
                cl = ClassFinder.findClass(beanName, cls);
duke@0
   212
            } catch (ClassNotFoundException ex) {
duke@0
   213
                // There is no appropriate class.  If we earlier tried to
duke@0
   214
                // deserialize an object and got an IO exception, throw that,
duke@0
   215
                // otherwise rethrow the ClassNotFoundException.
duke@0
   216
                if (serex != null) {
duke@0
   217
                    throw serex;
duke@0
   218
                }
duke@0
   219
                throw ex;
duke@0
   220
            }
duke@0
   221
duke@0
   222
            /*
duke@0
   223
             * Try to instantiate the class.
duke@0
   224
             */
duke@0
   225
jtulach@1238
   226
                try {
duke@0
   227
                result = cl.newInstance();
duke@0
   228
            } catch (Exception ex) {
duke@0
   229
                // We have to remap the exception to one in our signature.
duke@0
   230
                // But we pass extra information in the detail message.
duke@0
   231
                throw new ClassNotFoundException("" + cl + " : " + ex, ex);
duke@0
   232
            }
duke@0
   233
        }
duke@0
   234
duke@0
   235
        if (result != null) {
duke@0
   236
duke@0
   237
            // Ok, if the result is an applet initialize it.
jtulach@1238
   238
            Iterator<AppletProxy> it = ServiceLoader.load(AppletProxy.class).iterator();
jtulach@1238
   239
            AppletProxy ap = it.hasNext() ? it.next() : null;
jtulach@1238
   240
            if (ap != null || !ap.initialize(
jtulach@1238
   241
                result, initializer, serialized, beanName, beanContext, cls
jtulach@1238
   242
            )) {
jtulach@1238
   243
                if (beanContext != null) beanContext.add(result);
jtulach@1238
   244
            }
duke@0
   245
        }
duke@0
   246
duke@0
   247
        return result;
duke@0
   248
    }
duke@0
   249
duke@0
   250
duke@0
   251
    /**
duke@0
   252
     * From a given bean, obtain an object representing a specified
duke@0
   253
     * type view of that source object.
duke@0
   254
     * <p>
duke@0
   255
     * The result may be the same object or a different object.  If
duke@0
   256
     * the requested target view isn't available then the given
duke@0
   257
     * bean is returned.
duke@0
   258
     * <p>
duke@0
   259
     * This method is provided in Beans 1.0 as a hook to allow the
duke@0
   260
     * addition of more flexible bean behaviour in the future.
duke@0
   261
     *
duke@0
   262
     * @param bean        Object from which we want to obtain a view.
duke@0
   263
     * @param targetType  The type of view we'd like to get.
duke@0
   264
     *
duke@0
   265
     */
duke@0
   266
    public static Object getInstanceOf(Object bean, Class<?> targetType) {
duke@0
   267
        return bean;
duke@0
   268
    }
duke@0
   269
duke@0
   270
    /**
duke@0
   271
     * Check if a bean can be viewed as a given target type.
duke@0
   272
     * The result will be true if the Beans.getInstanceof method
duke@0
   273
     * can be used on the given bean to obtain an object that
duke@0
   274
     * represents the specified targetType type view.
duke@0
   275
     *
duke@0
   276
     * @param bean  Bean from which we want to obtain a view.
duke@0
   277
     * @param targetType  The type of view we'd like to get.
duke@0
   278
     * @return "true" if the given bean supports the given targetType.
duke@0
   279
     *
duke@0
   280
     */
duke@0
   281
    public static boolean isInstanceOf(Object bean, Class<?> targetType) {
duke@0
   282
        return Introspector.isSubclass(bean.getClass(), targetType);
duke@0
   283
    }
duke@0
   284
duke@0
   285
duke@0
   286
    /**
duke@0
   287
     * Test if we are in design-mode.
duke@0
   288
     *
duke@0
   289
     * @return  True if we are running in an application construction
duke@0
   290
     *          environment.
duke@0
   291
     *
malenkov@1077
   292
     * @see DesignMode
duke@0
   293
     */
duke@0
   294
    public static boolean isDesignTime() {
malenkov@1077
   295
        Object value = AppContext.getAppContext().get(DESIGN_TIME);
malenkov@1077
   296
        return (value instanceof Boolean) && (Boolean) value;
duke@0
   297
    }
duke@0
   298
duke@0
   299
    /**
duke@0
   300
     * Determines whether beans can assume a GUI is available.
duke@0
   301
     *
duke@0
   302
     * @return  True if we are running in an environment where beans
duke@0
   303
     *     can assume that an interactive GUI is available, so they
duke@0
   304
     *     can pop up dialog boxes, etc.  This will normally return
duke@0
   305
     *     true in a windowing environment, and will normally return
duke@0
   306
     *     false in a server environment or if an application is
duke@0
   307
     *     running as part of a batch job.
duke@0
   308
     *
malenkov@1077
   309
     * @see Visibility
duke@0
   310
     *
duke@0
   311
     */
duke@0
   312
    public static boolean isGuiAvailable() {
malenkov@1077
   313
        Object value = AppContext.getAppContext().get(GUI_AVAILABLE);
malenkov@1077
   314
        return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless();
duke@0
   315
    }
duke@0
   316
duke@0
   317
    /**
duke@0
   318
     * Used to indicate whether of not we are running in an application
duke@0
   319
     * builder environment.
duke@0
   320
     *
duke@0
   321
     * <p>Note that this method is security checked
duke@0
   322
     * and is not available to (for example) untrusted applets.
duke@0
   323
     * More specifically, if there is a security manager,
duke@0
   324
     * its <code>checkPropertiesAccess</code>
duke@0
   325
     * method is called. This could result in a SecurityException.
duke@0
   326
     *
duke@0
   327
     * @param isDesignTime  True if we're in an application builder tool.
duke@0
   328
     * @exception  SecurityException  if a security manager exists and its
duke@0
   329
     *             <code>checkPropertiesAccess</code> method doesn't allow setting
duke@0
   330
     *              of system properties.
duke@0
   331
     * @see SecurityManager#checkPropertiesAccess
duke@0
   332
     */
duke@0
   333
duke@0
   334
    public static void setDesignTime(boolean isDesignTime)
duke@0
   335
                        throws SecurityException {
duke@0
   336
        SecurityManager sm = System.getSecurityManager();
duke@0
   337
        if (sm != null) {
duke@0
   338
            sm.checkPropertiesAccess();
duke@0
   339
        }
malenkov@1077
   340
        AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime));
duke@0
   341
    }
duke@0
   342
duke@0
   343
    /**
duke@0
   344
     * Used to indicate whether of not we are running in an environment
duke@0
   345
     * where GUI interaction is available.
duke@0
   346
     *
duke@0
   347
     * <p>Note that this method is security checked
duke@0
   348
     * and is not available to (for example) untrusted applets.
duke@0
   349
     * More specifically, if there is a security manager,
duke@0
   350
     * its <code>checkPropertiesAccess</code>
duke@0
   351
     * method is called. This could result in a SecurityException.
duke@0
   352
     *
duke@0
   353
     * @param isGuiAvailable  True if GUI interaction is available.
duke@0
   354
     * @exception  SecurityException  if a security manager exists and its
duke@0
   355
     *             <code>checkPropertiesAccess</code> method doesn't allow setting
duke@0
   356
     *              of system properties.
duke@0
   357
     * @see SecurityManager#checkPropertiesAccess
duke@0
   358
     */
duke@0
   359
duke@0
   360
    public static void setGuiAvailable(boolean isGuiAvailable)
duke@0
   361
                        throws SecurityException {
duke@0
   362
        SecurityManager sm = System.getSecurityManager();
duke@0
   363
        if (sm != null) {
duke@0
   364
            sm.checkPropertiesAccess();
duke@0
   365
        }
malenkov@1077
   366
        AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable));
duke@0
   367
    }
duke@0
   368
}
duke@0
   369
duke@0
   370
/**
duke@0
   371
 * This subclass of ObjectInputStream delegates loading of classes to
duke@0
   372
 * an existing ClassLoader.
duke@0
   373
 */
duke@0
   374
duke@0
   375
class ObjectInputStreamWithLoader extends ObjectInputStream
duke@0
   376
{
duke@0
   377
    private ClassLoader loader;
duke@0
   378
duke@0
   379
    /**
duke@0
   380
     * Loader must be non-null;
duke@0
   381
     */
duke@0
   382
duke@0
   383
    public ObjectInputStreamWithLoader(InputStream in, ClassLoader loader)
duke@0
   384
            throws IOException, StreamCorruptedException {
duke@0
   385
duke@0
   386
        super(in);
duke@0
   387
        if (loader == null) {
duke@0
   388
            throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
duke@0
   389
        }
duke@0
   390
        this.loader = loader;
duke@0
   391
    }
duke@0
   392
duke@0
   393
    /**
duke@0
   394
     * Use the given ClassLoader rather than using the system class
duke@0
   395
     */
duke@0
   396
    protected Class resolveClass(ObjectStreamClass classDesc)
duke@0
   397
        throws IOException, ClassNotFoundException {
duke@0
   398
duke@0
   399
        String cname = classDesc.getName();
duke@0
   400
        return ClassFinder.resolveClass(cname, this.loader);
duke@0
   401
    }
duke@0
   402
}
duke@0
   403