}
}
// Otherwise, we have to create the property, so first find a valid property definition ...
SessionCache cache = sessionCache();
MutableCachedNode node = mutable();
Name primaryType = node.getPrimaryType(cache);
Set<Name> mixinTypes = node.getMixinTypes(cache);
NodeTypes nodeTypes = session.nodeTypes();
JcrPropertyDefinition defn = null;
defn = nodeTypes.findPropertyDefinition(session, primaryType, mixinTypes, name, values, !skipProtectedValidation,
skipReferenceValidation);
if (defn == null) {
// Failed to find a valid property definition,
// so figure out if there's a definition that would work if it had no constraints ...
defn = nodeTypes.findPropertyDefinition(session, primaryType, mixinTypes, name, values, !skipProtectedValidation,
false);
String propName = readable(name);
if (defn != null) {
String defnName = defn.getName();
String nodeTypeName = defn.getDeclaringNodeType().getName();
I18n msg = JcrI18n.valueViolatesConstraintsOnDefinition;
throw new ConstraintViolationException(msg.text(propName, readable(values), location(), defnName, nodeTypeName));
}
// See if we can find a single-valued property definition ...
defn = nodeTypes.findPropertyDefinition(session, primaryType, mixinTypes, name, values[0], true, false);
if (defn == null) {
// The cardinality of the new values does not match the available property definition ...
I18n msg = JcrI18n.unableToSetSingleValuedPropertyUsingMultipleValues;
throw new javax.jcr.ValueFormatException(msg.text(readable(name), location(), workspaceName()));
}
I18n msg = JcrI18n.noPropertyDefinition;
throw new ConstraintViolationException(msg.text(propName, location(), readable(primaryType), readable(mixinTypes)));
}
// The 'findBestPropertyDefintion' method checks constraints for all definitions exception those with a
// require type of REFERENCE. This is because checking such constraints may cause unnecessary loading of nodes.
// Therefore, see if this is the case ...
int requiredType = defn.getRequiredType();
if (!skipReferenceValidation && (requiredType == PropertyType.REFERENCE || requiredType == PropertyType.WEAKREFERENCE)) {
// Check that the REFERENCE value satisfies the constraints ...
if (!defn.canCastToTypeAndSatisfyConstraints(values, session)) {
// The REFERENCE value did not satisfy the constraints ...
String propName = readable(name);
String defnName = defn.getName();
String nodeTypeName = defn.getDeclaringNodeType().getName();
I18n i18n = JcrI18n.weakReferenceValueViolatesConstraintsOnDefinition;
if (requiredType == PropertyType.REFERENCE) i18n = JcrI18n.referenceValueViolatesConstraintsOnDefinition;
throw new ConstraintViolationException(i18n.text(propName, readable(values), location(), defnName, nodeTypeName));
}
}
if (requiredType == PropertyType.UNDEFINED && values.length > 0) {
requiredType = values[0].getType();
}
// Create the JCR Property object ...
AbstractJcrProperty jcrProp = new JcrMultiValueProperty(this, name, requiredType);
jcrProp.setPropertyDefinitionId(defn.getId(), nodeTypes.getVersion());
AbstractJcrProperty otherProp = this.jcrProperties.putIfAbsent(name, jcrProp);
if (otherProp != null) {
// Someone snuck in and created this property while we created ours, so use that instance instead ...
// Check that the cardinality is correct ...
if (!jcrProp.isMultiple()) {
// Overwrite the value anyway ...
this.jcrProperties.put(name, jcrProp);
}
jcrProp = otherProp;
}
// The values may need to be converted to the definition's required type ...
int numValues = values.length;
Object[] objValues = new Object[numValues];
int propertyType = defn.getRequiredType();
if (propertyType == PropertyType.UNDEFINED || propertyType == jcrPropertyType) {
// Can use the values as is ...
for (int i = 0; i != numValues; ++i) {
objValues[i] = ((JcrValue)values[i]).value();
}
} else {
// A conversion is required ...
try {
org.modeshape.jcr.value.PropertyType msType = PropertyTypeUtil.modePropertyTypeFor(propertyType);
org.modeshape.jcr.value.ValueFactory<?> factory = context().getValueFactories().getValueFactory(msType);
for (int i = 0; i != numValues; ++i) {
objValues[i] = factory.create(((JcrValue)values[i]).value());
}
} catch (org.modeshape.jcr.value.ValueFormatException e) {
throw new ValueFormatException(e.getMessage());
}
}
// Set the property on the cached node (even if there was an 'otherProp' instance) ...
Property newProperty = session.propertyFactory().create(name, objValues);
node.setProperty(cache, newProperty);
return jcrProp;
}