KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > loaders > InstanceSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.loaders;
21
22
23 import java.io.*;
24 import java.lang.reflect.*;
25 import org.openide.cookies.InstanceCookie;
26 import org.openide.filesystems.FileObject;
27 import org.openide.util.*;
28
29 /** An instance cookie implementation that works with files or entries.
30 *
31 * @author Jan Jancura, Jaroslav Tulach
32 */

33 public class InstanceSupport extends Object JavaDoc implements InstanceCookie.Of {
34     /** entry to work with */
35     private MultiDataObject.Entry entry;
36
37     /** throw exception during loading of the class */
38     private Throwable JavaDoc clazzException;
39
40     /** the class of the instance */
41     private Class JavaDoc clazz;
42
43     /** the class is applet */
44     private Boolean JavaDoc applet;
45     /** the class is bean */
46     private Boolean JavaDoc bean;
47
48     /** New support for given entry. The file is taken from the
49     * entry and is updated if the entry moves or renames itself.
50     * @param entry entry to create instance from
51     */

52     public InstanceSupport(MultiDataObject.Entry entry) {
53         this.entry = entry;
54     }
55     
56     /** Accessor for the entry. Needed in InstanceDataObject.Ser
57      * @return the entry
58      */

59     MultiDataObject.Entry entry () {
60         return entry;
61     }
62     
63
64     // main methods .........................................................................................................
65

66     /* The bean name for the instance.
67     * @return the name for the instance
68     */

69     public String JavaDoc instanceName () {
70         // XXX does this make any sense? Is this method useful for anything?
71
String JavaDoc p = instanceOrigin().getPath();
72         int x = p.lastIndexOf('.');
73         if (x != -1 && x > p.lastIndexOf('/')) {
74             p = p.substring(0, x);
75         }
76         return p.replace('/', '.');
77     }
78
79     /* The class of the instance represented by this cookie.
80     * Can be used to test whether the instance is of valid
81     * class before it is created.
82     *
83     * <p>Note that <code>SecurityException</code> could be thrown
84     * if an attempt was made e.g. to create an instance of a class
85     * in a <code>java.*</code> package. Clients of <code>InstanceSupport</code>
86     * which expect that this might happen (e.g. creating instances of
87     * freeform user classes) should explicitly catch security exceptions
88     * and convert them into whatever else as needed.
89     *
90     * @return the class of the instance
91     * @exception IOException an I/O error occured
92     * @exception ClassNotFoundException the class has not been found
93     */

94     public Class JavaDoc<?> instanceClass()
95     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
96         return instanceClass(null);
97     }
98     
99     final Class JavaDoc<?> instanceClass(ClassLoader JavaDoc cl)
100     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
101         if (clazzException != null) {
102             if (clazzException instanceof IOException)
103                 throw (IOException)clazzException;
104             else if (clazzException instanceof ClassNotFoundException JavaDoc)
105                 throw (ClassNotFoundException JavaDoc)clazzException;
106             else
107                 throw (ThreadDeath JavaDoc)clazzException;
108         }
109         if (clazz != null) return clazz;
110         //System.out.println ("getClass " + fileName ); // NOI18N
111
try {
112             if (isSerialized ()) { // NOI18N
113
// read class from ser file
114
InputStream is = instanceOrigin ().getInputStream ();
115                 try {
116                     clazz = readClass (is);
117                     return clazz;
118                 } finally {
119                     is.close ();
120                 }
121             } else {
122                 // find class by class loader
123
clazz = findClass (instanceName (), cl);
124                 if (clazz == null) throw new ClassNotFoundException JavaDoc (instanceName());
125                 return clazz;
126             }
127         } catch (IOException ex) {
128             Exceptions.attachMessage(ex, "From file: " + entry.getFile()); // NOI18N
129
clazzException = ex;
130             throw ex;
131         } catch (ClassNotFoundException JavaDoc ex) {
132             Exceptions.attachMessage(ex, "From file: " + entry.getFile()); // NOI18N
133
clazzException = ex;
134             throw ex;
135         } catch (RuntimeException JavaDoc re) {
136             // turn other throwables into class not found ex.
137
clazzException = new ClassNotFoundException JavaDoc("From file: " + entry.getFile() + " due to: " + re.toString()); // NOI18N
138
clazzException.initCause(re);
139             throw (ClassNotFoundException JavaDoc) clazzException;
140         } catch (LinkageError JavaDoc le) {
141             clazzException = new ClassNotFoundException JavaDoc("From file: " + entry.getFile() + " due to: " + le.toString()); // NOI18N
142
clazzException.initCause(le);
143             throw (ClassNotFoundException JavaDoc) clazzException;
144         }
145     }
146
147     /*Query to found out if the object created by this cookie is
148     * instance of given type. Does:
149     * <pre>
150     * Class actualClass = instanceClass ();
151     * result = type.isAsignableFrom (actualClass);
152     * </pre>
153     *
154     * @param type the class type we want to check
155     * @return true if this cookie can produce object of given type
156     */

