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/04 19:55:21 UTC

svn commit: r160072 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: util/ValueHelper.java xml/DocViewImportHandler.java xml/ImportHandler.java xml/Importer.java xml/SessionImporter.java xml/SysViewImportHandler.java xml/TargetImportHandler.java xml/WorkspaceImporter.java

Author: stefan
Date: Mon Apr  4 10:55:20 2005
New Revision: 160072

URL: http://svn.apache.org/viewcvs?view=rev&rev=160072
Log:
re-implemented handling of values on import to allow import of large binary properties 

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java   (with props)
Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ValueHelper.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/Importer.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ValueHelper.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ValueHelper.java?view=diff&r1=160071&r2=160072
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ValueHelper.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/util/ValueHelper.java Mon Apr  4 10:55:20 2005
@@ -471,7 +471,8 @@
      * @param reader       reader for the string data to be deserialized
      * @param type         type of value
      * @param decodeBlanks if <code>true</code> <code>"_x0020_"</code>
-     *                     character sequences will be decoded to single space characters each.
+     *                     character sequences will be decoded to single space
+     *                     characters each.
      * @return the deserialized <code>Value</code>
      * @throws IOException          if an i/o error occured during the
      *                              serialization
@@ -487,6 +488,15 @@
             // 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);
+            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

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=160071&r2=160072
==============================================================================
--- 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 Mon Apr  4 10:55:20 2005
@@ -17,9 +17,7 @@
 package org.apache.jackrabbit.core.xml;
 
 import org.apache.jackrabbit.core.BaseException;
-import org.apache.jackrabbit.core.Constants;
 import org.apache.jackrabbit.core.IllegalNameException;
-import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.UnknownPrefixException;
@@ -27,7 +25,6 @@
 import org.apache.log4j.Logger;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -38,13 +35,10 @@
  * <code>DocViewImportHandler</code> processes Document View XML SAX events
  * and 'translates' them into <code>{@link Importer}</code> method calls.
  */
