jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r387961 - /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/
Date Wed, 22 Mar 2006 22:52:43 GMT
Author: jukka
Date: Wed Mar 22 14:52:40 2006
New Revision: 387961

URL: http://svn.apache.org/viewcvs?rev=387961&view=rev
Log:
JCR-325: Applied the xml-refactoring.patch that puts the PropInfo instances in charge of applying the imported property values to content nodes.

Added:
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NodeInfo.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/Importer.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java?rev=387961&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java Wed Mar 22 14:52:40 2006
@@ -0,0 +1,327 @@
+/*
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.util.Base64;
+import org.apache.jackrabbit.util.TransientFileFactory;
+import org.apache.jackrabbit.value.ValueHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <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
+ * <code>BufferedStringValue</code> instance is not used anymore.
+ */
+class BufferedStringValue implements TextValue {
+
+    private static Logger log = LoggerFactory.getLogger(BufferedStringValue.class);
+
+    /**
+     * max size for buffering data in memory
+     */
+    private static final int MAX_BUFFER_SIZE = 0x10000;
+    /**
+     * size of increment if capacity buffer needs to be enlarged
+     */
+    private static final int BUFFER_INCREMENT = 0x2000;
+    /**
+     * in-memory buffer
+     */
+    private char[] buffer;
+    /**
+     * current position within buffer (size of actual data in buffer)
+     */
+    private int bufferPos;
+
+    /**
+     * backing temporary file created when size of data exceeds
+     * MAX_BUFFER_SIZE
+     */
+    private File tmpFile;
+    /**
+     * writer used to write to tmpFile; writer & tmpFile are always
+     * instantiated together, i.e. they are either both null or both not null.
+     */
+    private Writer writer;
+
+    private final NamespaceResolver nsContext;
+
+    /**
+     * Constructs a new empty <code>BufferedStringValue</code>.
+     */
+    protected BufferedStringValue(NamespaceResolver nsContext) {
+        buffer = new char[0x2000];
+        bufferPos = 0;
+        tmpFile = null;
+        writer = null;
+        this.nsContext = nsContext;
+    }
+
+    /**
+     * Returns the length of the serialized value.
+     *
+     * @return the length of the serialized value
+     * @throws IOException if an I/O error occurs
+     */
+    public long length() throws IOException {
+        if (buffer != null) {
+            return bufferPos;
+        } else if (tmpFile != null) {
+            // flush writer first
+            writer.flush();
+            return tmpFile.length();
+        } else {
+            throw new IOException("this instance has already been disposed");
+        }
+    }
+
+    /**
+     * Retrieves the serialized value.
+     *
+     * @return the serialized value
+     * @throws IOException if an I/O error occurs
+     */
+    public String retrieve() throws IOException {
+        if (buffer != null) {
+            return new String(buffer, 0, bufferPos);
+        } else if (tmpFile != null) {
+            // flush writer first
+            writer.flush();
+            if (tmpFile.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");
+        }
+    }
+
+    /**
+     * Returns a <code>Reader</code> for reading the serialized value.
+     *
+     * @return a <code>Reader</code> for reading the serialized value.
+     * @throws IOException if an I/O error occurs
+     */
+    public Reader reader() throws IOException {
+        if (buffer != null) {
+            return new StringReader(new String(buffer, 0, bufferPos));
+        } else if (tmpFile != null) {
+            // flush writer first
+            writer.flush();
+            return new FileReader(tmpFile);
+        } else {
+            throw new IOException("this instance has already been disposed");
+        }
+    }
+
+    /**
+     * 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 IOException {
+        if (buffer != null) {
+            if (bufferPos + length > MAX_BUFFER_SIZE) {
+                // threshold for keeping data in memory exceeded;
+                // create temp file and spool buffer contents
+                TransientFileFactory fileFactory = TransientFileFactory.getInstance();
+                tmpFile = fileFactory.createTransientFile("txt", null, null);
+                final FileOutputStream fout = new FileOutputStream(tmpFile);
+                writer = new OutputStreamWriter(fout) {
+                    public void flush() throws IOException {
+                        // flush this writer
+                        super.flush();
+                        // force synchronization with underlying file
+                        fout.getFD().sync();
+                    }
+                };
+                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");
+        }
+    }
+
+    /**
+     * 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 {
+        if (buffer != null) {
+            // nop
+        } else if (tmpFile != null) {
+            writer.close();
+        } else {
+            throw new IOException("this instance has already been disposed");
+        }
+    }
+
+    //--------------------------------------------------------< TextValue >
+
+    public Value getValue(int targetType, NamespaceResolver resolver)
+            throws ValueFormatException, RepositoryException {
+        try {
+            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
+                
+                // convert serialized value to InternalValue using
+                // current namespace context of xml document
+                InternalValue ival =
+                    InternalValue.create(retrieve(), targetType, nsContext);
+                // convert InternalValue to Value using this
+                // session's namespace mappings
+                return ival.toJCRValue(resolver);
+            } else if (targetType == PropertyType.BINARY) {
+                if (length() < 0x10000) {
+                    // < 65kb: deserialize BINARY type using String
+                    return ValueHelper.deserialize(retrieve(), targetType, false);
+                } else {
+                    // >= 65kb: deserialize BINARY type using Reader
+                    Reader reader = reader();
+                    try {
+                        return ValueHelper.deserialize(reader, targetType, false);
+                    } finally {
+                        reader.close();
+                    }
+                }
+            } else {
+                // all other types
+                return ValueHelper.deserialize(retrieve(), targetType, true);
+            }
+        } catch (IOException e) {
+            String msg = "failed to retrieve serialized value";
+            log.debug(msg, e);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    public InternalValue getInternalValue(int type)
+            throws ValueFormatException, RepositoryException {
+        try {
+            if (type == PropertyType.BINARY) {
+                // base64 encoded BINARY type;
+                // decode using Reader
+                if (length() < 0x10000) {
+                    // < 65kb: deserialize BINARY type in memory
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    Base64.decode(retrieve(), baos);
+                    // no need to close ByteArrayOutputStream
+                    //baos.close();
+                    return 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 = reader();
+                    try {
+                        Base64.decode(reader, out);
+                    } finally {
+                        reader.close();
+                        out.close();
+                    }
+                    return InternalValue.create(tmpFile);
+                }
+            } else {
+                // convert serialized value to InternalValue using
+                // current namespace context of xml document
+                return InternalValue.create(retrieve(), type, nsContext);
+            }
+        } catch (IOException e) {
+            throw new RepositoryException("Error accessing property value", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void dispose() {
+        if (buffer != null) {
+            buffer = null;
+            bufferPos = 0;
+        } else if (tmpFile != null) {
+            try {
+                writer.close();
+                tmpFile.delete();
+                tmpFile = null;
+                writer = null;
+            } catch (IOException e) {
+                log.warn("Problem disposing property value", e);
+            }
+        } else {
+            log.warn("this instance has already been disposed");
+        }
+    }
+}
\ No newline at end of file

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

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java Wed Mar 22 14:52:40 2006
@@ -27,6 +27,8 @@
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
 import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;
@@ -47,7 +49,7 @@
      */
     private final Stack stack = new Stack();
     // buffer used to merge adjacent character data
-    private BufferedStringValue textHandler = new BufferedStringValue();
+    private BufferedStringValue textHandler = null;
 
     /**
      * Constructs a new <code>DocViewImportHandler</code>.
@@ -73,7 +75,7 @@
     private void appendCharacters(char[] ch, int start, int length)
             throws SAXException {
         if (textHandler == null) {
-            textHandler = new BufferedStringValue();
+            textHandler = new BufferedStringValue(nsContext);
         }
         try {
             textHandler.append(ch, start, length);
@@ -122,17 +124,16 @@
                     reader.close();
                 }
 
-                Importer.NodeInfo node =
-                        new Importer.NodeInfo(QName.JCR_XMLTEXT, null, null, null);
-                Importer.TextValue[] values =
-                        new Importer.TextValue[]{textHandler};
+                NodeInfo node =
+                        new NodeInfo(QName.JCR_XMLTEXT, null, null, null);
+                TextValue[] values =
+                        new TextValue[]{textHandler};
                 ArrayList props = new ArrayList();
-                Importer.PropInfo prop =
-                        new Importer.PropInfo(QName.JCR_XMLCHARACTERS,
-                                PropertyType.STRING, values);
+                PropInfo prop = new PropInfo(
+                        QName.JCR_XMLCHARACTERS, PropertyType.STRING, values);
                 props.add(prop);
                 // call Importer
-                importer.startNode(node, props, nsContext);
+                importer.startNode(node, props);
                 importer.endNode(node);
 
                 // reset handler
@@ -180,15 +181,15 @@
 
                 // value(s)
                 String attrValue = atts.getValue(i);
-                Importer.TextValue[] propValues;
+                TextValue[] propValues;
 
                 // always assume single-valued property for the time being
                 // until a way of properly serializing/detecting multi-valued
                 // properties on re-import is found (see JCR-325);
                 // see also DocViewSAXEventGenerator#leavingProperties(Node, int)
                 // todo proper multi-value serialization support
-                propValues = new Importer.TextValue[1];
-                propValues[0] = new StringValue(attrValue);
+                propValues = new TextValue[1];
+                propValues[0] = new StringValue(attrValue, nsContext);
 
                 if (propName.equals(QName.JCR_PRIMARYTYPE)) {
                     // jcr:primaryType
@@ -205,12 +206,14 @@
                     if (propValues.length > 0) {
                         mixinTypes = new QName[propValues.length];
                         for (int j = 0; j < propValues.length; j++) {
-                            String val = ((StringValue) propValues[j]).retrieve();
+                            Value value = 
+                                propValues[j].getValue(PropertyType.NAME, nsContext);
                             try {
-                                mixinTypes[j] = QName.fromJCRName(val, nsContext);
+                                mixinTypes[j] =
+                                    QName.fromJCRName(value.getString(), nsContext);
                             } catch (NameException ne) {
                                 throw new SAXException("illegal jcr:mixinTypes value: "
-                                        + val, ne);
+                                        + value.getString(), ne);
                             }
                         }
                     }
@@ -220,15 +223,15 @@
                         id = NodeId.valueOf(attrValue);
                     }
                 } else {
-                    props.add(new Importer.PropInfo(propName,
-                            PropertyType.UNDEFINED, propValues));
+                    props.add(new PropInfo(
+                            propName, PropertyType.UNDEFINED, propValues));
                 }
             }
 
-            Importer.NodeInfo node =
-                    new Importer.NodeInfo(nodeName, nodeTypeName, mixinTypes, id);
+            NodeInfo node =
+                    new NodeInfo(nodeName, nodeTypeName, mixinTypes, id);
             // all information has been collected, now delegate to importer
-            importer.startNode(node, props, nsContext);
+            importer.startNode(node, props);
             // push current node data onto stack
             stack.push(node);
         } catch (RepositoryException re) {
@@ -268,7 +271,7 @@
         // process buffered character data
         processCharacters();
 
-        Importer.NodeInfo node = (Importer.NodeInfo) stack.peek();
+        NodeInfo node = (NodeInfo) stack.peek();
         try {
             // call Importer
             importer.endNode(node);

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/Importer.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/Importer.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/Importer.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/Importer.java Wed Mar 22 14:52:40 2006
@@ -17,12 +17,8 @@
 package org.apache.jackrabbit.core.xml;
 
 import org.apache.jackrabbit.name.NamespaceResolver;
-import org.apache.jackrabbit.name.QName;
-import org.apache.jackrabbit.core.NodeId;
 
 import javax.jcr.RepositoryException;
-import java.io.IOException;
-import java.io.Reader;
 import java.util.List;
 
 /**
@@ -38,10 +34,9 @@
     /**
      * @param nodeInfo
      * @param propInfos list of <code>PropInfo</code> instances
-     * @param nsContext prefix mappings of current context
      * @throws RepositoryException
      */
-    void startNode(NodeInfo nodeInfo, List propInfos, NamespaceResolver nsContext)
+    void startNode(NodeInfo nodeInfo, List propInfos)
             throws RepositoryException;
 
     /**
@@ -55,123 +50,4 @@
      */
     void end() throws RepositoryException;
 
-    //--------------------------------------------------------< inner classes >
-    static class NodeInfo {
-        private QName name;
-        private QName nodeTypeName;
-        private QName[] mixinNames;
-        private NodeId id;
-
-        public NodeInfo() {
-        }
-
-        public NodeInfo(QName name, QName nodeTypeName, QName[] mixinNames,
-                        NodeId id) {
-            this.name = name;
-            this.nodeTypeName = nodeTypeName;
-            this.mixinNames = mixinNames;
-            this.id = id;
-        }
-
-        public void setName(QName name) {
-            this.name = name;
-        }
-
-        public QName getName() {
-            return name;
-        }
-
-        public void setNodeTypeName(QName nodeTypeName) {
-            this.nodeTypeName = nodeTypeName;
-        }
-
-        public QName getNodeTypeName() {
-            return nodeTypeName;
-        }
-
-        public void setMixinNames(QName[] mixinNames) {
-            this.mixinNames = mixinNames;
-        }
-
-        public QName[] getMixinNames() {
-            return mixinNames;
-        }
-
-        public void setId(NodeId id) {
-            this.id = id;
-        }
-
-        public NodeId getId() {
-            return id;
-        }
-    }
-
-    static class PropInfo {
-        private QName name;
-        private int type;
-        private TextValue[] values;
-
-        public PropInfo() {
-        }
-
-        public PropInfo(QName name, int type, TextValue[] values) {
-            this.name = name;
-            this.type = type;
-            this.values = values;
-        }
-
-        public void setName(QName name) {
-            this.name = name;
-        }
-
-        public QName getName() {
-            return name;
-        }
-
-        public void setType(int type) {
-            this.type = type;
-        }
-
-        public int getType() {
-            return type;
-        }
-
-        public void setValues(TextValue[] values) {
-            this.values = values;
-        }
-
-        public TextValue[] getValues() {
-            return values;
-        }
-    }
-
-    /**
-     * <code>TextValue</code> represents a serialized property value read
-     * from a System or Document View XML document.
-     */
-    interface TextValue {
-        /**
-         * Returns the length of the serialized value.
-         *
-         * @return the length of the serialized value
-         * @throws IOException if an I/O error occurs
-         */
-        long length() throws IOException;
-
-        /**
-         * Retrieves the serialized value.
-         *
-         * @return the serialized value
-         * @throws IOException if an I/O error occurs
-         */
-        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 IOException if an I/O error occurs
-         */
-        Reader reader() throws IOException;
-    }
 }

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NodeInfo.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NodeInfo.java?rev=387961&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NodeInfo.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NodeInfo.java Wed Mar 22 14:52:40 2006
@@ -0,0 +1,56 @@
+/*
+ * 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.NodeId;
+import org.apache.jackrabbit.name.QName;
+
+public class NodeInfo {
+
+    private final QName name;
+
+    private final QName nodeTypeName;
+
+    private final QName[] mixinNames;
+
+    private final NodeId id;
+
+    public NodeInfo(QName name, QName nodeTypeName, QName[] mixinNames,
+                    NodeId id) {
+        this.name = name;
+        this.nodeTypeName = nodeTypeName;
+        this.mixinNames = mixinNames;
+        this.id = id;
+    }
+
+    public QName getName() {
+        return name;
+    }
+
+    public QName getNodeTypeName() {
+        return nodeTypeName;
+    }
+
+    public QName[] getMixinNames() {
+        return mixinNames;
+    }
+
+    public NodeId getId() {
+        return id;
+    }
+
+}

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

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java?rev=387961&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java Wed Mar 22 14:52:40 2006
@@ -0,0 +1,192 @@
+/*
+ * 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 javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.core.BatchedItemOperations;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.jackrabbit.core.state.NodeState;
+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.name.NamespaceResolver;
+import org.apache.jackrabbit.name.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PropInfo {
+
+    private static Logger log = LoggerFactory.getLogger(PropInfo.class);
+
+    private final QName name;
+
+    private final int type;
+
+    private final TextValue[] values;
+
+    public PropInfo(QName name, int type, TextValue[] values) {
+        this.name = name;
+        this.type = type;
+        this.values = values;
+    }
+
+    /**
+     * Disposes all values contained in this property.
+     */
+    public void dispose() {
+        for (int i = 0; i < values.length; i++) {
+            values[i].dispose();
+        }
+    }
+
+    private int getTargetType(PropDef def) {
+        int target = def.getRequiredType();
+        if (target != PropertyType.UNDEFINED) {
+            return target;
+        } else if (type != PropertyType.UNDEFINED) {
+            return type;
+        } else {
+            return PropertyType.STRING;
+        }
+    }
+
+    private PropDef getApplicablePropertyDef(EffectiveNodeType ent)
+            throws ConstraintViolationException {
+        if (values.length == 1) {
+            // could be single- or multi-valued (n == 1)
+            return ent.getApplicablePropertyDef(name, type);
+        } else {
+            // can only be multi-valued (n == 0 || n > 1)
+            return ent.getApplicablePropertyDef(name, type, true);
+        }
+    }
+
+    public void apply(NodeImpl node, NamespaceResolver resolver, ReferenceChangeTracker refTracker) throws RepositoryException, ConstraintViolationException, ValueFormatException, VersionException, LockException, ItemNotFoundException {
+        // find applicable definition
+        PropDef def = getApplicablePropertyDef(node.getEffectiveNodeType());
+        if (def.isProtected()) {
+            // skip protected property
+            log.debug("skipping protected property " + name);
+            return;
+        }
+        
+        // convert serialized values to Value objects
+        Value[] va = new Value[values.length];
+        int targetType = getTargetType(def);
+        for (int i = 0; i < values.length; i++) {
+            va[i] = values[i].getValue(targetType, resolver);
+        }
+        
+        // multi- or single-valued property?
+        if (va.length == 1) {
+            // could be single- or multi-valued (n == 1)
+            try {
+                // try setting single-value
+                node.setProperty(name, va[0]);
+            } catch (ValueFormatException vfe) {
+                // try setting value array
+                node.setProperty(name, va, type);
+            } catch (ConstraintViolationException cve) {
+                // try setting value array
+                node.setProperty(name, va, type);
+            }
+        } else {
+            // can only be multi-valued (n == 0 || n > 1)
+            node.setProperty(name, va, type);
+        }
+        if (type == PropertyType.REFERENCE) {
+            // store reference for later resolution
+            refTracker.processedReference(node.getProperty(name));
+        }
+    }
+
+    public void apply(NodeState node, BatchedItemOperations itemOps, NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker) throws ItemNotFoundException, RepositoryException, ItemExistsException, ConstraintViolationException, ValueFormatException {
+        PropertyState prop = null;
+        PropDef def = null;
+
+        if (node.hasPropertyName(name)) {
+            // a property with that name already exists...
+            PropertyId idExisting = new PropertyId(node.getNodeId(), name);
+            prop = (PropertyState) itemOps.getItemState(idExisting);
+            def = ntReg.getPropDef(prop.getDefinitionId());
+            if (def.isProtected()) {
+                // skip protected property
+                log.debug("skipping protected property "
+                        + itemOps.safeGetJCRPath(idExisting));
+                return;
+            }
+            if (!def.isAutoCreated()
+                    || (prop.getType() != type && type != PropertyType.UNDEFINED)
+                    || def.isMultiple() != prop.isMultiValued()) {
+                throw new ItemExistsException(itemOps.safeGetJCRPath(prop.getPropertyId()));
+            }
+        } else {
+            // there's no property with that name,
+            // find applicable definition
+            def = getApplicablePropertyDef(itemOps.getEffectiveNodeType(node));
+            if (def.isProtected()) {
+                // skip protected property
+                log.debug("skipping protected property " + name);
+                return;
+            }
+            
+            // create new property
+            prop = itemOps.createPropertyState(node, name, type, def);
+        }
+
+        // check multi-valued characteristic
+        if (values.length != 1 && !def.isMultiple()) {
+            throw new ConstraintViolationException(itemOps.safeGetJCRPath(prop.getPropertyId())
+                    + " is not multi-valued");
+        }
+
+        // convert serialized values to InternalValue objects
+        int targetType = getTargetType(def);
+        InternalValue[] iva = new InternalValue[values.length];
+        for (int i = 0; i < values.length; i++) {
+            iva[i] = values[i].getInternalValue(targetType);
+        }
+
+        // set values
+        prop.setValues(iva);
+
+        // make sure property is valid according to its definition
+        itemOps.validate(prop);
+
+        if (prop.getType() == PropertyType.REFERENCE) {
+            // store reference for later resolution
+            refTracker.processedReference(prop);
+        }
+
+        // store property
+        itemOps.store(prop);
+    }
+
+}

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

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java Wed Mar 22 14:52:40 2006
@@ -19,14 +19,9 @@
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
-import org.apache.jackrabbit.core.nodetype.PropDef;
 import org.apache.jackrabbit.core.util.ReferenceChangeTracker;
