KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.*;
25 import java.util.logging.*;
26 import javax.swing.Action JavaDoc;
27 import org.openide.filesystems.*;
28 import org.openide.nodes.NodeOp;
29 import org.openide.util.*;
30 import org.openide.util.actions.SystemAction;
31 import org.openide.util.io.SafeException;
32
33 /** A data loader recognizes {@link FileObject}s and creates appropriate
34 * {@link DataObject}s to represent them.
35 * The created data object must be a subclass
36 * of the <EM>representation class</EM> provided in the constructor.
37 * <P>
38 * Subclasses of <code>DataLoader</code> should be made <EM>JavaBeans</EM> with
39 * additional parameters, so a user may configure the loaders in the loader pool.
40 *
41 * @author Jaroslav Tulach
42 */

43 public abstract class DataLoader extends SharedClassObject {
44     /** error manager for logging the happenings in loaders */
45     static final Logger ERR = Logger.getLogger("org.openide.loaders.DataLoader"); // NOI18N
46

47     // XXX why is this necessary? otherwise reading loader pool now throws heavy
48
// InvalidClassException's reading (abstract!) DataLoader...? --jglick
49
private static final long serialVersionUID = 1986614061378346169L;
50
51     /** property name of display name */
52     public static final String JavaDoc PROP_DISPLAY_NAME = "displayName"; // NOI18N
53
/** property name of list of actions */
54     public static final String JavaDoc PROP_ACTIONS = "actions"; // NOI18N
55
/** property name of list of default actions */
56     private static final String JavaDoc PROP_DEF_ACTIONS = "defaultActions"; // NOI18N
57
/** key to hold reference to out action manager */
58     private static final Object JavaDoc ACTION_MANAGER = new Object JavaDoc ();
59     /** representation class, not public property */
60     private static final Object JavaDoc PROP_REPRESENTATION_CLASS = new Object JavaDoc ();
61     /** representation class name, not public property */
62     private static final Object JavaDoc PROP_REPRESENTATION_CLASS_NAME = new Object JavaDoc ();
63
64     private static final int LOADER_VERSION = 1;
65     
66     /** Create a new data loader.
67     * Pass its representation class as a parameter to the constructor.
68     * It is recommended that representation class is superclass of all
69     * DataObjects produced by the loaded, but it is not required any more.
70     *
71     * @param representationClass the superclass (not necessarily) of all objects
72     * returned from {@link #findDataObject}. The class may be anything but
73     * should be chosen to be as close as possible to the actual class of objects returned from the loader,
74     * to best identify the loader's data objects to listeners.
75     * @deprecated Use {@link #DataLoader(String)} instead.
76     */

77     @Deprecated JavaDoc
78     protected DataLoader(Class JavaDoc<? extends DataObject> representationClass) {
79         putProperty (PROP_REPRESENTATION_CLASS, representationClass);
80         putProperty (PROP_REPRESENTATION_CLASS_NAME, representationClass.getName());
81         if (representationClass.getClassLoader() == getClass().getClassLoader()) {
82             ERR.warning("Use of super(" + representationClass.getName() + ".class) in " + getClass().getName() + "() should be replaced with super(\"" + representationClass.getName() + "\") to reduce unnecessary class loading");
83         }
84     }
85
86     /** Create a new data loader.
87      * Pass its representation class name
88     * as a parameter to the constructor. The constructor is then allowed
89     * to return only subclasses of the representation class as the result of
90     * {@link #findDataObject}.
91     *
92     * @param representationClassName the name of the superclass for all objects
93      * returned from
94     * {@link #findDataObject}. The class may be anything but
95     * should be chosen to be as close as possible to the actual class of objects returned from the loader,
96     * to best identify the loader's data objects to listeners.
97     *
98     * @since 1.10
99     */

100     protected DataLoader( String JavaDoc representationClassName ) {
101         putProperty (PROP_REPRESENTATION_CLASS_NAME, representationClassName);
102     }
103     
104     /**
105      * Get the representation class for this data loader, as passed to the constructor.
106      * @return the representation class
107      */

108     public final Class JavaDoc<? extends DataObject> getRepresentationClass() {
109         Class JavaDoc<?> _cls = (Class JavaDoc<?>) getProperty(PROP_REPRESENTATION_CLASS);
110         if (_cls != null) {
111             return _cls.asSubclass(DataObject.class);
112         }
113
114         Class JavaDoc<? extends DataObject> cls;
115         String JavaDoc clsName = (String JavaDoc)getProperty (PROP_REPRESENTATION_CLASS_NAME);
116         try {
117             cls = Class.forName(clsName, false, getClass().getClassLoader()).asSubclass(DataObject.class);
118         } catch (ClassNotFoundException JavaDoc cnfe) {
119             throw new IllegalStateException JavaDoc (cnfe.toString ());
120         }
121     
122         putProperty (PROP_REPRESENTATION_CLASS, cls);
123         return cls;
124     }
125     
126     /**
127      * Get the name of the representation class for this data loader.
128      * Might avoid actually loading the class.
129      * @return the class name
130      * @see #getRepresentationClass
131      * @since 3.25
132      */

133     public final String JavaDoc getRepresentationClassName() {
134         return (String JavaDoc)getProperty (PROP_REPRESENTATION_CLASS_NAME);
135     }
136
137     /** Get actions.
138      * These actions are used to compose
139     * a popup menu for the data object. Also these actions should
140     * be customizable by the user, so he can modify the popup menu on a
141     * data object.
142     *
143     * @return array of system actions or <CODE>null</CODE> if this loader does not have any
144     * actions
145     */

146     public final SystemAction[] getActions () {
147         Action JavaDoc[] arr = getSwingActions ();
148         
149         List<SystemAction> list = new ArrayList<SystemAction>();
150         for (int i = 0; i < arr.length; i++) {
151             if (arr[i] instanceof SystemAction || arr[i] == null) {
152                 list.add((SystemAction) arr[i]);
153             }
154         }
155         
156         return list.toArray(new SystemAction[list.size()]);
157     }
158     
159     /** Swing actions getter, used from DataNode */
160     final Action JavaDoc[] getSwingActions () {
161         DataLdrActions mgr = findManager ();
162         if (mgr != null) {
163             Action JavaDoc[] actions;
164             try {
165                 actions = (Action JavaDoc[]) mgr.instanceCreate();
166             } catch (IOException ex) {
167                 Exceptions.printStackTrace(ex);
168                 actions = null;
169             } catch (ClassNotFoundException JavaDoc ex) {
170                 Exceptions.printStackTrace(ex);
171                 actions = null;
172             }
173             if (actions == null) {
174                 return new Action JavaDoc[0];
175             }
176         
177             return actions;
178         } else {
179             // old behaviour, that stores actions in properties
180
SystemAction[] actions = (SystemAction[])getProperty (PROP_ACTIONS);
181             if ( actions == null ) {
182                 actions = (SystemAction[])getProperty (PROP_DEF_ACTIONS);
183                 if ( actions == null ) {
184                     actions = defaultActions();
185                     putProperty (PROP_DEF_ACTIONS, actions, false);
186                 }
187             }
188             return actions;
189         }
190     }
191         
192     
193     /** Identifies the name of context in layer files where the
194      * loader wishes to store its own actions and also read them.
195      * In principle any {@link javax.swing.Action} instance can be registered
196      * in the context and it will be visible in the default DataNode
197      * for data object created by this loader. Only SystemAction can however
198      * be manipulated from DataLoader getActions/setActions methods.
199      * <p>
200      * The default implementation returns null to indicate that no
201      * layer reading should be used (use {@link #defaultActions} instead).
202      * <p>
203      * {@link javax.swing.JSeparator} instances may be used to separate items.
204      * <p>
205      * Suggested context name: <samp>Loaders/<em>PRIMARY-FILE/MIME-TYPE</em>/Actions</samp>
206      *
207      * @return the string name of the context on layer files to read/write actions to
208      * @since 5.0
209      */

210     protected String JavaDoc actionsContext () {
211         return null;
212     }
213     
214     /**
215      * Get default actions. Now deprecated;
216      * instead of overriding this method it
217      * is preferable to override {@link #actionsContext}.
218      * @return array of default system actions
219      */

220     protected SystemAction[] defaultActions () {
221         SystemAction[] actions = NodeOp.getDefaultActions();
222         return actions;
223     }
224     
225     /** Actions manager.
226      */

227     private final DataLdrActions findManager () {
228         Object JavaDoc manager = getProperty (ACTION_MANAGER);
229         if (manager instanceof Class JavaDoc) {
230             return null;
231         }
232         DataLdrActions mgr = (DataLdrActions)manager;
233         boolean newlyCreated = false;
234         if (mgr == null) {
235             String JavaDoc context = actionsContext ();
236             if (context == null) {
237                 // mark we have no context
238
putProperty (ACTION_MANAGER, getClass ());
239                 return null;
240             }
241             
242             FileObject fo = Repository.getDefault ().getDefaultFileSystem ().findResource (context);
243             if (fo == null) {
244                 fo = Repository.getDefault ().getDefaultFileSystem ().getRoot ();
245                 try {
246                     fo = FileUtil.createFolder (fo, context);
247
248                 } catch (IOException ex) {
249                     ERR.log(Level.WARNING, null, ex);
250                 }
251                 newlyCreated = true;
252             }
253             
254             mgr = new DataLdrActions (DataFolder.findFolder (fo), this);
255             if (newlyCreated) {
256                 SystemAction[] arr = defaultActions ();
257                 if (arr != null) {
258                     mgr.setActions (arr);
259                 }
260             }
261             putProperty (ACTION_MANAGER, mgr);
262         }
263         return mgr;
264     }
265     
266     /** Allows the friend code (package and tests) to wait while actions
267      * are synchronized with the state of disk.
268      */

269     final void waitForActions () {
270         DataLdrActions mgr = findManager ();
271         if (mgr != null) {
272             mgr.waitFinished ();
273         }
274     }
275     
276     /** Set actions.
277     * <p>Note that this method is public, not protected, so it is possible for anyone
278     * to modify the loader's popup actions externally (after finding the loader
279     * using {@link DataLoaderPool#firstProducerOf}).
280     * While this is possible, anyone doing so must take care to place new actions
281     * into sensible positions, including consideration of separators.
282     * This may also adversely affect the intended feel of the data objects.
283     * A preferable solution is generally to use {@link org.openide.actions.ToolsAction service actions}.
284     * @param actions actions for this loader or <CODE>null</CODE> if it should not have any
285     * @see #getActions
286     */

287     public final void setActions (SystemAction[] actions) {
288         DataLdrActions mgr = findManager ();
289         if (mgr != null) {
290             mgr.setActions (actions);
291         } else {
292             putProperty (PROP_ACTIONS, actions, true);
293         }
294     }
295     
296     /** Assigns this loader new array of swing actions.
297      * @param arr List<Action>
298      */

299     final void setSwingActions (List/*<Action>*/ arr) {
300         firePropertyChange (PROP_ACTIONS, null, null);
301     }
302
303     /** Get the current display name of this loader.
304     * @return display name
305     */

306     public final String JavaDoc getDisplayName () {
307         String JavaDoc dn = (String JavaDoc) getProperty (PROP_DISPLAY_NAME);
308         if (dn != null) {
309             return dn;
310         } else {
311             dn = defaultDisplayName();
312             if (dn != null) {
313                 return dn;
314             } else {
315                 return getRepresentationClassName();
316             }
317         }
318     }
319
320     /** Set the display name for this loader. Only subclasses should set the name.
321     * @param displayName new name
322     */

323     protected final void setDisplayName (final String JavaDoc displayName) {
324         putProperty (PROP_DISPLAY_NAME, displayName, true);
325     }
326
327     /** Get the default display name of this loader.
328     * @return default display name
329     */

330     protected String JavaDoc defaultDisplayName () {
331         return NbBundle.getBundle(DataLoader.class).getString ("LBL_loader_display_name");
332     }
333
334     /** Find a data object appropriate to the given file object--the meat of this class.
335      * <p>
336     * For example: for files with the same basename but extensions <EM>.java</EM> and <EM>.class</EM>, the handler
337     * should return the same <code>DataObject</code>.
338     * <P>
339     * The loader can add all files it has recognized into the <CODE>recognized</CODE>
340     * buffer. Then all these files will be excluded from further processing.
341     *
342     * @param fo file object to recognize
343     * @param recognized recognized file buffer
344     * @exception DataObjectExistsException if the data object for the
345     * primary file already exists
346     * @exception IOException if the object is recognized but cannot be created
347     * @exception InvalidClassException if the class is not instance of
348     * {@link #getRepresentationClass}
349     *
350     * @return suitable data object or <CODE>null</CODE> if the handler cannot
351     * recognize this object (or its group)
352     * @see #handleFindDataObject
353     */

354     public final DataObject findDataObject (
355         FileObject fo, RecognizedFiles recognized
356     ) throws IOException {
357     try {
358         return DataObjectPool.handleFindDataObject( this, fo, recognized );
359     } catch (IOException ioe) {
360         throw ioe;
361     } catch (ThreadDeath JavaDoc td) {
362         throw td;
363     } catch (RuntimeException JavaDoc e) {
364         if (e.getClass().getName().startsWith("org.openide.util.lookup")) { // NOI18N
365
// to propagate
366
// org.openide.util.lookup.AbstractLookup$ISE: You are trying to modify lookup from lookup query!
367
throw e;
368         }
369         // Some strange error, perhaps an unexpected exception in
370
// MultiFileLoader.findPrimaryFile. Such an error ought
371
// not cause whole folder recognizer to die! Assume that
372
// file/loader is kaput and continue.
373
IOException ioe = new IOException (e.toString());
374             Logger.getLogger(DataLoader.class.getName()).log(Level.WARNING, null, e);
375         ioe.initCause(e);
376         throw ioe;
377     }
378     
379     /*
380     if (obj != null && !getRepresentationClass ().isInstance (obj)) {
381         // does not fullfil representation class
382         throw new java.io.InvalidClassException (obj.getClass ().toString ());
383     }
384     
385     return obj;
386     */

387     }
388
389     /** Find a data object appropriate to the given file object (as implemented in subclasses).
390      * @see #findDataObject
391     * @param fo file object to recognize
392     * @param recognized recognized file buffer
393     * @exception DataObjectExistsException as in <code>#findDataObject</code>
394     * @exception IOException as in <code>#findDataObject</code>
395     *
396     * @return the data object or <code>null</code>
397     */

398     protected abstract DataObject handleFindDataObject (
399         FileObject fo, RecognizedFiles recognized
400     ) throws IOException;
401
402     /** Utility method to mark a file as belonging to this loader.
403     * When the file is to be recognized this loader will be used first.
404     * <P>
405     * This method is used by {@link DataObject#markFiles}.
406     *
407     * @param fo file to mark
408     * @exception IOException if setting the file's attribute failed
409     */

410     public final void markFile (FileObject fo) throws IOException {
411         DataLoaderPool.setPreferredLoader(fo, this);
412     }
413     
414     
415     
416
417     /** Writes nothing to the stream.
418     * @param oo ignored
419     */

420     public void writeExternal (ObjectOutput oo) throws IOException {
421         oo.writeObject( new Integer JavaDoc(LOADER_VERSION) );
422         
423         SystemAction[] arr = (SystemAction[])getProperty (PROP_ACTIONS);
424         if (arr == null) {
425             oo.writeObject (null);
426         } else {
427             // convert actions to class names
428
List<String JavaDoc> names = new LinkedList<String JavaDoc>();
429             for (int i = 0; i < arr.length; i++) {
430                 if (arr[i] == null) {
431                     names.add (null);
432                 } else {
433                     names.add (arr[i].getClass ().getName ());
434                 }
435             }
436             oo.writeObject (names.toArray ());
437         }
438         
439         String JavaDoc dn = (String JavaDoc) getProperty (PROP_DISPLAY_NAME);
440         if ( dn == null )
441             dn = ""; // NOI18N
442
oo.writeUTF ( dn );
443     }
444
445     /** Reads actions and display name from the stream.
446     * @param oi input source to read from
447     * @exception SafeException if some of the actions is not found in the
448     * stream, but all the content has been read ok. Subclasses can
449     * catch this exception and continue reading from the stream
450     */

451     public void readExternal (ObjectInput oi)
452     throws IOException, ClassNotFoundException JavaDoc {
453         Exception JavaDoc main = null;
454         int version = 0;
455         
456         Object JavaDoc first = oi.readObject ();
457         if ( first instanceof Integer JavaDoc ) {
458             version = ((Integer JavaDoc)first).intValue();
459             first = oi.readObject ();
460         }
461         // new version that reads the names of the actions - NB3.1
462
Object JavaDoc[] arr = (Object JavaDoc[])first;
463         boolean isdefault = true;
464
465         SystemAction[] defactions = getActions ();
466
467         if ( version > 0 || ( version == 0 && arr.length != defactions.length ))
468             isdefault = false;
469         if (arr != null) {
470             List<SystemAction> ll = new ArrayList<SystemAction>(arr.length);
471             for (int i = 0; i < arr.length; i++) {
472                 if (arr[i] == null) {
473                     ll.add (null);
474                     if ( version == 0 && isdefault && defactions[i] != null)
475                         isdefault = false;
476                     continue;
477                 }
478
479                 try {
480                     ClassLoader JavaDoc loader = Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
481                     if (loader == null) {
482                         loader = getClass ().getClassLoader ();
483                     }
484                     Class JavaDoc<? extends SystemAction> c = Class.forName (
485                         Utilities.translate((String JavaDoc)arr[i]),
486                         false, // why resolve?? --jglick
487
loader
488                     ).asSubclass(SystemAction.class);
489                     SystemAction ac = SystemAction.get(c);
490
491                     ll.add (ac);
492                     if ( version == 0 && isdefault && !defactions[i].equals(ac))
493                         isdefault = false;
494                 } catch (ClassNotFoundException JavaDoc ex) {
495                     if (main == null) {
496                         main = ex;
497                     } else {
498                         Throwable JavaDoc t = main;
499                         while (t.getCause() != null) {
500                             t = t.getCause();
501                         }
502                         t.initCause(ex);
503                     }
504                 }
505             }
506             if (main == null && !isdefault) {
507                 // Whole action list was successfully read.
508
setActions(ll.toArray(new SystemAction[ll.size()]));
509             } // Else do not try to override the default action list if it is incomplete anyway.
510
}
511         
512         String JavaDoc displayName = oi.readUTF ();
513         if ( displayName.equals("") || ( version == 0 && displayName.equals(defaultDisplayName()))) // NOI18N
514
displayName = null;
515         setDisplayName( displayName );
516         
517         if (main != null) {
518             // exception occured during reading
519
SafeException se = new SafeException (main);
520             // Provide a localized message explaining that there is no big problem.
521
String JavaDoc message = NbBundle.getMessage (DataLoader.class, "EXC_missing_actions_in_loader", getDisplayName ());
522             Exceptions.attachLocalizedMessage(se, message);
523             throw se;
524         }
525     }
526
527     protected boolean clearSharedData () {
528         return false;
529     }
530
531     /** Get a registered loader from the pool.
532      * @param loaderClass exact class of the loader (<em>not</em> its data object representation class)
533      * @return the loader instance, or <code>null</code> if there is no such loader registered
534      * @see DataLoaderPool#allLoaders
535      */

536     public static <T extends DataLoader> T getLoader(Class JavaDoc<T> loaderClass) {
537         return findObject(loaderClass, true);
538     }
539
540     // XXX huh? --jglick
541
// The parameter can be <CODE>null</CODE> to
542
// simplify testing whether the file object fo is valid or not
543
/** Buffer holding a list of primary and secondary files marked as already recognized, to prevent further scanning.
544     */

545     public interface RecognizedFiles {
546         /** Mark this file as being recognized. It will be excluded
547         * from further processing.
548         *
549         * @param fo file object to exclude
550         */

551         public void markRecognized (FileObject fo);
552     }
553
554 }
555
Popular Tags