157     public boolean instanceOf(Class JavaDoc<?> type) {
158         try {
159             return type.isAssignableFrom (instanceClass ());
160         } catch (IOException ex) {
161             return false;
162         } catch (ClassNotFoundException JavaDoc ex) {
163             return false;
164         }
165     }
166
167     /** Returns the origin of the instance.
168     * @return the origin
169     */

170     public FileObject instanceOrigin () {
171         // return getEntry ().getFile ();
172
return entry.getFile ();
173     }
174
175     /*
176     * @return an object to work with
177     * @exception IOException an I/O error occured
178     * @exception ClassNotFoundException the class has not been found
179     */

180     public Object JavaDoc instanceCreate ()
181     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
182         try {
183             if (isSerialized ()) {
184                 // create from ser file
185
BufferedInputStream bis = new BufferedInputStream(instanceOrigin().getInputStream(), 1024);
186                 org.openide.util.io.NbObjectInputStream nbis = new org.openide.util.io.NbObjectInputStream(bis);
187                 Object JavaDoc o = nbis.readObject();
188                 nbis.close();
189                 return o;
190             } else {
191                 Class JavaDoc<?> c = instanceClass ();
192                 if (SharedClassObject.class.isAssignableFrom (c)) {
193                     // special support
194
return SharedClassObject.findObject (c.asSubclass(SharedClassObject.class), true);
195                 } else {
196                     // create new instance
197
return c.newInstance();
198                 }
199             }
200         } catch (IOException ex) {
201             // [PENDING] annotate with localized message
202
Exceptions.attachLocalizedMessage(ex, instanceName());
203             throw ex;
204         } catch (ClassNotFoundException JavaDoc ex) {
205             throw ex;
206         } catch (Exception JavaDoc e) {
207             // turn other throwables into class not found ex.
208
throw new ClassNotFoundException JavaDoc("Cannot instantiate " + instanceName() + " for " + entry.getFile(), e); // NOI18N
209
} catch (LinkageError JavaDoc e) {
210             throw new ClassNotFoundException JavaDoc("Cannot instantiate " + instanceName() + " for " + entry.getFile(), e); // NOI18N
211
}
212     }
213
214     /** Is this an applet?
215     * @return <code>true</code> if this class is a <code>java.applet.Applet</code>
216     * @deprecated This method probably should not be used, as it catches a variety of potentially
217     * serious exceptions and errors, and swallows them so as to produce a simple boolean
218     * result. (Notifying them all would be inappropriate as they typically come from user
219     * code.) Better to directly parse the bytecode, using e.g. the classfile module,
220     * which is immune to this class of errors.
221     */

222     @Deprecated JavaDoc
223     public boolean isApplet () {
224         if (applet != null) return applet.booleanValue ();
225         boolean b = instanceOf (java.applet.Applet JavaDoc.class);
226         applet = b ? Boolean.TRUE : Boolean.FALSE;
227         return b;
228     }
229
230     /** Is this a standalone executable?
231     * @return <code>true</code> if this class has main method
232     * (e.g., <code>public static void main (String[] arguments)</code>).
233     * @deprecated This method probably should not be used, as it catches a variety of potentially
234     * serious exceptions and errors, and swallows them so as to produce a simple boolean
235     * result. (Notifying them all would be inappropriate as they typically come from user
236     * code.) Better to directly parse the bytecode, using e.g. the classfile module,
237     * which is immune to this class of errors.
238     */

