SLING-6843 : Update to ResourceProvider SPI

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1794379 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 8b33f28..64002f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,7 +81,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.3.0</version>
+            <version>2.16.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/bundleresource/impl/Activator.java b/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
index 919921d..a2d8aa2 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
@@ -40,13 +40,14 @@
     /** default log */
     private final Logger log = LoggerFactory.getLogger(getClass());
 
-    private Map<Long, BundleResourceProvider> bundleResourceProviderMap = new HashMap<Long, BundleResourceProvider>();
+    private final Map<Long, BundleResourceProvider[]> bundleResourceProviderMap = new HashMap<>();
 
-    private BundleContext bundleContext;
+    private volatile BundleContext bundleContext;
 
     /**
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
+    @Override
     public void start(final BundleContext context) throws Exception {
 
         this.bundleContext = context;
@@ -54,8 +55,8 @@
         context.addBundleListener(this);
 
         try {
-            Bundle[] bundles = context.getBundles();
-            for (Bundle bundle : bundles) {
+            final Bundle[] bundles = context.getBundles();
+            for (final Bundle bundle : bundles) {
                 if (bundle.getState() == Bundle.ACTIVE) {
                     // add bundle resource provider for active bundles
                     addBundleResourceProvider(bundle);
@@ -73,6 +74,7 @@
     /**
      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
      */
