alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 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-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.loaders;

import java.beans.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.openide.filesystems.*;
import org.openide.windows.CloneableTopComponent;
import org.openide.windows.CloneableOpenSupport;
import org.openide.util.WeakSet;
import org.openide.util.NbBundle;

/** Simple support for an openable file.
* Can be used either as an {@link org.openide.cookies.OpenCookie},
* {@link org.openide.cookies.ViewCookie}, or {@link org.openide.cookies.CloseCookie},
* depending on which cookies the subclass implements.
*
* @author Jaroslav Tulach
*/
public abstract class OpenSupport extends CloneableOpenSupport {
    /** Entry to work with. */
    protected MultiDataObject.Entry entry;

    /** New support for a given entry. The file is taken from the
    * entry and is updated if the entry moves or renames itself.
    * @param entry entry to create instance from
    */
    public OpenSupport (MultiDataObject.Entry entry) {
        this (entry, new Env (entry.getDataObject ()));
    }
    
    /** Constructor that allows subclasses to provide their own environment.
    * Used probably only by EditorSupport.
    *
    * @param entry the entry to work on
    * @param env the environment to work on
    */
    protected OpenSupport (MultiDataObject.Entry entry, Env env) {
        super (env);
        this.entry = entry;
    }
    

    /** Message to display when an object is being opened.
    * @return the message or null if nothing should be displayed
    */
    protected String messageOpening () {
        DataObject obj = entry.getDataObject ();

        return NbBundle.getMessage (OpenSupport.class , "CTL_ObjectOpen", // NOI18N
            obj.getName(),
            obj.getPrimaryFile().toString()
        );
    }
    

    /** Message to display when an object has been opened.
    * @return the message or null if nothing should be displayed
    */
    protected String messageOpened () {
        return NbBundle.getMessage (OpenSupport.class, "CTL_ObjectOpened");
    }


    /** Method to access all editors from subclasses. Needed for compilation by 1.2
    */
    final CloneableTopComponent.Ref allEditors () {
        return allEditors;
    }

