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.1.0
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-contentloader.git

commit 06c581e216bceffbea0143e859e8ffe80dae7894
Author: Eric Norman <[email protected]>
AuthorDate: Sun Jun 27 19:36:49 2010 +0000

    SLING-1172 Allow uploading JSON files to create content structures
    
    git-svn-id: 
https://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/contentloader@958411 
13f79535-47bb-0310-9956-ffa450edef68
---
 .../jcr/contentloader/ContentImportListener.java   |  67 ++++++
 .../sling/jcr/contentloader/ContentImporter.java   |  53 +++++
 .../ContentReader.java => ImportOptions.java}      |  25 +--
 .../contentloader/internal/BaseImportLoader.java   |  54 +++++
 .../internal/ContentLoaderService.java             |   4 +-
 .../jcr/contentloader/internal/ContentReader.java  |   9 +
 .../internal/DefaultContentCreator.java            |  76 ++++++-
 .../internal/DefaultContentImporter.java           | 238 +++++++++++++++++++++
 .../{ContentReader.java => JcrContentHelper.java}  |  31 +--
 .../sling/jcr/contentloader/internal/Loader.java   |  36 +---
 .../jcr/contentloader/internal/PathEntry.java      |  12 +-
 .../contentloader/internal/readers/JsonReader.java |   3 +-
 .../contentloader/internal/readers/XmlReader.java  |  25 ++-
 .../contentloader/internal/readers/ZipReader.java  |  16 +-
 14 files changed, 569 insertions(+), 80 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/ContentImportListener.java 