-import org.apache.jackrabbit.core.value.InternalValue;
-import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.QName;
 import org.apache.jackrabbit.value.ReferenceValue;
-import org.apache.jackrabbit.value.ValueHelper;
 import org.apache.jackrabbit.uuid.UUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,11 +33,9 @@
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.nodetype.NodeDefinition;
-import java.io.IOException;
-import java.io.Reader;
+
 import java.util.Iterator;
 import java.util.List;
 import java.util.Stack;
@@ -198,8 +191,7 @@
     /**
      * {@inheritDoc}
      */
-    public void startNode(NodeInfo nodeInfo, List propInfos,
-                          NamespaceResolver nsContext)
+    public void startNode(NodeInfo nodeInfo, List propInfos)
             throws RepositoryException {
         NodeImpl parent = (NodeImpl) parents.peek();
 
@@ -267,121 +259,7 @@
         Iterator iter = propInfos.iterator();
         while (iter.hasNext()) {
             PropInfo pi = (PropInfo) iter.next();
-            QName propName = pi.getName();
-            TextValue[] tva = pi.getValues();
-            int type = pi.getType();
-
-            // find applicable definition
-            EffectiveNodeType ent = node.getEffectiveNodeType();
-            PropDef def;
-            // multi- or single-valued property?
-            if (tva.length == 1) {
-                // could be single- or multi-valued (n == 1)
-                def = ent.getApplicablePropertyDef(propName, type);
-            } else {
-                // can only be multi-valued (n == 0 || n > 1)
-                def = ent.getApplicablePropertyDef(propName, type, true);
-            }
-
-            if (def.isProtected()) {
-                // skip protected property
-                log.debug("skipping protected property " + propName);
-                continue;
-            }
-
-            // 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(serValue, targetType, nsContext);
-                    // convert InternalValue to Value using this
-                    // session's namespace mappings
-                    va[i] = ival.toJCRValue(session.getNamespaceResolver());
-                } else if (targetType == PropertyType.BINARY) {
-                    try {
-                        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);
-                        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);
-                }
-            }
-
-            // multi- or single-valued property?
-            if (va.length == 1) {
-                // could be single- or multi-valued (n == 1)
-                try {
-                    // try setting single-value
-                    node.setProperty(propName, va[0]);
-                } catch (ValueFormatException vfe) {
-                    // try setting value array
-                    node.setProperty(propName, va, type);
-                } catch (ConstraintViolationException cve) {
-                    // try setting value array
-                    node.setProperty(propName, va, type);
-                }
-            } else {
-                // can only be multi-valued (n == 0 || n > 1)
-                node.setProperty(propName, va, type);
-            }
-            if (type == PropertyType.REFERENCE) {
-                // store reference for later resolution
-                refTracker.processedReference(node.getProperty(propName));
-            }
+            pi.apply(node, session.getNamespaceResolver(), refTracker);
         }
 
         parents.push(node);

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java?rev=387961&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/StringValue.java Wed Mar 22 14:52:40 2006
@@ -0,0 +1,100 @@
+/*
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.util.Base64;
+import org.apache.jackrabbit.value.ValueHelper;
+
+/**
+ * <code>StringValue</code> represents an immutable serialized value.
+ */
+class StringValue implements TextValue {
+
+    private final String value;
+
+    private final NamespaceResolver nsContext;
+
+    /**
+     * Constructs a new <code>StringValue</code> representing the given
+     * value.
+     *
+     * @param value
+     */
+    protected StringValue(String value, NamespaceResolver nsContext) {
+        this.value = value;
+        this.nsContext = nsContext;
+    }
+
+    //--------------------------------------------------------< TextValue >
+
+    public Value getValue(int type, NamespaceResolver resolver)
+            throws ValueFormatException, RepositoryException {
+        if (type == PropertyType.NAME || type == PropertyType.PATH) {
+            // NAME and PATH require special treatment because
+            // they depend on the current namespace context
+            // of the xml document
+            
+            // convert serialized value to InternalValue using
+            // current namespace context of xml document
+            InternalValue ival = InternalValue.create(value, type, nsContext);
+            // convert InternalValue to Value using this
+            // session's namespace mappings
+            return ival.toJCRValue(resolver);
+        } else if (type == PropertyType.BINARY) {
+            return ValueHelper.deserialize(value, type, false);
+        } else {
+            // all other types
+            return ValueHelper.deserialize(value, type, true);
+        }
+    }
+
+    public InternalValue getInternalValue(int targetType)
+            throws ValueFormatException, RepositoryException {
+        try {
+            if (targetType == PropertyType.BINARY) {
+                // base64 encoded BINARY type;
+                // decode using Reader
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                Base64.decode(value, baos);
+                return InternalValue.create(baos.toByteArray());
+            } else {
+                // convert serialized value to InternalValue using
+                // current namespace context of xml document
+                return InternalValue.create(value, targetType, nsContext);
+            }
+        } catch (IOException e) {
+            throw new RepositoryException("Error decoding Base64 content", e);
+        }
+    }
+
+    public void dispose() {
+        // do nothing
+    }
+
+}
\ No newline at end of file

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

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/SysViewImportHandler.java Wed Mar 22 14:52:40 2006
@@ -51,7 +51,7 @@
     private int currentPropType = PropertyType.UNDEFINED;
     // list of AppendableValue objects
     private ArrayList currentPropValues = new ArrayList();
