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:47:18 UTC

[sling-org-apache-sling-jcr-contentloader] 15/36: SLING-1161 implemented. Now supports including external files with nt:file in content loader XML

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

commit 50de0c92a5eb0a8d10e18818070d1d19cc31417a
Author: Vidar Skauge Ramdal <vr...@apache.org>
AuthorDate: Tue Oct 27 09:43:56 2009 +0000

    SLING-1161 implemented. Now supports including external files with nt:file in content loader XML
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/jcr/contentloader@830106 13f79535-47bb-0310-9956-ffa450edef68
---
 .../contentloader/internal/readers/XmlReader.java  | 137 ++++++++++++++++++++-
 .../internal/readers/XmlReaderTest.java            |  68 +++++++++-
 src/test/resources/reader/filesample.xml           |  21 ++++
 src/test/resources/reader/testfile.txt             |   1 +
 4 files changed, 220 insertions(+), 7 deletions(-)

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 39a69a8..a4a525a 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
@@ -25,12 +25,18 @@ import java.io.InputStream;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.net.URL;
+import java.net.MalformedURLException;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.text.DateFormat;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -52,7 +58,7 @@ import org.xmlpull.v1.XmlPullParserException;
 /**
  * This reader reads an xml file defining the content. The xml format should have this
  * format:
- * 
+ *
  * <pre>
  * &lt;node&gt;
  *   &lt;name&gt;the name of the node&lt;/name&gt;
@@ -81,6 +87,9 @@ import org.xmlpull.v1.XmlPullParserException;
  *   &lt;/nodes&gt;
  * &lt;/node&gt;
  * </pre>
+ *
+ * If you want to include a binary file in your loaded content, you may specify it using a
+ * {@link org.apache.sling.jcr.contentloader.internal.readers.XmlReader.FileDescription <code>&lt;nt:file&gt;</code>} element.
  */
 public class XmlReader implements ContentReader {
 
@@ -113,6 +122,9 @@ public class XmlReader implements ContentReader {
 
     private static final String HREF_ATTRIBUTE = "href";
 
+    private static final String ELEM_FILE_NAMESPACE = "http://www.jcp.org/jcr/nt/1.0";
+    private static final String ELEM_FILE_NAME = "file";
+
     public static final ImportProvider PROVIDER = new ImportProvider() {
         private XmlReader xmlReader;
 
@@ -131,6 +143,12 @@ public class XmlReader implements ContentReader {
 
     XmlReader() {
         this.xmlParser = new KXmlParser();
+        try {
+            // Make namespace-aware
+            this.xmlParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     // ---------- XML content access -------------------------------------------
@@ -165,6 +183,7 @@ public class XmlReader implements ContentReader {
 
         NodeDescription.SHARED.clear();
         PropertyDescription.SHARED.clear();
+        FileDescription.SHARED.clear();
 
         NodeDescription currentNode = null;
         PropertyDescription currentProperty = null;
@@ -200,6 +219,22 @@ public class XmlReader implements ContentReader {
                 } else if (ELEM_NODE.equals(currentElement)) {
                     currentNode = NodeDescription.create(currentNode, creator);
                     currentNode = NodeDescription.SHARED;
+                } else if (ELEM_FILE_NAME.equals(currentElement) && ELEM_FILE_NAMESPACE.equals(this.xmlParser.getNamespace())) {
+                    int attributeCount = this.xmlParser.getAttributeCount();
+                    if (attributeCount < 2 || attributeCount > 3) {
+                        throw new IOException("File element must have these attributes: url, mimeType and lastModified");
+                    }
+                    try {
+                        AttributeMap attributes = AttributeMap.getInstance();
+                        attributes.setValues(xmlParser);
+                        FileDescription.SHARED.setBaseLocation(xmlLocation);
+                        FileDescription.SHARED.setValues(attributes);
+                        attributes.clear();
+                    } catch (ParseException e) {
+                        throw new IOException("Error parsing file description", e);
+                    }
+                    FileDescription.SHARED.create(creator);
+                    FileDescription.SHARED.clear();
                 }
 
             } else if (eventType == XmlPullParser.END_TAG) {
@@ -243,7 +278,6 @@ public class XmlReader implements ContentReader {
                     }
                     currentNode.addMixinType(content);
                 }
-
             } else if (eventType == XmlPullParser.TEXT || eventType == XmlPullParser.CDSECT) {
                 contentBuffer.append(this.xmlParser.getText());
             }
@@ -455,4 +489,103 @@ public class XmlReader implements ContentReader {
         }
 
     }
+
+    /**
+     * Represents a reference to a file that is to be loaded into the repository. The file is referenced by an
+     * XML element named <code>&lt;nt:file&gt;</code>, with the attributes <code>src</code>,
+     * <code>mimeType</code> and <code>lastModified</code>. <br/><br/>Example:
+     * <pre>
+     * &lt;nt:file src="../../image.png" mimeType="image/png" lastModified="1977-06-01T07:00:00+0100" /&gt;
+     * </pre>
+     * The date format for <code>lastModified</code> is <code>yyyy-MM-dd'T'HH:mm:ssZ</code>.
+     * The <code>lastModified</code> attribute is optional. If missing, it will be set to the current time.
+     */
+    protected static final class FileDescription {
+
+        private URL url;
+        private String mimeType;
+        private URL baseLocation;
+        private Long lastModified;
+
+        public static FileDescription SHARED = new FileDescription();
+        private static final String SRC_ATTRIBUTE = "src";
+        private static final String MIME_TYPE_ATTRIBUTE = "mimeType";
+        private static final String LAST_MODIFIED_ATTRIBUTE = "lastModified";
+        public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+
+        static {
+            DATE_FORMAT.setLenient(true);
+        }
+
+        public void setValues(AttributeMap attributes) throws MalformedURLException, ParseException {
+            Set<String> attributeNames = attributes.keySet();
+            for (String name : attributeNames) {
+                String value = attributes.get(name);
+                if (name.equals(SRC_ATTRIBUTE)) {
+                    url = new URL(baseLocation, value);
+                } else if (name.equals(MIME_TYPE_ATTRIBUTE)) {
+                    mimeType = value;
+                } else if (name.equals(LAST_MODIFIED_ATTRIBUTE)) {
+                    lastModified = DATE_FORMAT.parse(value).getTime();
+                }
+            }
+        }
+
+        public void create(ContentCreator creator) throws RepositoryException, IOException {
+            String[] parts = url.getPath().split("/");
+            String name = parts[parts.length - 1];
+            InputStream stream = url.openStream();
+            creator.createFileAndResourceNode(name, stream, mimeType, lastModified != null ? lastModified : Calendar.getInstance().getTimeInMillis());
+            closeStream(stream);
+            creator.finishNode();
+            creator.finishNode();
+            this.clear();
+        }
+
+        public URL getUrl() {
+            return url;
+        }
+
+        public String getMimeType() {
+            return mimeType;
+        }
+
+        public Long getLastModified() {
+            return lastModified;
+        }
+
+        public void clear() {
+            this.url = null;
+            this.mimeType = null;
+            this.lastModified = null;
+        }
+
+        public void setBaseLocation(URL xmlLocation) {
+            this.baseLocation = xmlLocation;
+        }
+    }
+
+    /**
+     * Utility class for dealing with attributes from KXmlParser.
+     */
+    protected static class AttributeMap extends HashMap<String, String> {
+
+        private static final AttributeMap instance = new AttributeMap();
+
+        public static AttributeMap getInstance() {
+            return instance;
+        }
+
+        /**
+         * Puts values in an <code>AttributeMap</code> by extracting attributes from the <code>xmlParser</code>.
+         * @param xmlParser <code>xmlParser</code> to extract attributes from. The parser must be
+         * in {@link org.xmlpull.v1.XmlPullParser#START_TAG} state.
+         */
+        public void setValues(KXmlParser xmlParser) {
+            final int count = xmlParser.getAttributeCount();
+            for (int i = 0; i < count; i++) {
+                this.put(xmlParser.getAttributeName(i), xmlParser.getAttributeValue(i));
+            }
+        }
+    }
 }
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
index 46119dd..2bc5ab2 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
@@ -22,29 +22,82 @@ import junit.framework.TestCase;
 import org.apache.sling.jcr.contentloader.internal.ContentCreator;
 
 import javax.jcr.RepositoryException;
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
-/**
- * 	Test the XmlReader with an XSLT transform
- */
 public class XmlReaderTest extends TestCase {
 
+    private XmlReader reader;
+    private MockContentCreator creator;
+
+    /**
+     * 	Test the XmlReader with an XSLT transform.
+     */
     public void testXmlReader() throws Exception {
-        XmlReader reader = new XmlReader();
         File file = new File("src/test/resources/reader/sample.xml");
         final URL testdata  = file.toURI().toURL();
-        final MockContentCreator creator = new MockContentCreator();
         reader.parse(testdata, creator);
         assertEquals("Did not create expected number of nodes", 1, creator.size());
     }
 
+    /**
+     * Test inclusion of binary files.
+     */
+    public void testCreateFile() throws Exception {
+        File input = new File("src/test/resources/reader/filesample.xml");
+        final URL testdata = input.toURI().toURL();
+        reader.parse(testdata, creator);
+        assertEquals("Did not create expected number of files", 2, creator.filesCreated.size());
+        MockContentCreator.FileDescription file = creator.filesCreated.get(0);
+        try {
+            file.data.available();
+            TestCase.fail("Did not close inputstream");
+        } catch (IOException ignore) {
+            // Expected
+        }
+        assertEquals("mimeType mismatch", "application/test", file.mimeType);
+        assertEquals("lastModified mismatch", XmlReader.FileDescription.DATE_FORMAT.parse("1977-06-01T07:00:00+0100"), new Date(file.lastModified));
+        assertEquals("Could not read file", "This is a test file.", file.content);
+
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        reader = new XmlReader();
+        creator = new MockContentCreator();
+    }
+
     @SuppressWarnings("serial")
 	private static class MockContentCreator extends ArrayList<String> implements ContentCreator {
 
+        public static class FileDescription {
+            public String name;
+            public InputStream data;
+            public String mimeType;
+            public long lastModified;
+            public String content;
+
+            public FileDescription(String name, InputStream data, String mimeType, long lastModified) throws IOException {
+                this.name = name;
+                this.data = data;
+                this.mimeType = mimeType;
+                this.lastModified = lastModified;
+                BufferedReader reader = new BufferedReader(new InputStreamReader(data));
+                this.content = reader.readLine();
+                reader.close();
+            }
+        }
+
+        public List<FileDescription> filesCreated = new ArrayList<FileDescription>();
+
 		public MockContentCreator() {
         }
 
@@ -68,6 +121,11 @@ public class XmlReaderTest extends TestCase {
         }
 
         public void createFileAndResourceNode(String name, InputStream data, String mimeType, long lastModified) throws RepositoryException {
+            try {
+                this.filesCreated.add(new FileDescription(name, data, mimeType, lastModified));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
         }
 
         public boolean switchCurrentNode(String subPath, String newNodeType) throws RepositoryException {
diff --git a/src/test/resources/reader/filesample.xml b/src/test/resources/reader/filesample.xml
new file mode 100644
index 0000000..ce4607b
--- /dev/null
+++ b/src/test/resources/reader/filesample.xml
@@ -0,0 +1,21 @@
+<node xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
+    <name>nodeName</name>
+    <primaryNodeType>type</primaryNodeType>
+    <mixinNodeTypes>
+        <mixinNodeType>mixtype1</mixinNodeType>
+        <mixinNodeType>mixtype2</mixinNodeType>
+    </mixinNodeTypes>
+    <properties>
+        <property>
+            <name>propName</name>
+            <value>propValue</value>
+            <type>String</type>
+        </property>
+        <!-- more properties -->
+    </properties>
+    <nodes>
+        <!-- child nodes -->
+        <nt:file src="testfile.txt" mimeType="application/test" lastModified="1977-06-01T07:00:00+0100"/>
+        <nt:file src="testfile.txt" mimeType="application/test" lastModified="1977-06-01T07:00:00+0100"/>
+    </nodes>
+</node>
diff --git a/src/test/resources/reader/testfile.txt b/src/test/resources/reader/testfile.txt
new file mode 100644
index 0000000..6de7b8c
--- /dev/null
+++ b/src/test/resources/reader/testfile.txt
@@ -0,0 +1 @@
+This is a test file.

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