Package org.jboss.dna.graph.property

Nodes in a graph contain properties, and this package defines the interfaces, classes and exceptions for representing and working with properties and their values.

See:
          Description

Interface Summary
Binary Value holder for binary data.
BinaryFactory A factory for creating Binary instances.
DateTime An immutable date-time class that represents an instance in time.
DateTimeFactory A factory for creating date-time instants.
Name A qualified name consisting of a namespace and a local name.
NameFactory A factory for creating names.
NamespaceRegistry Registry of namespaces, which are used to provide isolated and independent domains for names.
NamespaceRegistry.Namespace Representation of a single namespace at a single point in time.
Path An object representation of a node path within a repository.
Path.Segment Representation of the segments that occur within a path.
PathFactory A factory for creating paths.
Property Representation of a property consisting of a name and value(s).
PropertyFactory  
Readable An interface defining methods to obtain a "readable" string representation.
Reference A representation of a reference to another node.
UuidFactory A factory for creating UUID instances.
ValueFactories The set of standard ValueFactory instances.
ValueFactory<T> A factory for Property values.
 

Class Summary
PathExpression An expression that defines an acceptable path using a regular-expression-like language.
PathExpression.Matcher  
ValueComparators  
 

Enum Summary
PropertyType  
 

Exception Summary
InvalidPathException  
InvalidPathExpressionException  
IoException  
NamespaceException  
PathNotFoundException  
ReferentialIntegrityException  
ValueFormatException  
 

Package org.jboss.dna.graph.property Description

Nodes in a graph contain properties, and this package defines the interfaces, classes and exceptions for representing and working with properties and their values.

A property consists of a name and a set of values. A property name is represented by Name, and is defined as a local name in a namespace. Property values can be of any type, although there are specific interfaces for the known types:

Creating and converting property values

The design of properties and their values was centered around one key principle: when using a property value, you often don't care what type the property value actually is, but instead care about converting it to a property type that you know how to work with. For example, you may be working with a property that represents a date, and you want to work with the value as a DateTime object, regardless of whether the values are actually String, DateTime, Binary, or even Calendar or Date instances. You know its should be a date, so you want to get a value that behaves as a date.

This notion of working with a desired type implies the ability to convert from one value type to another. And in fact, creating values is really just converting from "other" types into a known type. So, we can use the factory design pattern to have a single concept of a component that creates property values from a variety of types. But by using generics, we can use a single factory interface that has the same methods for creating value objects, but make the return type specific to the type we want to create.

The ValueFactory interface is defined as follows:

   public interface ValueFactory<T> {
       T create( String value ) throws ValueFormatException;
       T create( int value ) throws ValueFormatException;
       T create( long value ) throws ValueFormatException;
       T create( double value ) throws ValueFormatException;
       ...
       T create( java.util.Date value ) throws ValueFormatException;
       T create( java.util.Calendar value ) throws ValueFormatException;
       T create( DateTime value ) throws ValueFormatException;
       ...
       T create( java.util.UUID value ) throws ValueFormatException;
       T create( java.net.URI value ) throws ValueFormatException;
       T create( Reference value ) throws ValueFormatException;
       T create( Name value ) throws ValueFormatException;
       T create( Path value ) throws ValueFormatException;
       ...
       T create( InputStream value, long approximateLength ) throws ValueFormatException;
       T create( Reader value, long approximateLength ) throws ValueFormatException;
       T create( Binary value ) throws ValueFormatException;
       ...
       T[] create( String[] value ) throws ValueFormatException;
       T[] create( int[] value ) throws ValueFormatException;
       T[] create( long[] value ) throws ValueFormatException;
       T[] create( double[] value ) throws ValueFormatException;
       ...
   }
 
Notice that all the methods are called create, and most take a single parameter whose type is one of the known types, a primitive, or a number of "other" types frequently encountered. (The create(...) methods that take an InputStream or Reader have a second parameter that specifies the length of the data.) Finally, note that almost all of the create methods have a form that each take an array of values and return an array of T.

These methods also all throw a ValueFormatException, in case the supplied parameter cannot be converted to the desired type. In many cases, there is a conversion (e.g., from the String "123" to an integer), but there certainly are cases where no conversion is allowed (e.g., the String "a123" cannot be converted to an integer, and a Name cannot be converted to a boolean). All types can be converted to a string, and all factories support converting that string back to its original form.

The factory for creating DateTime objects would then be an implementation of ValueFactory<DateTime>, a factory for creating Binary objects would be an implementation of ValueFactory<Binary, and so on. In some cases, we'd like to add additional forms of create(...) for specific values, and we can do this by extending a typed ValueFactory. For example, the DateTimeFactory adds more methods for creating DateTime objects for the current time, current time in UTC, from another time and an offset, and from individual field values:

   public interface DateTimeFactory extends ValueFactories<DateTime> {
       DateTime create();
       DateTime createUtc();
       DateTime create( DateTime original, long offsetInMillis );
       DateTime create( int year, int monthOfYear, int dayOfMonth,
                        int hourOfDay, int minuteOfHour, int secondOfMinute, int millisecondsOfSecond );
       DateTime create( int year, int monthOfYear, int dayOfMonth,
                        int hourOfDay, int minuteOfHour, int secondOfMinute, int millisecondsOfSecond,
                        int timeZoneOffsetHours );
       DateTime create( int year, int monthOfYear, int dayOfMonth,
                        int hourOfDay, int minuteOfHour, int secondOfMinute, int millisecondsOfSecond,
                        String timeZoneId );
   }
 
There are specialized factory interfaces for several other types, including PathFactory, NameFactory, and UuidFactory.

The ValueFactories interface collects all the factories into a single spot:

   public interface ValueFactories<T> {
       ValueFactory<String> getStringFactory();
       ValueFactory<Binary> getBinaryFactory();
       ValueFactory<Long> getLongFactory();
       ValueFactory<Double> getDoubleFactory();
       ValueFactory<BigDecimal> getDecimalFactory();
       DateTimeFactory getDateFactory();
       ValueFactory<Boolean> getBooleanFactory();
       NameFactory getNameFactory();
       ValueFactory<Reference> getReferenceFactory();
       PathFactory getPathFactory();
       ValueFactory<URI> getUriFactory();
       UuidFactory getUuidFactory();
       ValueFactory<Object> getObjectFactory();
       
       ValueFactory<?> getValueFactory( PropertyType type );
       ValueFactory<?> getValueFactory( Object prototype );
   }
 
This allows us to programmatically get the correct factory for a type known at compile time, but also to obtain the correct factory given a prototype object or the enumeration literal representing the desired type. Thus, the following code compiles:
    ValueFactories factories = ...
    DateTime now = factories.getDateFactory.create();
    String stringValue = factories.getStringFactory().create(now);
 
A ValueFactories is provided as part of the ExecutionContext. In this way, the environment may use a different implementation of one or more factories.

Comparing property values

Because we have a mixture of standard Java types and custom interfaces for property values, we need a set of Comparator implementations that allow us to compare property values. The ValueComparators class defines a number of singleton comparators that can be used. Plus, the PropertyType enumeration has the ability to get the comparator for the specific type (e.g., PropertyType.BINARY.getComparator()).



Copyright © 2008-Present JBoss a division of Red Hat. All Rights Reserved.