b/src/main/java/org/apache/sling/jcr/contentloader/ContentImportListener.java
new file mode 100644
index 0000000..b27735c
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/ContentImportListener.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.contentloader;
+
+/**
+ * Listener interface to provide callbacks for all imported updates
+ * for interested parties.  This is primarily used to record
+ * the modifications during the "import" post operation.
+ */
+public interface ContentImportListener {
+
+    /**
+     * Content has been updated. The source path provides the path of
+     * the modified Item.
+     */
+       void onModify(String srcPath);
+
+    /**
+     * An Item has been deleted. The source path provides the path of the
+     * deleted Item.
+     */
+       void onDelete(String srcPath);
+       
+    /**
+     * An Item has been moved to a new location. The source provides the
+     * original path of the Item, the destination provides the new path of the
+     * Item.
+     */
+       void onMove(String srcPath, String destPath);
+
+    /**
+     * An Item has been copied to a new location. The source path provides the
+     * path of the copied Item, the destination path provides the path of the
+     * new Item.
+     */
+       void onCopy(String srcPath, String destPath);
+
+    /**
+     * A Node has been created. The source path provides the path of the newly
+     * created Node.
+     */
+       void onCreate(String srcPath);
+
+    /**
+     * A child Node has been reordered. The orderedPath provides the path of 
the
+     * node, which has been reordered. ThebeforeSibbling provides the name of
+     * the sibling node before which the source Node has been ordered. 
+     */
+       void onReorder(String orderedPath, String beforeSibbling);
+       
+}
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/ContentImporter.java 
b/src/main/java/org/apache/sling/jcr/contentloader/ContentImporter.java
new file mode 100644
index 0000000..e780324
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/contentloader/ContentImporter.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.contentloader;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+
+/**
+ * The <code>ContentImporter</code> service
+ * <p>
+ * This interface is not intended to be implemented by bundles. It is
+ * implemented by this bundle and may be used by client bundles.
+ * </p>
+ */
+public interface ContentImporter {
+
+       /**
+        * Import content into the repository by parsing the provided
+        * content stream.
+        * 
+        * @param parent the root node for the imported content
+        * @param name the name of the imported content.  The file extension 
determines the content type
+        * @param contentStream the content stream to be imported
+        * @param importOptions (optional) additional options to control the 
import
+        * @param importListener (optional) listener to receive callbacks for 
each change in the import
+        * @throws RepositoryException
+        * @throws IOException
+        */
+       void importContent(Node parent, String name,
+                       InputStream contentStream, ImportOptions importOptions,
+                       ContentImportListener importListener) throws 
RepositoryException, IOException;
+
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java 
b/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
similarity index 60%
copy from 
src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
copy to src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
index 14bdbc0..fa3d53c 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/ImportOptions.java
@@ -16,25 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.contentloader.internal;
+package org.apache.sling.jcr.contentloader;
 
-import java.io.IOException;
-import java.net.URL;
-
-import javax.jcr.RepositoryException;
 
 /**
- * The <code>ContentReader</code>
- * A content reader is provided by an {@link ImportProvider}.
+ * Encapsulates the options for the content import. 
  */
-public interface ContentReader {
+public abstract class ImportOptions {
+
+       public abstract boolean isOverwrite();
+
+       public abstract boolean isCheckin();
 
-    /**
-     * Read the content from the URL and create the
-     * content using the provided content creator.
-     * @param url The input stream.
-     * @throws IOException
-     */
-    void parse(URL url, ContentCreator creator) throws IOException, 
RepositoryException;
+       public abstract boolean isIgnoredImportProvider(String extension);
 
-}
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/BaseImportLoader.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/BaseImportLoader.java
new file mode 100644
index 0000000..dd8c2f4
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/BaseImportLoader.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.contentloader.internal;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+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;
+
+/**
+ * Base class that takes care of the details that are common to bundle content
+ * loader and the POST operation "import" loader.
+ */
+public abstract class BaseImportLoader {
+    public static final String EXT_XML = ".xml";
+    public static final String EXT_JCR_XML = ".jcr.xml";
+    public static final String EXT_JSON = ".json";
+    public static final String EXT_JAR = ".jar";
+    public static final String EXT_ZIP = ".zip";
+
+    /** All available import providers. */
+    Map<String, ImportProvider> defaultImportProviders;
+
+       public BaseImportLoader() {
+        defaultImportProviders = new LinkedHashMap<String, ImportProvider>();
+        defaultImportProviders.put(EXT_JCR_XML, null);
+        defaultImportProviders.put(EXT_JSON, JsonReader.PROVIDER);
+        defaultImportProviders.put(EXT_XML, XmlReader.PROVIDER);
+        defaultImportProviders.put(EXT_JAR, ZipReader.JAR_PROVIDER);
+        defaultImportProviders.put(EXT_ZIP, ZipReader.ZIP_PROVIDER);
+       }
+
+    public void dispose() {
+        defaultImportProviders = null;
+    }
+}
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 2d68b2c..b023d68 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
@@ -58,7 +58,7 @@ import org.slf4j.LoggerFactory;
  *               Content Loader Implementation"
  * @scr.property name="service.vendor" value="The Apache Software Foundation"
  */
-public class ContentLoaderService implements SynchronousBundleListener {
+public class ContentLoaderService implements SynchronousBundleListener, 
JcrContentHelper {
 
     /** The manifest header to specify the workspace for initial content 
loading. */
     public static final String CONTENT_WORKSPACE_HEADER = 
"Sling-Initial-Content-Workspace";
@@ -220,7 +220,7 @@ public class ContentLoaderService implements 
SynchronousBundleListener {
      * @return the digested value
      * @throws IllegalArgumentException
      */
-    protected String digestPassword(String pwd) throws 
IllegalArgumentException {
+    public String digestPassword(String pwd) throws IllegalArgumentException {
         try {
             StringBuffer password = new StringBuffer();
             password.append("{").append(passwordDigestAlgoritm).append("}");
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 14bdbc0..a7b3dfc 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
@@ -19,6 +19,7 @@
 package org.apache.sling.jcr.contentloader.internal;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 
 import javax.jcr.RepositoryException;
@@ -37,4 +38,12 @@ public interface ContentReader {
      */
     void parse(URL url, ContentCreator creator) throws IOException, 
RepositoryException;
 
+    /**
+     * Read the content from the input stream and create the
+     * content using the provided content creator.
+     * @param ins the input stream.
+     * @throws IOException
+     */
+    void parse(InputStream ins, ContentCreator contentCreator) throws 
IOException, RepositoryException;
+    
 }
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
index b1bc0e3..3c5565d 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
@@ -24,6 +24,10 @@ import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.contentloader.ContentImportListener;
+import org.apache.sling.jcr.contentloader.ImportOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
@@ -59,7 +63,10 @@ import javax.jcr.ValueFactory;
  */
 public class DefaultContentCreator implements ContentCreator {
 
-       private PathEntry configuration;
+    /** default log */
+    final Logger log = LoggerFactory.getLogger(getClass());
+
+       private ImportOptions configuration;
 
     private final Pattern jsonDatePattern = 
Pattern.compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}[-+]{1}[0-9]{2}[:]{0,1}[0-9]{2}$");
     private final SimpleDateFormat jsonDateFormat = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
@@ -85,7 +92,7 @@ public class DefaultContentCreator implements ContentCreator {
     private static final String DEFAULT_CONTENT_TYPE = 
"application/octet-stream";
 
     /** Helper class to get the mime type of a file. */
-    private final ContentLoaderService jcrContentHelper;
+    private final JcrContentHelper jcrContentHelper;
 
     /** List of active import providers mapped by extension. */
     private Map<String, ImportProvider> importProviders;
@@ -93,6 +100,9 @@ public class DefaultContentCreator implements ContentCreator 
{
     /** Optional list of created nodes (for uninstall) */
     private List<String> createdNodes;
 
+    /** Optional listener to get notified about changes */
+    private ContentImportListener importListener;
+    
     /**
      * A one time use seed to randomize the user location.
      */
@@ -107,7 +117,7 @@ public class DefaultContentCreator implements 
ContentCreator {
      * Constructor.
      * @param jcrContentHelper Helper class to get the mime type of a file
      */
-    public DefaultContentCreator(ContentLoaderService jcrContentHelper) {
+    public DefaultContentCreator(JcrContentHelper jcrContentHelper) {
         this.jcrContentHelper = jcrContentHelper;
     }
 
@@ -117,9 +127,10 @@ public class DefaultContentCreator implements 
ContentCreator {
      * @param defaultImportProviders List of all import providers.
      * @param createdNodes Optional list to store new nodes (for uninstall)
      */
-    public void init(final PathEntry pathEntry,
+    public void init(final ImportOptions pathEntry,
                      final Map<String, ImportProvider> defaultImportProviders,
-                     final List<String> createdNodes) {
+                     final List<String> createdNodes,
+                     final ContentImportListener importListener) {
         this.configuration = pathEntry;
         // create list of allowed import providers
         this.importProviders = new HashMap<String, ImportProvider>();
@@ -131,6 +142,7 @@ public class DefaultContentCreator implements 
ContentCreator {
             }
         }
         this.createdNodes = createdNodes;
+        this.importListener = importListener;
     }
 
     /**
@@ -254,7 +266,9 @@ public class DefaultContentCreator implements 
ContentCreator {
                 if ( this.createdNodes != null ) {
                     this.createdNodes.add(node.getPath());
                 }
-
+                if ( this.importListener != null ) {
+                       this.importListener.onCreate(node.getPath());
+                }
             } else {
 
                 // explicit primary node type
@@ -262,6 +276,9 @@ public class DefaultContentCreator implements 
ContentCreator {
                 if ( this.createdNodes != null ) {
                     this.createdNodes.add(node.getPath());
                 }
+                if ( this.importListener != null ) {
+                       this.importListener.onCreate(node.getPath());
+                }
             }
 
             // ammend mixin node types
@@ -305,6 +322,10 @@ public class DefaultContentCreator implements 
ContentCreator {
             String uuid = getUUID(node.getSession(), propPath, 
getAbsPath(node, value));
             if (uuid != null) {
                 node.setProperty(name, uuid, propertyType);
+                
+                if ( this.importListener != null ) {
+                       
this.importListener.onCreate(node.getProperty(name).getPath());
+                }
             }
 
         } else if ("jcr:isCheckedOut".equals(name)) {
@@ -325,12 +346,18 @@ public class DefaultContentCreator implements 
ContentCreator {
               // Fall back to default behaviour if this fails
               node.setProperty(name, value, propertyType);
             }
+            if ( this.importListener != null ) {
+               this.importListener.onCreate(node.getProperty(name).getPath());
+            }
         } else {
             if (propertyType == PropertyType.UNDEFINED) {
                 node.setProperty(name, value);
             } else {
                 node.setProperty(name, value, propertyType);
             }
+            if ( this.importListener != null ) {
+               this.importListener.onCreate(node.getProperty(name).getPath());
+            }
         }
     }
 
@@ -358,6 +385,9 @@ public class DefaultContentCreator implements 
ContentCreator {
             }
 
             node.setProperty(name, uuids, propertyType);
+            if ( this.importListener != null ) {
+               this.importListener.onCreate(node.getProperty(name).getPath());
+            }
 
             if (!hasAll) {
                 delayedMultipleReferences.put(propPath, uuidOrPaths);
@@ -376,16 +406,21 @@ public class DefaultContentCreator implements 
ContentCreator {
             }
             catch (ParseException e) {
               // If this failes, fallback to the default
-              jcrContentHelper.log.warn("Could not create dates for property, 
fallingback to defaults", e);
+              log.warn("Could not create dates for property, fallingback to 
defaults", e);
               node.setProperty(name, values, propertyType);
             }
-
+            if ( this.importListener != null ) {
+               this.importListener.onCreate(node.getProperty(name).getPath());
+            }
         } else {
             if (propertyType == PropertyType.UNDEFINED) {
                 node.setProperty(name, values);
             } else {
                 node.setProperty(name, values, propertyType);
             }
+            if ( this.importListener != null ) {
+               this.importListener.onCreate(node.getProperty(name).getPath());
+            }
         }
     }
 
@@ -515,12 +550,18 @@ public class DefaultContentCreator implements 
ContentCreator {
                         }
                     }
                     parentNode.setProperty(name, uuids, 
PropertyType.REFERENCE);
+                    if ( this.importListener != null ) {
+                       
this.importListener.onCreate(parentNode.getProperty(name).getPath());
+                    }
 
                     if (hasAll) {
                         delayedMultipleReferences.remove(property);
                     }
                 } else {
                     parentNode.setProperty(name, uuid, PropertyType.REFERENCE);
+                    if ( this.importListener != null ) {
+                       
this.importListener.onCreate(parentNode.getProperty(name).getPath());
+                    }
                 }
             }
         }
@@ -594,11 +635,18 @@ public class DefaultContentCreator implements 
ContentCreator {
         }
         if ( value == null ) {
             if ( node.hasProperty(name) ) {
+               String propPath = node.getProperty(name).getPath();
                 node.getProperty(name).remove();
+                if ( this.importListener != null ) {
+                       this.importListener.onDelete(propPath);
+                }
             }
         } else {
             final Value jcrValue = 
this.createValue(node.getSession().getValueFactory(), value);
             node.setProperty(name, jcrValue);
+            if ( this.importListener != null ) {
+               this.importListener.onModify(node.getProperty(name).getPath());
+            }
         }
     }
 
@@ -612,7 +660,11 @@ public class DefaultContentCreator implements 
ContentCreator {
         }
         if ( values == null || values.length == 0 ) {
             if ( node.hasProperty(name) ) {
+               String propPath = node.getProperty(name).getPath();
                 node.getProperty(name).remove();
+                if ( this.importListener != null ) {
+                       this.importListener.onDelete(propPath);
+                }
             }
         } else {
             final Value[] jcrValues = new Value[values.length];
@@ -620,6 +672,9 @@ public class DefaultContentCreator implements 
ContentCreator {
                 jcrValues[i] = 
this.createValue(node.getSession().getValueFactory(), values[i]);
             }
             node.setProperty(name, jcrValues);
+            if ( this.importListener != null ) {
+               this.importListener.onModify(node.getProperty(name).getPath());
+            }
         }
     }
 
@@ -651,7 +706,7 @@ public class DefaultContentCreator implements 
ContentCreator {
         if (mimeType == null) {
             mimeType = jcrContentHelper.getMimeType(name);
             if (mimeType == null) {
-                jcrContentHelper.log.info(
+                log.info(
                     "createFile: Cannot find content type for {}, using {}",
                     name, DEFAULT_CONTENT_TYPE);
                 mimeType = DEFAULT_CONTENT_TYPE;
@@ -687,6 +742,9 @@ public class DefaultContentCreator implements 
ContentCreator {
                 if ( this.createdNodes != null ) {
                     this.createdNodes.add(n.getPath());
                 }
+                if ( this.importListener != null ) {
+                       this.importListener.onCreate(node.getPath());
+                }
             }
             node = node.getNode(token);
         }
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
new file mode 100644
index 0000000..c974fd7
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentImporter.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.jcr.contentloader.internal;
+
+import static javax.jcr.ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import javax.jcr.InvalidSerializedDataException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.jcr.contentloader.ContentImportListener;
+import org.apache.sling.jcr.contentloader.ContentImporter;
+import org.apache.sling.jcr.contentloader.ImportOptions;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>DefaultContentImporter</code> is the default implementation of 
the 
+ * ContentImporter service providing the following functionality:
+ * <ul>
+ * <li>Import content into the content repository.
+ * </ul>
+ *
+ * @scr.component immediate="false" label="%content.import.service.name"
+ *                description="%content.import.service.description"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="service.description"
+ *               value="Apache Sling Contnet Importer Service"
+ * @scr.service interface="org.apache.sling.jcr.contentloader.ContentImporter"
+ */
+public class DefaultContentImporter extends BaseImportLoader implements 
JcrContentHelper, ContentImporter {
+
+    /** default log */
+    private final Logger log = 
LoggerFactory.getLogger(DefaultContentImporter.class);
+
+    /**
+     * The MimeTypeService used by the initial content initialContentLoader to
+     * resolve MIME types for files to be installed.
+     *
+     * @scr.reference
+     */
+    private MimeTypeService mimeTypeService;
+    
+    /**
+     * To be used for the encryption. E.g. for passwords in
+     * {@link javax.jcr.SimpleCredentials#getPassword()} SimpleCredentials}
+     *
+     * @scr.property valueRef="DEFAULT_PASSWORD_DIGEST_ALGORITHM"
+     */
+    private static final String PROP_PASSWORD_DIGEST_ALGORITHM = 
"password.digest.algorithm";
+    private static final String DEFAULT_PASSWORD_DIGEST_ALGORITHM = "sha1";
+    private String passwordDigestAlgoritm = null;
+    
+    
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.ContentImporter#importContent(javax.jcr.Node,
 java.lang.String, java.io.InputStream, 
org.apache.sling.jcr.contentloader.ImportOptions, 
org.apache.sling.jcr.contentloader.ContentImportListener)
+        */
+       public void importContent(Node parent, String name,
+                       InputStream contentStream, ImportOptions importOptions,
+                       ContentImportListener importListener) throws 
RepositoryException, IOException {
+               
+        // special treatment for system view imports
+        if (name.endsWith(EXT_JCR_XML)) {
+            Node node = importSystemView(parent, name, contentStream);
+            if (node != null) {
+               if (importListener != null) {
+                       importListener.onCreate(node.getPath());
+               }
+               return;
+            }
+        }
+               
+       DefaultContentCreator contentCreator = new DefaultContentCreator(this);
+        List<String> createdPaths = new ArrayList<String>();
+        contentCreator.init(importOptions, this.defaultImportProviders, 
createdPaths, importListener);
+        
+        contentCreator.prepareParsing(parent, toPlainName(contentCreator, 
name));
+        
+        final ImportProvider ip = contentCreator.getImportProvider(name);
+        ContentReader reader = ip.getReader();
+               reader.parse(contentStream, contentCreator);
+
+               //save changes
+        Session session = parent.getSession();
+               session.save();
+
+        // finally checkin versionable nodes
+        for (final Node versionable : contentCreator.getVersionables()) {
+            versionable.checkin();
+        }
+    }
+    
+    private String toPlainName(DefaultContentCreator contentCreator, String 
name) {
+        final String providerExt = 
contentCreator.getImportProviderExtension(name);
+        if (providerExt != null) {
+            return name.substring(0, name.length() - providerExt.length());
+        }
+        return name;
+    }
+
+    
+    /**
+     * 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.
+     *
+     * @param parent The parent node below which to import
+     * @param name the name of the import resource
+     * @param contentStream The XML content to import
+     * @return <code>true</code> if the import succeeds, <code>false</code>
+     *         if the import fails due to XML format errors.
+     * @throws IOException If an IO error occurrs reading the XML file.
+     */
+    private Node importSystemView(Node parent, String name, InputStream 
contentStream)
+               throws IOException {
+        InputStream ins = null;
+        try {
+
+            // check whether we have the content already, nothing to do then
+            if ( name.endsWith(EXT_JCR_XML) ) {
+                name = name.substring(0, name.length() - EXT_JCR_XML.length());
+            }
+            if (parent.hasNode(name)) {
+                log.debug(
+                    "importSystemView: Node {} for XML already exists, nothing 
to to",
+                    name);
+                return parent.getNode(name);
+            }
+
+            ins = contentStream;
+            Session session = parent.getSession();
+            session.importXML(parent.getPath(), ins, IMPORT_UUID_CREATE_NEW);
+
+            // additionally check whether the expected child node exists
+            return (parent.hasNode(name)) ? parent.getNode(name) : null;
+        } catch (InvalidSerializedDataException isde) {
+
+            // the xml might not be System or Document View export, fall back
+            // to old-style XML reading
+            log.info(
+                "importSystemView: XML does not seem to be system view export, 
trying old style; cause: {}",
+                isde.toString());
+            return null;
+        } catch (RepositoryException re) {
+
+            // any other repository related issue...
+            log.info(
+                "importSystemView: Repository issue loading XML, trying old 
style; cause: {}",
+                re.toString());
+            return null;
+        } finally {
+            if (ins != null) {
+                try {
+                    ins.close();
+                } catch (IOException ignore) {
+                    // ignore
+                }
+            }
+        }
+    }
+    
+    
+    // ---------- JcrContentHelper implementation 
---------------------------------------------
+    
+       /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.JcrContentHelper#digestPassword(java.lang.String)
+        */
+       public String digestPassword(String pwd) throws 
IllegalArgumentException {
+        try {
+            StringBuffer password = new StringBuffer();
+            password.append("{").append(passwordDigestAlgoritm).append("}");
+            
password.append(DefaultContentCreator.digest(passwordDigestAlgoritm,
+                pwd.getBytes("UTF-8")));
+            return password.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e.toString());
+        } catch (UnsupportedEncodingException e) {
+            throw new IllegalArgumentException(e.toString());
+        }
+       }
+
+       /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.JcrContentHelper#getMimeType(java.lang.String)
+        */
+       public String getMimeType(String name) {
+        // local copy to not get NPE despite check for null due to concurrent
+        // unbind
+        MimeTypeService mts = mimeTypeService;
+        return (mts != null) ? mts.getMimeType(name) : null;
+       }
+       
+       
+    // ---------- SCR Integration ---------------------------------------------
+
+    /** Activates this component, called by SCR before registering as a 
service */
+    protected void activate(ComponentContext componentContext) {
+        Dictionary<?, ?> props = componentContext.getProperties();
+        Object propValue = props.get(PROP_PASSWORD_DIGEST_ALGORITHM);
+        if (propValue instanceof String) {
+            passwordDigestAlgoritm = (String) propValue;
+        } else {
+            passwordDigestAlgoritm = DEFAULT_PASSWORD_DIGEST_ALGORITHM;
+        }
+    }
+ 
+    /** Deativates this component, called by SCR to take out of service */
+    protected void deactivate(ComponentContext componentContext) {
+        passwordDigestAlgoritm = null;
+    }
+    
+}
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrContentHelper.java
similarity index 62%
copy from 
src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
copy to 
src/main/java/org/apache/sling/jcr/contentloader/internal/JcrContentHelper.java
index 14bdbc0..734bf59 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/ContentReader.java
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/JcrContentHelper.java
@@ -18,23 +18,26 @@
  */
 package org.apache.sling.jcr.contentloader.internal;
 
-import java.io.IOException;
-import java.net.URL;
-
-import javax.jcr.RepositoryException;
 
 /**
- * The <code>ContentReader</code>
- * A content reader is provided by an {@link ImportProvider}.
+ * Interface to provide helpers for the ContentCreator
+ *
  */
-public interface ContentReader {
+public interface JcrContentHelper {
+
+       /**
+        * Returns the MIME type from the MimeTypeService for the given name
+        * @param name the name of the file to get the mimeType for  
+        */
+       String getMimeType(String name);
 
-    /**
-     * Read the content from the URL and create the
-     * content using the provided content creator.
-     * @param url The input stream.
-     * @throws IOException
-     */
-    void parse(URL url, ContentCreator creator) throws IOException, 
RepositoryException;
+       /**
+        * Digest the given password using the configured digest algorithm
+        * 
+        * @param pwd the password to digest
+        * @return digested password
+        * @throws IllegalArgumentException
+        */
+    String digestPassword(String pwd) throws IllegalArgumentException;
 
 }
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 b52fb82..d00bb9e 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
@@ -31,7 +31,6 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -44,9 +43,7 @@ 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.apache.sling.jcr.contentloader.ImportOptions;
 import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,17 +51,7 @@ import org.slf4j.LoggerFactory;
 /**
  * The <code>Loader</code> loads initial content from the bundle.
  */
-public class Loader {
-
-    public static final String EXT_XML = ".xml";
-
-    public static final String EXT_JCR_XML = ".jcr.xml";
-
-    public static final String EXT_JSON = ".json";
-
-    public static final String EXT_JAR = ".jar";
-
-    public static final String EXT_ZIP = ".zip";
+public class Loader extends BaseImportLoader {
 
     public static final String ROOT_DESCRIPTOR = "/ROOT";
 
@@ -73,25 +60,16 @@ public class Loader {
 
     private ContentLoaderService contentLoaderService;
 
-    /** All available import providers. */
-    private Map<String, ImportProvider> defaultImportProviders;
-
     private final DefaultContentCreator contentCreator;
 
     // bundles whose registration failed and should be retried
     private List<Bundle> delayedBundles;
 
     public Loader(ContentLoaderService contentLoaderService) {
-        this.contentLoaderService = contentLoaderService;
+       super();
+       this.contentLoaderService = contentLoaderService;
         this.contentCreator = new DefaultContentCreator(contentLoaderService);
         this.delayedBundles = new LinkedList<Bundle>();
-
-        defaultImportProviders = new LinkedHashMap<String, ImportProvider>();
-        defaultImportProviders.put(EXT_JCR_XML, null);
-        defaultImportProviders.put(EXT_JSON, JsonReader.PROVIDER);
-        defaultImportProviders.put(EXT_XML, XmlReader.PROVIDER);
-        defaultImportProviders.put(EXT_JAR, ZipReader.JAR_PROVIDER);
-        defaultImportProviders.put(EXT_ZIP, ZipReader.ZIP_PROVIDER);
     }
 
     public void dispose() {
@@ -100,7 +78,7 @@ public class Loader {
             delayedBundles = null;
         }
         contentLoaderService = null;
-        defaultImportProviders = null;
+        super.dispose();
     }
 
     /**
@@ -369,7 +347,7 @@ public class Loader {
                                  final List<String> createdNodes)
     throws RepositoryException {
         //  init content creator
-        this.contentCreator.init(configuration, this.defaultImportProviders, 
createdNodes);
+        this.contentCreator.init(configuration, this.defaultImportProviders, 
createdNodes, null);
 
         final Map<URL, Node> processedEntries = new HashMap<URL, Node>();
 
@@ -598,7 +576,7 @@ public class Loader {
             path = srcPath.substring(0, pos + 1) + name;
         }
 
-        this.contentCreator.init(configuration, defaultImportProviders, 
createdNodes);
+        this.contentCreator.init(configuration, defaultImportProviders, 
createdNodes, null);
         this.contentCreator.prepareParsing(parent, name);
         final URLConnection conn = source.openConnection();
         final long lastModified = conn.getLastModified();
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
index 2532ee1..aa003c4 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/PathEntry.java
@@ -24,12 +24,13 @@ import java.util.List;
 import java.util.StringTokenizer;
 
 import org.apache.sling.commons.osgi.ManifestHeader;
+import org.apache.sling.jcr.contentloader.ImportOptions;
 import org.osgi.framework.Bundle;
 
 /**
  * A path entry from the manifest for initial content.
  */
-public class PathEntry {
+public class PathEntry extends ImportOptions {
 
     /** The manifest header to specify initial content to be loaded. */
     public static final String CONTENT_HEADER = "Sling-Initial-Content";
@@ -169,6 +170,9 @@ public class PathEntry {
         return this.path;
     }
 
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.ImportOptions#isOverwrite()
+        */
     public boolean isOverwrite() {
         return this.overwrite;
     }
@@ -177,10 +181,16 @@ public class PathEntry {
         return this.uninstall;
     }
 
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.ImportOptions#isCheckin()
+        */
     public boolean isCheckin() {
         return this.checkin;
     }
 
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.ImportOptions#isIgnoredImportProvider(java.lang.String)
+        */
     public boolean isIgnoredImportProvider(String extension) {
         if ( extension.startsWith(".") ) {
             extension = extension.substring(1);
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
index 2a8e599..4889357 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
@@ -156,7 +156,8 @@ public class JsonReader implements ContentReader {
             }
 
             JSONObject json = new JSONObject(jsonString);
-            this.createNode(null, json, contentCreator);
+            String optionalName = json.optString("name", null);
+            this.createNode(optionalName, json, contentCreator);
         } catch (JSONException je) {
             throw (IOException) new IOException(je.getMessage()).initCause(je);
         }
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
index 8cd74e1..5dfad35 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
@@ -172,14 +172,32 @@ public class XmlReader implements ContentReader {
         }
     }
 
-    private void parseInternal(final InputStream bufferedInput,
+    /* (non-Javadoc)
+        * @see 
org.apache.sling.jcr.contentloader.internal.ContentReader#parse(java.io.InputStream,
 org.apache.sling.jcr.contentloader.internal.ContentCreator)
+        */
+       public void parse(InputStream ins, ContentCreator creator)
+                       throws IOException, RepositoryException {
+        BufferedInputStream bufferedInput = null;
+        try {
+            // We need to buffer input, so that we can reset the stream if we 
encounter an XSL stylesheet reference
+            bufferedInput = new BufferedInputStream(ins);
+            URL xmlLocation = null;
+            parseInternal(bufferedInput, creator, xmlLocation);
+        } catch (XmlPullParserException xppe) {
+            throw (IOException) new 
IOException(xppe.getMessage()).initCause(xppe);
+        } finally {
+            closeStream(bufferedInput);
+        }
+       }
+
+       private void parseInternal(final InputStream bufferedInput,
                                final ContentCreator creator,
                                final URL xmlLocation)
     throws XmlPullParserException, IOException, RepositoryException {
         final StringBuilder contentBuffer = new StringBuilder();
         // Mark the beginning of the stream. We assume that if there's an XSL 
processing instruction,
         // it will occur in the first gulp - which makes sense, as processing 
instructions must be
-        // specified before the root elemeent of an XML file.
+        // specified before the root element of an XML file.
         bufferedInput.mark(bufferedInput.available());
         // set the parser input, use null encoding to force detection with
         // <?xml?>
@@ -594,7 +612,8 @@ public class XmlReader implements ContentReader {
      */
     protected static class AttributeMap extends HashMap<String, String> {
 
-        private static final AttributeMap instance = new AttributeMap();
+               private static final long serialVersionUID = 
-6304058237706001104L;
+               private static final AttributeMap instance = new AttributeMap();
 
         public static AttributeMap getInstance() {
             return instance;
diff --git 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
index e4debee..949f186 100644
--- 
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
+++ 
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/ZipReader.java
@@ -73,10 +73,16 @@ public class ZipReader implements ContentReader {
      * @see 
org.apache.sling.jcr.contentloader.internal.ContentReader#parse(java.net.URL, 
org.apache.sling.jcr.contentloader.internal.ContentCreator)
      */
     public void parse(java.net.URL url, ContentCreator creator)
-    throws IOException, RepositoryException {
-        InputStream ins = null;
+               throws IOException, RepositoryException {
+       parse(url.openStream(), creator);
+    }
+
+       /**
+        * @see 
org.apache.sling.jcr.contentloader.internal.ContentReader#parse(java.io.InputStream,
 org.apache.sling.jcr.contentloader.internal.ContentCreator)
+        */
+       public void parse(InputStream ins, ContentCreator creator)
+                       throws IOException, RepositoryException {
         try {
-            ins = url.openStream();
             creator.createNode(null, NT_FOLDER, null);
             final ZipInputStream zis = new ZipInputStream(ins);
             ZipEntry entry;
@@ -109,6 +115,6 @@ public class ZipReader implements ContentReader {
                 }
             }
         }
-    }
-
+       }
+    
 }

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to