-class DocViewImportHandler extends DefaultHandler implements Constants {
+class DocViewImportHandler extends TargetImportHandler {
 
     private static Logger log = Logger.getLogger(DocViewImportHandler.class);
 
-    private final Importer importer;
-    private final NamespaceResolver nsContext;
-
     /**
      * stack of NodeInfo instances; an instance is pushed onto the stack
      * in the startElement method and is popped from the stack in the
@@ -52,11 +46,16 @@
      */
     private final Stack stack = new Stack();
     // buffer used to merge adjacent character data
-    private final StringBuffer text = new StringBuffer();
+    private StringBufferValue textHandler = new StringBufferValue();
 
+    /**
+     * Constructs a new <code>DocViewImportHandler</code>.
+     *
+     * @param importer
+     * @param nsContext
+     */
     DocViewImportHandler(Importer importer, NamespaceResolver nsContext) {
-        this.importer = importer;
-        this.nsContext = nsContext;
+        super(importer, nsContext);
     }
 
     /**
@@ -68,30 +67,28 @@
      * @param text
      * @throws SAXException
      */
-    private void onTextNode(String text)
+    private void onTextNode(StringBufferValue text)
             throws SAXException {
-        if (text.trim().length() == 0) {
+        String s = textHandler.retrieve();
+        if (s.trim().length() == 0) {
             // ignore whitespace-only character data
-            log.debug("ignoring withespace character data: " + text);
+            log.debug("ignoring withespace character data: " + s);
             return;
         }
-        if (text.length() > 0) {
-            try {
-                Importer.NodeInfo node =
-                        new Importer.NodeInfo(JCR_XMLTEXT, null, null, null);
-                InternalValue[] values = new InternalValue[1];
-                values[0] = InternalValue.create(text.toString());
-                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);
-            } catch (RepositoryException re) {
-                throw new SAXException(re);
-            }
+        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);
+        } catch (RepositoryException re) {
+            throw new SAXException(re);
         }
     }
 
@@ -113,11 +110,12 @@
     public void startElement(String namespaceURI, String localName,
                              String qName, Attributes atts)
             throws SAXException {
-        if (text.length() > 0) {
+        if (textHandler != null && textHandler.length() > 0) {
             // there is character data that needs to be added to the current node
-            onTextNode(text.toString());
-            // reset buffer
-            text.setLength(0);
+            onTextNode(textHandler);
+            // reset handler
+            textHandler.dispose();
+            textHandler = null;
         }
 
         try {
@@ -162,7 +160,7 @@
 
                 // value(s)
                 String attrValue = atts.getValue(i);
-                InternalValue[] propValues;
+                Importer.TextValue[] propValues;
 /*
                 // @todo should attribute value be interpreted as LIST type (i.e. multi-valued property)?
                 String[] strings = Text.explode(attrValue, ' ', true);
@@ -200,19 +198,19 @@
                         uuid = attrValue;
                     }
                 } else {
-                    propValues = new InternalValue[1];
-                    propValues[0] = InternalValue.create(atts.getValue(i));
+                    propValues = new Importer.TextValue[1];
+                    propValues[0] = new StringValue(atts.getValue(i));
                     props.add(new Importer.PropInfo(propName,
                             PropertyType.UNDEFINED, propValues));
                 }
             }
 
-            Importer.NodeInfo nodeInfo =
+            Importer.NodeInfo node =
                     new Importer.NodeInfo(nodeName, nodeTypeName, mixinTypes, uuid);
             // all information has been collected, now delegate to importer
-            importer.startNode(nodeInfo, props, nsContext);
+            importer.startNode(node, props, nsContext);
             // push current node data onto stack
-            stack.push(nodeInfo);
+            stack.push(node);
         } catch (RepositoryException re) {
             throw new SAXException(re);
         }
@@ -221,23 +219,29 @@
     /**
      * {@inheritDoc}
      */
-    public void characters(char[] ch, int start, int length) throws SAXException {
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
         /**
          * buffer character data; will be processed
          * in endElement and startElement method
          */
-        text.append(ch, start, length);
+        if (textHandler == null) {
+            textHandler = new StringBufferValue();
+        }
+        textHandler.append(ch, start, length);
     }
 
     /**
      * {@inheritDoc}
      */
-    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
-        if (text.length() > 0) {
+    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(text.toString());
-            // reset buffer
-            text.setLength(0);
+            onTextNode(textHandler);
+            // reset handler
+            textHandler.dispose();
+            textHandler = null;
         }
         Importer.NodeInfo node = (Importer.NodeInfo) stack.peek();
         try {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java?view=diff&r1=160071&r2=160072
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/ImportHandler.java Mon Apr  4 10:55:20 2005
@@ -270,6 +270,9 @@
     }
 
     //--------------------------------------------------------< inner classes >
+    /**
+     * <code>NamespaceContext</code> supports scoped namespace declarations.
+     */
     class NamespaceContext implements NamespaceResolver {
 
         private final NamespaceSupport nsContext;
@@ -347,6 +350,5 @@
             }
             return prefix;
         }
-
     }
 }

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=160071&r2=160072
==============================================================================
--- 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 Mon Apr  4 10:55:20 2005
@@ -16,12 +16,13 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.jackrabbit.core.QName;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Workspace;
+import java.io.IOException;
+import java.io.Reader;
 import java.util.List;
 
 /**
@@ -29,10 +30,14 @@
  */
 public interface Importer {
 
-    public static final int IMPORT_UUID_CREATE_NEW = Workspace.IMPORT_UUID_CREATE_NEW;
-    public static final int IMPORT_UUID_COLLISION_REMOVE_EXISTING = Workspace.IMPORT_UUID_COLLISION_REMOVE_EXISTING;
-    public static final int IMPORT_UUID_COLLISION_REPLACE_EXISTING = Workspace.IMPORT_UUID_COLLISION_REPLACE_EXISTING;
-    public static final int IMPORT_UUID_COLLISION_THROW = Workspace.IMPORT_UUID_COLLISION_THROW;
+    public static final int IMPORT_UUID_CREATE_NEW =
+            Workspace.IMPORT_UUID_CREATE_NEW;
+    public static final int IMPORT_UUID_COLLISION_REMOVE_EXISTING =
+            Workspace.IMPORT_UUID_COLLISION_REMOVE_EXISTING;
+    public static final int IMPORT_UUID_COLLISION_REPLACE_EXISTING =
+            Workspace.IMPORT_UUID_COLLISION_REPLACE_EXISTING;
+    public static final int IMPORT_UUID_COLLISION_THROW =
+            Workspace.IMPORT_UUID_COLLISION_THROW;
 
     /**
      * @throws RepositoryException
@@ -113,12 +118,12 @@
     public static class PropInfo {
         private QName name;
         private int type;
-        private InternalValue[] values;
+        private TextValue[] values;
 
         public PropInfo() {
         }
 
-        public PropInfo(QName name, int type, InternalValue[] values) {
+        public PropInfo(QName name, int type, TextValue[] values) {
             this.name = name;
             this.type = type;
             this.values = values;
@@ -140,12 +145,48 @@
             return type;
         }
 
-        public void setValues(InternalValue[] values) {
+        public void setValues(TextValue[] values) {
             this.values = values;
         }
 
-        public InternalValue[] getValues() {
+        public TextValue[] getValues() {
             return values;
         }
+    }
+
+    /**
+     * <code>TextValue</code> represents a serialized property value read
+     * from a System or Document View XML document.
+     */
+    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;
+
+        /**
+         * 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;
+
+        /**
+         * 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;
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java?view=diff&r1=160071&r2=160072
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/SessionImporter.java Mon Apr  4 10:55:20 2005
@@ -38,6 +38,8 @@
 import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeDef;
+import java.io.IOException;
+import java.io.Reader;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Stack;
@@ -225,14 +227,14 @@
         while (iter.hasNext()) {
             PropInfo pi = (PropInfo) iter.next();
             QName propName = pi.getName();
-            InternalValue[] iva = pi.getValues();
+            TextValue[] tva = pi.getValues();
             int type = pi.getType();
 
             // find applicable definition
             EffectiveNodeType ent = node.getEffectiveNodeType();
             PropDef def;
             // multi- or single-valued property?
-            if (iva.length == 1) {
+            if (tva.length == 1) {
                 // could be single- or multi-valued (n == 1)
                 try {
                     // try single-valued
@@ -252,33 +254,66 @@
                 continue;
             }
 
-            // convert InternalValue objects to Value objects using this
-            // session's namespace mappings
-            Value[] va = new Value[iva.length];
-            // check whether type conversion is required
-            if (def.getRequiredType() != PropertyType.UNDEFINED
-                    && def.getRequiredType() != type) {
-                // type doesn't match required type,
-                // type conversion required
-                // FIXME: awkward code
-                for (int i = 0; i < iva.length; i++) {
-                    // convert InternalValue to Value of required type
-                    Value v =
-                            ValueHelper.convert(iva[i].toJCRValue(nsContext),
-                                    def.getRequiredType());
-                    // convert Value to InternalValue using
+            // convert serialized values to Value objects
+            Value[] va = new Value[tva.length];
+            int targetType = def.getRequiredType();
+            if (targetType == PropertyType.UNDEFINED) {
+                if (type == PropertyType.UNDEFINED) {
+                    targetType = PropertyType.STRING;
+                } else {
+                    targetType = type;
+                }
+            }
+            for (int i = 0; i < tva.length; i++) {
+                TextValue tv = tva[i];
+
+                if (targetType == PropertyType.NAME ||
+                        targetType == PropertyType.PATH) {
+                    // NAME and PATH require special treatment because
+                    // they depend on the current namespace context
+                    // of the xml document
+
+                    // retrieve serialized value
+                    String serValue;
+                    try {
+                        serValue = tv.retrieve();
+                    } catch (IOException ioe) {
+                        String msg = "failed to retrieve serialized value";
+                        log.debug(msg, ioe);
+                        throw new RepositoryException(msg, ioe);
+                    }
+
+                    // convert serialized value to InternalValue using
                     // current namespace context of xml document
-                    InternalValue ival = InternalValue.create(v, nsContext);
-                    // convert InternalValue back to Value using this
+                    InternalValue ival =
+                            InternalValue.create(serValue, targetType, nsContext);
+                    // convert InternalValue to Value using this
                     // session's namespace mappings
                     va[i] = ival.toJCRValue(session.getNamespaceResolver());
-                }
-            } else {
-                // no type conversion required:
-                // convert InternalValue to Value using this
-                // session's namespace mappings
-                for (int i = 0; i < iva.length; i++) {
-                    va[i] = iva[i].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);
+                    } catch (IOException ioe) {
+                        String msg = "failed to deserialize binary value";
+                        log.debug(msg, ioe);
+                        throw new RepositoryException(msg, ioe);
+                    }
+                } else {
+                    // all other types
+
+                    // retrieve serialized value
+                    String serValue;
+                    try {
+                        serValue = tv.retrieve();
+                    } catch (IOException ioe) {
+                        String msg = "failed to retrieve serialized value";
+                        log.debug(msg, ioe);
+                        throw new RepositoryException(msg, ioe);
+                    }
+
+                    va[i] = ValueHelper.deserialize(serValue, targetType, true);
                 }
             }
 

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=160071&r2=160072
==============================================================================
--- 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 Mon Apr  4 10:55:20 2005
@@ -17,34 +17,29 @@
 package org.apache.jackrabbit.core.xml;
 
 import org.apache.jackrabbit.core.BaseException;
-import org.apache.jackrabbit.core.Constants;
 import org.apache.jackrabbit.core.IllegalNameException;
-import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.jackrabbit.core.QName;
 import org.apache.jackrabbit.core.UnknownPrefixException;
-import org.apache.jackrabbit.core.util.ValueHelper;
 import org.apache.log4j.Logger;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
 
 import javax.jcr.InvalidSerializedDataException;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.Stack;
 
 /**
  * <code>SysViewImportHandler</code>  ...
  */
-class SysViewImportHandler extends DefaultHandler implements Constants {
+class SysViewImportHandler extends TargetImportHandler {
 
     private static Logger log = Logger.getLogger(SysViewImportHandler.class);
 
-    private final Importer importer;
-    private final NamespaceResolver nsContext;
-
     /**
      * stack of ImportState instances; an instance is pushed onto the stack
      * in the startElement method every time a sv:node element is encountered;
@@ -58,12 +53,18 @@
      */
     private QName currentPropName;
     private int currentPropType = PropertyType.UNDEFINED;
+    // list of AppendableValue objects
     private ArrayList currentPropValues = new ArrayList();
-    private StringBuffer currentPropValue;
+    private AppendableValue currentPropValue;
 
+    /**
+     * Constructs a new <code>SysViewImportHandler</code>.
+     *
+     * @param importer
+     * @param nsContext
+     */
     SysViewImportHandler(Importer importer, NamespaceResolver nsContext) {
-        this.importer = importer;
-        this.nsContext = nsContext;
+        super(importer, nsContext);
     }
 
     private void processNode(ImportState state, boolean start, boolean end)
@@ -83,6 +84,12 @@
         try {
             if (start) {
                 importer.startNode(node, state.props, nsContext);
+                // dispose temporary property values
+                for (Iterator iter = state.props.iterator(); iter.hasNext();) {
+                    Importer.PropInfo pi = (Importer.PropInfo) iter.next();
+                    disposePropertyValues(pi);
+                }
+
             }
             if (end) {
                 importer.endNode(node);
@@ -135,11 +142,7 @@
             // sv:node element
 
             // node name (value of sv:name attribute)
-            String name = atts.getValue(SysViewSAXEventGenerator.NS_SV_URI, SysViewSAXEventGenerator.NAME_ATTRIBUTE);
-            if (name == null) {
-                // try qualified name
-                name = atts.getValue(SysViewSAXEventGenerator.NS_SV_PREFIX + ":" + SysViewSAXEventGenerator.NAME_ATTRIBUTE);
-            }
+            String name = atts.getValue(SysViewSAXEventGenerator.PREFIXED_NAME_ATTRIBUTE);
             if (name == null) {
                 throw new SAXException(new InvalidSerializedDataException("missing mandatory sv:name attributeof element sv:node"));
             }
@@ -171,11 +174,7 @@
             currentPropValues.clear();
 
             // property name (value of sv:name attribute)
-            String name = atts.getValue(SysViewSAXEventGenerator.NS_SV_URI, SysViewSAXEventGenerator.NAME_ATTRIBUTE);
-            if (name == null) {
-                // try qualified name
-                name = atts.getValue(SysViewSAXEventGenerator.NS_SV_PREFIX + ":" + SysViewSAXEventGenerator.NAME_ATTRIBUTE);
-            }
+            String name = atts.getValue(SysViewSAXEventGenerator.PREFIXED_NAME_ATTRIBUTE);
             if (name == null) {
                 throw new SAXException(new InvalidSerializedDataException("missing mandatory sv:name attributeof element sv:property"));
             }
@@ -187,11 +186,7 @@
                 throw new SAXException(new InvalidSerializedDataException("illegal property name: " + name, upe));
             }
             // property type (sv:type attribute)
-            String type = atts.getValue(SysViewSAXEventGenerator.NS_SV_URI, SysViewSAXEventGenerator.TYPE_ATTRIBUTE);
-            if (type == null) {
-                // try qualified name
-                type = atts.getValue(SysViewSAXEventGenerator.NS_SV_PREFIX + ":" + SysViewSAXEventGenerator.TYPE_ATTRIBUTE);
-            }
+            String type = atts.getValue(SysViewSAXEventGenerator.PREFIXED_TYPE_ATTRIBUTE);
             if (type == null) {
                 throw new SAXException(new InvalidSerializedDataException("missing mandatory sv:type attributeof element sv:property"));
             }
@@ -200,7 +195,18 @@
             // sv:value element
 
             // reset temp fields
-            currentPropValue = new StringBuffer();
+            if (currentPropType == PropertyType.BINARY) {
+                // binary value; use temp-file backed value appender
+                try {
+                    currentPropValue = new CLOBValue();
+                } catch (IOException ioe) {
+                    throw new SAXException("error while processing property value",
+                            ioe);
+                }
+            } else {
+                // 'normal' value; use StringBuffer-backed value appender
+                currentPropValue = new StringBufferValue();
+            }
         } else {
             throw new SAXException(new InvalidSerializedDataException("unexpected element found in system view xml document: " + elemName));
         }
@@ -209,103 +215,112 @@
     /**
      * {@inheritDoc}
      */
-    public void characters(char[] ch, int start, int length) throws SAXException {
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
         if (currentPropValue != null) {
             // property value (character data of sv:value element)
-            currentPropValue.append(ch, start, length);
+            try {
+                currentPropValue.append(ch, start, length);
+            } catch (IOException ioe) {
+                throw new SAXException("error while processing property value",
+                        ioe);
+            }
         }
     }
 
     /**
      * {@inheritDoc}
      */
-    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
-        try {
-            String elemName;
-            if (localName != null && !"".equals(localName)) {
-                elemName = localName;
+    public void endElement(String namespaceURI, String localName, String qName)
+            throws SAXException {
+        String elemName;
+        if (localName != null && !"".equals(localName)) {
+            elemName = localName;
+        } else {
+            try {
+                elemName = QName.fromJCRName(qName, nsContext).getLocalName();
+            } catch (BaseException e) {
+                // should never happen...
+                String msg = "internal error: failed to parse/resolve element name " + qName;
+                log.debug(msg);
+                throw new SAXException(msg, e);
+            }
+        }
+        // check element name
+        ImportState state = (ImportState) stack.peek();
+        if (SysViewSAXEventGenerator.NODE_ELEMENT.equals(elemName)) {
+            // sv:node element
+            if (!state.started) {
+                // need to start & end current node
+                processNode(state, true, true);
+                state.started = true;
             } else {
+                // need to end current node
+                processNode(state, false, true);
+            }
+            // pop current state from stack
+            stack.pop();
+        } else if (SysViewSAXEventGenerator.PROPERTY_ELEMENT.equals(elemName)) {
+            // sv:property element
+
+            // check if all system properties (jcr:primaryType, jcr:uuid etc.)
+            // have been collected and create node as necessary
+            if (currentPropName.equals(JCR_PRIMARYTYPE)) {
+                AppendableValue val = (AppendableValue) currentPropValues.get(0);
+                String s = null;
                 try {
-                    elemName = QName.fromJCRName(qName, nsContext).getLocalName();
-                } catch (BaseException e) {
-                    // should never happen...
-                    String msg = "internal error: failed to parse/resolve element name " + qName;
-                    log.debug(msg);
-                    throw new SAXException(msg, e);
+                    s = val.retrieve();
+                    state.nodeTypeName = QName.fromJCRName(s, nsContext);
+                } catch (IOException ioe) {
+                    throw new SAXException("error while retrieving value", ioe);
+                } catch (IllegalNameException ine) {
+                    throw new SAXException(new InvalidSerializedDataException("illegal node type name: " + s, ine));
+                } catch (UnknownPrefixException upe) {
+                    throw new SAXException(new InvalidSerializedDataException("illegal node type name: " + s, upe));
                 }
-            }
-            // check element name
-            ImportState state = (ImportState) stack.peek();
-            if (SysViewSAXEventGenerator.NODE_ELEMENT.equals(elemName)) {
-                // sv:node element
-                if (!state.started) {
-                    // need to start & end current node
-                    processNode(state, true, true);
-                    state.started = true;
-                } else {
-                    // need to end current node
-                    processNode(state, false, true);
+            } else if (currentPropName.equals(JCR_MIXINTYPES)) {
+                if (state.mixinNames == null) {
+                    state.mixinNames = new ArrayList(currentPropValues.size());
                 }
-                // pop current state from stack
-                stack.pop();
-            } else if (SysViewSAXEventGenerator.PROPERTY_ELEMENT.equals(elemName)) {
-                // sv:property element
-
-                // check if all system properties (jcr:primaryType, jcr:uuid etc.)
-                // have been collected and create node as necessary
-                if (currentPropName.equals(JCR_PRIMARYTYPE)) {
+                for (int i = 0; i < currentPropValues.size(); i++) {
+                    AppendableValue val = (AppendableValue) currentPropValues.get(0);
+                    String s = null;
                     try {
-                        state.nodeTypeName = QName.fromJCRName((String) currentPropValues.get(0), nsContext);
+                        s = val.retrieve();
+                        QName mixin = QName.fromJCRName(s, nsContext);
+                        state.mixinNames.add(mixin);
+                    } catch (IOException ioe) {
+                        throw new SAXException("error while retrieving value", ioe);
                     } catch (IllegalNameException ine) {
-                        throw new SAXException(new InvalidSerializedDataException("illegal node type name: " + currentPropValues.get(0), ine));
+                        throw new SAXException(new InvalidSerializedDataException("illegal mixin type name: " + s, ine));
                     } catch (UnknownPrefixException upe) {
-                        throw new SAXException(new InvalidSerializedDataException("illegal node type name: " + currentPropValues.get(0), upe));
-                    }
-                } else if (currentPropName.equals(JCR_MIXINTYPES)) {
-                    if (state.mixinNames == null) {
-                        state.mixinNames = new ArrayList(currentPropValues.size());
-                    }
-                    for (int i = 0; i < currentPropValues.size(); i++) {
-                        try {
-                            QName mixin = QName.fromJCRName((String) currentPropValues.get(i), nsContext);
-                            state.mixinNames.add(mixin);
-                        } catch (IllegalNameException ine) {
-                            throw new SAXException(new InvalidSerializedDataException("illegal mixin type name: " + currentPropValues.get(i), ine));
-                        } catch (UnknownPrefixException upe) {
-                            throw new SAXException(new InvalidSerializedDataException("illegal mixin type name: " + currentPropValues.get(i), upe));
-                        }
+                        throw new SAXException(new InvalidSerializedDataException("illegal mixin type name: " + s, upe));
                     }
-                } else if (currentPropName.equals(JCR_UUID)) {
-                    state.uuid = (String) currentPropValues.get(0);
-                } else {
-                    // convert values to native type
-                    InternalValue[] vals = new InternalValue[currentPropValues.size()];
-                    for (int i = 0; i < currentPropValues.size(); i++) {
-                        String value = (String) currentPropValues.get(i);
-                        vals[i] = InternalValue.create(
-                                ValueHelper.deserialize(value, currentPropType,
-                                        false), nsContext);
-                    }
-                    Importer.PropInfo prop = new Importer.PropInfo();
-                    prop.setName(currentPropName);
-                    prop.setType(currentPropType);
-                    prop.setValues(vals);
-
-                    state.props.add(prop);
                 }
-
-                // reset temp fields
-                currentPropValues.clear();
-            } else if (SysViewSAXEventGenerator.VALUE_ELEMENT.equals(elemName)) {
-                // sv:value element
-                currentPropValues.add(currentPropValue.toString());
-                // reset temp fields
-                currentPropValue = null;
+            } else if (currentPropName.equals(JCR_UUID)) {
+                AppendableValue val = (AppendableValue) currentPropValues.get(0);
+                try {
+                    state.uuid = val.retrieve();
+                } catch (IOException ioe) {
+                    throw new SAXException("error while retrieving value", ioe);
+                }
             } else {
-                throw new SAXException(new InvalidSerializedDataException("invalid element in system view xml document: " + elemName));
+                Importer.PropInfo prop = new Importer.PropInfo();
+                prop.setName(currentPropName);
+                prop.setType(currentPropType);
+                prop.setValues((Importer.TextValue[])
+                        currentPropValues.toArray(new Importer.TextValue[currentPropValues.size()]));
+                state.props.add(prop);
             }
-        } catch (RepositoryException re) {
-            throw new SAXException(re);
+            // reset temp fields
+            currentPropValues.clear();
+        } else if (SysViewSAXEventGenerator.VALUE_ELEMENT.equals(elemName)) {
+            // sv:value element
+            currentPropValues.add(currentPropValue);
+            // reset temp fields
+            currentPropValue = null;
+        } else {
+            throw new SAXException(new InvalidSerializedDataException("invalid element in system view xml document: " + elemName));
         }
     }
 

Added: 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=auto&rev=160072
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java Mon Apr  4 10:55:20 2005
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.xml;
+
+import org.apache.jackrabbit.core.Constants;
+import org.apache.jackrabbit.core.NamespaceResolver;
+import org.apache.log4j.Logger;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+
+/**
+ * <code>TargetImportHandler</code> serves as the base class for the concrete
+ * classes <code>{@link DocViewImportHandler}</code> and
+ * <code>{@link SysViewImportHandler}</code>.
+ */
+abstract class TargetImportHandler extends DefaultHandler implements Constants {
+
+    private static Logger log = Logger.getLogger(TargetImportHandler.class);
+
+    protected final Importer importer;
+    protected final NamespaceResolver nsContext;
+
+    protected TargetImportHandler(Importer importer,
+                                  NamespaceResolver nsContext) {
+        this.importer = importer;
+        this.nsContext = nsContext;
+    }
+
+    protected void disposePropertyValues(Importer.PropInfo prop) {
+        Importer.TextValue[] vals = prop.getValues();
+        for (int i = 0; i < vals.length; i++) {
+            if (vals[i] instanceof AppendableValue) {
+                try {
+                    ((AppendableValue) vals[i]).dispose();
+                } catch (IOException ioe) {
+                    log.warn("error while disposing temporary value appender",
+                            ioe);
+                }
+            }
+        }
+    }
+
+    //--------------------------------------------------------< inner classes >
+    /**
+     * <code>AppendableValue</code> represents a serialized value that is
+     * appendable.
+     */
+    public interface AppendableValue extends Importer.TextValue {
+        public void append(char[] chars, int start, int length)
+                throws IllegalStateException, IOException;
+
+        /**
+         * @throws IOException
+         */
+        public void close() throws IOException;
+
+        /**
+         * @throws IOException
+         */
+        public void dispose() throws IOException;
+    }
+
+    /**
+     * <code>StringValue</code> represents an immutable serialized value.
+     */
+    protected class StringValue implements Importer.TextValue {
+
+        private final String value;
+
+        /**
+         * Constructs a new <code>StringValue</code> representing the given
+         * value.
+         *
+         * @param value
+         */
+        protected StringValue(String value) {
+            this.value = value;
+        }
+
+        //--------------------------------------------------------< TextValue >
+        /**
+         * {@inheritDoc}
+         */
+        public long length() {
+            return value.length();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String retrieve() {
+            return value;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Reader reader() {
+            return new StringReader(value);
+        }
+    }
+
+    /**
+     * <code>StringBufferValue</code> represents an appendable serialized value
+     * that is internally backed by a <code>StringBuffer</code>.
+     */
+    protected class StringBufferValue implements AppendableValue {
+
+        private final StringBuffer buffer;
+
+        /**
+         * Constructs a new empty <code>StringBufferValue</code>.
+         */
+        protected StringBufferValue() {
+            buffer = new StringBuffer();
+        }
+
+        //--------------------------------------------------------< TextValue >
+        /**
+         * {@inheritDoc}
+         */
+        public long length() {
+            return buffer.length();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String retrieve() {
+            return buffer.toString();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Reader reader() {
+            return new StringReader(buffer.toString());
+        }
+
+        //--------------------------------------------------< AppendableValue >
+        /**
+         * {@inheritDoc}
+         */
+        public void append(char[] chars, int start, int length) {
+            buffer.append(chars, start, length);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void close() {
+            // nop
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        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);
+        }
+
+        //--------------------------------------------------------< TextValue >
+        /**
+         * {@inheritDoc}
+         */
+        public long length() throws IllegalStateException, IOException {
+            if (tmpFile == null) {
+                throw new IllegalStateException();
+            }
+            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);
+            }
+            return buf.toString();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Reader reader() throws IllegalStateException, IOException {
+            if (tmpFile == null) {
+                throw new IllegalStateException();
+            }
+            return new FileReader(tmpFile);
+        }
+
+        //--------------------------------------------------< AppendableValue >
+        /**
+         * {@inheritDoc}
+         */
+        public void append(char[] chars, int start, int length)
+                throws IllegalStateException, IOException {
+            if (writer == null) {
+                throw new IllegalStateException();
+            }
+            writer.write(chars, start, length);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void close() throws IOException {
+            if (writer != null) {
+                writer.close();
+                writer = null;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void dispose() throws IOException {
+            close();
+            if (tmpFile != null) {
+                tmpFile.delete();
+                tmpFile = null;
+            }
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?view=diff&r1=160071&r2=160072
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Mon Apr  4 10:55:20 2005
@@ -40,16 +40,18 @@
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.state.UpdatableItemStateManager;
+import org.apache.jackrabbit.core.util.Base64;
 import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
-import org.apache.jackrabbit.core.util.ValueHelper;
 import org.apache.jackrabbit.core.util.uuid.UUID;
 import org.apache.log4j.Logger;
 
 import javax.jcr.ItemExistsException;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
-import javax.jcr.Value;
 import javax.jcr.nodetype.ConstraintViolationException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -178,7 +180,7 @@
                 String msg = "an applicable node type could not be determined for "
                         + nodeName;
                 log.debug(msg);
-                throw new ConstraintViolationException (msg);
+                throw new ConstraintViolationException(msg);
             }
         }
         NodeState node = stateMgr.createNew(uuid, nodeTypeName, parent.getUUID());
@@ -709,7 +711,7 @@
             while (iter.hasNext()) {
                 PropInfo pi = (PropInfo) iter.next();
                 QName propName = pi.getName();
-                InternalValue[] vals = pi.getValues();
+                TextValue[] tva = pi.getValues();
                 int type = pi.getType();
 
                 PropertyState prop = null;
@@ -742,7 +744,7 @@
                     // find applicable definition
 
                     // multi- or single-valued property?
-                    if (vals.length == 1) {
+                    if (tva.length == 1) {
                         // could be single- or multi-valued (n == 1)
                         try {
                             // try single-valued
@@ -770,29 +772,80 @@
                 }
 
                 // check multi-valued characteristic
-                if ((vals.length == 0 || vals.length > 1) && !def.isMultiple()) {
+                if ((tva.length == 0 || tva.length > 1) && !def.isMultiple()) {
                     throw new ConstraintViolationException(resolveJCRPath(prop.getId())
                             + " is not multi-valued");
                 }
 
-                // check whether type conversion is required
-                if (def.getRequiredType() != PropertyType.UNDEFINED
-                        && def.getRequiredType() != type) {
-                    // type doesn't match required type,
-                    // type conversion required
-                    for (int i = 0; i < vals.length; i++) {
-                        // convert InternalValue to Value of required type
-                        Value v =
-                                ValueHelper.convert(vals[i].toJCRValue(nsContext),
-                                        def.getRequiredType());
-                        // convert Value to InternalValue using
+                // convert serialized values to InternalValue objects
+                InternalValue[] iva = new InternalValue[tva.length];
+                int targetType = def.getRequiredType();
+                if (targetType == PropertyType.UNDEFINED) {
+                    if (type == PropertyType.UNDEFINED) {
+                        targetType = PropertyType.STRING;
+                    } else {
+                        targetType = type;
+                    }
+                }
+                for (int i = 0; i < tva.length; i++) {
+                    TextValue tv = tva[i];
+                    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();
+                            }
+                        }
+*/
+                        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);
+                            throw new RepositoryException(msg, ioe);
+                        }
+                    } else {
+                        // retrieve serialized value
+                        String serValue;
+                        try {
+                            serValue = tv.retrieve();
+                        } catch (IOException ioe) {
+                            String msg = "failed to retrieve serialized value";
+                            log.debug(msg, ioe);
+                            throw new RepositoryException(msg, ioe);
+                        }
+
+                        // convert serialized value to InternalValue using
                         // current namespace context of xml document
-                        vals[i] = InternalValue.create(v, nsContext);
+                        iva[i] = InternalValue.create(serValue, targetType,
+                                nsContext);
                     }
+
                 }
 
                 // set values
-                prop.setValues(vals);
+                prop.setValues(iva);
 
                 // make sure node is valid according to its definition
                 wsp.validate(prop);