239     @Deprecated JavaDoc
240     public boolean isExecutable () {
241         try {
242             Method main = instanceClass ().getDeclaredMethod ("main", new Class JavaDoc[] { // NOI18N
243
String JavaDoc[].class
244                           });
245
246             int m = main.getModifiers ();
247             return Modifier.isPublic (m) && Modifier.isStatic (m) && Void.TYPE.equals (
248                        main.getReturnType ()
249                    );
250         } catch (Exception JavaDoc ex) {
251             return false;
252         } catch (LinkageError JavaDoc re) {
253             // false when other errors occur (NoClassDefFoundError etc...)
254
return false;
255         }
256     }
257
258     /** Is this a JavaBean?
259     * @return <code>true</code> if this class represents JavaBean (is public and has a public default constructor).
260     * @deprecated This method probably should not be used, as it catches a variety of potentially
261     * serious exceptions and errors, and swallows them so as to produce a simple boolean
262     * result. (Notifying them all would be inappropriate as they typically come from user
263     * code.) Better to directly parse the bytecode, using e.g. the classfile module,
264     * which is immune to this class of errors.
265     */

266     @Deprecated JavaDoc
267     public boolean isJavaBean () {
268         if (bean != null) return bean.booleanValue ();
269         
270         // if from ser file => definitely it is a java bean
271
if (isSerialized ()) {
272             bean = Boolean.TRUE;
273             return true;
274         }
275         
276         // try to find out...
277
try {
278             Class JavaDoc clazz = instanceClass();
279             int modif = clazz.getModifiers ();
280             if (!Modifier.isPublic (modif) || Modifier.isAbstract (modif)) {
281                 bean = Boolean.FALSE;
282                 return false;
283             }
284             Constructor c;
285             try {
286                 c = clazz.getConstructor (new Class JavaDoc [0]);
287             } catch (NoSuchMethodException JavaDoc e) {
288                 bean = Boolean.FALSE;
289                 return false;
290             }
291             if ((c == null) || !Modifier.isPublic (c.getModifiers ())) {
292                 bean = Boolean.FALSE;
293                 return false;
294             }
295             // check: if the class is an inner class, all outer classes have
296
// to be public and in the static context:
297

298             for (Class JavaDoc outer = clazz.getDeclaringClass(); outer != null; outer = outer.getDeclaringClass()) {
299                 // check if the enclosed class is static
300
if (!Modifier.isStatic(modif))
301                     return false;
302                 modif = outer.getModifiers();
303                 // ... and the enclosing class is public
304
if (!Modifier.isPublic(modif))
305                     return false;
306             }
307         } catch (Exception JavaDoc ex) {
308             bean = Boolean.FALSE;
309             return true;
310         } catch (LinkageError JavaDoc e) {
311             // false when other errors occur (NoClassDefFoundError etc...)
312
bean = Boolean.FALSE;
313             return false;
314         }
315         // okay, this is bean...
316
// return isBean = java.io.Serializable.class.isAssignableFrom (clazz);
317
bean = Boolean.TRUE;
318         return true;
319     }
320
321     /** Is this an interface?
322     * @return <code>true</code> if the class is an interface
323     * @deprecated This method probably should not be used, as it catches a variety of potentially
324     * serious exceptions and errors, and swallows them so as to produce a simple boolean
325     * result. (Notifying them all would be inappropriate as they typically come from user
326     * code.) Better to directly parse the bytecode, using e.g. the classfile module,
327     * which is immune to this class of errors.
328     */

