org.modeshape.jcr.PropertyDefinitionId Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* 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.modeshape.jcr;
import java.util.HashMap;
import javax.jcr.PropertyType;
import org.modeshape.common.annotation.Immutable;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.NameFactory;
import org.modeshape.jcr.value.ValueFormatException;
/**
* An immutable identifier for a property definition. Although instances cannot be serialized, the property definitions are often
* stored within the graph as {@link #getString() string values} on a property. These string values can later be
* {@link #fromString(String, NameFactory) parsed} to reconstruct the identifier. Note that this string representation does not
* use namespace prefixes, so they are long-lasting and durable.
*
* What distinguishes one property definition from another is not well documented in the JSR-170 specification. The closest this
* version of the spec gets is Section 6.7.15, but that merely says that more than one property definition can have the same name.
* The JSR-283 specification does clarify this more: Section 3.7.2.1.3 says :
*
*
* "A node type may have two or more property definitions with identical name attributes (the value returned by
* ItemDefinition.getName) as long as the definitions are otherwise distinguishable by either the required type attribute (the
* value returned by PropertyDefinition.getRequiredType) or the multiple attribute (the value returned by
* PropertyDefinition.isMultiple)."
*
*
* This class is {@link Immutable} and designed to be used as a key in a {@link HashMap}.
*
*/
@Immutable
final class PropertyDefinitionId {
/**
* The string-form of the name that can be used to represent a residual property definition.
*/
public static final String ANY_NAME = JcrNodeType.RESIDUAL_ITEM_NAME;
private final Name nodeTypeName;
private final Name propertyDefinitionName;
private final int propertyType;
private final boolean allowsMultiple;
/**
* A cached string representation, which is used for {@link #equals(Object)} and {@link #hashCode()} among other things.
*/
private final String stringRepresentation;
/**
* Create a new identifier for a property definition.
*
* @param nodeTypeName the name of the node type; may not be null
* @param propertyDefinitionName the name of the property definition, which may be a {@link #ANY_NAME residual property}; may
* not be null
* @param propertyType the required property type for the definition; must be a valid {@link PropertyType} value
* @param allowsMultiple true if the property definition should allow multiple values, or false if it is a single-value
* property definition
*/
public PropertyDefinitionId( Name nodeTypeName,
Name propertyDefinitionName,
int propertyType,
boolean allowsMultiple ) {
this.nodeTypeName = nodeTypeName;
this.propertyDefinitionName = propertyDefinitionName;
this.propertyType = propertyType;
this.allowsMultiple = allowsMultiple;
this.stringRepresentation = this.nodeTypeName.getString() + '/' + this.propertyDefinitionName.getString() + '/'
+ org.modeshape.jcr.api.PropertyType.nameFromValue(propertyType) + '/' + (allowsMultiple ? '*' : '1');
}
/**
* Get the name of the node type on which the property definition is defined
*
* @return the node type's name; may not be null
*/
public Name getNodeTypeName() {
return nodeTypeName;
}
/**
* Get the name of the property definition.
*
* @return the property definition's name; never null
*/
public Name getPropertyDefinitionName() {
return propertyDefinitionName;
}
/**
* Get the required property type
*
* @return the property type; always a valid {@link PropertyType} value
*/
public int getPropertyType() {
return propertyType;
}
/**
* Return whether the property definition allows multiple values.
*
* @return true if the property definition allows multiple values, or false if it is a single-value property definition
*/
public boolean allowsMultiple() {
return allowsMultiple;
}
/**
* Determine whether this property definition allows properties with any name.
*
* @return true if this node definition allows properties with any name, or false if this definition requires a particular
* property name
*/
public boolean allowsAnyChildName() {
return propertyDefinitionName.getLocalName().equals(ANY_NAME) && propertyDefinitionName.getNamespaceUri().length() == 0;
}
/**
* Get the string form of this identifier. This form can be persisted, since it does not rely upon namespace prefixes.
*
* @return the string form
*/
public String getString() {
return this.stringRepresentation;
}
/**
* Parse the supplied string for of an identifer, and return the object form for that identifier.
*
* @param definition the {@link #getString() string form of the identifier}; may not be null
* @param factory the factory that should be used to create Name objects; may not be null
* @return the object form of the identifier; never null
* @throws ValueFormatException if the definition is not the valid format
*/
public static PropertyDefinitionId fromString( String definition,
NameFactory factory ) {
String[] parts = definition.split("/");
String nodeTypeNameString = parts[0];
String propertyDefinitionNameString = parts[1];
Name nodeTypeName = factory.create(nodeTypeNameString);
Name propertyDefinitionName = factory.create(propertyDefinitionNameString);
int propertyType = org.modeshape.jcr.api.PropertyType.valueFromName(parts[2]);
boolean allowsMultiple = parts[3].charAt(0) == '*';
return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, allowsMultiple);
}
public PropertyDefinitionId asSingleValued() {
return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, false);
}
public PropertyDefinitionId asMultiValued() {
return new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, propertyType, true);
}
@Override
public int hashCode() {
return this.stringRepresentation.hashCode();
}
@Override
public boolean equals( Object obj ) {
if (obj == this) return true;
if (obj instanceof PropertyDefinitionId) {
PropertyDefinitionId that = (PropertyDefinitionId)obj;
return this.stringRepresentation.equals(that.stringRepresentation);
}
return false;
}
@Override
public String toString() {
return this.stringRepresentation;
}
}