Author: rhauch
Date: 2009-03-12 16:54:55 -0400 (Thu, 12 Mar 2009)
New Revision: 776
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
trunk/dna-jcr/src/test/resources/repositoryForTckTests.xml
Log:
DNA-297 JcrSession.exportDocumentView Does Not Export Carriage Returns, Line Feeds, and
Tabs Correctly
Applied the "redux" patch, and verified that all tests do pass.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-03-12
20:40:20 UTC (rev 775)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-03-12
20:54:55 UTC (rev 776)
@@ -24,7 +24,11 @@
package org.jboss.dna.jcr;
import java.io.OutputStream;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
@@ -33,6 +37,8 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.text.XmlNameEncoder;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.ValueFactories;
@@ -50,6 +56,8 @@
@NotThreadSafe
class JcrDocumentViewExporter extends AbstractJcrExporter {
+ private static final TextEncoder VALUE_ENCODER = new
JcrDocumentViewExporter.JcrDocumentViewPropertyEncoder();
+
JcrDocumentViewExporter( JcrSession session ) {
super(session, Collections.<String>emptyList());
}
@@ -111,7 +119,7 @@
propName.getLocalName(),
localPropName,
PropertyType.nameFromValue(prop.getType()),
- value.getString());
+ VALUE_ENCODER.encode(value.getString()));
}
Name name;
@@ -211,4 +219,74 @@
return xmlCharacters.getValue().getString();
}
+ /**
+ * Special {@link TextEncoder} that implements the subset of XML name encoding
suggested by section 6.4.4 of the JCR 1.0.1
+ * specification. This encoder only encodes space (0x20), carriage return (0x0D),
new line (0x0A), tab (0x09), and any
+ * underscore characters that might otherwise suggest an encoding, as defined in
{@link XmlNameEncoder}.
+ *
+ */
+ protected static class JcrDocumentViewPropertyEncoder extends XmlNameEncoder {
+ private static final Set<Character> MAPPED_CHARACTERS;
+
+ static {
+ MAPPED_CHARACTERS = new HashSet<Character>();
+ MAPPED_CHARACTERS.add(' ');
+ MAPPED_CHARACTERS.add('\r');
+ MAPPED_CHARACTERS.add('\n');
+ MAPPED_CHARACTERS.add('\t');
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.text.TextEncoder#encode(java.lang.String)
+ */
+ // See section 6.4.4 of the JCR 1.0.1 spec for why these hoops must be jumped
through
+ @Override
+ public String encode( String text ) {
+ if (text == null) return null;
+ if (text.length() == 0) return text;
+ StringBuilder sb = new StringBuilder();
+ String hex = null;
+ CharacterIterator iter = new StringCharacterIterator(text);
+ for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
+ if (c == '_') {
+ // Read the next character (if there is one) ...
+ char next = iter.next();
+ if (next == CharacterIterator.DONE) {
+ sb.append(c);
+ break;
+ }
+ // If the next character is not 'x', then these are just
regular characters ...
+ if (next != 'x') {
+ sb.append(c).append(next);
+ continue;
+ }
+ // The next character is 'x', so write out the '_'
character in encoded form ...
+ sb.append("_x005f_");
+ // And then write out the next character ...
+ sb.append(next);
+ } else if (!MAPPED_CHARACTERS.contains(c)) {
+ // Legal characters for an XML Name ...
+ sb.append(c);
+ } else {
+ // All other characters must be escaped with '_xHHHH_' where
'HHHH' is the hex string for the code point
+ hex = Integer.toHexString(c);
+ // The hex string excludes the leading '0's, so check the
character values so we know how many to prepend
+ if (c >= '\u0000' && c <= '\u000f') {
+ sb.append("_x000").append(hex);
+ } else if (c >= '\u0010' && c <=
'\u00ff') {
+ sb.append("_x00").append(hex);
+ } else if (c >= '\u0100' && c <=
'\u0fff') {
+ sb.append("_x0").append(hex);
+ } else {
+ sb.append("_x").append(hex);
+ }
+ sb.append('_');
+ }
+ }
+ return sb.toString();
+ }
+ }
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-03-12 20:40:20
UTC (rev 775)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-03-12 20:54:55
UTC (rev 776)
@@ -1,5 +1,5 @@
/*
- * JBoss DNA (
http://www.jboss.org/dna)
+* JBoss DNA (
http://www.jboss.org/dna)
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
@@ -23,6 +23,7 @@
*/
package org.jboss.dna.jcr;
+import static org.junit.Assert.assertTrue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNot.not;
@@ -31,7 +32,9 @@
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
+import java.io.OutputStream;
import java.security.AccessControlException;
import java.security.Principal;
import java.util.Calendar;
@@ -67,6 +70,8 @@
*/
public class JcrSessionTest {
+ private static final String MULTI_LINE_VALUE = "Line\t1\nLine 2\rLine 3\r\nLine
4";
+
private String workspaceName;
private ExecutionContext context;
private InMemoryRepositorySource source;
@@ -96,7 +101,8 @@
graph.create("/a").and().create("/a/b").and().create("/a/b/c");
graph.set("booleanProperty").on("/a/b").to(true);
graph.set("stringProperty").on("/a/b/c").to("value");
-
+
graph.set("multiLineProperty").on("/a/b/c").to(MULTI_LINE_VALUE);
+
// Make sure the path to the namespaces exists ...
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
@@ -388,4 +394,14 @@
assertThat(session.getNamespaceURI("sv"),
is("http://www.jcp.org/jcr/sv/1.0"));
// assertThat(session.getNamespaceURI("xml"),
is("http://www.w3.org/XML/1998/namespace"));
}
+
+ @Test
+ public void shouldExportMultiLinePropertiesInSystemView() throws Exception {
+ OutputStream os = new ByteArrayOutputStream();
+
+ session.exportSystemView("/a/b/c", os, false, true);
+
+ String fileContents = os.toString();
+ assertTrue(fileContents.contains(MULTI_LINE_VALUE));
+ }
}
Modified: trunk/dna-jcr/src/test/resources/repositoryForTckTests.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryForTckTests.xml 2009-03-12 20:40:20 UTC
(rev 775)
+++ trunk/dna-jcr/src/test/resources/repositoryForTckTests.xml 2009-03-12 20:54:55 UTC
(rev 776)
@@ -25,14 +25,27 @@
~ Boston, MA 02110-1301 USA
-->
<testroot
xmlns:jcr="http://www.jcp.org/jcr/1.0"
-
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
-
xmlns:dna="http://www.jboss.org/dna/1.0"
- jcr:primaryType="nt:unstructured">
- <nt:unstructured jcr:name="node1"
prop1="<foo&foo>" >
- <!-- This stanza checks for the jcr:xmltext special case for document export. DO
NOT change this element. -->
- <nt:unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="This is
my "XML" text!" />
- </nt:unstructured>
- <nt:unstructured jcr:name="node2 has a multi-word name"
prop2="bar" />
- <nt:unstructured jcr:name="node3" />
- <nt:unstructured jcr:name="node4" />
+
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
+
xmlns:dna="http://www.jboss.org/dna/1.0"
+ jcr:primaryType="nt:unstructured">
+ <nt:unstructured jcr:name="node1"
prop1="<foo&foo>" >
+ <!--
+ This stanza checks for the jcr:xmltext special case for export as per JCR
1.0.1 section 6.4.2.3
+ -->
+ <nt:unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="This
is my "XML" text!" />
+ </nt:unstructured>
+ <nt:unstructured jcr:name="node2 has a multi-word name"
multi-valued-property="bar baz blah">
+ <!--
+ This stanza checks that consecutive jcr:xmltext elements will be merged in the
export as
+ per JCR 1.0.1 section 6.4.2.3
+ -->
+ <nt:unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="This
is my "XML" text!" />
+ <nt:unstructured jcr:name="jcr:xmltext" jcr:xmlcharacters="This
is my "other" text!" />
+ </nt:unstructured>
+ <nt:unstructured jcr:name="node3" />
+ <!--
+ Test of unprintable character exports.
+ Cannot test \r character here on Windows as TCK XML Parser will replace it with \n
and fail the comparison
+ -->
+ <nt:unstructured jcr:name="node4"
multi-line-property="Line	1
Line 2"/>
</testroot>
\ No newline at end of file