329     @Deprecated JavaDoc
330     public boolean isInterface () {
331         try {
332             return instanceClass ().isInterface ();
333         } catch (IOException ex) {
334             return false;
335         } catch (ClassNotFoundException JavaDoc cnfe) {
336             return false;
337         }
338     }
339
340     public String JavaDoc toString () {
341         return instanceName ();
342     }
343
344     /** Find context help for some instance.
345     * Helper method useful in nodes or data objects that provide an instance cookie;
346     * they may choose to supply their own help context based on this.
347     * All API classes which can provide help contexts will be tested for
348     * (including <code>HelpCtx</code> instances themselves).
349     * <code>JComponent</code>s are checked for an attached help ID property,
350     * as with {@link HelpCtx#findHelp(java.awt.Component)} (but not traversing parents).
351     * <p>Also, partial compliance with the JavaHelp section on JavaBeans help is implemented--i.e.,
352     * if a Bean in its <code>BeanInfo</code> provides a <code>BeanDescriptor</code> which
353     * has the attribute <code>helpID</code>, this will be returned. The value is not
354     * defaulted (because it would usually be nonsense and would mask a useful default
355     * help for the instance container), nor is the help set specification checked,
356     * since someone should have installed the proper help set anyway, and the APIs
357     * cannot add a new reference to a help set automatically.
358     * See <code>javax.help.HelpUtilities.getIDStringFromBean</code> for details.
359     * <p>Special IDs are added, corresponding to the class name, for all standard visual components.
360     * @param instance the instance to check for help (it is permissible for the {@link InstanceCookie#instanceCreate} to return <code>null</code>)
361     * @return the help context found on the instance or inferred from a Bean,
362     * or <code>null</code> if none was found (or it was {@link HelpCtx#DEFAULT_HELP})
363      *
364      *
365      * @deprecated use org.openide.util.HelpCtx.findHelp (Object)
366     */

367     @Deprecated JavaDoc
368     public static HelpCtx findHelp (InstanceCookie instance) {
369         try {
370             Class JavaDoc clazz = instance.instanceClass();
371             // [a.n] I have moved the code here as those components's BeanInfo do not contain helpID
372
// - it is faster
373
// Help on some standard components. Note that borders/layout managers do not really work here.
374
if (java.awt.Component JavaDoc.class.isAssignableFrom (clazz) || java.awt.MenuComponent JavaDoc.class.isAssignableFrom (clazz)) {
375                 String JavaDoc name = clazz.getName ();
376                 String JavaDoc[] pkgs = new String JavaDoc[] { "java.awt.", "javax.swing.", "javax.swing.border." }; // NOI18N
377
for (int i = 0; i < pkgs.length; i++) {
378                     if (name.startsWith (pkgs[i]) && name.substring (pkgs[i].length ()).indexOf ('.') == -1)
379                         return new HelpCtx (name);
380                 }
381             }
382             Object JavaDoc o = instance.instanceCreate();
383             if (o != null && o != instance) {
384                 HelpCtx h = HelpCtx.findHelp(o);
385                 if (h != HelpCtx.DEFAULT_HELP) {
386                     return h;
387                 }
388             }
389         } catch (Exception JavaDoc e) {
390             // #63238: Ignore - generally not important context for us to be checking errors.
391
}
392         return null;
393     }
394     
395     /** Test whether the instance represents serialized version of a class
396      * or not.
397      * @return true if the file entry extension is ser
398      */

399     private boolean isSerialized () {
400         return instanceOrigin ().getExt ().equals ("ser"); // NOI18N
401
}
402     
403     /** Reads a class from input stream. Expects a serialized object to be stored
404     * in the stream and reads only a class from it.
405     * @param is input stream to read from
406     * @return the class of that stream
407     * @exception IOException if something fails
408     */

