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/11/16 16:27:28 UTC

svn commit: r345037 - in /incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit: core/xml/DocViewImportHandler.java core/xml/SessionImporter.java core/xml/WorkspaceImporter.java value/ValueHelper.java

Author: stefan
Date: Wed Nov 16 07:27:23 2005
New Revision: 345037

URL: http://svn.apache.org/viewcvs?rev=345037&view=rev
Log:
improved handling of (potentially large) binary data on import

Modified:
    incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
    incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
    incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
    incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java

Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java?rev=345037&r1=345036&r2=345037&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java Wed Nov 16 07:27:23 2005
@@ -27,6 +27,7 @@
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import java.io.IOException;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Stack;
 
@@ -99,14 +100,25 @@
                 // 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 whitespace character data: " + text);
-                    // reset handler
-                    textHandler.dispose();
-                    textHandler = null;
-                    return;
+                // check for pure whitespace character data
+                Reader reader = textHandler.reader();
+                try {
+                    int ch;
+                    while ((ch = reader.read()) != -1) {
+                        if (ch > 0x20) {
+                            break;
+                        }
+                    }
+                    if (ch == -1) {
+                        // the character data consists of pure whitespace, ignore
+                        log.debug("ignoring pure whitespace character data...");
+                        // reset handler
+                        textHandler.dispose();
+                        textHandler = null;
+                        return;
+                    }
+                } finally {
+                    reader.close();
                 }
 
                 Importer.NodeInfo node =

Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java?rev=345037&r1=345036&r2=345037&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java Wed Nov 16 07:27:23 2005
@@ -322,10 +322,19 @@
                     // session's namespace mappings
                     va[i] = ival.toJCRValue(session.getNamespaceResolver());
                 } else if (targetType == PropertyType.BINARY) {
-                    // deserialize BINARY type using Reader
                     try {
-                        Reader reader = tv.reader();
-                        va[i] = ValueHelper.deserialize(reader, targetType, false);
+                        if (tv.length() < 0x10000) {
+                            // < 65kb: deserialize BINARY type using String
+                            va[i] = ValueHelper.deserialize(tv.retrieve(), targetType, false);
+                        } else {
+                            // >= 65kb: deserialize BINARY type using Reader
+                            Reader reader = tv.reader();
+                            try {
+                                va[i] = ValueHelper.deserialize(reader, targetType, false);
+                            } finally {
+                                reader.close();
+                            }
+                        }
                     } catch (IOException ioe) {
                         String msg = "failed to deserialize binary value";
                         log.debug(msg, ioe);

Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=345037&r1=345036&r2=345037&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Wed Nov 16 07:27:23 2005
@@ -22,7 +22,6 @@
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.WorkspaceImpl;
-import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
 import org.apache.jackrabbit.core.nodetype.NodeDef;
 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
@@ -32,11 +31,13 @@
 import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
 import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.name.MalformedPathException;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.Path;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.util.Base64;
+import org.apache.jackrabbit.util.TransientFileFactory;
 import org.apache.jackrabbit.uuid.UUID;
 import org.apache.log4j.Logger;
 
@@ -50,9 +51,11 @@
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.Reader;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Stack;
@@ -573,34 +576,29 @@
                     if (targetType == PropertyType.BINARY) {
                         // base64 encoded BINARY type;
                         // decode using Reader
-/*
-                        // @todo decode to temp file and pass FileInputStream to InternalValue factory method
-                        File tmpFile = null;
                         try {
-                            tmpFile = File.createTempFile("bin", null);
-                            FileOutputStream out = new FileOutputStream(tmpFile);
-                            Base64.decode(tv.reader(), out);
-                            out.close();
-                            iva[i] = InternalValue.create(new FileInputStream(tmpFile));
-                        } catch (IOException ioe) {
-                            String msg = "failed to decode binary value";
-                            log.debug(msg, ioe);
-                            throw new RepositoryException(msg, ioe);
-                        } finally {
-                            // the temp file can be deleted because
-                            // the InternalValue instance has spooled
-                            // its contents
-                            if (tmpFile != null) {
-                                tmpFile.delete();
+                            if (tv.length() < 0x10000) {
+                                // < 65kb: deserialize BINARY type in memory
+                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                                Base64.decode(tv.retrieve(), baos);
+                                // no need to close ByteArrayOutputStream
+                                //baos.close();
+                                iva[i] = InternalValue.create(baos.toByteArray());
+                            } else {
+                                // >= 65kb: deserialize BINARY type
+                                // using Reader and temporay file
+                                TransientFileFactory fileFactory = TransientFileFactory.getInstance();
+                                File tmpFile = fileFactory.createTransientFile("bin", null, null);
+                                FileOutputStream out = new FileOutputStream(tmpFile);
+                                Reader reader = tv.reader();
+                                try {
+                                    Base64.decode(reader, out);
+                                } finally {
+                                    reader.close();
+                                    out.close();
+                                }
+                                iva[i] = InternalValue.create(tmpFile);
                             }
-                        }
-*/
-                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                        try {
-                            Base64.decode(tv.reader(), baos);
-                            // no need to close ByteArrayOutputStream
-                            //baos.close();
-                            iva[i] = InternalValue.create(new ByteArrayInputStream(baos.toByteArray()));
                         } catch (IOException ioe) {
                             String msg = "failed to decode binary value";
                             log.debug(msg, ioe);

Modified: incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java?rev=345037&r1=345036&r2=345037&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java (original)
+++ incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java Wed Nov 16 07:27:23 2005
@@ -22,6 +22,7 @@
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.util.Base64;
 import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.util.TransientFileFactory;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -33,6 +34,9 @@
 import java.io.Reader;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
 
 /**
  * The <code>ValueHelper</code> class provides several <code>Value</code>
@@ -50,7 +54,7 @@
      * @param srcValue
      * @param targetType
      * @return
-     * @throws javax.jcr.ValueFormatException
+     * @throws ValueFormatException
      * @throws IllegalArgumentException
      */
     public static Value convert(String srcValue, int targetType)
@@ -66,7 +70,7 @@
      * @param srcValues
      * @param targetType
      * @return
-     * @throws javax.jcr.ValueFormatException
+     * @throws ValueFormatException
      * @throws IllegalArgumentException
      */
     public static Value[] convert(String[] srcValues, int targetType)
@@ -85,7 +89,7 @@
      * @param srcValues
      * @param targetType
      * @return
-     * @throws javax.jcr.ValueFormatException
+     * @throws ValueFormatException
      * @throws IllegalArgumentException
      */
     public static Value[] convert(Value[] srcValues, int targetType)
@@ -119,7 +123,7 @@
      * @param srcValue
      * @param targetType
      * @return
-     * @throws javax.jcr.ValueFormatException
+     * @throws ValueFormatException
      * @throws IllegalStateException
      * @throws IllegalArgumentException
      */
@@ -417,14 +421,14 @@
      * Serializes the given value to a <code>String</code>. The serialization
      * format is the same as used by Document & System View XML, i.e.
      * binary values will be Base64-encoded whereas for all others
-     * <code>{@link javax.jcr.Value#getString()}</code> will be used.
+     * <code>{@link Value#getString()}</code> will be used.
      *
      * @param value        the value to be serialized
      * @param encodeBlanks if <code>true</code> space characters will be encoded
      *                     as <code>"_x0020_"</code> within he output string.
      * @return a string representation of the given value.
      * @throws IllegalStateException if the given value is in an illegal state
-     * @throws javax.jcr.RepositoryException   if an error occured during the serialization.
+     * @throws RepositoryException   if an error occured during the serialization.
      */
     public static String serialize(Value value, boolean encodeBlanks)
             throws IllegalStateException, RepositoryException {
@@ -442,17 +446,16 @@
      * Outputs the serialized value to a <code>Writer</code>. The serialization
      * format is the same as used by Document & System View XML, i.e.
      * binary values will be Base64-encoded whereas for all others
-     * <code>{@link javax.jcr.Value#getString()}</code> will be used for
-     * serialization.
+     * <code>{@link Value#getString()}</code> will be used for serialization.
      *
      * @param value        the value to be serialized
      * @param encodeBlanks if <code>true</code> space characters will be encoded
      *                     as <code>"_x0020_"</code> within he output string.
      * @param writer       writer to output the encoded data
      * @throws IllegalStateException if the given value is in an illegal state
-     * @throws java.io.IOException           if an i/o error occured during the
+     * @throws IOException           if an i/o error occured during the
      *                               serialization
-     * @throws javax.jcr.RepositoryException   if an error occured during the serialization.
+     * @throws RepositoryException   if an error occured during the serialization.
      */
     public static void serialize(Value value, boolean encodeBlanks,
                                  Writer writer)
@@ -492,9 +495,9 @@
      *                     character sequences will be decoded to single space
      *                     characters each.
      * @return the deserialized <code>Value</code>
-     * @throws javax.jcr.ValueFormatException if the string data is not of the required
+     * @throws ValueFormatException if the string data is not of the required
      *                              format
-     * @throws javax.jcr.RepositoryException  if an error occured during the
+     * @throws RepositoryException  if an error occured during the
      *                              deserialization.
      */
     public static Value deserialize(String value, int type,
@@ -533,11 +536,11 @@
      *                     character sequences will be decoded to single space
      *                     characters each.
      * @return the deserialized <code>Value</code>
-     * @throws java.io.IOException          if an i/o error occured during the
+     * @throws IOException          if an i/o error occured during the
      *                              serialization
-     * @throws javax.jcr.ValueFormatException if the string data is not of the required
+     * @throws ValueFormatException if the string data is not of the required
      *                              format
-     * @throws javax.jcr.RepositoryException  if an error occured during the
+     * @throws RepositoryException  if an error occured during the
      *                              deserialization.
      */
     public static Value deserialize(Reader reader, int type,
@@ -547,20 +550,63 @@
             // base64 encoded binary value;
             // the encodeBlanks flag can be ignored since base64-encoded
             // data cannot contain encoded space characters
-/*
-            // @todo decode to temp file and pass FileInputStream to BinaryValue constructor
-            File tmpFile = File.createTempFile("bin", null);
+
+            // decode to temp file
+            TransientFileFactory fileFactory = TransientFileFactory.getInstance();
+            final File tmpFile = fileFactory.createTransientFile("bin", null, null);
             FileOutputStream out = new FileOutputStream(tmpFile);
-            tmpFile.deleteOnExit();
-            Base64.decode(reader, out);
-            out.close();
-            return new BinaryValue(new FileInputStream(tmpFile));
-*/
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            Base64.decode(reader, baos);
-            // no need to close ByteArrayOutputStream
-            //baos.close();
-            return new BinaryValue(baos.toByteArray());
+            try {
+                Base64.decode(reader, out);
+            } finally {
+                out.close();
+            }
+
+            // create an InputStream that keeps a hard reference to the temp file
+            // in order to prevent its automatic deletion once the associated
+            // File object is reclaimed by the garbage collector;
+            // pass InputStream to BinaryValue constructor
+            return new BinaryValue(new InputStream() {
+                File f = tmpFile;
+                InputStream in = new FileInputStream(f);
+
+                public int available() throws IOException {
+                    return in.available();
+                }
+
+                public void close() throws IOException {
+                    in.close();
+                    // now it's safe to prepare temp file to be gc'ed
+                    f = null;
+                }
+
+                public synchronized void mark(int readlimit) {
+                    in.mark(readlimit);
+                }
+
+                public boolean markSupported() {
+                    return in.markSupported();
+                }
+
+                public int read(byte b[]) throws IOException {
+                    return in.read(b);
+                }
+
+                public int read(byte b[], int off, int len) throws IOException {
+                    return in.read(b, off, len);
+                }
+
+                public synchronized void reset() throws IOException {
+                    in.reset();
+                }
+
+                public long skip(long n) throws IOException {
+                    return in.skip(n);
+                }
+
+                public int read() throws IOException {
+                    return in.read();
+                }
+            });
         } else {
             char[] chunk = new char[8192];
             int read;