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>
* <node>
* <name>the name of the node</name>
@@ -81,6 +87,9 @@ import org.xmlpull.v1.XmlPullParserException;
* </nodes>
* </node>
* </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><nt:file></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><nt:file></code>, with the attributes <code>src</code>,
+ * <code>mimeType</code> and <code>lastModified</code>. <br/><br/>Example:
+ * <pre>
+ * <nt:file src="../../image.png" mimeType="image/png" lastModified="1977-06-01T07:00:00+0100" />
+ * </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>.