Interface Property
- All Superinterfaces:
Cloneable
,Iterable<Property>
,Serializable
- All Known Subinterfaces:
DocumentPart
- All Known Implementing Classes:
AbstractProperty
,ArrayProperty
,BinaryProperty
,BlobProperty
,BlobProperty.ScalarMemberProperty
,BooleanProperty
,ComplexProperty
,DateProperty
,DocumentPartImpl
,DoubleProperty
,ExternalBlobProperty
,ListProperty
,LongProperty
,MapProperty
,RemovedProperty
,ScalarProperty
,StringProperty
You can say that a Field
object is like a Java class and a Property object like a class instance. Thus,
schemas defines fields (or elements) which have a name and a type, and each field of a document can be instantiated
(if the schema permits) as a Property object.
Properties are always bound to a schema field that provides the type and constraints on the property values. An
exception is the root property the DocumentPart
object which is not bound to a field but to a schema.
So properties are holding the actual values for each defined field.
The usual way of using properties is to get a document from the storage server then modify document properties and send them back to the storage server to that modifications are be stored.
Note that the storage server can be on a remote machine so when modifying properties remotely they are serialized and sent through the network between the two machines. This means properties must hold serializable values and also they must store some state flags so that the storage can decide which property was modified and how in order to correctly update the stored versions.
As we have seen each property may hold a serializable value which we will refer to as the normalized
property value. For each schema field type there is only one java serializable object representation that will be
used as the normalized value. The property API is giving you the possibility to use different compatible objects when
setting or getting property values. Each property implementation will automatically convert the given value into a
normalized one; so internally only the normalized value is stored.
For example, for date properties you may use either Date
or Calendar
when setting or
retrieving a property value, but the normalized value will be the Calendar
one.
As we have seen, properties keep some state flags. Property flags can be divided in two groups:
- Dirty Flags - that reflect the public status of the document
- Internal Flags - that reflect some internal state
Property Types:
Before going deeper in property flags, we will talk first about property types. There are several types of properties that are very closed on the type of fields they are bound onto.
- Root Property (or
DocumentPart
) - this is a special property that is bound to a schema instead of a field And it is the root of the property tree. - Complex Properties - container properties that are bound to complex field types that can be represented as java
Map
objects. These properties contains a set of schema defined properties. You cannot add new child properties. You can only modify existing child properties. Complex property values are expressed as javaMap
objects.- Structured Properties - this is a special case of complex properties. The difference is that structured property
values are expressed as scalar java objects instead of java maps. By scalar java objects we mean any well
structured object which is not a container like a
Map
or aCollection
. These objects are usually as scalar values - it doesn't make sense for example to set only some parts of that objects without creating the object completely. An example of usage are Blob properties that useBlob
values.
- Structured Properties - this is a special case of complex properties. The difference is that structured property
values are expressed as scalar java objects instead of java maps. By scalar java objects we mean any well
structured object which is not a container like a
- List Properties - container properties that are bound to list field types.
- Scalar Properties - atomic properties that are bound to scalar field types and that are using as values scalar or primitive java objects like arrays, primitives, String, Date etc.
As we've seen there are 2 categories of properties: container properties and scalar properties Complex and list properties are container properties while structured and scalar properties are scalar.
Dirty Flags:
Dirty flags are used to keep track of the dirty state of a property. The following flags are supported:
IS_PHANTOM
- whether the property is existing in the storage (was explicitly set by the user) or it was dynamically generated using the default value by the implementation to fulfill schema definition. This applies to all property typesIS_MODIFIED
- whether the property value was modified. This applies to all property types.IS_NEW
- whether the property is a new property that was added to a parent list property This applies only to properties that are children of a list property.IS_REMOVED
- whether a property was removed. A removed property will be removed from the storage and the next time you access the property it will be aphantom
one. This applies only to properties that are children of a complex property.IS_MOVED
- whether the property was moved on another position inside the container list. This applies only to properties that are children of a list property.
There are several constraints on how property flags may change. This is a list of all changes that may occur over dirty flags:
- NONE + MODIFIED => MODFIED
- NONE + REMOVED => REMOVED
- NONE + MOVED => MOVED
- PHANTOM + MODIFIED => MODIFIED
- NEW + MODIFIED => NEW | MODIFIED
- NEW + MOVED => NEW | MOVED
- MODIFIED + REMOVED => REMOVED
- MODIFIED + MOVED => MODIFIED | MOVED
- MODIFIED + MODIFIED => MODIFIED
The combinations not listed above are not permitted.
In case of list items, the REMOVED flag is not used since the property will be physically removed from the property tree.
Also when the dirty flag of a children property changes, its parent is informed to update its MODIFIED flag if needed. This way a modification on a children property is propagated to parents in the form of a MODIFIED flag.
Internal Flags:
Internal flags are used by the implementation to keep some internal state. For these flags you should look into the implementation
- Author:
- Bogdan Stefanescu
- See Also:
-
- "<code>TestPropertyModel</code> for usage of property API"
-
Field Summary
Modifier and TypeFieldDescriptionstatic final int
A mask for public flags.static final int
A mask for the first 4 flags: NEW, REMOVED, MODIFIED, MOVED.static final int
Flag used to mark a property as dirty.static final int
Flag used to mark a property as dirty.static final int
Flag used to mark a property as new.static final int
Flag used to mark a property as phantom.static final int
Flag used to mark a property as dirty.static final int
No dirty flags set. -
Method Summary
Modifier and TypeMethodDescriptionvoid
accept
(PropertyVisitor visitor, Object arg) Method that implement the visitor pattern.addEmpty()
Creates an empty child property and adds it as a property to the list container.Inserts at the given position a new value to the list.Appends a new value to the list.void
Notify the property that its changes was stored so it can safely remove dirty flags.<T> T
convertTo
(Serializable value, Class<T> toType) Converts the given normalized value to the given type.get
(int index) Get the child property given it's index.Gets the child property having the given name.Get a collection over the children properties.Gets an iterator over the dirty children properties.int
Get the dirty flags that are set on this property.getField()
Gets the field corresponding to this property.getName()
Gets the property name.Gets the property parent.getRoot()
Gets the root property.Gets the document schema defining the property tree from which the property belongs.getType()
Get the type of the field corresponding to this property.getValue()
Gets the property normalized value.<T> T
Gets the property value as the given type.<T> T
Gets the value of the property resolved using the given path.Gets the value of the property resolved using the given path.Gets the property normalized value for write.getXPath()
Gets the xpath of this property.boolean
Whether or not this property has a default value.void
init
(Serializable value) Initializes the property with the given normalized value.boolean
Tests whether this property is of a map (complex) type.boolean
Whether this property is a container - this means the property value is a map or a list.boolean
isDirty()
Tests whether a property is dirty.boolean
only for SimpleDocumentModelboolean
isList()
Tests whether this property is of a list type.boolean
Tests if a property value was modified.boolean
isMoved()
Tests if a property value was moved to another index in the parent list if any.boolean
isNew()
Tests if this property is new (just created but not yet stored).boolean
isNormalized
(Object value) Checks if the given value is a normalized one.boolean
Tests if the property is a phantom.boolean
Whether the property is read only.boolean
Tests if a property is flagged as removed.boolean
Compare the two properties by content.boolean
isScalar()
Tests whether this property is of a scalar type.boolean
Returnstrue
if this property is flagged as secured in system.void
moveTo
(int index) Moves a property position into the parent container list.Creates a new and empty instance of a normalized value.Normalizes the given value as dictated by the property type.remove()
Removes this property from the tree.resolvePath
(String path) Same asresolvePath(Path)
but with a string path as argument.resolvePath
(Path path) Resolves the given path relative to the current property and return the property if any is found otherwise throws an exception.void
Sets the child property having the given name.void
setForceDirty
(boolean forceDirty) only for SimpleDocumentModelvoid
setReadOnly
(boolean value) Sets the read only flag.void
Sets a child property value given its index.void
Sets this property value.void
Sets the value of the property resolved using the given path.int
size()
Get the count of the children properties.boolean
validateType
(Class<?> type) Validates the given value type.Methods inherited from interface java.lang.Iterable
forEach, iterator, spliterator
-
Field Details
-
NONE
static final int NONENo dirty flags set.- See Also:
-
IS_NEW
static final int IS_NEWFlag used to mark a property as new. Property was added to a list.- See Also:
-
IS_MODIFIED
static final int IS_MODIFIEDFlag used to mark a property as dirty. Property value was modified.- See Also:
-
IS_REMOVED
static final int IS_REMOVEDFlag used to mark a property as dirty. Property was removed.- See Also:
-
IS_MOVED
static final int IS_MOVEDFlag used to mark a property as dirty. Property was moved to another index.- See Also:
-
IS_PHANTOM
static final int IS_PHANTOMFlag used to mark a property as phantom.- See Also:
-
IS_DIRTY
static final int IS_DIRTYA mask for the first 4 flags: NEW, REMOVED, MODIFIED, MOVED.- See Also:
-
DIRTY_MASK
static final int DIRTY_MASKA mask for public flags.- See Also:
-
-
Method Details
-
isNew
boolean isNew()Tests if this property is new (just created but not yet stored).A property is new when added to a collection. This is the typical state for a new property added to a list
- Returns:
- true if this property is new, false otherwise
-
isRemoved
boolean isRemoved()Tests if a property is flagged as removed. Removed properties are child property that were removed from their container.- Returns:
- if the property was removed, false otherwise
-
isModified
boolean isModified()Tests if a property value was modified.- Returns:
- if the property was removed, false otherwise
-
isMoved
boolean isMoved()Tests if a property value was moved to another index in the parent list if any.- Returns:
- if the property was removed, false otherwise
-
isPhantom
boolean isPhantom()Tests if the property is a phantom. This means it doesn't exists yet in the storage and it is not a new property. This is a placeholder for a property that is defined by the schema but was not yet set.- Returns:
- true if a phantom false otherwise
-
isDirty
boolean isDirty()Tests whether a property is dirty.This tests whether or not a dirty flag is set on the property.
- Returns:
- true if the property changed or is new
-
isForceDirty
boolean isForceDirty()only for SimpleDocumentModel -
setForceDirty
void setForceDirty(boolean forceDirty) only for SimpleDocumentModel -
getDirtyFlags
int getDirtyFlags()Get the dirty flags that are set on this property.- Returns:
- the dirty flags mask
-
clearDirtyFlags
void clearDirtyFlags()Notify the property that its changes was stored so it can safely remove dirty flags.Dirty flags are removed according to the type of the modifications. This way if the property was REMOVED it becomes a PHANTOM otherwise all dirty flags are cleared.
This method should be used by storage implementors to notify the property it should reset its dirty flags. Note that clearing dirty flags is not propagated to the parent property or to children. You need to clear dirty flags explicitly for each property.
-
isReadOnly
boolean isReadOnly()Whether the property is read only.- Returns:
- true if read only false otherwise
-
setReadOnly
void setReadOnly(boolean value) Sets the read only flag.- Parameters:
value
- true to set this property read only false otherwise
-
isSecured
boolean isSecured()Returnstrue
if this property is flagged as secured in system.- Since:
- 11.1
-
isComplex
boolean isComplex()Tests whether this property is of a map (complex) type.- Returns:
- true if the property is of map type, false otherwise
-
isList
boolean isList()Tests whether this property is of a list type.- Returns:
- true if the property is of list type, false otherwise
-
isScalar
boolean isScalar()Tests whether this property is of a scalar type.- Returns:
- true if the property is of a scalar type, false otherwise
-
isContainer
boolean isContainer()Whether this property is a container - this means the property value is a map or a list.Container properties don't have a scalar values. Container values are computed each time they are requested - by calling on of the
getValue
methods - by collecting the values of the child properties.- Returns:
- true if scalar false otherwise
-
hasDefaultValue
boolean hasDefaultValue()Whether or not this property has a default value. For complex property, this method will lookup in its children.- Returns:
- true if property has a default value
- Since:
- 11.1
-
getName
String getName()Gets the property name.- Returns:
- the property name
-
getXPath
String getXPath()Gets the xpath of this property.The xpath is of the form
pref:foo/mylist/123/elem
, of note:- there is no initial
/
- the schema prefix is only present if a prefix is configured for the base property's schema
- list elements indexes start at 0
- list elements aren't using the old syntax
foo/bar[123]/baz
but the new syntaxfoo/123/baz
- Returns:
- the xpath
- Since:
- 9.1
- there is no initial
-
getType
Type getType()Get the type of the field corresponding to this property.- Returns:
- the property type
-
getField
Field getField()Gets the field corresponding to this property.The field is the object defining the property. You can see the field as a java class and the property as a class instance
-
getParent
Property getParent()Gets the property parent.- Returns:
- the property parent for sub properties or null for top level properties
-
getSchema
Schema getSchema()Gets the document schema defining the property tree from which the property belongs.- Returns:
- the document schema owning the field corresponding to the property
-
getRoot
DocumentPart getRoot()Gets the root property.- Returns:
- the root property
-
init
Initializes the property with the given normalized value.The given value must be normalized - note that no check is done on that.
The phantom flag is unset by this operation.
This method should be used to initialize properties.
- Parameters:
value
- the normalized value to set- Throws:
PropertyException
-
setValue
Sets this property value. The value will be first normalized and then set.For complex or list properties the value will be set recursively (as a map or list value).
- Parameters:
value
- the value to set- Throws:
InvalidPropertyValueException
- if the given value type is not compatible with the expected value typePropertyException
-
getValue
Gets the property normalized value.Normalized values are of the java type that correspond to the field type.
- Returns:
- the property value, which may be null
- Throws:
PropertyException
-
getValueForWrite
Gets the property normalized value for write.Can be different fropm
getValue()
in cases where the property adapts the value it is given to store.- Returns:
- the property value to use for write, which may be null
- Throws:
PropertyException
- Since:
- 5.2.1
-
getValue
Gets the property value as the given type.The value is converted using the registered converter to the given type.
If conversion is not supported a runtime exception will be triggered.
- Returns:
- the property value, which may be null
- Throws:
PropertyException
-
remove
Removes this property from the tree.This method marks the property as dirty and sets its value to null.
- Returns:
- the old property value
- Throws:
PropertyException
-
get
Gets the child property having the given name.If the property is a scalar, this will return always null.
The given name should be the full name (i.e. prefixed name if any prefix exists).
If a non prefixed name is given, the first child property having the given local name will be returned.
Relative paths are not resolved. THis method is intended to lookup direct children. For path lookups use
resolvePath(String)
instead.- Parameters:
name
- the child property name (the full name including the prefix if any)- Returns:
- the child property if any null if no child property with that name is found or if the property is a scalar
- Throws:
UnsupportedOperationException
- if the property is a scalar property (doesn't have children)PropertyNotFoundException
- if the child property is not found in the type definition
-
get
Get the child property given it's index. This operation is mandatory for List properties.If this method is not supported an
UnsupportedOperationException
must be thrownRelative paths are not resolved. THis method is intended to lookup direct chilren. For path lookups, use
resolvePath(String)
instead.- Returns:
- the child property if any null if no child property with that name is found or if the property is a scalar
- Throws:
UnsupportedOperationException
- if the property is a scalar property (doesn't have children)PropertyNotFoundException
- if the child property is not found in the type definition
-
set
Sets the child property having the given name.The given name should be the full name (i.e. prefixed name if any prefix exists).
If a non prefixed name is given, the first child property having the given local name will be returned.
Relative paths are not resolved. This method is intended to lookup direct children. For path lookups use
resolvePath(String)
instead.- Parameters:
name
- the child property name (the full name including the prefix if any)property
- the child property to set- Throws:
UnsupportedOperationException
- if the current property is a scalar property (doesn't have children)PropertyNotFoundException
- if the child property is not found in the type definitionPropertyException
- Since:
- 11.1
-
setValue
Sets a child property value given its index. This method is required only for List properties.If this method is not supported, an
UnsupportedOperationException
must be thrown.This method will mark the child value as dirty for existing values and in the case of map properties it will mark phantom properties as new properties.
- Parameters:
value
- the new value- Throws:
UnsupportedOperationException
- if the property is a scalar property (doesn't have children)PropertyNotFoundException
- if the child property is not found in the type definitionPropertyException
-
getChildren
Collection<Property> getChildren()Get a collection over the children properties. This includes all children including phantom ones (those who are not yet set by the user).The returned collection is ordered for list properties, and unordered for complex properties
Be aware that this method is creating phantom child properties for all schema fields that are not yet set.
- Returns:
- the children properties
-
size
int size()Get the count of the children properties. This includes phantom properties. So the returned size will be equal to the one returned by the propertyComplexType.getFieldsCount()
.- Returns:
- the children properties count
-
addValue
Appends a new value to the list. A new property will be created to store the given value and appended to the children list.The created property will be marked as
isNew()
.- Returns:
- the added property
- Throws:
PropertyException
-
addValue
Inserts at the given position a new value to the list. A new property will be created to store the given value and appended to the children list.The created property will be marked as
isNew()
.- Parameters:
index
- the position to insert the value- Returns:
- the added property
- Throws:
PropertyException
-
addEmpty
Creates an empty child property and adds it as a property to the list container.This method is useful to construct lists.
- Returns:
- the created property
- Throws:
PropertyException
-
moveTo
void moveTo(int index) Moves a property position into the parent container list.This method applies only for list item properties. The given index includes removed properties.
- Parameters:
index
- the position in the parent container to move this property- Throws:
UnsupportedOperationException
- if the operation is not supported by the target property
-
resolvePath
Same asresolvePath(Path)
but with a string path as argument. This is the same as callingresolvePath(new Path(path))
.- Parameters:
path
- the string path to resolve.- Returns:
- the resolved property
- Throws:
PropertyNotFoundException
- if the path cannot be resolved
-
resolvePath
Resolves the given path relative to the current property and return the property if any is found otherwise throws an exception.The path format is a subset of XPath. Thus, / is used as path element separator, [n] for list element indexes. Attribute separator '@' are not supported since all properties are assumed to be elements. Also you .. and . can be used as element names.
Example of paths:
dc:title
attachments/item[2]/mimeType
../dc:title
- Parameters:
path
- the path to resolve.- Returns:
- the resolved property
- Throws:
PropertyNotFoundException
- if the path cannot be resolved
-
getValue
Gets the value of the property resolved using the given path.This method is a shortcut for:
resolvePath(path).getValue()
.- Parameters:
path
- the path to the property- Returns:
- the property value
- Throws:
PropertyException
-
getValue
Gets the value of the property resolved using the given path.The value will be converted to the given type if possible, otherwise an exception will be thrown.
This method is a shortcut for:
resolvePath(path).getValue(type)
.- Type Parameters:
T
- The type of the value to return- Parameters:
type
- the class of the valuepath
- the java path of the property value- Returns:
- the value
- Throws:
PropertyException
-
setValue
Sets the value of the property resolved using the given path.This method is a shortcut for:
resolvePath(path).setValue(value)
.- Parameters:
path
- the property pathvalue
- the value- Throws:
PropertyException
-
normalize
Normalizes the given value as dictated by the property type.Normalized values are the ones that are used for transportation over the net and that are given to the storage implementation to be stored in the repository
Normalized values must be
Serializable
If the given value is already normalized it will be returned back.
- Parameters:
value
- the value to normalize according to the property type- Returns:
- the normalized value
- Throws:
PropertyConversionException
-
isNormalized
Checks if the given value is a normalized one. This means the value has a type that is normalized.Null values are considered as normalized.
- Parameters:
value
- the value to check- Returns:
- true if the value is normalized false otherwise
-
convertTo
Converts the given normalized value to the given type.If the value has already the given type it will be returned back.
- Parameters:
value
- the normalized value to converttoType
- the conversion type- Returns:
- the converted value, which may be null
- Throws:
PropertyConversionException
- if the conversion cannot be made because of type incompatibilities
-
validateType
Validates the given value type.Tests if the given value type can be converted to a normalized type and thus a value of this type can be set to that property.
- Parameters:
type
- the type to validate- Returns:
- true if the type is valid, false otherwise
-
newInstance
Object newInstance()Creates a new and empty instance of a normalized value.Empty is used in the sense of a value that has not been initialized or can be considered as an empty value. For example for the
String
type the empty value will be the empty string ""- Returns:
- the empty instance the empty instance, or null for some implementations
-
accept
Method that implement the visitor pattern.The visitor must return null to stop visiting children otherwise a context object that will be passed as the arg argument to children
- Parameters:
visitor
- the visitor to acceptarg
- an argument passed to the visitor. This should be used by the visitor to carry on the visiting context.- Throws:
PropertyException
-
isSameAs
Compare the two properties by content.- Returns:
- true If the properties have a similar content, otherwise false
- Throws:
PropertyException
-
getDirtyChildren
Gets an iterator over the dirty children properties.- Returns:
- the iterator
-
getObjectResolver
PropertyObjectResolver getObjectResolver()- Returns:
- A
PropertyObjectResolver
to manage this property reference to external entities, null if this property's type has no resolver. - Since:
- 7.1
-