Author: vramdal
Date: Tue Oct 27 09:43:56 2009
New Revision: 830106
URL: http://svn.apache.org/viewvc?rev=830106&view=rev
Log:
SLING-1161 implemented. Now supports including external files with nt:file in
content loader XML
Added:
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/filesample.xml
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/testfile.txt
Modified:
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
Modified:
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java?rev=830106&r1=830105&r2=830106&view=diff
==============================================================================
---
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
(original)
+++
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReader.java
Tue Oct 27 09:43:56 2009
@@ -25,12 +25,18 @@
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 @@
/**
* 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 @@
* </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 @@
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 @@
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 @@
NodeDescription.SHARED.clear();
PropertyDescription.SHARED.clear();
+ FileDescription.SHARED.clear();
NodeDescription currentNode = null;
PropertyDescription currentProperty = null;
@@ -200,6 +219,22 @@
} 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 @@
}
currentNode.addMixinType(content);
}
-
} else if (eventType == XmlPullParser.TEXT || eventType ==
XmlPullParser.CDSECT) {
contentBuffer.append(this.xmlParser.getText());
}
@@ -455,4 +489,103 @@
}
}
+
+ /**
+ * 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));
+ }
+ }
+ }
}
Modified:
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java?rev=830106&r1=830105&r2=830106&view=diff
==============================================================================
---
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
(original)
+++
sling/trunk/bundles/jcr/contentloader/src/test/java/org/apache/sling/jcr/contentloader/internal/readers/XmlReaderTest.java
Tue Oct 27 09:43:56 2009
@@ -22,29 +22,82 @@
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 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 {
Added:
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/filesample.xml
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/filesample.xml?rev=830106&view=auto
==============================================================================
---
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/filesample.xml
(added)
+++
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/filesample.xml
Tue Oct 27 09:43:56 2009
@@ -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>
Added:
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/testfile.txt
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/testfile.txt?rev=830106&view=auto
==============================================================================
---
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/testfile.txt
(added)
+++
sling/trunk/bundles/jcr/contentloader/src/test/resources/reader/testfile.txt
Tue Oct 27 09:43:56 2009
@@ -0,0 +1 @@
+This is a test file.