A Practical Guide on Node Types in onedb
onedb is at its heart a cloud-based platform to connect pieces of information from various applications. These 'pieces of information' are represented and accessed in various ways in the onedb API.
The article "onedb Architecture and Design" provides a conceptual definition of most ways in which these 'pieces of information' are represented and the article "onedb Tutorial: Getting Started and First Steps" uses the various representations extensively.
In addition to the two articles mentioned above, this article provides a practical guide to understand and use the various data representations in onedb. In particular, the following four representations are discussed:
Nodes are the central component of onedb's data model. Basically, every piece of information be it a basic data type such as
Integer, etc. a custom object (
new MyPerson()) or onedb object (
One.newNode(..)) is managed as a node by the onedb engine.
However, only those objects are nodes, which have been appended and or loaded using the onedb API. For instance, in the following example
text1 is not a node while
String text1="I am just another string"; String text2="I will be a node"; One.append(text2).to(root).in(client);
Every node managed by a onedb client has got an address and an identity as described in the following section.
2. Addresses and Identities
Nodes in onedb are identified by a global unique identifier. These global unique identifiers are encoded as resolvable Uniform Resource Identifiers (URIs).
Hence, every piece of information in onedb has a unique identity, which can be expressed in form of a resolvable address.
Examples for such resolvable addresses usually look as follows:
https://u1.linnk.it/4hxdr8/query/bob https://u1.linnk.it/zednuw/types/customer https://u1.linnk.it/4hxdr8/query/This_is_a_1
Most operations in the One API do not work with addresses directly but use so called references. A reference is nothing more than a simple wrapper object around an address.
onedb favors the usage of addresses 'wrapped' in reference objects over simply supplying an address in form of a
String object to distinguish objects, which by chance hold a value which 'looks like' an URI, from objects, which are meant to represent links to entities within onedb.
Given an address in text form, it is very easy to create references...
OneTypedReference<?> reference1 = One.reference("https://u1.linnk.it/4hxdr8/query/bob"); OneTypedReference<?> reference2 = One.newNode("https://u1.linnk.it/4hxdr8/query/bob").asReference(); // reference1.equals(reference2) == true
... and to obtain the address, which is wrapped by a reference object:
String address1 = reference1.getId(); // address1.equals("https://u1.linnk.it/4hxdr8/query/bob") == true
Moreover, for every object that has been added to a onedb client, a reference can be determined:
String text1="I will be a node"; One.append(text1).to(lr.root()).in(client); OneTypedReference<Object> ref = One.reference((Object) text1).in(client);
Note in the example above that the
text1 object has been cast to
Object in the invocation of the
One.reference(..) operation. This is necessary for the API to know that no address but a generic object is passed to the operation. For other types of objects (e.g.
Integer) this explicit cast to
Object is not necessary.
References can also be used to obtain the resolved object of a node. For instance, the resolved object of the node
text1 in the example above would be "I will be a node". The resolved object of a node given its reference can be obtained as follows:
Integer value1=42; One.append(value1).to(lr.root()).in(client); OneTypedReference<Integer> ref = One.reference(value1).in(client); Integer value = One.dereference(ref).in(client); // value.equals(42) == true
4. Value Nodes
While virtually any Java object can become a node (given the object's class implements the
Serializable interface), there is one special kind of object, which can be added to a onedb client: value nodes.
These objects are special in that they 'know' their own address. For instance, the object
value1 above is of the class
Integer and there is therefore no possibility this object would know its own address; since the class
Integer is final in Java and no additional methods/attributes can be defined for instance of this class.
OneNode is used to denote classes which have knowledge of their own address. This interface defines a single method
getId(), which will return the address of the node/object. As it can be seen above, the mentioned reference objects belong to this type of objects.
Value nodes are a special type of object within the
OneNode category. They are nodes, which implement the interface
OneValue<Type extends Serializable> These nodes, apart from knowing their own address, define a value object of any type implementing the Serializable interface. This object can be accessed using the method
In the following example, a value node
bob is created and its two properties address and decorated object are accessed:
OneValue<String> bob = One.newNode("bob").at("https://u1.linnk.it/4hxdr8/query/bob"); bob.getId(); // == "https://u1.linnk.it/4hxdr8/query/bob" bob.getValue(); // == "bob"
Value nodes can turned into back and forth from reference to resolved object like any other object:
OneTypedReference<OneValue<String>> ref = One.reference(bob); OneValue<String> value = One.dereference(ref).in(client); value.getValue(); // == "bob"
Note that the call to
One.reference(..) for the value node is made without the addition
.in(client) as has been done above for the
Integer objects. The client does not need to be specified for determining the reference of any object, which by itself 'knows' its own address.
It is usually a good practice to wrap objects whenever possible into value nodes. This allows for better performance, since the onedb engine does not have to derive the address of nodes from their object identity. Since object identities can also change in often unexpected ways, it is also usually safer to work with value objects.
The easiest way to define value nodes is generally by defining the
.atAddress(...) parameter when appending a new object to an existing node. For instance, in the following example a new value node with the value
alice is appended to the node
root with the address
./alice relative to the root node's address:
Given the root node is defined at the address
http://u1.linnk.it/example/root, this append statement would result in the creation of the following node arrangement:
One.value("root").at("http://u1.linnk.it/example/root") --> One.value("alice").at("http://u1.linnk.it/example/root/alice")
This article has discussed the various ways in which data is represented and accessed using the onedb client. Essentially, all data is encoded in form of Java objects:
- Any Java object can be turned into nodes by appending it to node in a onedb client.
- Java objects, which are managed as nodes, have a globally unique address.
- This address can be used to define a lightweight (and portable) reference to the Java object.
- References can used to resolve the original defined Java object.
- Java objects can be wrapped in special value nodes, which allow the onedb engine to manage these objects more effectively and securely.