|
What this is
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-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.core; import java.util.*; import java.beans.*; import org.openide.ErrorManager; import org.openide.cookies.InstanceCookie; import org.openide.filesystems.*; import org.openide.loaders.*; import org.openide.util.RequestProcessor; import org.openide.util.Task; import org.openide.util.TaskListener; import org.netbeans.core.projects.*; /** * This class implements compile/runtime library path needed for the installed * modules to work well with the IDE. The folder watches for changes in the path * and mounts/unmounts FileSystems to/from repository. * * @author Jaroslav Tulach */ public class AutomountSupport extends FolderInstance implements RepositoryListener, Runnable { /** processor for working with automount */ private static RequestProcessor RP = new RequestProcessor ("Automount"); // NOI18N /** thread variable to signal that we caused the update of filesystems */ private static ThreadLocal VAR = new ThreadLocal (); /** A task to signal when processing has finished or began */ private static DblTask defaultTask; /** store delay */ private static final int DELAY = 1000; /** set of filesystems that were discovered by the folder recognizer and * added by it. The rest of filesystems that are not in the list is * either added by Repository.addFileSystem by somebody else and thus * is waiting for being flushed or was removed */ private static Set createdByMe = new org.openide.util.WeakSet (); /** set of filesystems that was recently added and should not be removed */ private static Set sticky = new org.openide.util.WeakSet (); // private static Set sticky = new HashSet (); /** set of filesystems that was recently removed and should not be added */ private static Set shineAway = new org.openide.util.WeakSet (); // private static Set shineAway = new HashSet (); /** cookies, which are known to throw errors */ private static Set errCookies = new org.openide.util.WeakSet (); /** is the default instance */ private boolean defaultInstance; /** New recognizer of the folder */ private AutomountSupport(DataObject.Container fld, boolean defaultInstance) { super(fld); this.defaultInstance = defaultInstance; } /** Constructs an array of filesystems to */ protected Object createInstance(InstanceCookie[] cookies) throws java.io.IOException, ClassNotFoundException { ArrayList arr = new ArrayList (); for (int i = 0; i < cookies.length; i++) { Object obj; try { obj = cookies[i].instanceCreate (); } catch (java.io.IOException ex) { if (errCookies.add(cookies[i])) { ErrorManager.getDefault ().notify(ErrorManager.INFORMATIONAL, ex); } continue; } errCookies.remove(cookies[i]); if (obj instanceof FileSystem) { arr.add (obj); continue; } if (obj instanceof FileSystem[]) { arr.addAll (Arrays.asList ((FileSystem[])obj)); continue; } } Object retValue; if (arr.size () == 1) { // return the filesystem retValue = arr.get (0); } else { // return array of filesystems retValue = arr.toArray (new FileSystem[0]); } if (defaultInstance) { // update for the topmost instance updateFileSystems (arr); } return retValue; } protected Object instanceForCookie (DataObject obj, InstanceCookie cookie) throws java.io.IOException, ClassNotFoundException { if (errCookies.contains(cookie)) { obj.delete(); return null; } try { return super.instanceForCookie(obj, cookie); } catch (java.io.IOException ioe) { ErrorManager.getDefault ().notify(ErrorManager.INFORMATIONAL, ioe); obj.delete(); return null; } } /** Accepts also folders - by creating the AutomountSupport for them. */ protected InstanceCookie acceptContainer (DataObject.Container container) { return new AutomountSupport (container, false); } /** * Accepts only FileSystem instances. */ protected InstanceCookie acceptCookie(InstanceCookie cookie) throws java.io.IOException, ClassNotFoundException { if (cookie instanceof InstanceCookie.Of) { InstanceCookie.Of of = (InstanceCookie.Of)cookie; if (of.instanceOf (FileSystem.class) || of.instanceOf (FileSystem[].class)) { return cookie; } else { return null; } } // else the regular check for filesystems from the instance Class c = cookie.instanceClass(); if (c.isArray ()) { c = c.getComponentType (); } //System.err.println("AcceptCookie on " + c); if (FileSystem.class.isAssignableFrom(c)) return cookie; else return null; } /** Processing of filesystems will be done in a separate thread. */ protected Task postCreationTask (Runnable run) { return RP.post (run); } /** Returns a list of objects created in this instance. */ private List getList () { Object fsOrFss = null; try { fsOrFss = instanceCreate (); } catch (java.io.IOException ex) { ErrorManager.getDefault ().notify (ex); } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } if (fsOrFss == null) { return Collections.EMPTY_LIST; } if (fsOrFss instanceof FileSystem) { return Collections.nCopies (1, fsOrFss); } else { return Arrays.asList ((FileSystem[])fsOrFss); } } /** Initialize the support. * @return the task one can use to wait for the process to finish */ public static synchronized Task initialize () { // if (defaultInstance != null) { // return defaultInstance; // } if (defaultTask != null) { return defaultTask; } DataFolder folder = NbPlaces.getDefault().findSessionFolder ("Mount"); // NOI18N AutomountSupport auto = new AutomountSupport (folder, true); RequestProcessor.Task storeTask = RP.create (auto); // give the store task minimal priority to work as // less as possible storeTask.setPriority (Thread.MIN_PRIORITY); defaultTask = new DblTask (auto, storeTask); // // because the listener auto.fileSystemAdded and auto.fileSystemRemoved // delegates to defaultTask the task should be initilized before we // attach the listener to the repository // Repository rep = Repository.getDefault (); rep.addRepositoryListener (auto); synchronized (auto) { sticky.addAll (Arrays.asList (rep.toArray ())); if (sticky.size () > 1) { // there is more than just default filesystem => then check // if everything is stored defaultTask.store (); } } // // the start of processing should be done at the end, when all tasks // are initialized (storeTask, defaultTask) // auto.recreate (); return defaultTask; } /** Checks whether everything is saved. */ public void run () { // and save try { FileSystem fs = Repository.getDefault ().getDefaultFileSystem(); fs.runAtomicAction (new FileSystem.AtomicAction () { public void run () { DataFolder df = NbPlaces.getDefault().findSessionFolder ("Mount"); // NOI18N List list = getList (); /* iterate all subfolders recursively and check whether everything is saved as it should be*/ Enumeration en = df.getPrimaryFile().getFolders(true); while (en.hasMoreElements()) { try { DataFolder dfChild = (DataFolder)DataFolder.find((FileObject)en.nextElement()); checkSaved(list,dfChild, dfChild.getChildren(), false); } catch (DataObjectNotFoundException e) { continue; } } /* and finally check mount folder */ checkSaved (list, df, df.getChildren (), true); } }); } catch (java.io.IOException ex) { // cannot be thrown because it is not thrown from the inside code either throw new IllegalStateException (); } } /** FileSystem added. RepositoryListener. */ public void fileSystemAdded (final RepositoryEvent ev) { defaultTask.fs (ev); } /** FileSystem removed. RepositoryListener. */ public void fileSystemRemoved (final RepositoryEvent ev) { defaultTask.fs (ev); } /** FileSystem reorder. RepositoryListener. */ public void fileSystemPoolReordered (RepositoryReorderedEvent ev) { if (VAR.get () == null) { if (isLog ()) { log ("Reorder in repository"); // NOI18N synchronized (Repository.getDefault ()) { FileSystem[] arr = Repository.getDefault ().toArray (); for (int i = 0; i < arr.length; i++) { log (" " + i + "th = " + arr[i]); } } } defaultTask.store (); } else { log ("Repository reordered by AU"); // NOI18N } } /** Finds out whether a filesystem is contained in a repository. * @param fs filesystem * @return true if so false otherwise */ private static boolean containsFS (FileSystem fs) { FileSystem[] arr = Repository.getDefault ().toArray (); for (int i = 0; i < arr.length; i++) { if (arr[i] == fs) { return true; } } return false; } /** compute filename in the same manner as InstanceDataObject.create * [PENDING] in next version this should be replaced by public support * likely from FileUtil * @see issue #17186 */ private static String escape(String name) throws java.io.IOException { try { java.lang.reflect.Method escape = InstanceDataObject.class.getDeclaredMethod( "escapeAndCut", new Class[] {String.class}); //NOI18N escape.setAccessible(true); return (String) escape.invoke(null, new String[] {name}); } catch (Exception ex) { throw (java.io.IOException) ErrorManager.getDefault(). annotate(new java.io.IOException("Escape support failed"), ex); // NOI18N } } /** * Computes a new name of file for use in folder df. If the reguested file * already exists in the given folder try to append a number. * This method should be deleted after #21083 is implemented. */ public static String computeNewName(String requiredName, DataFolder df) throws java.io.IOException { if ((requiredName == null) || (requiredName.length() == 0)) { return null; } boolean isUsed = true; String srcName = requiredName; int i = 1; while (isUsed) { isUsed = false; String escaped = escape(srcName); String uniqueName = FileUtil.findFreeFileName( df.getPrimaryFile(), escaped, "settings" // NOI18N ); if (!escaped.equals(uniqueName)) { isUsed = true; srcName = requiredName + "_" + i; i++; } } return srcName; } /** Stores filesystems that are not stored now. * @param now list of FileSystems read from disk * @param arr array of dat objects in the Mount folder */ private void checkSaved (List now, DataFolder df, DataObject[] arr, boolean isSaveEnabled) { Repository rep = Repository.getDefault (); synchronized (rep) { List asList = Arrays.asList (rep.toArray ()); List exists = new ArrayList (asList); exists.removeAll(createdByMe); exists.removeAll (now); ArrayList order = new ArrayList (asList.size () * 2); order.addAll (Arrays.asList (arr)); sticky.removeAll(now); // remove all data objects in the main level, that should not be there HashSet doNotDeleteFileSystems = new HashSet (asList); // just work with those that are created by me doNotDeleteFileSystems.retainAll (createdByMe); // if the order is different we will need diff List onlyOrder = new ArrayList (asList); onlyOrder.retainAll (now); boolean diff = onlyOrder.size () == now.size () && !onlyOrder.equals (now); if (diff) { // improve the order of data objects class Cmp extends HashMap implements Comparator { public int compare (Object o1, Object o2) { return index (o1) - index (o2); } private int index (Object o1) { return ((Integer)get (o1)).intValue (); } } Cmp cmp = new Cmp (); int i = onlyOrder.size (); Iterator it = order.iterator (); while (it.hasNext ()) { DataObject obj = (DataObject)it.next (); i++; InstanceCookie ic = (InstanceCookie)obj.getCookie (InstanceCookie.class); if (ic != null) { try { Object o = ic.instanceCreate (); int indx = onlyOrder.indexOf (o); if (indx >= 0) { cmp.put (obj, new Integer (indx)); continue; } } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex); } catch (java.io.IOException ex) { ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex); } } cmp.put (obj, new Integer (i)); } Collections.sort (order, cmp); } Iterator it = exists.iterator (); if (isSaveEnabled) { while (it.hasNext ()) { FileSystem fs = (FileSystem)it.next (); if (fs.isDefault ()) { continue; } try { InstanceDataObject dobj; String name = computeNewName(fs.getDisplayName(), df); try { dobj = InstanceDataObject.create (df, name, fs, null); createdByMe.add(fs); } catch(java.io.NotSerializableException nse) { // this can happen when filesystem fs refuses to store itself by // returning null from writeReplace continue; } if (dobj.instanceCreate () != fs) { StringBuffer sb = new StringBuffer (255); sb.append ("This bug is caused by wrong implementation of InstanceDataObject, see "); // NOI18N sb.append ("http://www.netbeans.org/issues/show_bug.cgi?id=14557"); // NOI18N sb.append ("\nSTORING: "); // NOI18N sb.append (fs); sb.append ("\nINSTNCE: "); // NOI18N sb.append (dobj.instanceCreate ()); // NOI18N throw new IllegalStateException (sb.toString ()); } // if we wrote the FS to disk, we do not want to delete it doNotDeleteFileSystems.add (fs); if (isLog ()) { log (" written to disk: " + fs + " into: " + dobj); // NOI18N } order.add (dobj); sticky.remove (fs); diff = true; } catch (java.io.IOException ex) { ErrorManager.getDefault ().notify (ex); } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } } } for (int i = 0; i < arr.length; i++) { InstanceCookie ic = (InstanceCookie)arr[i].getCookie (InstanceCookie.class); if (ic != null) { try { Object obj = ic.instanceCreate (); if ((obj instanceof FileSystem) && !doNotDeleteFileSystems.contains (obj)) { arr[i].delete (); createdByMe.retainAll (Arrays.asList(rep.toArray ())); if (isLog ()) { log (" deleted from disk: " + obj + " from: " + arr[i]); // NOI18N } order.remove (arr[i]); diff = true; } } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } catch (java.io.IOException ex) { ErrorManager.getDefault ().notify (ex); } } } // update the order of filesystems if (diff) { try { df.setOrder ((DataObject[])order.toArray (new DataObject[0])); if (isFinished ()) { log ("I should not be finished"); waitFinished (); log ("And I am not no longer: " + isFinished ()); } if (isLog ()) { log ("Changed order on the disk"); // NOI18N Iterator x = order.iterator (); int i = 0; while (x.hasNext ()) { DataObject obj = (DataObject)x.next (); InstanceCookie ic = (InstanceCookie)obj.getCookie (InstanceCookie.class); if (ic != null) { log (" " + i++ + " is: " + ic.instanceCreate ()); // NOI18N } } } } catch (java.io.IOException ex) { ErrorManager.getDefault ().notify (ex); } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } } /* // add all filestems that are missing ArrayList list = new ArrayList (now); list.addAll (Arrays.asList (rep.toArray ())); updateFileSystems (list); */ } } /* * Updates the filesystems. * @param current collection of FileSystem objects */ private static void updateFileSystems (List future) { Repository rep = Repository.getDefault (); synchronized (rep) { List exists = Arrays.asList (rep.toArray ()); // remove all existing without those future Collection toRemove = new LinkedList (exists); toRemove.removeAll (future); // also do not remove sticky filesystems toRemove.removeAll (sticky); log ("sticky: " + sticky); // just keep those filesystems that are created by me toRemove.retainAll (createdByMe); // log ("by me : " + createdByMe); if (isLog ()) { Iterator it = toRemove.iterator (); while (it.hasNext ()) { FileSystem fs = (FileSystem)it.next (); log (" r: " + fs + " contains: " + sticky.contains (fs)); // NOI18N } } // add all future without those that exists Collection toAdd = new LinkedList (future); toAdd.removeAll (exists); // also do not add filesystems recently removed toAdd.removeAll (shineAway); // log ("shineAway: " + shineAway); // NOI18N if (isLog ()) { Iterator it = toAdd.iterator (); while (it.hasNext ()) { FileSystem fs = (FileSystem)it.next (); log (" a: " + fs + " contains: " + sticky.contains (fs)); // NOI18N } } VAR.set (VAR); // remove & add changes cycleFileSystems (toRemove, false); cycleFileSystems (toAdd, true); // mount the new ones to the repository VAR.set (null); // now all that are recognized by me (future) can be also treated // as created by me createdByMe.addAll (future); // and as such no other filesystems are created by me any longer createdByMe.retainAll (Arrays.asList(rep.toArray ())); // update the order FileSystem[] arr = rep.toArray (); // in future keep only those that are in filesystems List future1 = new LinkedList (future); future1.retainAll (Arrays.asList (arr)); int[] perm = new int[arr.length]; int old = future1.size () + 1; boolean diff = false; for (int i = 0; i < arr.length; i++) { if (arr[i].isDefault ()) { perm[i] = 0; continue; } int indx = future1.indexOf (arr[i]); if (indx == -1) { // filesystem added by somebody else indx = old++; } else { indx++; } perm[indx] = i; diff |= indx != i; } if (diff) { if (isLog ()) { log ("Doing reorder"); // NOI18N for (int i = 0; i < arr.length; i++) { log (" " + i + " <- " + perm[i] + " now: " + arr[i]); // NOI18N } log ("On disk"); // NOI18N Iterator x = future1.iterator (); while (x.hasNext ()) { log (" " + x.next ()); // NOI18N } log ("------"); // NOI18N } VAR.set (VAR); try { rep.reorder (perm); } finally { VAR.set (null); } } else { log ("No reoder"); // NOI18N } /* arr = rep.toArray (); if (future.size () != arr.length - 1) { log ("Not the same size: " + future.size () + " arr: " + arr.length); } else { for (int i = 0; i < arr.length - 1; i++) { if (arr[i + 1] != future.get (i)) { log (" Help:" + i + " arr: " + arr[i + 1] + " current: " + future.get (i)); } else { log (" " + i + " arr: " + arr[i + 1]); } } } */ } } private static void cycleFileSystems (Collection fss, boolean add) { Repository repository = Repository.getDefault (); for (Iterator it = fss.iterator(); it.hasNext(); ) { FileSystem fs = (FileSystem)it.next(); if (add) { // special handling for already mounted filesystems FileSystem old = repository.findFileSystem (fs.getSystemName ()); if (old != null && old != fs && sticky.remove (old)) { // if the sticky object was there (for example mounted before // the automount was initialized) => replace it with this one repository.removeFileSystem (old); } repository.addFileSystem(fs); } else { repository.removeFileSystem (fs); } } } /** error manager. */ private static ErrorManager err; /** Checks whether we log. */ private static boolean isLog () { if (err == null) { err = ErrorManager.getDefault ().getInstance ("org.netbeans.core.AutomountSupport"); // NOI18N } return err.isLoggable (ErrorManager.INFORMATIONAL); } /** Logs to error manager. */ private static void log (String msg) { if (isLog ()) { err.log (msg); } } /** Double task. Delegates to two tasks. */ private static final class DblTask extends Task implements TaskListener { /** task that loads objects in */ private Task defaultInstance; /** task that stores objects to disk */ private RequestProcessor.Task storeTask; /** task that updates state of AutomountSupport from Repository */ private Task updateTask = Task.EMPTY; /** true if store task has been called at least once */ private boolean isStoring; public DblTask (Task defaultInstance, RequestProcessor.Task storeTask) { this.defaultInstance = defaultInstance; this.storeTask = storeTask; defaultInstance.addTaskListener (this); storeTask.addTaskListener (this); } /** Invokes the store task. */ public void store () { synchronized (this) { storeTask.schedule (DELAY); isStoring = true; } notifyRunning (); } /** Test whether the task has finished running. * @return |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
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.