    /** Environment that connects the support together with DataObject.
    */
    public static class Env extends Object 
    implements CloneableOpenSupport.Env, java.io.Serializable,
    PropertyChangeListener, VetoableChangeListener {
        /** generated Serialized Version UID */
        static final long serialVersionUID = -1934890789745432531L;
        /** object to serialize and be connected to*/
        private DataObject obj;
        
        /** support for firing of property changes
        */
        private transient PropertyChangeSupport propSupp;
        /** support for firing of vetoable changes
        */
        private transient VetoableChangeSupport vetoSupp;

        // #27587
        /** Map of FileSystem to its listener (weak reference of it). 
         * One listener per one filesystem for all env's from that fs. */
        private static final Map fsListenerMap = new WeakHashMap(30);
        
        // A private lock  
        private static final Object LOCK_SUPPORT = new Object();
        
        /** Constructor. Attaches itself as listener to 
        * the data object so, all property changes of the data object
        * are also rethrown to own listeners.
        *
        * @param obj data object to be attached to
        */
        public Env (DataObject obj) {
            this.obj = obj;
            init();
        }
        
        private void readObject (ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
            ois.defaultReadObject();
            init();
        }
        
        private void init() {
            obj.addPropertyChangeListener(org.openide.util.WeakListeners.propertyChange(this, obj));

            // XXX #25400. Ugly patch for being able to react
            // on change of root directory of filesystem, see more in the issue.
            final FileSystem fs;
            try {
                fs = obj.getPrimaryFile().getFileSystem();
            } catch(FileStateInvalidException fsie) {
                IllegalStateException ise = new IllegalStateException(
                    "FileSystem is invalid for " + obj.getPrimaryFile() + "!" // NOI18N
                );
                org.openide.ErrorManager.getDefault().annotate(ise, fsie);
                throw ise;
            }

            FileSystemNameListener fsListener;
            boolean initListening = false;
            synchronized(fsListenerMap) {
                Reference fsListenerRef = (Reference)fsListenerMap.get(fs);
                fsListener = fsListenerRef == null 
                                ? null
                                : (FileSystemNameListener)fsListenerRef.get();
                        
                if(fsListener == null) {
                    // Create listener for that filesystem.
                    fsListener = new FileSystemNameListener();
                    fsListenerMap.put(fs, new WeakReference(fsListener));
                    initListening = true;
                }
            }

            if(initListening) {
                fs.addPropertyChangeListener(fsListener);
                fs.addVetoableChangeListener(fsListener);
            }

            fsListener.add(this);
            // End of patch #25400.
        }
        
        /** Getter for data object.
        */
        protected final DataObject getDataObject () {
            return obj;
        }

        /** Adds property listener.
         */
        public void addPropertyChangeListener(PropertyChangeListener l) {
            prop ().addPropertyChangeListener (l);
        }

        /** Removes property listener.
         */
        public void removePropertyChangeListener(PropertyChangeListener l) {
            prop ().removePropertyChangeListener (l);
        }

        /** Adds veto listener.
         */
        public void addVetoableChangeListener(VetoableChangeListener l) {
            veto ().addVetoableChangeListener (l);
        }

        /** Removes veto listener.
         */
        public void removeVetoableChangeListener(VetoableChangeListener l) {
            veto ().removeVetoableChangeListener (l);
        }

        /** Test whether the support is in valid state or not.
        * It could be invalid after deserialization when the object it
        * referenced to does not exist anymore.
        *
        * @return true or false depending on its state
        */
        public boolean isValid () {
            return getDataObject ().isValid ();
        }
        
        /** Test whether the object is modified or not.
         * @return true if the object is modified
         */
        public boolean isModified() {
            return getDataObject ().isModified ();
        }

        /** Support for marking the environement modified.
        * @exception IOException if the environment cannot be marked modified
        *   (for example when the file is readonly), when such exception
        *   is the support should discard all previous changes
        */
        public void markModified() throws java.io.IOException {
            getDataObject ().setModified (true);
        }
        
        /** Reverse method that can be called to make the environment 
        * unmodified.
        */
        public void unmarkModified() {
            getDataObject ().setModified (false);
        }
        
        /** Method that allows environment to find its 
         * cloneable open support.
        * @return the support or null if the environemnt is not in valid 
        * state and the CloneableOpenSupport cannot be found for associated
        * data object
        */
        public CloneableOpenSupport findCloneableOpenSupport() {
            return (CloneableOpenSupport)getDataObject ().getCookie (CloneableOpenSupport.class);
        }
        
        /** Accepts property changes from DataObject and fires them to
        * own listeners.
        */
        public void propertyChange(PropertyChangeEvent ev) {
            if (DataObject.PROP_MODIFIED.equals (ev.getPropertyName())) {
                if (getDataObject ().isModified ()) {
                    getDataObject ().addVetoableChangeListener(this);
                } else {
                    getDataObject ().removeVetoableChangeListener(this);
                }
            }
            
            firePropertyChange (
                ev.getPropertyName (),
                ev.getOldValue (),
                ev.getNewValue ()
            );
        }
        
        /** Accepts vetoable changes and fires them to own listeners.
        */
        public void vetoableChange(PropertyChangeEvent ev) throws PropertyVetoException {
            fireVetoableChange (
                ev.getPropertyName (),
                ev.getOldValue (),
                ev.getNewValue ()
            );
        }
        
        /** Fires property change.
        * @param name the name of property that changed
        * @param oldValue old value
        * @param newValue new value
        */
        protected void firePropertyChange (String name, Object oldValue, Object newValue) {
            prop ().firePropertyChange (name, oldValue, newValue);
        }
        
        /** Fires vetoable change.
        * @param name the name of property that changed
        * @param oldValue old value
        * @param newValue new value
        */
        protected void fireVetoableChange (String name, Object oldValue, Object newValue) 
        throws PropertyVetoException {
            veto ().fireVetoableChange (name, oldValue, newValue);
        }
        
        /** Lazy getter for change support.
        */
        private PropertyChangeSupport prop () {
            synchronized (LOCK_SUPPORT) {
                if (propSupp == null) {
                    propSupp = new PropertyChangeSupport (this);
                }
                return propSupp;
            }
        }
        
        /** Lazy getter for veto support.
        */
        private VetoableChangeSupport veto () {
            synchronized (LOCK_SUPPORT) {
                if (vetoSupp == null) {
                    vetoSupp = new VetoableChangeSupport (this);
                }
                return vetoSupp;
            }
        }
    }
    
    
    /** Listener for FileSystem.PROP_SYSTEM_NAME proeperty. */
    private static final class FileSystemNameListener
    implements PropertyChangeListener, VetoableChangeListener {
        /** Set of Env's interested in changes on fs name. */
        private final Set environments = new WeakSet(30);
        
        public FileSystemNameListener() {
        }

        /** Adds another Env which is interested on fs name changes. */
        public void add(Env env) {
            synchronized(environments) {
                environments.add(env);
            }
        }
        
        public void propertyChange(PropertyChangeEvent evt) {
            if(FileSystem.PROP_SYSTEM_NAME.equals(evt.getPropertyName())) {
                Set envs;
                synchronized(environments) {
                    envs = new HashSet(environments);
                }
                
                for(Iterator it = envs.iterator(); it.hasNext(); ) {
                    Env env = (Env)it.next();
                    env.firePropertyChange(DataObject.PROP_VALID,
                        Boolean.TRUE, Boolean.FALSE);
                }
            }
        }
        
        public void vetoableChange(PropertyChangeEvent evt) 
        throws PropertyVetoException {
            if(FileSystem.PROP_SYSTEM_NAME.equals(evt.getPropertyName())) {
                Set envs;
                synchronized(environments) {
                    envs = new HashSet(environments);
                }
                
                for(Iterator it = envs.iterator(); it.hasNext(); ) {
                    Env env = (Env)it.next();
                    env.fireVetoableChange(DataObject.PROP_VALID,
                        Boolean.TRUE, Boolean.FALSE);
                }
            }
        }
    } // End of class FileSystemNameListener.

    /** Only for backward compatibility of settings
    */
    private static final class Listener extends CloneableTopComponent.Ref {
        /** generated Serialized Version UID */
        static final long serialVersionUID = -1934890789745432531L;
        /** entry to serialize */
        private MultiDataObject.Entry entry;
        
        Listener() {}

        public Object readResolve () {
            DataObject obj = entry.getDataObject ();
            OpenSupport os = (OpenSupport)obj.getCookie (OpenSupport.class);
            if (os == null) {
                // problem! no replace!?
                return this;
            }
            // use the editor support's CloneableTopComponent.Ref
            return os.allEditors ();
        }
    }
}

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.