+    @Override
     public void stop(final BundleContext context) throws Exception {
         BundleResourceWebConsolePlugin.destroyPlugin();
 
@@ -88,7 +90,8 @@
      * @param event The <code>BundleEvent</code> representing the bundle state
      *            change.
      */
-    public void bundleChanged(BundleEvent event) {
+    @Override
+    public void bundleChanged(final BundleEvent event) {
         switch (event.getType()) {
             case BundleEvent.STARTED:
                 // register resource provider for the started bundle
@@ -104,8 +107,8 @@
 
     // ---------- Bundle provided resources -----------------------------------
 
-    private void addBundleResourceProvider(Bundle bundle) {
-        String prefixes = (String) bundle.getHeaders().get(
+    private void addBundleResourceProvider(final Bundle bundle) {
+        final String prefixes = bundle.getHeaders().get(
             BUNDLE_RESOURCE_ROOTS);
         if (prefixes != null) {
             log.debug(
@@ -113,22 +116,31 @@
                 new Object[] { prefixes, bundle.getSymbolicName(),
                     bundle.getBundleId() });
 
-            BundleResourceProvider brp = new BundleResourceProvider(bundle,
-                prefixes);
-            long id = brp.registerService(bundleContext);
-            bundleResourceProviderMap.put(bundle.getBundleId(), brp);
+            final MappedPath[] roots = BundleResourceProvider.getRoots(bundle, prefixes);
+            final BundleResourceProvider[] providers = new BundleResourceProvider[roots.length];
 
-            log.debug("addBundleResourceProvider: Service ID = {}", id);
+            int index = 0;
+            for(final MappedPath path : roots) {
+                final BundleResourceProvider brp = new BundleResourceProvider(bundle, path);
+                final long id = brp.registerService(bundleContext);
+                providers[index] = brp;
+                bundleResourceProviderMap.put(bundle.getBundleId(), providers);
+
+                log.debug("addBundleResourceProvider: Service ID = {}", id);
+                index++;
+            }
         }
     }
 
-    private void removeBundleResourceProvider(Bundle bundle) {
-        BundleResourceProvider brp = bundleResourceProviderMap.remove(bundle.getBundleId());
+    private void removeBundleResourceProvider(final Bundle bundle) {
+        final BundleResourceProvider[] brp = bundleResourceProviderMap.remove(bundle.getBundleId());
         if (brp != null) {
             log.debug(
                 "removeBundleResourceProvider: Unregistering resources for bundle {}/{}",
                 new Object[] { bundle.getSymbolicName(), bundle.getBundleId() });
-            brp.unregisterService();
+            for(final BundleResourceProvider provider : brp) {
+                provider.unregisterService();
+            }
         }
     }
 }
diff --git a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
index 25d5a01..c24f3c1 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
@@ -25,27 +25,28 @@
 import java.util.Iterator;
 import java.util.List;
 
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.sling.api.SlingException;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceProvider;
-import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.commons.osgi.ManifestHeader;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 
-public class BundleResourceProvider implements ResourceProvider {
+public class BundleResourceProvider extends ResourceProvider<Object> {
+
+    public static final String PROP_BUNDLE = BundleResourceProvider.class.getName();
 
     /** The bundle providing the resources */
     private final BundleResourceCache bundle;
 
-    /** The root paths */
-    private final MappedPath[] roots;
+    /** The root path */
+    private final MappedPath root;
 
-    private ServiceRegistration serviceRegistration;
+    @SuppressWarnings("rawtypes")
+    private volatile ServiceRegistration<ResourceProvider> serviceRegistration;
 
     public static MappedPath[] getRoots(final Bundle bundle, final String rootList) {
         List<MappedPath> prefixList = new ArrayList<>();
@@ -68,33 +69,22 @@
      * supporting resources below root paths given by the rootList which is a
      * comma (and whitespace) separated list of absolute paths.
      */
-    public BundleResourceProvider(final Bundle bundle, final String rootList) {
+    public BundleResourceProvider(final Bundle bundle, final MappedPath root) {
         this.bundle = new BundleResourceCache(bundle);
-        List<MappedPath> prefixList = new ArrayList<>();
-
-        final ManifestHeader header = ManifestHeader.parse(rootList);
-        for (final ManifestHeader.Entry entry : header.getEntries()) {
-            final String resourceRoot = entry.getValue();
-            final String pathDirective = entry.getDirectiveValue("path");
-            if (pathDirective != null) {
-                prefixList.add(new MappedPath(resourceRoot, pathDirective));
-            } else {
-                prefixList.add(MappedPath.create(resourceRoot));
-            }
-        }
-        this.roots = getRoots(bundle, rootList);
+        this.root = root;
     }
 
     //---------- Service Registration
 
-    long registerService(BundleContext context) {
-        Dictionary<String, Object> props = new Hashtable<>();
+    long registerService(final BundleContext context) {
+        final Dictionary<String, Object> props = new Hashtable<>();
         props.put(Constants.SERVICE_DESCRIPTION,
             "Provider of bundle based resources");
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
-        props.put(ROOTS, getRoots());
+        props.put(ResourceProvider.PROPERTY_ROOT, getRoot());
+        props.put(PROP_BUNDLE, this.bundle.getBundle().getBundleId());
 
-        serviceRegistration = context.registerService(SERVICE_NAME, this, props);
+        serviceRegistration = context.registerService(ResourceProvider.class, this, props);
         return (Long) serviceRegistration.getReference().getProperty(
             Constants.SERVICE_ID);
     }
@@ -107,22 +97,18 @@
 
     // ---------- ResourceProvider interface
 
-    @Override
-    public Resource getResource(ResourceResolver resourceResolver,
-            HttpServletRequest request, String path) {
-        return getResource(resourceResolver, path);
-    }
-
     /**
      * Returns a BundleResource for the path if such an entry exists in the
-     * bundle of this provider. The JcrResourceResolver is ignored by this
-     * implementation.
+     * bundle of this provider.
      */
     @Override
-    public Resource getResource(ResourceResolver resourceResolver, String path) {
-        MappedPath mappedPath = getMappedPath(path);
+    public Resource getResource(final ResolveContext<Object> ctx,
+            final String path,
+            final ResourceContext resourceContext,
+            final Resource parent) {
+        final MappedPath mappedPath = getMappedPath(path);
         if (mappedPath != null) {
-            return BundleResource.getResource(resourceResolver, bundle,
+            return BundleResource.getResource(ctx.getResourceResolver(), bundle,
                 mappedPath, path);
         }
 
@@ -130,9 +116,7 @@
     }
 
     @Override
-    public Iterator<Resource> listChildren(final Resource parent)
-            throws SlingException {
-
+    public Iterator<Resource> listChildren(ResolveContext<Object> ctx, Resource parent) {
      	if (parent instanceof BundleResource && ((BundleResource)parent).getBundle() == this.bundle) {
             // bundle resources can handle this request directly when the parent
     		//  resource is in the same bundle as this provider.
@@ -159,26 +143,20 @@
         return bundle;
     }
 
-    MappedPath[] getMappedPaths() {
-        return roots;
+    MappedPath getMappedPath() {
+        return root;
     }
 
     // ---------- internal
 
-    /** Returns the root paths */
-    private String[] getRoots() {
-        String[] rootPaths = new String[roots.length];
-        for (int i = 0; i < roots.length; i++) {
-            rootPaths[i] = roots[i].getResourceRoot();
-        }
-        return rootPaths;
+    /** Returns the root path */
+    private String getRoot() {
+        return this.root.getResourceRoot();
     }
 
     private MappedPath getMappedPath(String resourcePath) {
-        for (MappedPath mappedPath : roots) {
-            if (mappedPath.isChild(resourcePath)) {
-                return mappedPath;
-            }
+        if (this.root.isChild(resourcePath)) {
+            return root;
         }
 
         return null;
diff --git a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
index d0358d3..709e3a8 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
@@ -31,7 +31,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -45,11 +45,12 @@
 
     private static final String LABEL = "bundleresources";
 
-    private ServiceRegistration serviceRegistration;
+    private volatile ServiceRegistration<Servlet> serviceRegistration;
 
-    private ServiceTracker providerTracker;
+    @SuppressWarnings("rawtypes")
+    private volatile ServiceTracker<ResourceProvider, ResourceProvider> providerTracker;
 
-    private List<BundleResourceProvider> provider = new ArrayList<>();
+    private final List<BundleResourceProvider> provider = new ArrayList<>();
 
     //--------- setup and shutdown
 
@@ -92,7 +93,7 @@
         for (BundleResourceProvider bundleResourceProvider : brp) {
 
             BundleResourceCache cache = bundleResourceProvider.getBundleResourceCache();
-            MappedPath[] paths = bundleResourceProvider.getMappedPaths();
+            MappedPath path = bundleResourceProvider.getMappedPath();
 
             pw.println("<tr class='content'>");
 
@@ -114,15 +115,12 @@
             pw.println("<table>");
 
             pw.println("<tr>");
-            pw.println("<td>Mappings</td>");
+            pw.println("<td>Mapping</td>");
             pw.println("<td>");
-            for (MappedPath mappedPath : paths) {
-                pw.print(mappedPath.getResourceRoot());
-                if (mappedPath.getEntryRoot() != null) {
-                    pw.print(" ==> ");
-                    pw.print(mappedPath.getEntryRoot());
-                }
-                pw.print("<br>");
+            pw.print(path.getResourceRoot());
+            if (path.getEntryRoot() != null) {
+                pw.print(" ==> ");
+                pw.print(path.getEntryRoot());
             }
             pw.println("</td>");
             pw.println("</tr>");
@@ -149,21 +147,26 @@
 
     }
 
+    @SuppressWarnings("rawtypes")
     public void activate(BundleContext context) {
-        providerTracker = new ServiceTracker(context,
-            ResourceProvider.SERVICE_NAME, null) {
+        providerTracker = new ServiceTracker<ResourceProvider, ResourceProvider>(context,
+            ResourceProvider.class.getName(), null) {
+
             @Override
-            public Object addingService(ServiceReference reference) {
-                Object service = super.addingService(reference);
-                if (service instanceof BundleResourceProvider) {
-                    provider.add((BundleResourceProvider) service);
+            public ResourceProvider addingService(final ServiceReference<ResourceProvider> reference) {
+                ResourceProvider service = null;
+                if ( reference.getProperty(BundleResourceProvider.PROP_BUNDLE) != null ) {
+                    service = super.addingService(reference);
+                    if (service instanceof BundleResourceProvider) {
+                        provider.add((BundleResourceProvider) service);
+                    }
                 }
                 return service;
             }
 
             @Override
-            public void removedService(ServiceReference reference,
-                    Object service) {
+            public void removedService(final ServiceReference<ResourceProvider> reference,
+                    final ResourceProvider service) {
                 if (service instanceof BundleResourceProvider) {
                     provider.remove(service);
                 }
@@ -181,7 +184,7 @@
         props.put("felix.webconsole.category", "Sling");
 
         serviceRegistration = context.registerService(
-            Servlet.class.getName(), this, props);
+            Servlet.class, this, props);
     }
 
     public void deactivate() {
@@ -196,7 +199,7 @@
         }
     }
 
-    private String getName(Bundle bundle) {
+    private String getName(final Bundle bundle) {
         String name = bundle.getHeaders().get(Constants.BUNDLE_NAME);
         if (name == null) {
             name = bundle.getSymbolicName();