Return-Path: Delivered-To: apmail-incubator-jackrabbit-commits-archive@www.apache.org Received: (qmail 90099 invoked from network); 20 Sep 2004 16:53:45 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 20 Sep 2004 16:53:45 -0000 Received: (qmail 82995 invoked by uid 500); 20 Sep 2004 16:53:45 -0000 Mailing-List: contact jackrabbit-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: jackrabbit-dev@incubator.apache.org Delivered-To: mailing list jackrabbit-commits@incubator.apache.org Received: (qmail 82829 invoked by uid 500); 20 Sep 2004 16:53:43 -0000 Delivered-To: apmail-incubator-jackrabbit-cvs@incubator.apache.org Received: (qmail 82685 invoked by uid 99); 20 Sep 2004 16:53:42 -0000 X-ASF-Spam-Status: No, hits=-10.0 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.28) with SMTP; Mon, 20 Sep 2004 09:53:41 -0700 Received: (qmail 90020 invoked by uid 65534); 20 Sep 2004 16:53:40 -0000 Date: 20 Sep 2004 16:53:40 -0000 Message-ID: <20040920165340.90018.qmail@minotaur.apache.org> From: stefan@apache.org To: jackrabbit-cvs@incubator.apache.org Subject: svn commit: rev 46941 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core: . nodetype xml X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N Author: stefan Date: Mon Sep 20 09:53:38 2004 New Revision: 46941 Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/NodeImpl.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/Test.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/EffectiveNodeType.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeDefId.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeTypeImpl.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/PropDefId.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/builtin_nodetypes.xml incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/DocViewImportHandler.java incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/SysViewImportHandler.java Log: differentiated handling of single vs. multi-valued properties: multi-valued property can only be set with value array and vice versa Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/NodeImpl.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/NodeImpl.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/NodeImpl.java Mon Sep 20 09:53:38 2004 @@ -15,7 +15,6 @@ */ package org.apache.jackrabbit.jcr.core; -import org.apache.log4j.Logger; import org.apache.jackrabbit.jcr.core.nodetype.*; import org.apache.jackrabbit.jcr.core.state.*; import org.apache.jackrabbit.jcr.core.version.FrozenNode; @@ -25,6 +24,7 @@ import org.apache.jackrabbit.jcr.util.ChildrenCollector; import org.apache.jackrabbit.jcr.util.IteratorHelper; import org.apache.jackrabbit.jcr.util.uuid.UUID; +import org.apache.log4j.Logger; import javax.jcr.*; import javax.jcr.access.AccessDeniedException; @@ -173,7 +173,7 @@ return genValues; } - protected PropertyImpl getOrCreateProperty(String name, int type) + protected PropertyImpl getOrCreateProperty(String name, int type, boolean multiValued) throws RepositoryException { try { return (PropertyImpl) getProperty(name); @@ -190,18 +190,18 @@ throw new RepositoryException("invalid property name: " + name, upe); } // find definition for the specified property and create property - PropertyDefImpl def = getApplicablePropertyDef(qName, type); + PropertyDefImpl def = getApplicablePropertyDef(qName, type, multiValued); return createChildProperty(qName, type, def); } - protected PropertyImpl getOrCreateProperty(QName name, int type) + protected PropertyImpl getOrCreateProperty(QName name, int type, boolean multiValued) throws RepositoryException { try { return (PropertyImpl) getProperty(name); } catch (ItemNotFoundException e) { // does not exist yet: // find definition for the specified property and create property - PropertyDefImpl def = getApplicablePropertyDef(name, type); + PropertyDefImpl def = getApplicablePropertyDef(name, type, multiValued); return createChildProperty(name, type, def); } } @@ -533,7 +533,7 @@ prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(), PROPNAME_MIXINTYPES)); } else { // find definition for the jcr:mixinTypes property and create property - PropertyDefImpl def = getApplicablePropertyDef(PROPNAME_MIXINTYPES, PropertyType.NAME); + PropertyDefImpl def = getApplicablePropertyDef(PROPNAME_MIXINTYPES, PropertyType.NAME, true); prop = createChildProperty(PROPNAME_MIXINTYPES, PropertyType.NAME, def); } @@ -599,13 +599,15 @@ * * @param propertyName * @param type + * @param multiValued * @return * @throws RepositoryException if no applicable property definition * could be found */ - protected PropertyDefImpl getApplicablePropertyDef(QName propertyName, int type) + protected PropertyDefImpl getApplicablePropertyDef(QName propertyName, + int type, boolean multiValued) throws RepositoryException { - PropDef pd = getEffectiveNodeType().getApplicablePropertyDef(propertyName, type); + PropDef pd = getEffectiveNodeType().getApplicablePropertyDef(propertyName, type, multiValued); return session.getNodeTypeManager().getPropDef(new PropDefId(pd)); } @@ -656,6 +658,7 @@ /** * Checks if this node is the root node. * todo: is this the root node of this workspace? + * * @return */ protected boolean isRepositoryRoot() { @@ -677,11 +680,22 @@ */ public Property internalSetProperty(QName name, InternalValue value) throws ValueFormatException, RepositoryException { + // check state of this instance + checkItemState(); + + int type; + if (value == null) { + type = PropertyType.STRING; + } else { + type = value.getType(); + } + PropertyImpl prop = getOrCreateProperty(name, type, false); if (value == null) { - return internalSetProperty(name, (InternalValue[]) null); + prop.internalSetValue((InternalValue[]) null, type); } else { - return internalSetProperty(name, new InternalValue[]{value}); + prop.internalSetValue(new InternalValue[]{value}, type); } + return prop; } /** @@ -708,7 +722,7 @@ } else { type = values[0].getType(); } - PropertyImpl prop = getOrCreateProperty(name, type); + PropertyImpl prop = getOrCreateProperty(name, type, true); prop.internalSetValue(values, type); return prop; } @@ -885,7 +899,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.NAME); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.NAME, false); prop.setValue(value); return prop; } @@ -905,7 +919,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.NAME); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.NAME, true); prop.setValue(values); return prop; } @@ -932,12 +946,34 @@ } else { type = values[0].getType(); } - PropertyImpl prop = getOrCreateProperty(name, type); + PropertyImpl prop = getOrCreateProperty(name, type, true); prop.setValue(values); return prop; } /** + * Same as {@link Node#setProperty(String, Value)} except that + * this method takes a QName name argument instead of a + * String. + * + * @param name + * @param value + * @return + * @throws ValueFormatException + * @throws RepositoryException + */ + public PropertyImpl setProperty(QName name, Value value) + throws ValueFormatException, RepositoryException { + // check state of this instance + checkItemState(); + + int type = (value == null) ? PropertyType.STRING : value.getType(); + PropertyImpl prop = getOrCreateProperty(name, type, false); + prop.setValue(value); + return prop; + } + + /** * @see ItemImpl#getQName() */ public QName getQName() throws RepositoryException { @@ -1254,7 +1290,7 @@ } else { type = values[0].getType(); } - PropertyImpl prop = getOrCreateProperty(name, type); + PropertyImpl prop = getOrCreateProperty(name, type, true); prop.setValue(values); return prop; } @@ -1267,7 +1303,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.STRING); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.STRING, true); prop.setValue(values); return prop; } @@ -1279,7 +1315,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.STRING); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.STRING, false); prop.setValue(value); return prop; } @@ -1293,7 +1329,7 @@ checkItemState(); int type = (value == null) ? PropertyType.STRING : value.getType(); - PropertyImpl prop = getOrCreateProperty(name, type); + PropertyImpl prop = getOrCreateProperty(name, type, false); prop.setValue(value); return prop; } @@ -1306,7 +1342,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.BINARY); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.BINARY, false); prop.setValue(value); return prop; } @@ -1319,7 +1355,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.BOOLEAN); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.BOOLEAN, false); prop.setValue(value); return prop; } @@ -1332,7 +1368,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.DOUBLE); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.DOUBLE, false); prop.setValue(value); return prop; } @@ -1345,7 +1381,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.LONG); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.LONG, false); prop.setValue(value); return prop; } @@ -1358,7 +1394,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.DATE); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.DATE, false); prop.setValue(value); return prop; } @@ -1371,7 +1407,7 @@ // check state of this instance checkItemState(); - PropertyImpl prop = getOrCreateProperty(name, PropertyType.REFERENCE); + PropertyImpl prop = getOrCreateProperty(name, PropertyType.REFERENCE, false); prop.setValue(value); return prop; } @@ -2163,7 +2199,7 @@ RepositoryException { NodeImpl srcNode = getCorrespondingNode(srcWorkspaceName); - if (srcNode==null) { + if (srcNode == null) { throw new ItemNotFoundException("No corresponding node for " + safeGetJCRPath()); } // not sure, if clone overrides 'this' node. @@ -2173,25 +2209,26 @@ /** * Returns the corresponding node in the scrWorkspaceName of * this node. - *

+ *

* Given a node N1 in workspace W1, its corresponding node N2 in workspace * W2 is defined as follows: *

    *
  • If N1 is the root node of W1 then N2 is the root node of W2. *
  • If N1 is referenceable (has a UUID) then N2 is the node in W2 with - * the same UUID. + * the same UUID. *
  • If N1 is not referenceable (does not have a UUID) then there is some - * node M1 which is either the nearest ancestor of N1 that is - * referenceable, or is the root node of W1. If the corresponding node - * of M1 is M2 in W2, then N2 is the node with the same relative path - * from M2 as N1 has from M1. + * node M1 which is either the nearest ancestor of N1 that is + * referenceable, or is the root node of W1. If the corresponding node + * of M1 is M2 in W2, then N2 is the node with the same relative path + * from M2 as N1 has from M1. *
+ * * @param srcWorkspaceName * @return the corresponding node or null if no corresponding * node exists. * @throws NoSuchWorkspaceException If srcWorkspace does not exist. - * @throws AccessDeniedException If the current session does not have sufficient rights to perform the operation. - * @throws RepositoryException If another error occurs. + * @throws AccessDeniedException If the current session does not have sufficient rights to perform the operation. + * @throws RepositoryException If another error occurs. */ private NodeImpl getCorrespondingNode(String srcWorkspaceName) throws NoSuchWorkspaceException, AccessDeniedException, @@ -2229,7 +2266,7 @@ // n1.getPath() = /foo/bar/something[1] // m1.getPath() = /foo // relpath = bar/something[1] - String relPath = getPath().substring(m1.getPath().length()+1); + String relPath = getPath().substring(m1.getPath().length() + 1); try { return (NodeImpl) srcSession.getNodeByUUID(m1.getUUID()).getNode(relPath); } catch (ItemNotFoundException e) { @@ -2245,7 +2282,7 @@ AccessDeniedException, MergeException, RepositoryException { NodeImpl srcNode = doMergeTest(srcWorkspace, bestEffort); - if (srcNode!=null) { + if (srcNode != null) { // remove properties PropertyIterator pi = getProperties(); while (pi.hasNext()) { @@ -2315,7 +2352,7 @@ // If N does not have a corresponding node then the merge result for N is leave. NodeImpl srcNode = getCorrespondingNode(srcWorkspace); - if (srcNode==null) { + if (srcNode == null) { return null; } @@ -2350,7 +2387,7 @@ // add 'offending' version to jcr:mergeFailed property if (hasProperty(ItemImpl.PROPNAME_MERGE_FAILED)) { Value[] values = getProperty(ItemImpl.PROPNAME_MERGE_FAILED).getValues(); - Value[] newValues = new Value[values.length+1]; + Value[] newValues = new Value[values.length + 1]; System.arraycopy(values, 0, newValues, 0, values.length); newValues[values.length] = new ReferenceValue(vp); setProperty(ItemImpl.PROPNAME_MERGE_FAILED, newValues); @@ -2554,11 +2591,14 @@ * Little helper to retrieve the opv value for a property. depends on the * implementaion. if nt:frozen is used, need to lookup prop def. * - * @param prop + * @param name + * @param type + * @param multiValued * @return + * @throws RepositoryException */ - private int getOPV(PropertyImpl prop) throws RepositoryException { - PropertyDefImpl def = getApplicablePropertyDef(prop.getQName(), PropertyType.UNDEFINED); + private int guessOPV(QName name, int type, boolean multiValued) throws RepositoryException { + PropertyDefImpl def = getApplicablePropertyDef(name, type, multiValued); return def.getOnParentVersion(); } @@ -2629,7 +2669,16 @@ // ignore } else { // normal property - int opv = getOPV(prop); + int type = PropertyType.UNDEFINED; + if (prop.getDefinition().isMultiple()) { + Value[] values = prop.getValues(); + if (values.length != 0) { + type = values[0].getType(); + } + } else { + type = prop.getValue().getType(); + } + int opv = guessOPV(prop.getQName(), type, prop.getDefinition().isMultiple()); switch (opv) { case OnParentVersionAction.ABORT: throw new RepositoryException("Checkin aborted due to OPV in " + prop.safeGetJCRPath()); @@ -2652,7 +2701,7 @@ if (child.isNodeType(NodeTypeRegistry.NT_FROZEN)) { FrozenNode f = (FrozenNode) child; // if frozen node exist, replace - // todo: make work for samename siblings + // todo: make work for same name siblings if (hasNode(child.getName())) { remove(child.getName()); } Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/Test.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/Test.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/Test.java Mon Sep 20 09:53:38 2004 @@ -99,9 +99,12 @@ //root.setProperty("blob", new FileInputStream(new File("d:/temp/jckrabbit.zip"))); - //root.setProperty("blah", 1); - //root.setProperty("blah", 1.4); - //root.setProperty("blah", "blahblah"); + if (root.hasProperty("blah")) { + root.remove("blah"); + } + root.setProperty("blah", 1); + root.setProperty("blah", 1.4); + root.setProperty("blah", "blahblah"); Node file = root.addNode("blu", "nt:file"); file.addNode("jcr:content", "nt:unstructured"); root.addNode("blu", "nt:folder"); @@ -123,8 +126,8 @@ root.save(); - if (root.hasProperty("bla")) { - root.setProperty("bla", (String) null); + if (root.hasProperty("blah")) { + root.setProperty("blah", (String) null); } if (!root.hasProperty("blah")) { String[] strings = new String[]{"huey", "louie", null, "dewey"}; @@ -160,18 +163,17 @@ Node misc = root.addNode("misc", "nt:unstructured"); misc.addMixin("mix:referenceable"); - Property link = misc.setProperty("link", new Value[]{PathValue.valueOf("../blu[2]")}); + Property link = misc.setProperty("link", PathValue.valueOf("../blu[2]")); root.save(); - Node linkTarget = link.getParent().getNode(link.getValues()[0].getString()); + Node linkTarget = link.getParent().getNode(link.getValue().getString()); System.out.println(link.getPath() + " refers to " + linkTarget.getPath()); - root.setProperty("ref", new Value[]{new ReferenceValue(misc)}); + root.setProperty("ref", new ReferenceValue(misc)); root.save(); PropertyIterator pi = misc.getReferences(); while (pi.hasNext()) { Property prop = pi.nextProperty(); - String uuid = prop.getValues()[0].getString(); - Node target = session.getNodeByUUID(uuid); + Node target = prop.getNode(); System.out.println(prop.getPath() + " is a reference to " + target.getPath()); } /* @@ -184,9 +186,9 @@ } */ String date1 = "2003-07-28T06:18:57.848+01:00"; - root.setProperty("date", new Value[]{new DateValue(new StringValue(date1).getDate())}); + root.setProperty("date", new DateValue(new StringValue(date1).getDate())); Property p = root.getProperty("date"); - Value val = p.getValues()[0]; + Value val = p.getValue(); Calendar d = val.getDate(); Node imported = null; @@ -196,7 +198,7 @@ imported = root.getNode("imported"); } - importNode(new File("d:/dev/jackrabbit/src/java"), imported); + importNode(new File("d:/dev/jsr170/jackrabbit/src/java"), imported); if (root.hasNode("foo")) { root.remove("foo"); @@ -205,8 +207,8 @@ Node n = root.addNode("foo", "nt:folder"); Node n2 = n.addNode("foofile", "nt:file"); Node n3 = n2.addNode("jcr:content", "nt:unstructured"); - Property prop1 = n3.setProperty("prop1", new Value[]{new LongValue(123)}); - Property prop2 = n3.setProperty("prop2", new Value[]{new StringValue("blahblah")}); + Property prop1 = n3.setProperty("prop1", new LongValue(123)); + Property prop2 = n3.setProperty("prop2", new StringValue("blahblah")); System.out.println("before save()..."); System.out.println(); Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/EffectiveNodeType.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/EffectiveNodeType.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/EffectiveNodeType.java Mon Sep 20 09:53:38 2004 @@ -455,11 +455,12 @@ * * @param name * @param type + * @param multiValued * @return * @throws ConstraintViolationException if no applicable property definition * could be found */ - public PropDef getApplicablePropertyDef(QName name, int type) + public PropDef getApplicablePropertyDef(QName name, int type, boolean multiValued) throws ConstraintViolationException { ChildItemDef def = (ChildItemDef) namedItemDefs.get(name); if (def == null) { @@ -473,8 +474,11 @@ if (reqType == PropertyType.UNDEFINED || type == PropertyType.UNDEFINED || reqType == type) { - // found match - return pd; + // match multiValued flag + if (multiValued == pd.isMultiple()) { + // found match + return pd; + } } } } else { @@ -486,8 +490,11 @@ if (reqType == PropertyType.UNDEFINED || type == PropertyType.UNDEFINED || reqType == type) { - // found match - return pd; + // match multiValued flag + if (multiValued == pd.isMultiple()) { + // found match + return pd; + } } } } @@ -617,13 +624,28 @@ ChildItemDef existing = (ChildItemDef) iter.next(); // compare with existing definition if (def.definesNode() == existing.definesNode()) { - // conflict - String msg = "An item definition in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existing.getDeclaringNodeType() + "': ambiguos residual item definition"; - log.error(msg); - throw new NodeTypeConflictException(msg); + if (!def.definesNode()) { + // property definition + PropDef pd = (PropDef) def; + PropDef epd = (PropDef) existing; + // compare type & multiValued flag + if (pd.getRequiredType() == epd.getRequiredType() && + pd.isMultiple() == epd.isMultiple()) { + // conflict + String msg = "A property definition in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existing.getDeclaringNodeType() + "': ambiguos residual property definition"; + log.error(msg); + throw new NodeTypeConflictException(msg); + } + } else { + // child node definition + // conflict + String msg = "A child node definition in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existing.getDeclaringNodeType() + "': ambiguos residual child node definition"; + log.error(msg); + throw new NodeTypeConflictException(msg); + } } } - // @todo check for ambiguous definitions & other conflicts + // @todo do further checks for ambiguous definitions & other conflicts unnamedItemDefs.add(def); } // @todo implement further validations Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeDefId.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeDefId.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeDefId.java Mon Sep 20 09:53:38 2004 @@ -37,6 +37,7 @@ if (def == null) { throw new IllegalArgumentException("ChildNodeDef argument can not be null"); } + // build key (format: ///) StringBuffer sb = new StringBuffer(); sb.append(def.getDeclaringNodeType().toString()); Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeTypeImpl.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeTypeImpl.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/NodeTypeImpl.java Mon Sep 20 09:53:38 2004 @@ -104,13 +104,15 @@ * * @param propertyName * @param type + * @param multiValued * @return * @throws RepositoryException if no applicable property definition * could be found */ - public PropertyDefImpl getApplicablePropertyDef(QName propertyName, int type) + public PropertyDefImpl getApplicablePropertyDef(QName propertyName, int type, + boolean multiValued) throws RepositoryException { - return new PropertyDefImpl(ent.getApplicablePropertyDef(propertyName, type), + return new PropertyDefImpl(ent.getApplicablePropertyDef(propertyName, type, multiValued), ntMgr, nsResolver); } @@ -378,14 +380,59 @@ * @see NodeType#canSetProperty(String, Value) */ public boolean canSetProperty(String propertyName, Value value) { + if (value == null) { + // setting a property to null is equivalent of removing it + return canRemoveItem(propertyName); + } try { QName name = QName.fromJCRName(propertyName, nsResolver); - PropertyDefImpl def = getApplicablePropertyDef(name, value == null ? PropertyType.UNDEFINED : value.getType()); + int type = (value == null) ? PropertyType.UNDEFINED : value.getType(); + PropertyDefImpl def = getApplicablePropertyDef(name, type, false); if (def.isProtected()) { return false; } + if (def.isMultiple()) { + return false; + } InternalValue internalValue = InternalValue.create(value, nsResolver); checkSetPropertyValueConstraints(def, new InternalValue[]{internalValue}); + return true; + } catch (BaseException be) { + // implementation specific exception, fall through + } catch (RepositoryException re) { + // fall through + } + return false; + } + + /** + * @see NodeType#canSetProperty(String, Value[]) + */ + public boolean canSetProperty(String propertyName, Value values[]) { + if (values == null) { + // setting a property to null is equivalent of removing it + return canRemoveItem(propertyName); + } + try { + QName name = QName.fromJCRName(propertyName, nsResolver); + int type = (values == null || values.length == 0) ? PropertyType.UNDEFINED : values[0].getType(); + PropertyDefImpl def = getApplicablePropertyDef(name, type, true); + if (def.isProtected()) { + return false; + } + if (!def.isMultiple()) { + return false; + } + ArrayList list = new ArrayList(); + // convert values and compact array (purge null entries) + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + InternalValue internalValue = InternalValue.create(values[i], nsResolver); + list.add(internalValue); + } + } + InternalValue[] internalValues = (InternalValue[]) list.toArray(new InternalValue[list.size()]); + checkSetPropertyValueConstraints(def, internalValues); return true; } catch (BaseException be) { // implementation specific exception, fall through Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/PropDefId.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/PropDefId.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/PropDefId.java Mon Sep 20 09:53:38 2004 @@ -34,7 +34,7 @@ if (def == null) { throw new IllegalArgumentException("PropDef argument can not be null"); } - // build key (format: ///) + // build key (format: ///) StringBuffer sb = new StringBuffer(); sb.append(def.getDeclaringNodeType().toString()); Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/builtin_nodetypes.xml ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/builtin_nodetypes.xml (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/nodetype/builtin_nodetypes.xml Mon Sep 20 09:53:38 2004 @@ -64,6 +64,7 @@ + @@ -124,6 +125,7 @@ + Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/DocViewImportHandler.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/DocViewImportHandler.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/DocViewImportHandler.java Mon Sep 20 09:53:38 2004 @@ -15,9 +15,9 @@ */ package org.apache.jackrabbit.jcr.core.xml; -import org.apache.log4j.Logger; import org.apache.jackrabbit.jcr.core.*; import org.apache.jackrabbit.jcr.core.nodetype.NodeTypeRegistry; +import org.apache.log4j.Logger; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; @@ -25,7 +25,6 @@ import javax.jcr.RepositoryException; import javax.jcr.StringValue; -import javax.jcr.Value; import java.util.Stack; /** @@ -87,7 +86,7 @@ } } StringValue val = new StringValue(atts.getValue(i)); - currentParent.setProperty(propName, new Value[]{val}); + currentParent.setProperty(propName, val); } } catch (RepositoryException re) { throw new SAXException(re); @@ -105,8 +104,7 @@ NodeImpl currentParent = (NodeImpl) parents.peek(); NodeImpl txtNode = (NodeImpl) currentParent.addNode(DocViewSAXEventGenerator.NODENAME_XMLTEXT); StringValue val = new StringValue(new String(ch, start, length)); - txtNode.setProperty(DocViewSAXEventGenerator.PROPNAME_XMLCHARACTERS, - new Value[]{val}); + txtNode.setProperty(DocViewSAXEventGenerator.PROPNAME_XMLCHARACTERS, val); } catch (RepositoryException re) { throw new SAXException(re); } Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/SysViewImportHandler.java ============================================================================== --- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/SysViewImportHandler.java (original) +++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/jcr/core/xml/SysViewImportHandler.java Mon Sep 20 09:53:38 2004 @@ -28,6 +28,7 @@ import javax.jcr.*; import javax.jcr.nodetype.NodeDef; import javax.jcr.nodetype.PropertyDef; +import javax.jcr.nodetype.ConstraintViolationException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -272,10 +273,25 @@ } if (current.node.hasProperty(currentPropName)) { PropertyDef def = current.node.getProperty(currentPropName).getDefinition(); - if (!def.isProtected()) { + if (def.isProtected()) { + // ignore protected property + // reset temp fields and get outta here + currentPropValues = null; + return; + } + } + // multi- or single-valued property? + if (vals.length == 1) { + // could be single- or multi-valued (n == 1) + try { + // try setting single-value + current.node.setProperty(currentPropName, vals[0]); + } catch (ConstraintViolationException cve) { + // try setting value array current.node.setProperty(currentPropName, vals); } } else { + // can only be multi-valued (n == 0 || n > 1) current.node.setProperty(currentPropName, vals); } }