-    private AppendableValue currentPropValue;
+    private BufferedStringValue currentPropValue;
 
     /**
      * Constructs a new <code>SysViewImportHandler</code>.
@@ -68,24 +68,25 @@
         if (!start && !end) {
             return;
         }
-        Importer.NodeInfo node = new Importer.NodeInfo();
-        node.setName(state.nodeName);
-        node.setNodeTypeName(state.nodeTypeName);
+        QName[] mixinNames = null;
         if (state.mixinNames != null) {
-            QName[] mixins = (QName[]) state.mixinNames.toArray(new QName[state.mixinNames.size()]);
-            node.setMixinNames(mixins);
+            mixinNames = (QName[]) state.mixinNames.toArray(
+                    new QName[state.mixinNames.size()]);
         }
+        NodeId id = null;
         if (state.uuid != null) {
-            node.setId(NodeId.valueOf(state.uuid));
+            id = NodeId.valueOf(state.uuid);
         }
+        NodeInfo node =
+            new NodeInfo(state.nodeName, state.nodeTypeName, mixinNames, id);
         // call Importer
         try {
             if (start) {
-                importer.startNode(node, state.props, nsContext);
+                importer.startNode(node, state.props);
                 // dispose temporary property values
                 for (Iterator iter = state.props.iterator(); iter.hasNext();) {
-                    Importer.PropInfo pi = (Importer.PropInfo) iter.next();
-                    disposePropertyValues(pi);
+                    PropInfo pi = (PropInfo) iter.next();
+                    pi.dispose();
                 }
 
             }
@@ -171,7 +172,7 @@
             // sv:value element
 
             // reset temp fields
-            currentPropValue = new BufferedStringValue();
+            currentPropValue = new BufferedStringValue(nsContext);
         } else {
             throw new SAXException(new InvalidSerializedDataException("unexpected element found in system view xml document: "
                     + localName));
@@ -238,7 +239,7 @@
             // check if all system properties (jcr:primaryType, jcr:uuid etc.)
             // have been collected and create node as necessary
             if (currentPropName.equals(QName.JCR_PRIMARYTYPE)) {
-                AppendableValue val = (AppendableValue) currentPropValues.get(0);
+                BufferedStringValue val = (BufferedStringValue) currentPropValues.get(0);
                 String s = null;
                 try {
                     s = val.retrieve();
@@ -255,8 +256,8 @@
                     state.mixinNames = new ArrayList(currentPropValues.size());
                 }
                 for (int i = 0; i < currentPropValues.size(); i++) {
-                    AppendableValue val =
-                            (AppendableValue) currentPropValues.get(i);
+                    BufferedStringValue val =
+                            (BufferedStringValue) currentPropValues.get(i);
                     String s = null;
                     try {
                         s = val.retrieve();
@@ -271,18 +272,17 @@
                     }
                 }
             } else if (currentPropName.equals(QName.JCR_UUID)) {
-                AppendableValue val = (AppendableValue) currentPropValues.get(0);
+                BufferedStringValue val = (BufferedStringValue) currentPropValues.get(0);
                 try {
                     state.uuid = val.retrieve();
                 } catch (IOException ioe) {
                     throw new SAXException("error while retrieving value", ioe);
                 }
             } else {
-                Importer.PropInfo prop = new Importer.PropInfo();
-                prop.setName(currentPropName);
-                prop.setType(currentPropType);
-                prop.setValues((Importer.TextValue[])
-                        currentPropValues.toArray(new Importer.TextValue[currentPropValues.size()]));
+                PropInfo prop = new PropInfo(
+                        currentPropName, currentPropType,
+                        (TextValue[]) currentPropValues.toArray(
+                                new TextValue[currentPropValues.size()]));
                 state.props.add(prop);
             }
             // reset temp fields

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TargetImportHandler.java Wed Mar 22 14:52:40 2006
@@ -16,20 +16,9 @@
  */
 package org.apache.jackrabbit.core.xml;
 
