Issue #169338: add more options for Lookups.forPath's behavior, including nonrecursive folders and files.
diff --git a/openide.filesystems/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFiles.java b/openide.filesystems/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFiles.java
--- a/openide.filesystems/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFiles.java
+++ b/openide.filesystems/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFiles.java
@@ -68,29 +68,31 @@
private static final Logger LOG = Logger.getLogger(RecognizeInstanceFiles.class.getName());
- public Lookup create(String path) {
- return new OverFiles(path);
+ public Lookup create(String path, Lookups.RecursionMode mode) {
+ return new OverFiles(path, mode);
}
private static final class OverFiles extends ProxyLookup
implements FileChangeListener {
private final String path;
+ private final Lookups.RecursionMode mode;
private final FileChangeListener weakL;
private final AbstractLookup.Content content;
private final AbstractLookup lkp;
- public OverFiles(String path) {
- this(path, new ArrayList(), new AbstractLookup.Content());
+ public OverFiles(String path, Lookups.RecursionMode mode) {
+ this(path, mode, new ArrayList(), new AbstractLookup.Content());
}
- private OverFiles(String path, List items, AbstractLookup.Content cnt) {
- this(path, items, new AbstractLookup(cnt), cnt);
+ private OverFiles(String path, Lookups.RecursionMode mode, List items, AbstractLookup.Content cnt) {
+ this(path, mode, items, new AbstractLookup(cnt), cnt);
}
- private OverFiles(String path, List items, AbstractLookup lkp, AbstractLookup.Content cnt) {
- super(computeDelegates(path, items, lkp));
+ private OverFiles(String path, Lookups.RecursionMode mode, List items, AbstractLookup lkp, AbstractLookup.Content cnt) {
+ super(computeDelegates(path, mode, items, lkp));
this.path = path;
+ this.mode = mode;
this.lkp = lkp;
this.content = cnt;
this.content.setPairs(order(items));
@@ -122,22 +124,30 @@
return;
}
List items = new ArrayList();
- Lookup[] delegates = computeDelegates(path, items, lkp);
+ Lookup[] delegates = computeDelegates(path, mode, items, lkp);
this.content.setPairs(order(items));
this.setLookups(delegates);
}
- private static Lookup[] computeDelegates(String p, List items, Lookup lkp) {
+ private static Lookup[] computeDelegates(String p, Lookups.RecursionMode mode, List items, Lookup lkp) {
FileObject fo = FileUtil.getConfigFile(p);
List delegates = new LinkedList();
delegates.add(lkp);
if (fo != null) {
- for (FileObject f : fo.getChildren()) {
- if (f.isFolder()) {
- delegates.add(new OverFiles(f.getPath()));
- } else {
- if (f.hasExt("instance") || f.getAttribute("instanceCreate") != null) {
- items.add(new FOItem(f));
+ switch (mode) {
+ case FILE:
+ items.add(new FOItem(fo));
+ break;
+ default:
+ for (FileObject f : fo.getChildren()) {
+ if (f.isFolder()) {
+ if (mode != Lookups.RecursionMode.NONRECURSIVE_FOLDER) {
+ delegates.add(new OverFiles(f.getPath(), mode));
+ }
+ } else {
+ if (f.hasExt("instance") || f.getAttribute("instanceCreate") != null) {
+ items.add(new FOItem(f));
+ }
}
}
}
diff --git a/openide.filesystems/test/unit/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFilesTest.java b/openide.filesystems/test/unit/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFilesTest.java
--- a/openide.filesystems/test/unit/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFilesTest.java
+++ b/openide.filesystems/test/unit/src/org/netbeans/modules/openide/filesystems/RecognizeInstanceFilesTest.java
@@ -221,4 +221,25 @@
public static final class Shared extends SharedClassObject {}
+ public void testLoadSingleFile() throws Exception {
+ String path = "inst/class/" + Inst.class.getName().replace('.', '-') + ".instance";
+ FileUtil.createData(root, path);
+ Lookup l = Lookups.forPath(path, Lookups.RecursionMode.FILE);
+ assertNotNull("Instance created", l.lookup(Inst.class));
+ assertEquals(1, l.lookupAll(Object.class).size());
+ }
+
+ public void testFolderRecursion() throws Exception {
+ FileUtil.createData(root, "parent/" + Inst.class.getName().replace('.', '-') + ".instance");
+ FileUtil.createData(root, "parent/child/" + Shared.class.getName().replace('.', '-') + ".instance");
+ Lookup l = Lookups.forPath("parent", Lookups.RecursionMode.NONRECURSIVE_FOLDER);
+ assertEquals(1, l.lookupAll(Object.class).size());
+ l = Lookups.forPath("parent/", Lookups.RecursionMode.NONRECURSIVE_FOLDER);
+ assertEquals(1, l.lookupAll(Object.class).size());
+ l = Lookups.forPath("parent", Lookups.RecursionMode.RECURSIVE_FOLDER);
+ assertEquals(2, l.lookupAll(Object.class).size());
+ l = Lookups.forPath("parent/", Lookups.RecursionMode.RECURSIVE_FOLDER);
+ assertEquals(2, l.lookupAll(Object.class).size());
+ }
+
}
diff --git a/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java b/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java
--- a/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java
+++ b/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java
@@ -48,21 +48,22 @@
private static final Map> map = Collections.synchronizedMap(new HashMap>());
- public abstract Lookup create(String path);
+ public abstract Lookup create(String path, Lookups.RecursionMode mode);
- public static Lookup find(String path) {
- if (!path.endsWith("/")) {
+ public static Lookup find(String path, Lookups.RecursionMode mode) {
+ if (!path.endsWith("/") && mode != Lookups.RecursionMode.FILE) {
path = path + "/";
}
- Reference ref = map.get(path);
+ String key = mode + "/" + path;
+ Reference ref = map.get(key);
Lookup lkp = ref == null ? null : ref.get();
if (lkp != null) {
return lkp;
}
NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
if (prov != null) {
- lkp = prov.create(path);
+ lkp = prov.create(path, mode);
} else {
ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
if (l == null) {
@@ -71,10 +72,15 @@
l = NamedServicesProvider.class.getClassLoader();
}
}
+ switch (mode) {
+ case RECURSIVE_FOLDER:
+ case FILE:
+ throw new UnsupportedOperationException("metaInfServices does not support " + mode);
+ }
lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
}
- map.put(path, new WeakReference(lkp));
+ map.put(key, new WeakReference(lkp));
return lkp;
}
diff --git a/openide.util/src/org/openide/util/Utilities.java b/openide.util/src/org/openide/util/Utilities.java
--- a/openide.util/src/org/openide/util/Utilities.java
+++ b/openide.util/src/org/openide/util/Utilities.java
@@ -2823,7 +2823,7 @@
*/
public static List extends Action> actionsForPath(String path) {
List actions = new ArrayList();
- for (Lookup.Item
*
* Read more about the usage of this method.
@@ -214,7 +216,40 @@
* @since 7.9
*/
public static Lookup forPath(String path) {
- return NamedServicesProvider.find(path);
+ return forPath(path, RecursionMode.UNSPECIFIED_FOLDER);
+ }
+
+ /**
+ * Creates a named lookup as in {@link #forPath(String)} but specifying a recursion mode.
+ * @param path a folder or file path
+ * @param mode how to deal with folders and files
+ * @return a lookup associated with the path
+ * @throws UnsupportedOperationException if mode is not {@link Lookups.RecursionMode#UNSPECIFIED_FOLDER}
+ * and the active provider cannot handle this recursion mode
+ * @since XXX
+ */
+ public static Lookup forPath(String path, RecursionMode mode) throws UnsupportedOperationException {
+ Parameters.notNull("path", path);
+ Parameters.notNull("mode", mode);
+ return NamedServicesProvider.find(path, mode);
+ }
+
+ /**
+ * Controls how files and folders are interpreted by {@link #forPath(String, RecursionMode)}.
+ * @since XXX
+ */
+ public enum RecursionMode {
+ /**
+ * Default mode for compatibility: behavior is dependent on the provider
+ * (may be like {@link #NONRECURSIVE_FOLDER} or like {@link #RECURSIVE_FOLDER}).
+ */
+ UNSPECIFIED_FOLDER,
+ /** The path is a folder and instances will be searched for in direct children of the folder only. */
+ NONRECURSIVE_FOLDER,
+ /** The path is a folder and instances will be searched for in all recursive descendants of the folder. */
+ RECURSIVE_FOLDER,
+ /** The path is a single file to be treated as an instance. */
+ FILE;
}
/** Creates a lookup that wraps another one and filters out instances
diff --git a/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java b/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java
--- a/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java
+++ b/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java
@@ -284,7 +284,7 @@
public void testActionsForPath() throws Exception {
MockLookup.setInstances(new NamedServicesProvider() {
- public Lookup create(String path) {
+ public Lookup create(String path, Lookups.RecursionMode _ignore) {
if (!path.equals("stuff/")) {
return Lookup.EMPTY;
}
diff --git a/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java b/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java
--- a/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java
+++ b/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java
@@ -94,7 +94,7 @@
@Override
- public Lookup create(String path) {
+ public Lookup create(String path, Lookups.RecursionMode _ignore) {
int indx = -1;
if (path.equals("MyServices/")) {
indx = 0;
diff --git a/settings/src/org/netbeans/modules/settings/RecognizeInstanceObjects.java b/settings/src/org/netbeans/modules/settings/RecognizeInstanceObjects.java
--- a/settings/src/org/netbeans/modules/settings/RecognizeInstanceObjects.java
+++ b/settings/src/org/netbeans/modules/settings/RecognizeInstanceObjects.java
@@ -36,13 +36,19 @@
import java.util.Collections;
import java.util.logging.Logger;
import org.netbeans.modules.openide.util.NamedServicesProvider;
+import org.openide.cookies.InstanceCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObject.Container;
+import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.WeakListeners;
+import org.openide.util.lookup.AbstractLookup;
+import org.openide.util.lookup.InstanceContent;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
@@ -55,8 +61,8 @@
private static final Logger LOG = Logger.getLogger(RecognizeInstanceObjects.class.getName());
- public Lookup create(String path) {
- return new OverObjects(path);
+ public Lookup create(String path, Lookups.RecursionMode mode) {
+ return new OverObjects(path, mode);
}
@@ -65,15 +71,17 @@
private static Lookup.Result CL = Lookup.getDefault().lookupResult(ClassLoader.class);
private final String path;
+ private final Lookups.RecursionMode mode;
- public OverObjects(String path) {
- super(delegates(path));
+ public OverObjects(String path, Lookups.RecursionMode mode) {
+ super(delegates(path, mode));
this.path = path;
+ this.mode = mode;
CL.addLookupListener(WeakListeners.create(LookupListener.class, this, CL));
}
@SuppressWarnings("deprecation")
- private static Lookup[] delegates(String path) {
+ private static Lookup[] delegates(final String path, final Lookups.RecursionMode mode) {
Collection extends ClassLoader> allCL = CL.allInstances();
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl != null) {
@@ -84,6 +92,41 @@
}
}
try {
+ if (mode == Lookups.RecursionMode.FILE) {
+ FileObject fo = FileUtil.getConfigFile(path);
+ if (fo != null) {
+ InstanceCookie cookie = DataObject.find(fo).getLookup().lookup(InstanceCookie.class);
+ if (cookie != null) {
+ InstanceContent ic = new InstanceContent();
+ ic.add(cookie, new InstanceContent.Convertor() {
+ public Object convert(InstanceCookie cookie) {
+ try {
+ return cookie.instanceCreate();
+ } catch (Exception x) {
+ Exceptions.printStackTrace(x);
+ return null;
+ }
+ }
+ public Class extends Object> type(InstanceCookie cookie) {
+ try {
+ return cookie.instanceClass();
+ } catch (Exception x) {
+ Exceptions.printStackTrace(x);
+ return Object.class;
+ }
+ }
+ public String id(InstanceCookie cookie) {
+ return path;
+ }
+ public String displayName(InstanceCookie cookie) {
+ return path;
+ }
+ });
+ return new Lookup[] {new AbstractLookup(ic)};
+ }
+ }
+ return new Lookup[0];
+ }
FileObject fo = FileUtil.createFolder(FileUtil.getConfigRoot(), path);
String s;
@@ -94,7 +137,14 @@
}
org.openide.loaders.FolderLookup l;
- l = new org.openide.loaders.FolderLookup(DataFolder.findFolder(fo), s);
+ l = new org.openide.loaders.FolderLookup(DataFolder.findFolder(fo), s) {
+ protected @Override InstanceCookie acceptFolder(DataFolder df) {
+ return mode == Lookups.RecursionMode.NONRECURSIVE_FOLDER ? null : super.acceptFolder(df);
+ }
+ protected @Override InstanceCookie acceptContainer(Container df) {
+ return mode == Lookups.RecursionMode.NONRECURSIVE_FOLDER ? null : super.acceptContainer(df);
+ }
+ };
return new Lookup[] { l.getLookup(), Lookups.metaInfServices(allCL.iterator().next(), "META-INF/namedservices/" + path) }; // NOI18N
} catch (IOException ex) {
return new Lookup[] { Lookups.metaInfServices(allCL.iterator().next(), "META-INF/namedservices/" + path) }; // NOI18N
@@ -103,7 +153,7 @@
}
public void resultChanged(LookupEvent ev) {
- setLookups(delegates(path));
+ setLookups(delegates(path, mode));
}
} // end of OverObjects
}