You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:46:47 UTC

[sling-org-apache-sling-jcr-contentloader] 21/36: SLING-766 : Don't uninstall content when bundle is stopped. The content is now only uninstalled when the bundle is uninstalled. During installation a string array containing all paths that will be removed later on is collected which makes the uninstall easier. Also refactored the classes and packages a little bit.

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.jcr.contentloader-2.0.4-incubator
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-contentloader.git

commit 5736f529eee826aebb640984215f426f0049ce55
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Dec 16 13:32:17 2008 +0000

    SLING-766 : Don't uninstall content when bundle is stopped. The content is now only uninstalled when the bundle is uninstalled. During installation a string
    array containing all paths that will be removed later on is collected which makes the uninstall easier. Also refactored the classes and packages a little bit.
    
    git-svn-id: https://svn.apache.org/repos/asf/incubator/sling/trunk/jcr/contentloader@727047 13f79535-47bb-0310-9956-ffa450edef68
---
 .../jcr/contentloader/internal/ContentCreator.java |   2 +-
 .../internal/ContentLoaderService.java             |  40 +++-
 .../jcr/contentloader/internal/ContentReader.java  |   2 +-
 ...ntentLoader.java => DefaultContentCreator.java} |  52 ++++-
 .../jcr/contentloader/internal/ImportProvider.java |   4 +-
 .../sling/jcr/contentloader/internal/Loader.java   | 238 +++++++--------------
 .../internal/{ => readers}/JsonReader.java         |   9 +-
 .../internal/{ => readers}/XmlReader.java          |   7 +-
 .../internal/{ => readers}/ZipReader.java          |  11 +-
 .../jcr/contentloader/internal/JsonReaderTest.java |   1 +
 10 files changed, 177 insertions(+), 189 deletions(-)

diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentCreator.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentCreator.java
index 4390f4e..3e93ac1 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentCreator.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentCreator.java
@@ -28,7 +28,7 @@ import javax.jcr.RepositoryException;
  *
  * @since 2.0.4
  */