-import org.apache.jackrabbit.util.TransientFileFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.Writer;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
 import java.util.Map;
 
 import javax.jcr.RepositoryException;
@@ -41,8 +30,6 @@
  */
 abstract class TargetImportHandler extends DefaultHandler {
 
-    private static Logger log = LoggerFactory.getLogger(TargetImportHandler.class);
-
     protected final Importer importer;
 
     /**
@@ -59,28 +46,6 @@
     }
 
     /**
-     * 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++) {
-            if (vals[i] instanceof AppendableValue) {
-                try {
-                    ((AppendableValue) vals[i]).dispose();
-                } catch (IOException ioe) {
-                    log.warn("error while disposing temporary value", ioe);
-                    // fall through...
-                }
-            }
-        }
-    }
-
-    //-------------------------------------------------------< ContentHandler >
-
-    /**
      * Initializes the underlying {@link Importer} instance. This method
      * is called by the XML parser when the XML document starts.
      *
@@ -132,265 +97,4 @@
         nsContext = nsContext.getParent();
     }
 
-    //--------------------------------------------------------< inner classes >
-    /**
-     * <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
-     * <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
-         */
-        void append(char[] chars, int start, int length)
-                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
-         */
-        void close() 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
-         */
-        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>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
-     * <code>BufferedStringValue</code> instance is not used anymore.
-     */
-    protected class BufferedStringValue implements AppendableValue {
-
-        /**
-         * max size for buffering data in memory
-         */
-        private static final int MAX_BUFFER_SIZE = 0x10000;
-        /**
-         * size of increment if capacity buffer needs to be enlarged
-         */
-        private static final int BUFFER_INCREMENT = 0x2000;
-        /**
-         * in-memory buffer
-         */
-        private char[] buffer;
-        /**
-         * current position within buffer (size of actual data in buffer)
-         */
-        private int bufferPos;
-
-        /**
-         * backing temporary file created when size of data exceeds
-         * MAX_BUFFER_SIZE
-         */
-        private File tmpFile;
-        /**
-         * writer used to write to tmpFile; writer & tmpFile are always
-         * instantiated together, i.e. they are either both null or both not null.
-         */
-        private Writer writer;
-
-        /**
-         * Constructs a new empty <code>BufferedStringValue</code>.
-         */
-        protected BufferedStringValue() {
-            buffer = new char[0x2000];
-            bufferPos = 0;
-            tmpFile = null;
-            writer = null;
-        }
-
-        //--------------------------------------------------------< TextValue >
-        /**
-         * {@inheritDoc}
-         */
-        public long length() throws IOException {
-            if (buffer != null) {
-                return bufferPos;
-            } else if (tmpFile != null) {
-                // flush writer first
-                writer.flush();
-                return tmpFile.length();
-            } else {
-                throw new IOException("this instance has already been disposed");
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String retrieve() throws IOException {
-            if (buffer != null) {
-                return new String(buffer, 0, bufferPos);
-            } else if (tmpFile != null) {
-                // flush writer first
-                writer.flush();
-                if (tmpFile.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");
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Reader reader() throws IOException {
-            if (buffer != null) {
-                return new StringReader(new String(buffer, 0, bufferPos));
-            } else if (tmpFile != null) {
-                // flush writer first
-                writer.flush();
-                return new FileReader(tmpFile);
-            } else {
-                throw new IOException("this instance has already been disposed");
-            }
-        }
-
-        //--------------------------------------------------< AppendableValue >
-        /**
-         * {@inheritDoc}
-         */
-        public void append(char[] chars, int start, int length)
-                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
-                    TransientFileFactory fileFactory = TransientFileFactory.getInstance();
-                    tmpFile = fileFactory.createTransientFile("txt", null, null);
-                    final FileOutputStream fout = new FileOutputStream(tmpFile);
-                    writer = new OutputStreamWriter(fout) {
-                        public void flush() throws IOException {
-                            // flush this writer
-                            super.flush();
-                            // force synchronization with underlying file
-                            fout.getFD().sync();
-                        }
-                    };
-                    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");
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void close() throws IOException {
-            if (buffer != null) {
-                // nop
-            } else if (tmpFile != null) {
-                writer.close();
-            } else {
-                throw new IOException("this instance has already been disposed");
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void dispose() throws IOException {
-            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");
-            }
-        }
-    }
 }

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java?rev=387961&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/TextValue.java Wed Mar 22 14:52:40 2006
@@ -0,0 +1,45 @@
+/*
+ * 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 javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.name.NamespaceResolver;
+
+/**
+ * <code>TextValue</code> represents a serialized property value read
+ * from a System or Document View XML document.
+ */
+public interface TextValue {
+
+    Value getValue(int type, NamespaceResolver resolver)
+        throws ValueFormatException, RepositoryException;
+
+    InternalValue getInternalValue(int type)
+        throws ValueFormatException, RepositoryException;
+
+    /**
+     * 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.
+     */
+    void dispose();
+
+}

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

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=387961&r1=387960&r2=387961&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Wed Mar 22 14:52:40 2006
@@ -33,11 +33,8 @@
 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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,11 +49,6 @@
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.version.VersionException;
 import javax.jcr.version.VersionHistory;
-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;
@@ -346,8 +338,7 @@
     /**
      * {@inheritDoc}
      */
-    public void startNode(NodeInfo nodeInfo, List propInfos,
-                          NamespaceResolver nsContext)
+    public void startNode(NodeInfo nodeInfo, List propInfos)
             throws RepositoryException {
         if (aborted) {
             // the import has been aborted, get outta here...
@@ -502,140 +493,7 @@
             Iterator iter = propInfos.iterator();
             while (iter.hasNext()) {
                 PropInfo pi = (PropInfo) iter.next();
-                QName propName = pi.getName();
-                TextValue[] tva = pi.getValues();
-                int type = pi.getType();
-
-                PropertyState prop = null;
-                PropDef def = null;
-
-                if (node.hasPropertyName(propName)) {
-                    // a property with that name already exists...
-                    PropertyId idExisting = new PropertyId(node.getNodeId(), propName);
-                    PropertyState existing =
-                            (PropertyState) itemOps.getItemState(idExisting);
-                    def = ntReg.getPropDef(existing.getDefinitionId());
-                    if (def.isProtected()) {
-                        // skip protected property
-                        log.debug("skipping protected property "
-                                + itemOps.safeGetJCRPath(idExisting));
-                        continue;
-                    }
-                    if (def.isAutoCreated() && (existing.getType() == type
-                            || type == PropertyType.UNDEFINED)
-                            && def.isMultiple() == existing.isMultiValued()) {
-                        // this property has already been auto-created,
-                        // no need to create it
-                        prop = existing;
-                    } else {
-                        throw new ItemExistsException(itemOps.safeGetJCRPath(existing.getPropertyId()));
-                    }
-                }
-                if (prop == null) {
-                    // there's no property with that name,
-                    // find applicable definition
-
-                    // multi- or single-valued property?
-                    if (tva.length == 1) {
-                        // could be single- or multi-valued (n == 1)
-                        def = itemOps.findApplicablePropertyDefinition(propName,
-                                type, node);
-                    } else {
-                        // can only be multi-valued (n == 0 || n > 1)
-                        def = itemOps.findApplicablePropertyDefinition(propName,
-                                type, true, node);
-                    }
-
-                    if (def.isProtected()) {
-                        // skip protected property
-                        log.debug("skipping protected property " + propName);
-                        continue;
-                    }
-
-                    // create new property
-                    prop = itemOps.createPropertyState(node, propName, type, def);
-                }
-
-                // check multi-valued characteristic
-                if ((tva.length == 0 || tva.length > 1) && !def.isMultiple()) {
-                    throw new ConstraintViolationException(itemOps.safeGetJCRPath(prop.getPropertyId())
-                            + " is not multi-valued");
-                }
-
-                // 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
-                        try {
-                            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);
-                            }
-                        } 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
-                        iva[i] = InternalValue.create(serValue, targetType,
-                                nsContext);
-                    }
-                }
-
-                // set values
-                prop.setValues(iva);
-
-                // make sure property is valid according to its definition
-                itemOps.validate(prop);
-
-                if (prop.getType() == PropertyType.REFERENCE) {
-                    // store reference for later resolution
-                    refTracker.processedReference(prop);
-                }
-
-                // store property
-                itemOps.store(prop);
+                pi.apply(node, itemOps, ntReg, refTracker);
             }
 
             // store affected nodes



Mime
View raw message