Annotations to declare MIME type
--- a/openide.filesystems/manifest.mf
+++ a/openide.filesystems/manifest.mf
@@ -2,5 +2,5 @@
OpenIDE-Module: org.openide.filesystems
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
-OpenIDE-Module-Specification-Version: 7.58
+OpenIDE-Module-Specification-Version: 7.59
--- a/openide.filesystems/src/org/openide/filesystems/Repository.java
+++ a/openide.filesystems/src/org/openide/filesystems/Repository.java
@@ -56,13 +56,8 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
+import java.util.*;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.Manifest;
import java.util.logging.Level;
@@ -72,6 +67,7 @@
import org.openide.util.LookupListener;
import org.openide.util.NbCollections;
import org.openide.util.io.NbMarshalledObject;
+import org.openide.util.lookup.ServiceProvider;
/**
* Holder for NetBeans default (system, configuration) filesystem, used for most
@@ -143,6 +139,70 @@
return repository;
}
+
+ /** Contributes to content of {@link #getDefaultFileSystem() system file system}
+ * (which influences structure under {@link FileUtil#getConfigRoot()}). The
+ * method {@link #registerLayers(java.util.Collection)}
+ * is called during initialization of {@link Repository} and
+ * implementors (registered via {@link ServiceProvider} annotation) may
+ * add their layers (later processed via {@link XMLFileSystem}) into
+ * the general collection of existing providers.
+ *
+ * The list of layers as well as their content may be cached.
+ * In a typical NetBeans Platform application, the cache remains until
+ * list of modules
+ * and their enabled state remain the same. While it does, the {@link LayersProvider}s
+ * are not queried again.
+ *
+ * @since 7.59
+ */
+ public static abstract class LayersProvider {
+ /** Allows providers to add their additions to the structure
+ * beneath {@link FileUtil#getConfigRoot()}. The method is
+ * supposed to collect all additional layers and {@link Collection#add(java.lang.Object) add}
+ * them into the context
collection. The provided
+ * layers will be processed by {@link XMLFileSystem}-like manner later.
+ *
+ * @param context the context where to register the additions
+ */
+ protected abstract void registerLayers(Collection super URL> context);
+
+ /** Method to call when set of URLs returned from the {@link #layers()}
+ * method changed and there is a need to refresh it. Refresh is very likely
+ * a time consuming task - consider invoking it on a background thread and
+ * don't hold any locks while calling the method
+ */
+ protected final void refresh() {
+ Repository.getDefault().refreshAdditionalLayers();
+ }
+ }
+
+ /** Methods that tells {@link Repository} subclasses to refresh list of
+ * URLs provided by {@link LayersProvider}s.
+ * @since 7.59
+ */
+ protected void refreshAdditionalLayers() {
+ if (getDefaultFileSystem() instanceof MainFS) {
+ ((MainFS)getDefaultFileSystem()).refreshLayers();
+ }
+ }
+
+ /** Allows subclasses registered as {@link Repository#getDefault()} to
+ * find out list of URLs for a given provider. The method just calls
+ * {@link LayersProvider#layers()}.
+ *
+ * @param p the provider.
+ * @return ordered list of URLs
+ * @since 7.59
+ */
+ protected final List extends URL> findLayers(LayersProvider p) {
+ if (this != Repository.getDefault()) {
+ return Collections.emptyList();
+ }
+ List urls = new ArrayList();
+ p.registerLayers(urls);
+ return urls;
+ }
private static final class MainFS extends MultiFileSystem implements LookupListener {
private static final Lookup.Result ALL = Lookup.getDefault().lookupResult(FileSystem.class);
@@ -151,29 +211,13 @@
public MainFS() {
ALL.addLookupListener(this);
+ refreshLayers();
+ }
+
+ final void refreshLayers() {
List layerUrls = new ArrayList();
- ClassLoader l = Thread.currentThread().getContextClassLoader();
try {
- for (URL manifest : NbCollections.iterable(l.getResources("META-INF/MANIFEST.MF"))) { // NOI18N
- InputStream is = manifest.openStream();
- try {
- Manifest mani = new Manifest(is);
- String layerLoc = mani.getMainAttributes().getValue("OpenIDE-Module-Layer"); // NOI18N
- if (layerLoc != null) {
- URL layer = l.getResource(layerLoc);
- if (layer != null) {
- layerUrls.add(layer);
- } else {
- LOG.warning("No such layer: " + layerLoc);
- }
- }
- } finally {
- is.close();
- }
- }
- for (URL generatedLayer : NbCollections.iterable(l.getResources("META-INF/generated-layer.xml"))) { // NOI18N
- layerUrls.add(generatedLayer);
- }
+ provideLayer(layerUrls);
layers.setXmlUrls(layerUrls.toArray(new URL[layerUrls.size()]));
LOG.log(Level.FINE, "Loading classpath layers: {0}", layerUrls);
} catch (Exception x) {
@@ -182,6 +226,33 @@
resultChanged(null); // run after add listener - see PN1 in #26338
}
+ private void provideLayer(List layerUrls) throws IOException {
+ ClassLoader l = Thread.currentThread().getContextClassLoader();
+ for (URL manifest : NbCollections.iterable(l.getResources("META-INF/MANIFEST.MF"))) { // NOI18N
+ InputStream is = manifest.openStream();
+ try {
+ Manifest mani = new Manifest(is);
+ String layerLoc = mani.getMainAttributes().getValue("OpenIDE-Module-Layer"); // NOI18N
+ if (layerLoc != null) {
+ URL layer = l.getResource(layerLoc);
+ if (layer != null) {
+ layerUrls.add(layer);
+ } else {
+ LOG.warning("No such layer: " + layerLoc);
+ }
+ }
+ } finally {
+ is.close();
+ }
+ }
+ for (URL generatedLayer : NbCollections.iterable(l.getResources("META-INF/generated-layer.xml"))) { // NOI18N
+ layerUrls.add(generatedLayer);
+ }
+ for (LayersProvider p : Lookup.getDefault().lookupAll(LayersProvider.class)) {
+ p.registerLayers(layerUrls);
+ }
+ }
+
private static FileSystem[] computeDelegates() {
List arr = new ArrayList();
arr.add(MEMORY);
--- a/openide.filesystems/test/unit/src/org/openide/filesystems/ContentProviderTest.java
+++ a/openide.filesystems/test/unit/src/org/openide/filesystems/ContentProviderTest.java
@@ -0,0 +1,95 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.openide.filesystems;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.netbeans.junit.MockServices;
+import org.netbeans.junit.NbTestCase;
+import org.openide.filesystems.Repository.LayersProvider;
+import org.openide.util.Lookup;
+
+public class ContentProviderTest extends NbTestCase {
+ static {
+ MockServices.setServices(MyProvider.class);
+ }
+
+ public ContentProviderTest(String name) {
+ super(name);
+ }
+
+ public void testCheckAFileFromOurLayer() {
+ FileObject fo = FileUtil.getConfigFile("foo/bar");
+ assertNotNull("foo/bar is provided", fo);
+ assertEquals("value is val", "val", fo.getAttribute("x"));
+ }
+
+ public void testRefreshTheProvider() throws Exception {
+ MyProvider my = Lookup.getDefault().lookup(MyProvider.class);
+ assertNotNull("My provider found", my);
+
+ my.clear();
+
+ FileObject fo = FileUtil.getConfigFile("foo/bar");
+ assertNull("foo/bar is no longer available", fo);
+
+ }
+
+ public static final class MyProvider extends LayersProvider {
+ private boolean empty;
+
+ @Override
+ protected void registerLayers(Collection super URL> context) {
+ if (empty) {
+ return;
+ }
+ context.add(ContentProviderTest.class.getResource("test-layer-attribs.xml"));
+ }
+
+ final void clear() throws Exception {
+ empty = true;
+ refresh();
+ }
+ }
+}