![JAR search and dependency download from the Maven repository](/logo.png)
org.openide.loaders.FolderList 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-2004 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.loaders;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.ref.Reference;
import java.io.IOException;
import java.util.*;
import org.openide.ErrorManager;
import org.openide.util.datatransfer.*;
import org.openide.filesystems.*;
import org.openide.util.*;
/** Watches a folder and its children.
*
* {@link java.beans.PropertyChangeListener}s
* may be registered which will be informed about changes in the ordered
* children list. The {@link java.beans.PropertyChangeEvent}s fired by instances
* of this class do neither contain information about the old value nor about
* the new value of the children list.
*
* The list of children can be retrieved by calls to
* the methods {@link #getChildren()} resp. {@link #getChildrenList()}. If you
* want to filter the children which shall be included into the folder list,
* call {@link #computeChildrenList(FolderListListener)}. The same is true
* if you want to trigger children computation asynchronously. In this case
* the implementation of {@link FolderListListener#finished(List)} shall be
* used to get informed about the result of the computation.
*
* To retrieve the appropriate instance of this class for a given folder
* call {@link #find(FileObject, boolean)}.
*
* @author Jaroslav Tulach
*/
final class FolderList extends Object
implements FileChangeListener, DataObject.Container {
/* -------------------------------------------------------------------- */
/* -- Constants ------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/** serial version UID */
static final long serialVersionUID = -592616022226761148L;
/** priority for tasks that can be run later */
private static final int LATER_PRIORITY = Thread.NORM_PRIORITY;
/** request processor for recognizing of folders */
private static final RequestProcessor PROCESSOR = new RequestProcessor (
"Folder recognizer" // NOI18N
);
/** map of (FileObject, Reference (FolderList)) */
private static final Map map = new WeakHashMap (101);
/** refresh time in milliseconds */
private static int REFRESH_TIME = -1; // will be updated in getRefreshTime
/* -------------------------------------------------------------------- */
/* -- Instance attributes --------------------------------------------- */
/* -------------------------------------------------------------------- */
/** data folder to work with */
protected FileObject folder;
/** The task that computes the content of FolderList. There is also
* only one computation task in the PROCESSOR for each FolderList.
* Whenever a new change notification arrives (thru file listener)
* the previous task is canceled (if not running) and new is created.
*/
transient private RequestProcessor.Task refreshTask;
/** task that is non-null if a setOrder has been called
*/
transient private volatile RequestProcessor.Task comparatorTask;
/** Primary files in this folder. Maps (FileObject, Reference (DataObject))
*/
transient private HashMap primaryFiles = null;
/** order of primary files (FileObject) */
transient private List order;
private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.openide.loaders.FolderList"); // NOI18N
/** property change support */
transient private PropertyChangeSupport pcs;
/**
* If true, this folder has been fully created (though it might
* still be refreshing etc.). Used to avoid e.g. MDO.PROP_FILES
* firing before the folder is ready.
*/
transient private boolean folderCreated = false;
/* -------------------------------------------------------------------- */
/* -- Constructor (private) ------------------------------------------- */
/* -------------------------------------------------------------------- */
/**
* @param df data folder to show
*/
private FolderList (FileObject folder, boolean attach) {
this.folder = folder;
if (attach) {
// creates object that handles all elements in array and
// assignes it to the
folder.addFileChangeListener (org.openide.filesystems.FileUtil.weakFileChangeListener (this, folder));
}
}
/* final void reassign(DataFolder df, FileObject fo) {
folder = df;
// reassign is called from DataFolder.handleMove()
// in this time the folder - df - does not have
// setup the right primary file
// so the fo is the new primary file for df
fo.addFileChangeListener (WeakListener.fileChange (this, fo));
}
*/
public String toString () {
return "FolderList{" + folder + "}"; // NOI18N
}
/* -------------------------------------------------------------------- */
/* -- Factory method (static) ----------------------------------------- */
/* -------------------------------------------------------------------- */
/** A public method to get the correct list for given file object.
*
* @param folder the folder to find FolderList for
* @param create if true than new FolderList should be created if it does not exists
* @return the FolderList or null if create was false
*/
public static FolderList find (FileObject folder, boolean create) {
FolderList list = null;
synchronized (FolderList.class) {
Reference ref = (Reference)map.get (folder);
list = ref == null ? null : (FolderList)ref.get ();
if (list == null && create) {
list = new FolderList (folder, true);
map.put (folder, new SoftReference (list));
}
}
return list;
}
/**
* Has this FolderList finished creation of this list (at least once)?
* @return true if it has been created (may still be refreshing), false if still in progress
*/
public boolean isCreated() {
return folderCreated;
}
/* -------------------------------------------------------------------- */
/* -- Static methods -------------------------------------------------- */
/* -------------------------------------------------------------------- */
/** Checks whether the calling thread is the FolderRecognizer.
*/
public static boolean isFolderRecognizerThread () {
return PROCESSOR.isRequestProcessorThread ();
}
/* -------------------------------------------------------------------- */
/* -- Static methods to inform FolderList for a given folder ---------- */
/* -------------------------------------------------------------------- */
/** A method used to notify the FolderList system that order has changed
* for a given file object.
*
* @param folder the affected file object
*/
public static void changedFolderOrder (FileObject folder) {
FolderList list = find (folder, false);
if (list != null) {
list.changeComparator ();
}
}
/** Called when a data system changed so much that there is a need for refresh
* of a content of a folder.
*
* @param folder file object that can be affected
*/
public static void changedDataSystem (FileObject folder) {
FolderList list = find (folder, false);
if (list != null) {
list.refresh ();
}
}
/* -------------------------------------------------------------------- */
/* -- Folder content and content processing --------------------------- */
/* -------------------------------------------------------------------- */
/** Computes array of children associated
* with this folder.
*/
public DataObject[] getChildren () {
List res = getChildrenList ();
DataObject[] arr = new DataObject[res.size ()];
res.toArray (arr);
return arr;
}
/** List all children.
* @return array with children
*/
public List getChildrenList () {
ListTask lt;
try {
DataObjectPool.getPOOL().enterPriviledgedProcessor (PROCESSOR);
lt = getChildrenList (null);
lt.task.waitFinished();
} finally {
DataObjectPool.getPOOL().exitPriviledgedProcessor (PROCESSOR);
}
return lt.result;
}
/** Blocks if the processing of content of folder is in progress.
*/
public void waitProcessingFinished () {
Task t = comparatorTask;
if (t != null) {
t.waitFinished ();
}
t = refreshTask;
if (t != null) {
t.waitFinished ();
}
}
/** Starts computation of children list asynchronously.
*/
public RequestProcessor.Task computeChildrenList (FolderListListener filter) {
return getChildrenList (filter).task;
}
private ListTask getChildrenList (FolderListListener filter) {
ListTask lt = new ListTask (filter);
int priority = Thread.currentThread().getPriority();
// and then post your read task and wait
lt.task = PROCESSOR.post (lt, 0, priority);
return lt;
}
/** Setter for sort mode.
*/
private synchronized void changeComparator () {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("changeComparator on " + folder);
final RequestProcessor.Task previous = comparatorTask;
final RequestProcessor.Task[] COMP = new RequestProcessor.Task[1];
synchronized (COMP) {
comparatorTask = PROCESSOR.post (new Runnable () {
public void run () {
synchronized (COMP) {
if (previous != null) {
previous.waitFinished ();
}
// if has been notified
// change mode and regenerated children
if (primaryFiles != null) {
// the old children
if (LOG) err.log ("changeComparator on " + folder + ": get old");
List v = getObjects (null);
if (v.size () != 0) {
// the new children - also are stored to be returned next time from getChildrenList ()
order = null;
if (LOG) err.log ("changeComparator: get new");
List r = getObjects (null);
if (LOG) err.log ("changeComparator: fire change");
fireChildrenChange (r, v);
}
}
synchronized (FolderList.this) {
// clean the task if is my own not assigned by somebody else
if (comparatorTask == COMP[0]) {
comparatorTask = null;
}
}
}
}
}, 0, Thread.MIN_PRIORITY);
COMP[0] = comparatorTask;
}
}
/* -------------------------------------------------------------------- */
/* -- Refresh --------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/** Refreshes the list of children.
*/
public void refresh () {
final long now = System.currentTimeMillis();
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("refresh on " + folder + " @" + now);
synchronized (this) {
if (refreshTask == null) {
refreshTask = PROCESSOR.post (new Runnable () {
public void run () {
RequestProcessor.Task t = comparatorTask;
if (t != null) {
// first of all finish setting up comparator
t.waitFinished ();
}
if (LOG) err.log ("-- refresh on " + folder + ": now=" + now);
if (primaryFiles != null) {
// list of children is created, recreate it for new files
createBoth (null, true);
}
}
}, getRefreshTime(), LATER_PRIORITY);
} else {
refreshTask.schedule(getRefreshTime());
}
}
}
/** Tries to read the value of the refresh time from a system property.
* If the system property is not present a default value (currently 10)
* is used.
*/
private static int getRefreshTime() {
if (REFRESH_TIME >= 0) {
return REFRESH_TIME;
}
String sysProp = System.getProperty("org.openide.loaders.FolderList.refresh.interval"); // NOI18N
if (sysProp != null) {
try {
REFRESH_TIME = Integer.parseInt(sysProp);
} catch (NumberFormatException nfe) {
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, nfe);
}
}
if (REFRESH_TIME < 0) {
REFRESH_TIME = 10;
}
return REFRESH_TIME;
}
/* -------------------------------------------------------------------- */
/* -- Implementation of FileChangeListener ---------------------------- */
/* -------------------------------------------------------------------- */
/** Fired when a file has been changed. Refreshes the list when a
* has be changed which up to now was not a member of the list but
* becomes a member as a consequence of the change.
*
* @param fe the event describing context where action has taken place
*/
public void fileChanged (FileEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("fileChanged: " + fe);
FileObject fo = fe.getFile ();
/** condition fo.isValid () is hot fix for solving problem (similar to #17328)
* inside filesystems and should be reviewed.
*/
if (fo.isData () && fo.isValid ()) {
// when a data on the disk has been changed, look whether we
// should reparse children
if (primaryFiles != null) {
// a file has been changed and the list of files is created
try {
DataObject obj = DataObject.find (fo);
if (!primaryFiles.containsKey (obj.getPrimaryFile ())) {
// BUGFIX: someone who recognized the file and who isn't registered
// yet =>
// may be still not O.K.
// this primary file is not registered yet
// so recreate list of children
refresh();
}
} catch (DataObjectNotFoundException ex) {
ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex);
// file without data object => no changes
}
}
// Resort if sorting by last modification or size:
DataFolder.SortMode sortMode = getComparator().getSortMode();
if (sortMode == DataFolder.SortMode.LAST_MODIFIED || sortMode == DataFolder.SortMode.SIZE) {
changeComparator();
}
}
}
/** Fired when a file has been deleted.
* @param fe the event describing context where action has taken place
*/
public void fileDeleted (FileEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("fileDeleted: " + fe);
// boolean debug = fe.getFile().toString().equals("P"); // NOI18N
//if (debug) System.out.println ("fileDeleted: " + fe.getFile ()); // NOI18N
//if (debug) System.out.println ("fileList: " + fileList + " file: " + fileList.get (fe.getFile ())); // NOI18N
if (primaryFiles == null || primaryFiles.containsKey (fe.getFile ())) {
// one of main files has been deleted => reparse
//if (debug) System.out.println ("RecreateChildenList"); // NOI18N
refresh();
//if (debug) System.out.println ("Done"); // NOI18N
}
}
/** Fired when a new file has been created. This action can only be
* listened in folders containing the created file up to the root of
* file system.
*
* @param fe the event describing context where action has taken place
*/
public void fileDataCreated (FileEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("fileDataCreated: " + fe);
refresh();
}
/** Fired when a new file has been created. This action can only be
* listened in folders containing the created file up to the root of
* file system.
*
* @param fe the event describing context where action has taken place
*/
public void fileFolderCreated (FileEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("fileFolderCreated: " + fe);
refresh();
}
/** Fired when a new file has been renamed.
*
* @param fe the event describing context where action has taken place
*/
public void fileRenamed (FileRenameEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("fileRenamed: " + fe);
refresh();
// Typically order may change as a result (#13820):
changeComparator();
}
/** Fired when a file attribute has been changed.
*
* @param fe the event describing context where action has taken place
*/
public void fileAttributeChanged(FileAttributeEvent fe) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log("fileAttributeChanged: " + fe);
// update list when attrs defining order were changed
if (fe.getFile() == folder) {
/** Means one of attributes were changed*/
if (fe.getName() == null) {
changeComparator();
return;
}
if (DataFolder.EA_ORDER.equals(fe.getName()) ||
DataFolder.EA_SORT_MODE.equals(fe.getName()) ||
-1 != fe.getName().indexOf("/")) {
changeComparator();
}
}
}
/* -------------------------------------------------------------------- */
/* -- Processing methods (only called in PROCESSOR) ------------------- */
/* -------------------------------------------------------------------- */
/** The comparator for this file objects.
* @return the comparator to use
*/
private FolderOrder getComparator () {
return FolderOrder.findFor (folder);
}
/** Getter for list of children.
* @param f filter to be notified about additions
* @return List with DataObject types
*/
private List getObjects (FolderListListener f) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("getObjects on " + folder);
List res;
if (primaryFiles == null) {
res = createBoth (f, false);
} else {
if (order != null) {
res = createObjects (order, primaryFiles, f);
} else {
res = createObjects (primaryFiles.keySet (), primaryFiles, f);
res = carefullySort (res, getComparator ());
order = createOrder (res);
}
}
return res;
/* createChildrenAndFiles ();/*
ArrayList v = (Collection)childrenList.get ();
//if (debug) System.out.println ("Children list xxxxxxxxxxxxxx");
if (v == null) {
//if (debug) System.out.println ("Create them xxxxxxxxxxxx");
v = createChildrenList (f);
//if (debug) System.out.println ("result: " + v);
}
return v;*/
}
/** Sort a list of DataObject's carefully.
* The supplied comparator should supply a basic ordering,
* and may also have an associated overriding partial ordering.
* If the partial ordering is given and is self-contradictory,
* it will be ignored and a warning issued.
* @param l the list to sort
* @param c a comparator and maybe partial comparator to use
* @return the sorted list (may or may not be the same)
*/
private /*static*/ List carefullySort (List l, FolderOrder c) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("carefullySort on " + folder);
// Not quite right: topologicalSort will not guarantee that these are left alone,
// even if the constraints do not mention files in the existing folder order.
// Adding constraints between adjacent pairs in the existing folder order is
// not good either, since that could produce an inconsistency relative to
// the explicitly specified constraints. E.g. you have:
// {a, b, c, d, e, x, y} Folder-Order=[a, b, c, d, e] c/x c/y x/d y/d
// This will currently produce the order: [a, b, c, e, x, y, d]
// If you had the existing folder order [a, b, d, c, e], then trying to make
// the sort stabler would just cause it to fail. XXX could try to add in the
// stabilizing constraints first, and if that fails, try again without them...
Collections.sort (l, c);
Map constraints = c.getOrderingConstraints(l);
if (constraints == null) {
return l;
} else {
if (LOG) err.log ("carefullySort: partial orders");
try {
return Utilities.topologicalSort(l, constraints);
} catch (TopologicalSortException ex) {
List corrected = ex.partialSort();
if (err.isLoggable(ErrorManager.WARNING)) {
err.log (ErrorManager.WARNING, "Note: folder " + folder + " cannot be consistently sorted due to ordering conflicts."); // NOI18N
err.notify (ErrorManager.INFORMATIONAL, ex);
err.log (ErrorManager.WARNING, "Using partial sort: " + corrected); // NOI18N
}
return corrected;
}
}
}
/** Creates list of primary files from the list of data objects.
* @param list list of DataObject
* @return list of FileObject
*/
private static List createOrder (List list) {
int size = list.size ();
List res = new ArrayList (size);
for (int i = 0; i < size; i++) {
res.add (((DataObject)list.get (i)).getPrimaryFile ());
}
return res;
}
/** Creates array of data objects from given order
* and mapping between files and data objects.
*
* @param order list of FileObjects that define the order to use
* @param map mapping (FileObject, Reference (DataObject)) to create data objects from
* @param f filter that is notified about additions - only items
* which are accepted by the filter will be added. Null means no filtering.
* @return array of data objects
*/
private /*static*/ List createObjects (
Collection order, Map map, FolderListListener f
) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("createObjects on " + folder);
int size = order.size ();
Iterator it = order.iterator ();
List res = new ArrayList (size);
for (int i = 0; i < size; i++) {
FileObject fo = (FileObject)it.next ();
if (!fo.isValid ()) continue;
Reference ref = (Reference)map.get (fo);
DataObject obj = ref != null ? (DataObject)ref.get() : null;
if (obj == null) {
// try to find new data object
try {
obj = DataObject.find (fo);
ref = new SoftReference (obj);
} catch (DataObjectNotFoundException ex) {
ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex);
}
}
// add if accepted
if (obj != null) {
// JST: Cannot be avoided otherwise DataObject.files () can be unconsistent
// avoid to checkFiles(this)
//obj.recognizedByFolder();
if (f == null) {
// accept all objects
res.add (obj);
} else {
// allow the listener f to filter
// objects in the array res
f.process (obj, res);
}
}
}
if (f != null) {
f.finished (res);
}
return res;
}
/** Scans for files in the folder and creates representation for
* children. Fires info about changes in the nodes.
*
* @param filter listener to addition of nodes or null
* @param notify true if changes in the children should be fired
* @return vector of children
*/
private List createBoth (FolderListListener filter, boolean notify) {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("createBoth on " + folder);
// map for (FileObject, DataObject)
final HashMap file = new HashMap ();
// list of all processed objects
List all = new ArrayList ();
// result list to return from the method
List res = new ArrayList ();
// map of current objects (FileObject, DataObject)
final HashMap remove = primaryFiles == null ?
new HashMap () : (HashMap)primaryFiles.clone ();
// list of new objects to add
final List add = new ArrayList ();
DataLoaderPool pool = DataLoaderPool.getDefault();
// hashtable with FileObjects that are marked to be recognized
// and that is why being out of enumeration
final HashSet marked = new HashSet ();
DataLoader.RecognizedFiles recog = new DataLoader.RecognizedFiles () {
/** Adds the file object to the marked hashtable.
* @param fo file object (can be null
)
*/
public void markRecognized (FileObject fo) {
if (fo != null) {
marked.add (fo);
}
}
};
// enumeration of all files in the folder
Enumeration en = folder.getChildren (false);
while (en.hasMoreElements ()) {
FileObject fo = (FileObject)en.nextElement ();
if (!marked.contains (fo)) {
// the object fo has not been yet marked as recognized
// => continue in computation
DataObject obj;
try {
obj = pool.findDataObject (fo, recog);
} catch (DataObjectExistsException ex) {
// use existing data object
obj = ex.getDataObject ();
} catch (IOException ex) {
// data object not recognized or not found
obj = null;
ErrorManager.getDefault ().notify(ex);
}
if (obj != null) {
// adds object to data if it is not already there
// avoid to checkFiles(this)
obj.recognizedByFolder();
// primary file
FileObject primary = obj.getPrimaryFile ();
boolean doNotRemovePrimaryFile = false;
if (!file.containsKey (primary)) {
// realy added object, test if it is new
// if we have not created primaryFiles before, then it is new
boolean goIn = primaryFiles == null;
if (!goIn) {
Reference r = (Reference)primaryFiles.get (primary);
// if its primary file is not between original primary files
// then data object is new
goIn = r == null;
if (!goIn) {
// if the primary file is there, but the previous data object
// exists and is different, then this one is new
DataObject obj2 = (DataObject)r.get ();
goIn = obj2 == null || obj2 != obj;
if (goIn) {
doNotRemovePrimaryFile = true;
}
}
}
if (goIn) {
// realy new
add.add (obj);
/* JST: In my opinion it should not be here
* so I moved this out of this if. Is it ok?
if (filter != null) {
// fire info about addition
filter.acceptDataObject (obj);
}
*/
}
// adds the object
all.add (obj);
if (filter == null) {
res.add (obj);
} else {
filter.process (obj, res);
}
}
if (!doNotRemovePrimaryFile) {
// this object exists it should not be removed
remove.remove (primary);
}
// add it to the list of primary files
file.put (primary, new WeakReference (obj));
} else {
// 1. nothing to add to data object list
// 2. remove this object if it was in list of previous ones
// 3. do not put the file into list of know primary files
// => do nothing at all
}
}
}
// !!! section that fires info about changes should be here !!!
// now file contains newly inserted files
// data contains data objects
// remove contains data objects that should be removed
// add contains data object that were added
primaryFiles = file;
all = carefullySort (all, getComparator ());
order = createOrder (all);
if (all.size () == res.size ()) {
// assume no filtering has been done
res = all;
} else {
// sort also content of res
res = carefullySort (res, getComparator ());
}
////if (debug) System.out.println ("Notified: " + notified + " added: " + add.size () + " removed: " + remove.size ()); // NOI18N
if (notify) {
fireChildrenChange (add, remove.keySet ());
}
// notify the filter
if (filter != null) {
filter.finished (res);
}
return res;
}
/* -------------------------------------------------------------------- */
/* -- PropertyChangeListener management ------------------------------- */
/* -------------------------------------------------------------------- */
/** Fires info about change of children to the folder.
* @param add added data objects
* @param removed removed data objects
*/
private void fireChildrenChange (Collection add, Collection removed) {
if (pcs != null) {
if (!add.isEmpty() || !removed.isEmpty()) {
pcs.firePropertyChange (PROP_CHILDREN, null, null);
}
}
}
/** Removes property change listener.
* @param l the listener
*/
public void removePropertyChangeListener(PropertyChangeListener l) {
if (pcs != null) {
pcs.removePropertyChangeListener (l);
}
}
/** Adds a listener.
* @param l the listener
*/
public void addPropertyChangeListener(PropertyChangeListener l) {
if (pcs == null) {
synchronized (this) {
if (pcs == null) {
pcs = new PropertyChangeSupport (this);
}
}
}
pcs.addPropertyChangeListener (l);
}
/* -------------------------------------------------------------------- */
/* -- Inner class ListTask -------------------------------------------- */
/* -------------------------------------------------------------------- */
/** Task that holds result and also task. Moreover
* can do the computation.
*/
private final class ListTask implements Runnable {
private FolderListListener filter;
public ListTask (FolderListListener filter) {
this.filter = filter;
}
public List result;
public RequestProcessor.Task task;
public void run () {
final boolean LOG = err.isLoggable(ErrorManager.INFORMATIONAL);
if (LOG) err.log ("ListTask.run 1 on " + folder);
// invokes the refresh task before we do anything else
if (comparatorTask != null) {
comparatorTask.waitFinished ();
}
if (refreshTask != null) {
refreshTask.waitFinished ();
}
err.log ("ListTask.run 2");
result = getObjects (filter);
err.log ("ListTask.run 3");
folderCreated = true;
}
}
}