-interface ContentCreator {
+public interface ContentCreator {
 
     /**
      * Create a new node.
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
index 341fda5..9781ce5 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoaderService.java
@@ -21,6 +21,7 @@ package org.apache.sling.jcr.contentloader.internal;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -28,6 +29,7 @@ import java.util.StringTokenizer;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
 import javax.jcr.lock.LockException;
 
 import org.apache.sling.commons.mime.MimeTypeService;
@@ -56,6 +58,11 @@ import org.slf4j.LoggerFactory;
 public class ContentLoaderService implements SynchronousBundleListener {
 
     public static final String PROPERTY_CONTENT_LOADED = "content-loaded";
+    private static final String PROPERTY_CONTENT_LOADED_AT = "content-load-time";
+    private static final String PROPERTY_CONTENT_LOADED_BY = "content-loaded-by";
+    private static final String PROPERTY_CONTENT_UNLOADED_AT = "content-unload-time";
+    private static final String PROPERTY_CONTENT_UNLOADED_BY = "content-unloaded-by";
+    public static final String PROPERTY_UNINSTALL_PATHS = "uninstall-paths";
 
     public static final String BUNDLE_CONTENT_NODE = "/var/sling/bundle-content";
 
@@ -140,7 +147,7 @@ public class ContentLoaderService implements SynchronousBundleListener {
                 // we will use this info when the new start event is triggered
                 this.updatedBundles.add(event.getBundle().getSymbolicName());
                 break;
-            case BundleEvent.STOPPED:
+            case BundleEvent.UNINSTALLED:
                 try {
                     Session session = getAdminSession();
                     initialContentLoader.unregisterBundle(session, event.getBundle());
@@ -269,11 +276,14 @@ public class ContentLoaderService implements SynchronousBundleListener {
      * @return The map of bundle content info or null.
      * @throws RepositoryException
      */
-    public Map<String, Object> getBundleContentInfo(final Session session, final Bundle bundle)
+    public Map<String, Object> getBundleContentInfo(final Session session, final Bundle bundle, boolean create)
     throws RepositoryException {
         final String nodeName = bundle.getSymbolicName();
         final Node parentNode = (Node)session.getItem(BUNDLE_CONTENT_NODE);
         if ( !parentNode.hasNode(nodeName) ) {
+            if ( !create ) {
+                return null;
+            }
             try {
                 final Node bcNode = parentNode.addNode(nodeName, "nt:unstructured");
                 bcNode.addMixin("mix:lockable");
@@ -300,22 +310,34 @@ public class ContentLoaderService implements SynchronousBundleListener {
         } else {
             info.put(ContentLoaderService.PROPERTY_CONTENT_LOADED, false);
         }
+        if ( bcNode.hasProperty(ContentLoaderService.PROPERTY_UNINSTALL_PATHS) ) {
+            final Value[] values = bcNode.getProperty(PROPERTY_UNINSTALL_PATHS).getValues();
+            final String[] s = new String[values.length];
+            for(int i=0; i<values.length; i++) {
+                s[i] = values[i].getString();
+            }
+            info.put(ContentLoaderService.PROPERTY_UNINSTALL_PATHS, s);
+        }
         return info;
     }
 
     public void unlockBundleContentInfo(final Session session,
                                         final Bundle  bundle,
-                                        final boolean contentLoaded)
+                                        final boolean contentLoaded,
+                                        final List<String> createdNodes)
     throws RepositoryException {
         final String nodeName = bundle.getSymbolicName();
         final Node parentNode = (Node)session.getItem(BUNDLE_CONTENT_NODE);
         final Node bcNode = parentNode.getNode(nodeName);
         if ( contentLoaded ) {
             bcNode.setProperty(ContentLoaderService.PROPERTY_CONTENT_LOADED, contentLoaded);
-            bcNode.setProperty("content-load-time", Calendar.getInstance());
-            bcNode.setProperty("content-loaded-by", this.slingId);
-            bcNode.setProperty("content-unload-time", (String)null);
-            bcNode.setProperty("content-unloaded-by", (String)null);
+            bcNode.setProperty(PROPERTY_CONTENT_LOADED_AT, Calendar.getInstance());
+            bcNode.setProperty(PROPERTY_CONTENT_LOADED_BY, this.slingId);
+            bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_AT, (String)null);
+            bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_BY, (String)null);
+            if ( createdNodes != null && createdNodes.size() > 0 ) {
+                bcNode.setProperty(PROPERTY_UNINSTALL_PATHS, createdNodes.toArray(new String[createdNodes.size()]));
+            }
             bcNode.save();
         }
         bcNode.unlock();
@@ -329,8 +351,8 @@ public class ContentLoaderService implements SynchronousBundleListener {
             if ( parentNode.hasNode(nodeName) ) {
                 final Node bcNode = parentNode.getNode(nodeName);
                 bcNode.setProperty(ContentLoaderService.PROPERTY_CONTENT_LOADED, false);
-                bcNode.setProperty("content-unload-time", Calendar.getInstance());
-                bcNode.setProperty("content-unloaded-by", this.slingId);
+                bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_AT, Calendar.getInstance());
+                bcNode.setProperty(PROPERTY_CONTENT_UNLOADED_BY, this.slingId);
                 bcNode.save();
             }
         } catch (RepositoryException re) {
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
index b36fa7d..2d5aaf1 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
@@ -27,7 +27,7 @@ import javax.jcr.RepositoryException;
  * The <code>ContentReader</code>
  * A content reader is provided by an {@link ImportProvider}.
  */
-interface ContentReader {
+public interface ContentReader {
 
     /**
      * Read the content from the input stream and create the
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
similarity index 92%
rename from src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoader.java
rename to src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
index a9c656a..c22b509 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentLoader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
@@ -41,7 +41,7 @@ import javax.jcr.ValueFactory;
  * The <code>ContentLoader</code> creates the nodes and properties.
  * @since 2.0.4
  */
-public class ContentLoader implements ContentCreator {
+public class DefaultContentCreator implements ContentCreator {
 
     private PathEntry configuration;
 
@@ -65,21 +65,32 @@ public class ContentLoader implements ContentCreator {
     // default content type for createFile()
     private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
 
+    /** Helper class to get the mime type of a file. */
     private final ContentLoaderService jcrContentHelper;
 
+    /** List of active import providers mapped by extension. */
     private Map<String, ImportProvider> importProviders;
 
-    public ContentLoader(ContentLoaderService jcrContentHelper) {
+    /** Optional list of created nodes (for uninstall) */
+    private List<String> createdNodes;
+
+    /**
+     * Constructor.
+     * @param jcrContentHelper Helper class to get the mime type of a file
+     */
+    public DefaultContentCreator(ContentLoaderService jcrContentHelper) {
         this.jcrContentHelper = jcrContentHelper;
     }
 
     /**
      * Initialize this component.
-     * @param pathEntry
+     * @param pathEntry The configuration for this import.
+     * @param defaultImportProviders List of all import providers.
+     * @param createdNodes Optional list to store new nodes (for uninstall)
      */
     public void init(final PathEntry pathEntry,
-                     final Map<String, ImportProvider> defaultImportProviders) {
-
+                     final Map<String, ImportProvider> defaultImportProviders,
+                     final List<String> createdNodes) {
         this.configuration = pathEntry;
         // create list of allowed import providers
         this.importProviders = new HashMap<String, ImportProvider>();
@@ -90,6 +101,7 @@ public class ContentLoader implements ContentCreator {
                 importProviders.put(current.getKey(), current.getValue());
             }
         }
+        this.createdNodes = createdNodes;
     }
 
     /**
@@ -121,6 +133,10 @@ public class ContentLoader implements ContentCreator {
         this.versionables.clear();
     }
 
+    /**
+     * Set the ignore overwrite flag.
+     * @param flag
+     */
     public void setIgnoreOverwriteFlag(boolean flag) {
         this.ignoreOverwriteFlag = flag;
     }
@@ -132,10 +148,19 @@ public class ContentLoader implements ContentCreator {
         return this.rootNode;
     }
 
+    /**
+     * Get all active import providers.
+     * @return A map of providers
+     */
     public Map<String, ImportProvider> getImportProviders() {
         return this.importProviders;
     }
 
+    /**
+     * Return the import provider for the name
+     * @param name The file name.
+     * @return The provider or <code>null</code>
+     */
     public ImportProvider getImportProvider(String name) {
         ImportProvider provider = null;
         final Iterator<String> ipIter = importProviders.keySet().iterator();
@@ -148,6 +173,11 @@ public class ContentLoader implements ContentCreator {
         return provider;
     }
 
+    /**
+     * Get the extension of the file name.
+     * @param name The file name.
+     * @return The extension a provider is registered for - or <code>null</code>
+     */
     public String getImportProviderExtension(String name) {
         String providerExt = null;
         final Iterator<String> ipIter = importProviders.keySet().iterator();
@@ -188,16 +218,21 @@ public class ContentLoader implements ContentCreator {
 
                 // use existing node
                 node = parentNode.getNode(name);
-
             } else if (primaryNodeType == null) {
 
                 // no explicit node type, use repository default
                 node = parentNode.addNode(name);
+                if ( this.createdNodes != null ) {
+                    this.createdNodes.add(node.getPath());
+                }
 
             } else {
 
                 // explicit primary node type
                 node = parentNode.addNode(name, primaryNodeType);
+                if ( this.createdNodes != null ) {
+                    this.createdNodes.add(node.getPath());
+                }
             }
 
             // ammend mixin node types
@@ -557,7 +592,10 @@ public class ContentLoader implements ContentCreator {
                 if ( newNodeType == null ) {
                     return false;
                 }
-                node.addNode(token, newNodeType);
+                final Node n = node.addNode(token, newNodeType);
+                if ( this.createdNodes != null ) {
+                    this.createdNodes.add(n.getPath());
+                }
             }
             node = node.getNode(token);
         }
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ImportProvider.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/ImportProvider.java
index 2cf8340..cfd85f6 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ImportProvider.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/ImportProvider.java
@@ -20,8 +20,8 @@ package org.apache.sling.jcr.contentloader.internal;
 
 import java.io.IOException;
 
-interface ImportProvider {
+public interface ImportProvider {
 
     ContentReader getReader() throws IOException;
-    
+
 }
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/Loader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/Loader.java
index 83622af..8db1b94 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/Loader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/Loader.java
@@ -26,15 +26,15 @@ import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.StringTokenizer;
 
 import javax.jcr.InvalidSerializedDataException;
@@ -43,6 +43,9 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.sling.jcr.contentloader.internal.readers.JsonReader;
+import org.apache.sling.jcr.contentloader.internal.readers.XmlReader;
+import org.apache.sling.jcr.contentloader.internal.readers.ZipReader;
 import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -72,14 +75,14 @@ public class Loader {
     /** All available import providers. */
     private Map<String, ImportProvider> defaultImportProviders;
 
-    private final ContentLoader contentCreator;
+    private final DefaultContentCreator contentCreator;
 
     // bundles whose registration failed and should be retried
     private List<Bundle> delayedBundles;
 
     public Loader(ContentLoaderService jcrContentHelper) {
         this.jcrContentHelper = jcrContentHelper;
-        this.contentCreator = new ContentLoader(jcrContentHelper);
+        this.contentCreator = new DefaultContentCreator(jcrContentHelper);
         this.delayedBundles = new LinkedList<Bundle>();
 
         defaultImportProviders = new LinkedHashMap<String, ImportProvider>();
@@ -108,6 +111,10 @@ public class Loader {
     public void registerBundle(final Session session,
                                final Bundle bundle,
                                final boolean isUpdate) {
+        // if this is an update, we have to uninstall the old content first
+        if ( isUpdate ) {
+            this.unregisterBundle(session, bundle);
+        }
 
         log.debug("Registering bundle {} for content loading.",
             bundle.getSymbolicName());
@@ -153,7 +160,7 @@ public class Loader {
 
             // check if the content has already been loaded
             final Map<String, Object> bundleContentInfo = jcrContentHelper.getBundleContentInfo(
-                session, bundle);
+                session, bundle, true);
 
             // if we don't get an info, someone else is currently loading
             if (bundleContentInfo == null) {
@@ -161,6 +168,7 @@ public class Loader {
             }
 
             boolean success = false;
+            List<String> createdNodes = null;
             try {
 
                 final boolean contentAlreadyLoaded = ((Boolean) bundleContentInfo.get(ContentLoaderService.PROPERTY_CONTENT_LOADED)).booleanValue();
@@ -172,7 +180,7 @@ public class Loader {
 
                 } else {
 
-                    installContent(session, bundle, pathIter,
+                    createdNodes = installContent(session, bundle, pathIter,
                         contentAlreadyLoaded);
 
                     if (isRetry) {
@@ -189,7 +197,7 @@ public class Loader {
 
             } finally {
                 jcrContentHelper.unlockBundleContentInfo(session, bundle,
-                    success);
+                    success, createdNodes);
             }
 
         } catch (RepositoryException re) {
@@ -211,29 +219,48 @@ public class Loader {
      */
     public void unregisterBundle(final Session session, final Bundle bundle) {
 
-        // check if bundle has initial content
-        final Iterator<PathEntry> pathIter = PathEntry.getContentPaths(bundle);
         if (delayedBundles.contains(bundle)) {
 
             delayedBundles.remove(bundle);
 
         } else {
+            try {
+                final Map<String, Object> bundleContentInfo = jcrContentHelper.getBundleContentInfo(
+                        session, bundle, false);
 
-            if (pathIter != null) {
-                uninstallContent(session, bundle, pathIter);
-                jcrContentHelper.contentIsUninstalled(session, bundle);
-            }
+                // if we don't get an info, someone else is currently loading or unloading
+                // or the bundle is already uninstalled
+                if (bundleContentInfo == null) {
+                    return;
+                }
 
+                try {
+                    uninstallContent(session, bundle, (String[])bundleContentInfo.get(ContentLoaderService.PROPERTY_UNINSTALL_PATHS));
+                    jcrContentHelper.contentIsUninstalled(session, bundle);
+                } finally {
+                    jcrContentHelper.unlockBundleContentInfo(session, bundle, false, null);
+
+                }
+            } catch (RepositoryException re) {
+                log.error("Cannot remove initial content for bundle "
+                        + bundle.getSymbolicName() + " : " + re.getMessage(), re);
+            }
         }
     }
 
     // ---------- internal -----------------------------------------------------
 
-    private void installContent(final Session session,
-                                final Bundle bundle,
-                                final Iterator<PathEntry> pathIter,
-                                final boolean contentAlreadyLoaded)
+    /**
+     * Install the content from the bundle.
+     * @return If the content should be removed on uninstall, a list of top nodes
+     */
+    private List<String> installContent(final Session session,
+                                        final Bundle bundle,
+                                        final Iterator<PathEntry> pathIter,
+                                        final boolean contentAlreadyLoaded)
     throws RepositoryException {
+        final List<String> createdNodes = new ArrayList<String>();
+
         log.debug("Installing initial content from bundle {}",
             bundle.getSymbolicName());
         try {
@@ -245,7 +272,23 @@ public class Loader {
                     final Node targetNode = getTargetNode(session, entry.getTarget());
 
                     if (targetNode != null) {
-                        installFromPath(bundle, entry.getPath(), entry, targetNode);
+                        installFromPath(bundle, entry.getPath(), entry, targetNode,
+                            entry.isUninstall() ? createdNodes : null);
+                    }
+                }
+            }
+
+            // now optimize created nodes list
+            Collections.sort(createdNodes);
+            if ( createdNodes.size() > 1) {
+                final Iterator<String> i = createdNodes.iterator();
+                String previous = i.next() + '/';
+                while ( i.hasNext() ) {
+                    final String current = i.next();
+                    if ( current.startsWith(previous) ) {
+                        i.remove();
+                    } else {
+                        previous = current + '/';
                     }
                 }
             }
@@ -274,6 +317,7 @@ public class Loader {
         log.debug("Done installing initial content from bundle {}",
             bundle.getSymbolicName());
 
+        return createdNodes;
     }
 
     /**
@@ -283,12 +327,14 @@ public class Loader {
      * @param path The path
      * @param overwrite Should the content be overwritten.
      * @param parent The parent node.
+     * @param createdNodes An optional list to store all new nodes. This list is used for an uninstall
      * @throws RepositoryException
      */
     private void installFromPath(final Bundle bundle,
                                  final String path,
                                  final PathEntry configuration,
-                                 final Node parent)
+                                 final Node parent,
+                                 final List<String> createdNodes)
     throws RepositoryException {
 
         @SuppressWarnings("unchecked")
@@ -298,7 +344,7 @@ public class Loader {
             return;
         }
         //  init content creator
-        this.contentCreator.init(configuration, this.defaultImportProviders);
+        this.contentCreator.init(configuration, this.defaultImportProviders, createdNodes);
 
         final Map<URL, Node> processedEntries = new HashMap<URL, Node>();
         // potential root node import/extension
@@ -342,7 +388,7 @@ public class Loader {
 
                 // walk down the line
                 if (node != null) {
-                    installFromPath(bundle, entry, configuration, node);
+                    installFromPath(bundle, entry, configuration, node, createdNodes);
                 }
 
             } else {
@@ -377,7 +423,7 @@ public class Loader {
                 // otherwise just place as file
                 if ( node == null ) {
                     try {
-                        createFile(configuration, parent, file);
+                        createFile(configuration, parent, file, createdNodes);
                         node = parent.getNode(name);
                     } catch (IOException ioe) {
                         log.warn("Cannot create file node for {}", file, ioe);
@@ -455,21 +501,6 @@ public class Loader {
     }
 
     /**
-     * Delete the node from the initial content.
-     *
-     * @param parent
-     * @param name
-     * @param nodeXML
-     * @throws RepositoryException
-     */
-    private void deleteNode(Node parent, String name)
-            throws RepositoryException {
-        if (parent.hasNode(name)) {
-            parent.getNode(name).remove();
-        }
-    }
-
-    /**
      * Create a folder
      *
      * @param parent The parent node.
@@ -499,7 +530,7 @@ public class Loader {
      * @throws IOException
      * @throws RepositoryException
      */
-    private void createFile(PathEntry configuration, Node parent, URL source)
+    private void createFile(PathEntry configuration, Node parent, URL source, List<String> createdNodes)
     throws IOException, RepositoryException {
         final String srcPath = source.getPath();
         int pos = srcPath.lastIndexOf("/");
@@ -511,7 +542,7 @@ public class Loader {
             path = srcPath.substring(0, pos + 1) + name;
         }
 
-        this.contentCreator.init(configuration, defaultImportProviders);
+        this.contentCreator.init(configuration, defaultImportProviders, createdNodes);
         this.contentCreator.prepareParsing(parent, name);
         final URLConnection conn = source.openConnection();
         final long lastModified = conn.getLastModified();
@@ -523,22 +554,6 @@ public class Loader {
     }
 
     /**
-     * Delete the file from the given url.
-     *
-     * @param parent
-     * @param source
-     * @throws IOException
-     * @throws RepositoryException
-     */
-    private void deleteFile(Node parent, URL source) throws IOException,
-            RepositoryException {
-        String name = getName(source.getPath());
-        if (parent.hasNode(name)) {
-            parent.getNode(name).remove();
-        }
-    }
-
-    /**
      * Gets and decods the name part of the <code>path</code>. The name is
      * the part of the path after the last slash (or the complete path if no
      * slash is contained). To support names containing unsupported characters
@@ -603,25 +618,20 @@ public class Loader {
     }
 
     private void uninstallContent(final Session session, final Bundle bundle,
-            final Iterator<PathEntry> pathIter) {
+            final String[] uninstallPaths) {
         try {
             log.debug("Uninstalling initial content from bundle {}",
                 bundle.getSymbolicName());
-            while (pathIter.hasNext()) {
-                final PathEntry entry = pathIter.next();
-                if (entry.isUninstall()) {
-                    Node targetNode = getTargetNode(session, entry.getTarget());
-                    if (targetNode != null)
-                        uninstallFromPath(bundle, entry.getPath(), entry, targetNode);
-                } else {
-                    log.debug(
-                        "Ignoring to uninstall content at {}, uninstall directive is not set.",
-                        entry.getPath());
+            if ( uninstallPaths != null && uninstallPaths.length > 0 ) {
+                for(final String path : uninstallPaths) {
+                    if ( session.itemExists(path) ) {
+                        session.getItem(path).remove();
+                    }
                 }
+                // persist modifications now
+                session.save();
             }
 
-            // persist modifications now
-            session.save();
             log.debug("Done uninstalling initial content from bundle {}",
                 bundle.getSymbolicName());
         } catch (RepositoryException re) {
@@ -641,98 +651,6 @@ public class Loader {
     }
 
     /**
-     * Handle content uninstallation for a single path.
-     *
-     * @param bundle The bundle containing the content.
-     * @param path The path
-     * @param parent The parent node.
-     * @throws RepositoryException
-     */
-    private void uninstallFromPath(final Bundle bundle,
-                                   final String path,
-                                   final PathEntry configuration,
-                                   final Node parent) throws RepositoryException {
-        @SuppressWarnings("unchecked")
-        Enumeration<String> entries = bundle.getEntryPaths(path);
-        if (entries == null) {
-            return;
-        }
-
-        this.contentCreator.init(configuration, defaultImportProviders);
-
-        final Set<URL> ignoreEntry = new HashSet<URL>();
-
-        // potential root node import/extension
-        Descriptor rootNodeDescriptor = getRootNodeDescriptor(bundle, path);
-        if (rootNodeDescriptor != null) {
-            ignoreEntry.add(rootNodeDescriptor.rootNodeDescriptor);
-        }
-
-        while (entries.hasMoreElements()) {
-            final String entry = entries.nextElement();
-            log.debug("Processing initial content entry {}", entry);
-            if (entry.endsWith("/")) {
-                // dir, check for node descriptor , else create dir
-                String base = entry.substring(0, entry.length() - 1);
-                String name = getName(base);
-
-                URL nodeDescriptor = null;
-                for (String ext : this.contentCreator.getImportProviders().keySet()) {
-                    nodeDescriptor = bundle.getEntry(base + ext);
-                    if (nodeDescriptor != null) {
-                        break;
-                    }
-                }
-
-                final Node node;
-                boolean delete = false;
-                if (nodeDescriptor != null
-                    && !ignoreEntry.contains(nodeDescriptor)) {
-                    node = (parent.hasNode(toPlainName(name))
-                            ? parent.getNode(toPlainName(name))
-                            : null);
-                    delete = true;
-                } else {
-                    node = (parent.hasNode(name) ? parent.getNode(name) : null);
-                }
-
-                if (node != null) {
-                    // walk down the line
-                    uninstallFromPath(bundle, entry, configuration, node);
-                }
-
-                if (delete) {
-                    deleteNode(parent, toPlainName(name));
-                    ignoreEntry.add(nodeDescriptor);
-                }
-
-            } else {
-                // file => create file
-                URL file = bundle.getEntry(entry);
-                if (ignoreEntry.contains(file)) {
-                    // this is a consumed node descriptor
-                    continue;
-                }
-
-                // uninstall if it is a descriptor
-                boolean foundProvider = this.contentCreator.getImportProvider(entry) != null;
-                if (foundProvider) {
-                    deleteNode(parent, toPlainName(getName(entry)));
-                    ignoreEntry.add(file);
-                    continue;
-                }
-
-                // otherwise just delete the file
-                try {
-                    deleteFile(parent, file);
-                } catch (IOException ioe) {
-                    log.warn("Cannot delete file node for {}", file, ioe);
-                }
-            }
-        }
-    }
-
-    /**
      * Import the XML file as JCR system or document view import. If the XML
      * file is not a valid system or document view export/import file,
      * <code>false</code> is returned.
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/JsonReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
similarity index 94%
rename from src/main/java/org/apache/sling/jcr/contentloader/internal/JsonReader.java
rename to src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
index 78a7f3e..19d7277 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/JsonReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.contentloader.internal;
+package org.apache.sling.jcr.contentloader.internal.readers;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
@@ -31,12 +31,15 @@ import javax.jcr.RepositoryException;
 import org.apache.sling.commons.json.JSONArray;
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.jcr.contentloader.internal.ContentCreator;
+import org.apache.sling.jcr.contentloader.internal.ContentReader;
+import org.apache.sling.jcr.contentloader.internal.ImportProvider;
 
 
 /**
  * The <code>JsonReader</code> TODO
  */
-class JsonReader implements ContentReader {
+public class JsonReader implements ContentReader {
 
     private static final String REFERENCE = "jcr:reference:";
     private static final String PATH = "jcr:path:";
@@ -53,7 +56,7 @@ class JsonReader implements ContentReader {
         ignoredNames.add("jcr:created");
     }
 
-    static final ImportProvider PROVIDER = new ImportProvider() {
+    public static final ImportProvider PROVIDER = new ImportProvider() {
         private JsonReader jsonReader;
 
         public ContentReader getReader() {
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/XmlReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
similarity index 96%
rename from src/main/java/org/apache/sling/jcr/contentloader/internal/XmlReader.java
rename to src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
index 98dd4a6..af3fa6a 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/XmlReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.contentloader.internal;
+package org.apache.sling.jcr.contentloader.internal.readers;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -26,6 +26,9 @@ import java.util.List;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 
+import org.apache.sling.jcr.contentloader.internal.ContentCreator;
+import org.apache.sling.jcr.contentloader.internal.ContentReader;
+import org.apache.sling.jcr.contentloader.internal.ImportProvider;
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -86,7 +89,7 @@ public class XmlReader implements ContentReader {
 
     private static final String ELEM_TYPE = "type";
 
-    static final ImportProvider PROVIDER = new ImportProvider() {
+    public static final ImportProvider PROVIDER = new ImportProvider() {
         private XmlReader xmlReader;
 
         public ContentReader getReader() throws IOException {
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/ZipReader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
similarity index 86%
rename from src/main/java/org/apache/sling/jcr/contentloader/internal/ZipReader.java
rename to src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
index fff0c82..4308f4d 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/ZipReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.contentloader.internal;
+package org.apache.sling.jcr.contentloader.internal.readers;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -26,6 +26,9 @@ import java.util.zip.ZipInputStream;
 import javax.jcr.RepositoryException;
 
 import org.apache.commons.io.input.CloseShieldInputStream;
+import org.apache.sling.jcr.contentloader.internal.ContentCreator;
+import org.apache.sling.jcr.contentloader.internal.ContentReader;
+import org.apache.sling.jcr.contentloader.internal.ImportProvider;
 
 
 /**
@@ -33,11 +36,11 @@ import org.apache.commons.io.input.CloseShieldInputStream;
  *
  * @since 2.0.4
  */
-class ZipReader implements ContentReader {
+public class ZipReader implements ContentReader {
 
     private static final String NT_FOLDER = "nt:folder";
 
-    static final ImportProvider ZIP_PROVIDER = new ImportProvider() {
+    public static final ImportProvider ZIP_PROVIDER = new ImportProvider() {
         private ZipReader zipReader;
 
         public ContentReader getReader() {
@@ -48,7 +51,7 @@ class ZipReader implements ContentReader {
         }
     };
 
-    static final ImportProvider JAR_PROVIDER = new ImportProvider() {
+    public static final ImportProvider JAR_PROVIDER = new ImportProvider() {
         private ZipReader zipReader;
 
         public ContentReader getReader() {
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
index 5b3463f..d403145 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
@@ -26,6 +26,7 @@ import javax.jcr.RepositoryException;
 
 import org.apache.sling.commons.json.JSONArray;
 import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.jcr.contentloader.internal.readers.JsonReader;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.jmock.Sequence;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.