409     private Class JavaDoc readClass (InputStream is) throws IOException, ClassNotFoundException JavaDoc {
410         /** object input stream */
411         class OIS extends ObjectInputStream {
412             public OIS (InputStream iss) throws IOException {
413                 super (iss);
414             }
415
416             /** Throws exception to signal the kind of class found.
417             */

418             public Class JavaDoc resolveClass (ObjectStreamClass osc)
419             throws IOException, ClassNotFoundException JavaDoc {
420                 Class JavaDoc c = findClass (osc.getName (), null);
421                 if (c == writeRepl) {
422                     // if this is write replace of shared object then
423
// continue in reading
424
return c;
425                 }
426                 
427                 // stop the reading expecting that we have read the class
428
// of the primary object
429
throw new ClassEx (c);
430             }
431         };
432
433         ObjectInputStream ois = new OIS (new BufferedInputStream (is));
434
435         try {
436             ois.readObject ();
437             // should not happen
438
throw new ClassNotFoundException JavaDoc ();
439         } catch (ClassEx ex) {
440             // good, we found the class
441
return ex.clazz;
442         }
443     }
444     
445     /** the variable for access to SharedClassObject$WriteReplace */
446     private static Class JavaDoc writeRepl;
447     static {
448         try {
449             writeRepl = Class.forName ("org.openide.util.SharedClassObject$WriteReplace"); // NOI18N
450
} catch (Exception JavaDoc ex) {
451             ex.printStackTrace();
452         }
453     }
454
455     /** Finds a class for given name.
456     * @param name name of the class
457     * @return the class for the name
458     * @exception ClassNotFoundException if the class cannot be found
459     */

460     private Class JavaDoc findClass (String JavaDoc name, ClassLoader JavaDoc customLoader) throws ClassNotFoundException JavaDoc {
461         try {
462             Class JavaDoc c;
463             try {
464                 if (customLoader != null) {
465                     c = customLoader.loadClass(name);
466                 } else {
467                     // to save the space with wasting classloaders, try the system first
468
ClassLoader JavaDoc loader = (ClassLoader JavaDoc)Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
469                     if (loader == null) {
470                         loader = getClass ().getClassLoader ();
471                     }
472                     c = loader.loadClass (name);
473                 }
474             } catch (ClassNotFoundException JavaDoc ex) {
475                 // ok, ignore and try our class loader
476
c = createClassLoader().loadClass(name);
477             }
478             return c;
479         } catch (ClassNotFoundException JavaDoc ex) {
480             throw ex;
481         } catch (RuntimeException JavaDoc ex) {
482             throw ex;
483         } catch (LinkageError JavaDoc le) {
484             throw new ClassNotFoundException JavaDoc(le.toString(), le);
485         }
486     }
487     
488     /** Creates new NbClassLoader with restricted PermissionCollection
489      * that contains only:
490      * java.io.FilePermission("&lt;&lt;ALL FILES>>", "read")
491      * java.util.PropertyPermission("*", "read")
492      *
493      * @return ClassLoader
494      */

495     protected ClassLoader JavaDoc createClassLoader() {
496         ClassLoader JavaDoc l = (ClassLoader JavaDoc)Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
497         return l;
498     }
499
500     /** Trivial supporting instance cookie for already-existing objects.
501     */

502     public static class Instance extends Object JavaDoc implements InstanceCookie.Of {
503         /** the object to represent */
504         private Object JavaDoc obj;
505
506
507         /** Create a new instance cookie.
508          * @param obj the object to represent in this cookie
509         */

510         public Instance (Object JavaDoc obj) {
511             this.obj = obj;
512         }
513
514         /* The bean name for the instance.
515         * @return the name for the instance
516         */

517         public String JavaDoc instanceName () {
518             return obj.getClass ().getName ();
519         }
520
521         /* The class of the instance represented by this cookie.
522         * Can be used to test whether the instance is of valid
523         * class before it is created.
524         *
525         * @return the class of the instance
526          */

527         public Class JavaDoc<?> instanceClass() {
528             return obj.getClass ();
529         }
530
531         /*
532         * @return an object to work with
533         */

534         public Object JavaDoc instanceCreate () {
535             return obj;
536         }
537
538         public boolean instanceOf(Class JavaDoc<?> type) {
539             return type.isAssignableFrom (instanceClass ());
540         }
541     }
542
543     /** The exception to use to signal succesful find of a class.
544     * Used in method readClass.
545     */

546     private static class ClassEx extends IOException {
547         /** founded class */
548         public Class JavaDoc clazz;
549
550         static final long serialVersionUID =4810039297880922426L;
551         /** @param c the class
552         */

553         public ClassEx (Class JavaDoc c) {
554             clazz = c;
555         }
556     }
557 }
558
Popular Tags