Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 74834 invoked from network); 22 Mar 2006 22:54:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 22 Mar 2006 22:54:19 -0000 Received: (qmail 31822 invoked by uid 500); 22 Mar 2006 22:53:57 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 31779 invoked by uid 500); 22 Mar 2006 22:53:57 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 31770 invoked by uid 99); 22 Mar 2006 22:53:57 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Mar 2006 14:53:57 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 22 Mar 2006 14:53:54 -0800 Received: (qmail 74379 invoked by uid 65534); 22 Mar 2006 22:53:32 -0000 Message-ID: <20060322225332.74376.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r387961 - /jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/ Date: Wed, 22 Mar 2006 22:52:43 -0000 To: commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.7 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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; + +/** + * BufferedStringValue represents an appendable + * serialized value that is either buffered in-memory or backed + * by a temporary file if its size exceeds a certain limit. + *

+ * Important: Note that in order to free resources + * {@link #dispose()} should be called as soon as + * BufferedStringValue 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 BufferedStringValue. + */ + 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 Reader for reading the serialized value. + * + * @return a Reader 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 DocViewImportHandler. @@ -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 PropInfo 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; - } - } - - /** - * TextValue 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 Reader for reading the serialized value. - * - * @return a Reader 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; + +/** + * StringValue represents an immutable serialized value. + */ +class StringValue implements TextValue { + + private final String value; + + private final NamespaceResolver nsContext; + + /** + * Constructs a new StringValue 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 SysViewImportHandler. @@ -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 AppendableValue 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 > - /** - * AppendableValue represents a serialized value that is - * appendable. - *

- * Important: Note that in order to free resources - * {@link #dispose()} should be called as soon as an - * AppendableValue 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; - } - - /** - * StringValue represents an immutable serialized value. - */ - protected class StringValue implements Importer.TextValue { - - private final String value; - - /** - * Constructs a new StringValue 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); - } - } - - /** - * BufferedStringValue represents an appendable - * serialized value that is either buffered in-memory or backed - * by a temporary file if its size exceeds a certain limit. - *

- * Important: Note that in order to free resources - * {@link #dispose()} should be called as soon as - * BufferedStringValue 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 BufferedStringValue. - */ - 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; + +/** + * TextValue 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