You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2005/04/07 19:15:43 UTC
svn commit: r160421 - in
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core:
SessionImpl.java xml/DocViewImportHandler.java xml/Importer.java
xml/SysViewImportHandler.java xml/TargetImportHandler.java
Author: stefan
Date: Thu Apr 7 10:15:42 2005
New Revision: 160421
URL: http://svn.apache.org/viewcvs?view=rev&rev=160421
Log:
optimized value handling on import
Modified:
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java?view=diff&r1=160420&r2=160421
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SessionImpl.java Thu Apr 7 10:15:42 2005
@@ -1057,7 +1057,7 @@
boolean skipBinary, boolean noRecurse)
throws InvalidSerializedDataException, IOException,
PathNotFoundException, RepositoryException {
- boolean indenting = true;
+ boolean indenting = false;
OutputFormat format = new OutputFormat("xml", "UTF-8", indenting);
XMLSerializer serializer = new XMLSerializer(out, format);
try {
@@ -1091,7 +1091,7 @@
public void exportSysView(String absPath, OutputStream out,
boolean skipBinary, boolean noRecurse)
throws IOException, PathNotFoundException, RepositoryException {
- boolean indenting = true;
+ boolean indenting = false;
OutputFormat format = new OutputFormat("xml", "UTF-8", indenting);
XMLSerializer serializer = new XMLSerializer(out, format);
try {
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java?view=diff&r1=160420&r2=160421
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java Thu Apr 7 10:15:42 2005
@@ -26,6 +26,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
@@ -44,7 +45,7 @@
*/
private final Stack stack = new Stack();
// buffer used to merge adjacent character data
- private StringBufferValue textHandler = new StringBufferValue();
+ private BufferedStringValue textHandler = new BufferedStringValue();
/**
* Constructs a new <code>DocViewImportHandler</code>.
@@ -57,34 +58,75 @@
}
/**
- * Translates character data encountered in
- * <code>{@link #characters(char[], int, int)}</code> into a
- * <code>jcr:xmltext</code> child node with a <code>jcr:xmlcharacters</code>
- * property.
+ * Appends the given character data to the internal buffer.
*
- * @param text
- * @throws SAXException
+ * @param ch the characters to be appended
+ * @param start the index of the first character to append
+ * @param length the number of characters to append
+ * @throws SAXException if an error occurs
+ * @see #characters(char[], int, int)
+ * @see #ignorableWhitespace(char[], int, int)
+ * @see #processCharacters()
*/
- private void onTextNode(StringBufferValue text)
+ private void appendCharacters(char ch[], int start, int length)
throws SAXException {
- String s = textHandler.retrieve();
- if (s.trim().length() == 0) {
- // ignore whitespace-only character data
- log.debug("ignoring withespace character data: " + s);
- return;
+ if (textHandler == null) {
+ textHandler = new BufferedStringValue();
}
try {
- Importer.NodeInfo node =
- new Importer.NodeInfo(JCR_XMLTEXT, null, null, null);
- Importer.TextValue[] values = new Importer.TextValue[]{text};
- ArrayList props = new ArrayList();
- Importer.PropInfo prop =
- new Importer.PropInfo(JCR_XMLCHARACTERS,
- PropertyType.STRING, values);
- props.add(prop);
- // call Importer
- importer.startNode(node, props, nsContext);
- importer.endNode(node);
+ textHandler.append(ch, start, length);
+ } catch (IOException ioe) {
+ String msg = "internal error while processing internal buffer data";
+ log.error(msg, ioe);
+ throw new SAXException(msg, ioe);
+ }
+ }
+
+ /**
+ * Translates character data reported by the
+ * <code>{@link #characters(char[], int, int)}</code> &
+ * <code>{@link #ignorableWhitespace(char[], int, int)}</code> SAX events
+ * into a <code>jcr:xmltext</code> child node with one
+ * <code>jcr:xmlcharacters</code> property.
+ *
+ * @throws SAXException if an error occurs
+ * @see #appendCharacters(char[], int, int)
+ */
+ private void processCharacters()
+ throws SAXException {
+ try {
+ if (textHandler != null && textHandler.length() > 0) {
+ // there is character data that needs to be added to
+ // the current node
+
+ String text = textHandler.retrieve();
+ if (text.trim().length() == 0) {
+ // ignore whitespace-only character data
+ log.debug("ignoring withespace character data: " + text);
+ return;
+ }
+
+ Importer.NodeInfo node =
+ new Importer.NodeInfo(JCR_XMLTEXT, null, null, null);
+ Importer.TextValue[] values =
+ new Importer.TextValue[]{textHandler};
+ ArrayList props = new ArrayList();
+ Importer.PropInfo prop =
+ new Importer.PropInfo(JCR_XMLCHARACTERS,
+ PropertyType.STRING, values);
+ props.add(prop);
+ // call Importer
+ importer.startNode(node, props, nsContext);
+ importer.endNode(node);
+
+ // reset handler
+ textHandler.dispose();
+ textHandler = null;
+ }
+ } catch (IOException ioe) {
+ String msg = "internal error while processing internal buffer data";
+ log.error(msg, ioe);
+ throw new SAXException(msg, ioe);
} catch (RepositoryException re) {
throw new SAXException(re);
}
@@ -108,13 +150,8 @@
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException {
- if (textHandler != null && textHandler.length() > 0) {
- // there is character data that needs to be added to the current node
- onTextNode(textHandler);
- // reset handler
- textHandler.dispose();
- textHandler = null;
- }
+ // process buffered character data
+ processCharacters();
try {
QName nodeName = new QName(namespaceURI, localName);
@@ -196,13 +233,10 @@
public void characters(char[] ch, int start, int length)
throws SAXException {
/**
- * buffer character data; will be processed
- * in endElement and startElement method
+ * buffer data reported by the characters event;
+ * will be processed on the next endElement or startElement event.
*/
- if (textHandler == null) {
- textHandler = new StringBufferValue();
- }
- textHandler.append(ch, start, length);
+ appendCharacters(ch, start, length);
}
/**
@@ -212,12 +246,9 @@
throws SAXException {
/**
* buffer data reported by the ignorableWhitespace event;
- * will be processed in endElement and startElement method
+ * will be processed on the next endElement or startElement event.
*/
- if (textHandler == null) {
- textHandler = new StringBufferValue();
- }
- textHandler.append(ch, start, length);
+ appendCharacters(ch, start, length);
}
/**
@@ -225,13 +256,9 @@
*/
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
- if (textHandler != null && textHandler.length() > 0) {
- // there is character data that needs to be added to the current node
- onTextNode(textHandler);
- // reset handler
- textHandler.dispose();
- textHandler = null;
- }
+ // process buffered character data
+ processCharacters();
+
Importer.NodeInfo node = (Importer.NodeInfo) stack.peek();
try {
// call Importer
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java?view=diff&r1=160420&r2=160421
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java Thu Apr 7 10:15:42 2005
@@ -161,32 +161,26 @@
public interface TextValue {
/**
* Returns the length of the serialized value.
+ *
* @return the length of the serialized value
- * @throws IllegalStateException if the serialized value is not
- * available anymore (e.g. because it
- * been discarded)
* @throws IOException if an I/O error occurs
*/
- public long length() throws IllegalStateException, IOException;
+ public long length() throws IOException;
/**
* Retrieves the serialized value.
+ *
* @return the serialized value
- * @throws IllegalStateException if the serialized value is not
- * available anymore (e.g. because it
- * been discarded)
* @throws IOException if an I/O error occurs
*/
- public String retrieve() throws IllegalStateException, IOException;
+ public String retrieve() throws IOException;
/**
* Returns a <code>Reader</code> for reading the serialized value.
+ *
* @return a <code>Reader</code> for reading the serialized value.
- * @throws IllegalStateException if the serialized value is not
- * available anymore (e.g. because it
- * been discarded)
* @throws IOException if an I/O error occurs
*/
- public Reader reader() throws IllegalStateException, IOException;
+ public Reader reader() throws IOException;
}
}
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java?view=diff&r1=160420&r2=160421
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java Thu Apr 7 10:15:42 2005
@@ -20,7 +20,6 @@
import org.apache.jackrabbit.core.NamespaceResolver;
import org.apache.jackrabbit.core.QName;
import org.apache.jackrabbit.core.UnknownPrefixException;
-import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -37,8 +36,6 @@
*/
class SysViewImportHandler extends TargetImportHandler {
- private static Logger log = Logger.getLogger(SysViewImportHandler.class);
-
/**
* stack of ImportState instances; an instance is pushed onto the stack
* in the startElement method every time a sv:node element is encountered;
@@ -179,20 +176,7 @@
// sv:value element
// reset temp fields
- if (currentPropType == PropertyType.BINARY) {
- // binary value; use temp-file backed value appender
- try {
- currentPropValue = new CLOBValue();
- } catch (IOException ioe) {
- String msg = "error while processing property value "
- + currentPropName;
- log.debug(msg, ioe);
- throw new SAXException(msg, ioe);
- }
- } else {
- // 'normal' value; use StringBuffer-backed value appender
- currentPropValue = new StringBufferValue();
- }
+ currentPropValue = new BufferedStringValue();
} else {
throw new SAXException(new InvalidSerializedDataException("unexpected element found in system view xml document: "
+ localName));
Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java?view=diff&r1=160420&r2=160421
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java Thu Apr 7 10:15:42 2005
@@ -47,6 +47,11 @@
this.nsContext = nsContext;
}
+ /**
+ * Disposes all instances of <code>AppendableValue</code> contained in the
+ * given property info's value array.
+ * @param prop property info
+ */
protected void disposePropertyValues(Importer.PropInfo prop) {
Importer.TextValue[] vals = prop.getValues();
for (int i = 0; i < vals.length; i++) {
@@ -54,8 +59,8 @@
try {
((AppendableValue) vals[i]).dispose();
} catch (IOException ioe) {
- log.warn("error while disposing temporary value appender",
- ioe);
+ log.warn("error while disposing temporary value", ioe);
+ // fall through...
}
}
}
@@ -65,18 +70,36 @@
/**
* <code>AppendableValue</code> represents a serialized value that is
* appendable.
+ * <p/>
+ * <b>Important:</b> Note that in order to free resources
+ * <code>{@link #dispose()}</code> should be called as soon as an an
+ * <code>AppendableValue</code> object is not used anymore.
*/
public interface AppendableValue extends Importer.TextValue {
+ /**
+ * Append a portion of an array of characters.
+ * @param chars the characters to be appended
+ * @param start the index of the first character to append
+ * @param length the number of characters to append
+ * @throws IOException if an I/O error occurs
+ */
public void append(char[] chars, int start, int length)
- throws IllegalStateException, IOException;
+ throws IOException;
/**
- * @throws IOException
+ * Close this value. Once a value has been closed,
+ * further append() invocations will cause an IOException to be thrown.
+ *
+ * @throws IOException if an I/O error occurs
*/
public void close() throws IOException;
/**
- * @throws IOException
+ * Dispose this value, i.e. free all bound resources. Once a value has
+ * been disposed, further method invocations will cause an IOException
+ * to be thrown.
+ *
+ * @throws IOException if an I/O error occurs
*/
public void dispose() throws IOException;
}
@@ -122,112 +145,108 @@
}
/**
- * <code>StringBufferValue</code> represents an appendable serialized value
- * that is internally backed by a <code>StringBuffer</code>.
+ * <code>BufferedStringValue</code> represents an appendable
+ * serialized value that is either buffered in-memory or backed
+ * by a temporary file if its size exceeds a certain limit.
+ * <p/>
+ * <b>Important:</b> Note that in order to free resources
+ * <code>{@link #dispose()}</code> should be called as soon as an
+ * <code>BufferedStringValue</code> instance is not used anymore.
*/
- protected class StringBufferValue implements AppendableValue {
-
- private final StringBuffer buffer;
+ protected class BufferedStringValue implements AppendableValue {
/**
- * Constructs a new empty <code>StringBufferValue</code>.
+ * max size for buffering data in memory
*/
- protected StringBufferValue() {
- buffer = new StringBuffer();
- }
-
- //--------------------------------------------------------< TextValue >
+ private static final int MAX_BUFFER_SIZE = 0x10000;
/**
- * {@inheritDoc}
+ * size of increment if capacity buffer needs to be enlarged
*/
- public long length() {
- return buffer.length();
- }
-
+ private static final int BUFFER_INCREMENT = 0x2000;
/**
- * {@inheritDoc}
+ * in-memory buffer
*/
- public String retrieve() {
- return buffer.toString();
- }
-
+ private char[] buffer;
/**
- * {@inheritDoc}
+ * current position within buffer (size of actual data in buffer)
*/
- public Reader reader() {
- return new StringReader(buffer.toString());
- }
+ private int bufferPos;
- //--------------------------------------------------< AppendableValue >
/**
- * {@inheritDoc}
+ * backing temporary file created when size of data exceeds
+ * MAX_BUFFER_SIZE
*/
- public void append(char[] chars, int start, int length) {
- buffer.append(chars, start, length);
- }
-
+ private File tmpFile;
/**
- * {@inheritDoc}
+ * writer used to write to tmpFile; writer & tmpFile are always
+ * instantiated together, i.e. they are either both null or both not null.
*/
- public void close() {
- // nop
- }
+ private Writer writer;
/**
- * {@inheritDoc}
+ * Constructs a new empty <code>BufferedStringValue</code>.
*/
- public void dispose() {
- buffer.setLength(0);
- }
- }
-
- /**
- * <code>CLOBValue</code> represents an appendable serialized value
- * that is internally backed by a temporary file.
- */
- protected class CLOBValue implements AppendableValue {
-
- private File tmpFile;
- private Writer writer;
-
- protected CLOBValue() throws IOException {
- tmpFile = File.createTempFile("bin", null);
- writer = new FileWriter(tmpFile);
+ protected BufferedStringValue() {
+ buffer = new char[0x2000];
+ bufferPos = 0;
+ tmpFile = null;
+ writer = null;
}
//--------------------------------------------------------< TextValue >
/**
* {@inheritDoc}
*/
- public long length() throws IllegalStateException, IOException {
- if (tmpFile == null) {
- throw new IllegalStateException();
+ public long length() throws IOException {
+ if (buffer != null) {
+ return bufferPos;
+ } else if (tmpFile != null) {
+ writer.flush();
+ return tmpFile.length();
+ } else {
+ throw new IOException("this instance has already been disposed");
}
- return tmpFile.length();
}
/**
* {@inheritDoc}
*/
- public String retrieve() throws IllegalStateException, IOException {
- Reader reader = reader();
- char[] chunk = new char[8192];
- int read;
- StringBuffer buf = new StringBuffer();
- while ((read = reader.read(chunk)) > -1) {
- buf.append(chunk, 0, read);
+ public String retrieve() throws IOException {
+ if (buffer != null) {
+ return new String(buffer, 0, bufferPos);
+ } else if (tmpFile != null) {
+ if (length() > Integer.MAX_VALUE) {
+ throw new IOException("size of value is too big, use reader()");
+ }
+ StringBuffer sb = new StringBuffer((int) tmpFile.length());
+ char[] chunk = new char[0x2000];
+ int read;
+ Reader reader = new FileReader(tmpFile);
+ try {
+ while ((read = reader.read(chunk)) > -1) {
+ sb.append(chunk, 0, read);
+ }
+ } finally {
+ reader.close();
+ }
+ return sb.toString();
+ } else {
+ throw new IOException("this instance has already been disposed");
}
- return buf.toString();
}
/**
* {@inheritDoc}
*/
- public Reader reader() throws IllegalStateException, IOException {
- if (tmpFile == null) {
- throw new IllegalStateException();
+ public Reader reader() throws IOException {
+ if (buffer != null) {
+ return new StringReader(new String(buffer, 0, bufferPos));
+ } else if (tmpFile != null) {
+ writer.flush();
+ return new FileReader(tmpFile);
+ } else {
+ throw new IOException("this instance has already been disposed");
}
- return new FileReader(tmpFile);
}
//--------------------------------------------------< AppendableValue >
@@ -235,20 +254,45 @@
* {@inheritDoc}
*/
public void append(char[] chars, int start, int length)
- throws IllegalStateException, IOException {
- if (writer == null) {
- throw new IllegalStateException();
+ throws IOException {
+ if (buffer != null) {
+ if (bufferPos + length > MAX_BUFFER_SIZE) {
+ // threshold for keeping data in memory exceeded;
+ // create temp file and spool buffer contents
+ tmpFile = File.createTempFile("txt", null);
+ writer = new FileWriter(tmpFile);
+ writer.write(buffer, 0, bufferPos);
+ writer.write(chars, start, length);
+ // reset fields
+ buffer = null;
+ bufferPos = 0;
+ } else {
+ if (bufferPos + length > buffer.length) {
+ // reallocate new buffer and spool old buffer contents
+ char[] newBuffer = new char[buffer.length + BUFFER_INCREMENT];
+ System.arraycopy(buffer, 0, newBuffer, 0, bufferPos);
+ buffer = newBuffer;
+ }
+ System.arraycopy(chars, start, buffer, bufferPos, length);
+ bufferPos += length;
+ }
+ } else if (tmpFile != null) {
+ writer.write(chars, start, length);
+ } else {
+ throw new IOException("this instance has already been disposed");
}
- writer.write(chars, start, length);
}
/**
* {@inheritDoc}
*/
public void close() throws IOException {
- if (writer != null) {
+ if (buffer != null) {
+ // nop
+ } else if (tmpFile != null) {
writer.close();
- writer = null;
+ } else {
+ throw new IOException("this instance has already been disposed");
}
}
@@ -256,10 +300,16 @@
* {@inheritDoc}
*/
public void dispose() throws IOException {
- close();
- if (tmpFile != null) {
+ if (buffer != null) {
+ buffer = null;
+ bufferPos = 0;
+ } else if (tmpFile != null) {
+ writer.close();
tmpFile.delete();
tmpFile = null;
+ writer = null;
+ } else {
+ throw new IOException("this instance has already been disposed");
}
}
}