All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.loaders.DataLoader Maven / Gradle / Ivy

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.loaders;

import java.beans.*;
import java.io.*;
import java.util.*;

import org.openide.ErrorManager;
import org.openide.filesystems.*;
import org.openide.nodes.NodeOp;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.SharedClassObject;
import org.openide.util.Utilities;
import org.openide.util.actions.SystemAction;
import org.openide.util.io.SafeException;

/** A data loader recognizes {@link FileObject}s and creates appropriate
* {@link DataObject}s to represent them.
* The created data object must be a subclass
* of the representation class provided in the constructor.
* 

* Subclasses of DataLoader should be made JavaBeans with * additional parameters, so a user may configure the loaders in the loader pool. * * @author Jaroslav Tulach */ public abstract class DataLoader extends SharedClassObject { // XXX why is this necessary? otherwise reading loader pool now throws heavy // InvalidClassException's reading (abstract!) DataLoader...? --jglick private static final long serialVersionUID = 1986614061378346169L; /** property name of display name */ public static final String PROP_DISPLAY_NAME = "displayName"; // NOI18N /** property name of list of actions */ public static final String PROP_ACTIONS = "actions"; // NOI18N /** property name of list of default actions */ private static final String PROP_DEF_ACTIONS = "defaultActions"; // NOI18N /** representation class, not public property */ private static final Object PROP_REPRESENTATION_CLASS = new Object (); /** representation class name, not public property */ private static final Object PROP_REPRESENTATION_CLASS_NAME = new Object (); private static final int LOADER_VERSION = 1; /** Create a new data loader. * Pass its representation class as a parameter to the constructor. * It is recommended that representation class is superclass of all * DataObjects produced by the loaded, but it is not required any more. * * @param representationClass the superclass (not necessarily) of all objects * returned from {@link #findDataObject}. The class may be anything but * should be chosen to be as close as possible to the actual class of objects returned from the loader, * to best identify the loader's data objects to listeners. * @deprecated Use {@link #DataLoader(String)} instead. */ protected DataLoader (Class representationClass) { putProperty (PROP_REPRESENTATION_CLASS, representationClass); putProperty (PROP_REPRESENTATION_CLASS_NAME, representationClass.getName()); if (representationClass.getClassLoader() == getClass().getClassLoader()) { ErrorManager.getDefault().log(ErrorManager.WARNING, "Use of super(" + representationClass.getName() + ".class) in " + getClass().getName() + "() should be replaced with super(\"" + representationClass.getName() + "\") to reduce unnecessary class loading"); } } /** Create a new data loader. * Pass its representation class name * as a parameter to the constructor. The constructor is then allowed * to return only subclasses of the representation class as the result of * {@link #findDataObject}. * * @param representationClassName the name of the superclass for all objects * returned from * {@link #findDataObject}. The class may be anything but * should be chosen to be as close as possible to the actual class of objects returned from the loader, * to best identify the loader's data objects to listeners. * * @since 1.10 */ protected DataLoader( String representationClassName ) { putProperty (PROP_REPRESENTATION_CLASS_NAME, representationClassName); } /** * Get the representation class for this data loader, as passed to the constructor. * @return the representation class */ public final Class getRepresentationClass() { Class cls = (Class)getProperty (PROP_REPRESENTATION_CLASS); if (cls != null) return cls; String clsName = (String)getProperty (PROP_REPRESENTATION_CLASS_NAME); try { cls = Class.forName (clsName, false, getClass().getClassLoader ()); } catch (ClassNotFoundException cnfe) { throw new IllegalStateException (cnfe.toString ()); } putProperty (PROP_REPRESENTATION_CLASS, cls); return cls; } /** * Get the name of the representation class for this data loader. * Might avoid actually loading the class. * @return the class name * @see #getRepresentationClass * @since 3.25 */ public final String getRepresentationClassName() { return (String)getProperty (PROP_REPRESENTATION_CLASS_NAME); } /** Get actions. * These actions are used to compose * a popup menu for the data object. Also these actions should * be customizable by the user, so he can modify the popup menu on a * data object. * * @return array of system actions or null if this loader does not have any * actions */ public final SystemAction[] getActions () { SystemAction[] actions = (SystemAction[])getProperty (PROP_ACTIONS); if ( actions == null ) { actions = (SystemAction[])getProperty (PROP_DEF_ACTIONS); if ( actions == null ) { actions = defaultActions(); putProperty (PROP_DEF_ACTIONS, actions, false); } } return actions; } /** Get default actions. * @return array of default system actions or null if this loader * does not have any actions. * Typical example of usage: *

    * return new SystemAction[] {
    *                    SystemAction.get (OpenAction.class), ...
    *                    SystemAction.get (PropertiesAction.class)
    *                };
    * 
*/ protected SystemAction[] defaultActions () { SystemAction[] actions = NodeOp.getDefaultActions(); return actions; } /** Set actions. *

Note that this method is public, not protected, so it is possible for anyone * to modify the loader's popup actions externally (after finding the loader * using {@link DataLoaderPool#firstProducerOf}). * While this is possible, anyone doing so must take care to place new actions * into sensible positions, including consideration of separators. * This may also adversely affect the intended feel of the data objects. * A preferable solution is generally to use {@link org.openide.actions.ToolsAction service actions}. * @param actions actions for this loader or null if it should not have any * @see #getActions */ public final void setActions (SystemAction[] actions) { putProperty (PROP_ACTIONS, actions, true); } /** Get the current display name of this loader. * @return display name */ public final String getDisplayName () { String dn = (String) getProperty (PROP_DISPLAY_NAME); if (dn != null) { return dn; } else { dn = defaultDisplayName(); if (dn != null) { return dn; } else { return getRepresentationClassName(); } } } /** Set the display name for this loader. Only subclasses should set the name. * @param displayName new name */ protected final void setDisplayName (final String displayName) { putProperty (PROP_DISPLAY_NAME, displayName, true); } /** Get the default display name of this loader. * @return default display name */ protected String defaultDisplayName () { return NbBundle.getBundle(DataLoader.class).getString ("LBL_loader_display_name"); } /** Find a data object appropriate to the given file object--the meat of this class. *

* For example: for files with the same basename but extensions .java and .class, the handler * should return the same DataObject. *

* The loader can add all files it has recognized into the recognized * buffer. Then all these files will be excluded from further processing. * * @param fo file object to recognize * @param recognized recognized file buffer * @exception DataObjectExistsException if the data object for the * primary file already exists * @exception IOException if the object is recognized but cannot be created * @exception InvalidClassException if the class is not instance of * {@link #getRepresentationClass} * * @return suitable data object or null if the handler cannot * recognize this object (or its group) * @see #handleFindDataObject */ public final DataObject findDataObject ( FileObject fo, RecognizedFiles recognized ) throws IOException { try { return DataObjectPool.handleFindDataObject( this, fo, recognized ); } catch (IOException ioe) { throw ioe; } catch (ThreadDeath td) { throw td; } catch (RuntimeException e) { // Some strange error, perhaps an unexpected exception in // MultiFileLoader.findPrimaryFile. Such an error ought // not cause whole folder recognizer to die! Assume that // file/loader is kaput and continue. IOException ioe = new IOException (e.toString()); ErrorManager.getDefault ().annotate (ioe, e); throw ioe; } /* if (obj != null && !getRepresentationClass ().isInstance (obj)) { // does not fullfil representation class throw new java.io.InvalidClassException (obj.getClass ().toString ()); } return obj; */ } /** Find a data object appropriate to the given file object (as implemented in subclasses). * @see #findDataObject * @param fo file object to recognize * @param recognized recognized file buffer * @exception DataObjectExistsException as in #findDataObject * @exception IOException as in #findDataObject * * @return the data object or null */ protected abstract DataObject handleFindDataObject ( FileObject fo, RecognizedFiles recognized ) throws IOException; /** Utility method to mark a file as belonging to this loader. * When the file is to be recognized this loader will be used first. *

* This method is used by {@link DataObject#markFiles}. * * @param fo file to mark * @exception IOException if setting the file's attribute failed */ public final void markFile (FileObject fo) throws IOException { DataLoaderPool.setPreferredLoader(fo, this); } /** Writes nothing to the stream. * @param oo ignored */ public void writeExternal (ObjectOutput oo) throws IOException { oo.writeObject( new Integer(LOADER_VERSION) ); SystemAction[] arr = (SystemAction[])getProperty (PROP_ACTIONS); if (arr == null) { oo.writeObject (null); } else { // convert actions to class names LinkedList names = new LinkedList (); for (int i = 0; i < arr.length; i++) { if (arr[i] == null) { names.add (null); } else { names.add (arr[i].getClass ().getName ()); } } oo.writeObject (names.toArray ()); } String dn = (String) getProperty (PROP_DISPLAY_NAME); if ( dn == null ) dn = ""; // NOI18N oo.writeUTF ( dn ); } /** Reads actions and display name from the stream. * @param oi input source to read from * @exception SafeException if some of the actions is not found in the * stream, but all the content has been read ok. Subclasses can * catch this exception and continue reading from the stream */ public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException { Exception main = null; int version = 0; Object first = oi.readObject (); if ( first instanceof Integer ) { version = ((Integer)first).intValue(); first = oi.readObject (); } // new version that reads the names of the actions - NB3.1 Object[] arr = (Object[])first; boolean isdefault = true; SystemAction[] defactions = getActions (); if ( version > 0 || ( version == 0 && arr.length != defactions.length )) isdefault = false; if (arr != null) { List ll = new ArrayList (arr.length); for (int i = 0; i < arr.length; i++) { if (arr[i] == null) { ll.add (null); if ( version == 0 && isdefault && defactions[i] != null) isdefault = false; continue; } try { Class c = Class.forName ( Utilities.translate((String)arr[i]), false, // why resolve?? --jglick (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class) ); SystemAction ac = SystemAction.get (c); ll.add (ac); if ( version == 0 && isdefault && !defactions[i].equals(ac)) isdefault = false; } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().annotate ( ex, org.openide.ErrorManager.INFORMATIONAL, null, null, null, null ); if (main == null) { main = ex; } else { ErrorManager.getDefault ().annotate (main, ex); } } } if (main == null && !isdefault) { // Whole action list was successfully read. setActions ((SystemAction[])ll.toArray(new SystemAction[ll.size()])); } // Else do not try to override the default action list if it is incomplete anyway. } String displayName = oi.readUTF (); if ( displayName.equals("") || ( version == 0 && displayName.equals(defaultDisplayName()))) // NOI18N displayName = null; setDisplayName( displayName ); if (main != null) { // exception occured during reading SafeException se = new SafeException (main); // Provide a localized message explaining that there is no big problem. String message = NbBundle.getMessage (DataLoader.class, "EXC_missing_actions_in_loader", getDisplayName ()); ErrorManager.getDefault ().annotate (se, message); throw se; } } protected boolean clearSharedData () { return false; } /** Get a registered loader from the pool. * @param loaderClass exact class of the loader (not its data object representation class) * @return the loader instance, or null if there is no such loader registered * @see DataLoaderPool#allLoaders */ public static DataLoader getLoader (Class loaderClass) { return (DataLoader)findObject (loaderClass, true); } // XXX huh? --jglick // The parameter can be null to // simplify testing whether the file object fo is valid or not /** Buffer holding a list of primary and secondary files marked as already recognized, to prevent further scanning. */ public interface RecognizedFiles { /** Mark this file as being recognized. It will be excluded * from further processing. * * @param fo file object to exclude */ public void markRecognized (FileObject fo); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy