Adaptive Objects
Throughout these guides, we will refer to objects, many of which were initially created in JSON format before being generated into native C structures and stored in physical memory. For convenience, we will often represent objects in the guides in JSON format. To learn more about the JSON format, please visit http://www.json.org.
Adaptive Object Model
Adaptive Objects
are similar to many Object
paradigms you may have been introduced to in a programming or data
structure lessons. They contain data in a structured way, just as
key/values, dictionaries or hashes encapsulate data in other popular
languages. With Adaptive Objects
, the object
that contains data is described by another object, called its
Object Type
. The keys and values on the Adaptive
Object are referred to as Adaptive Properties
and the definitions of those properties, which are contained within
the Object Type definition, are called Property
Types
. These definitions provide us with useful metadata
that can be used for data validation, user interface representation,
authorization controls, and even data transformation and generation.
The following diagram illustrates these relationships, and is
commonly referred to as the Type Square Pattern:
An Adaptive Object may have one or more Adaptive Properties. Likewise, an Object Type may have one or more Property Types. Moreover, an Object Type describes one or more Adaptive Object instances, just as an Adaptive Property Type may describe one or more Adaptive Properties. Let's examine these objects, in detail, in order to get a better sense of how they are related.
Let's define an Adaptive Object of interest with something that is
familiar. As a Person
, I have some properties
that describe me. For example, I have a First Name
,
a Last Name
and an Age
.
{
"First Name": "Kevin",
"Last Name": "Smith",
"Age": 40
}
Other people also have names and ages. Therefore, we can describe a
Person using an Object Type. This Object Type contains Property
Types, declared under a special name,
propertyTypes
, for "First Name", "Last Name" and
"Age". In this example, you will find "First Name", "Last Name" and
"Age" all have Property Type values of structured objects that
contain information about them. "First Name" and "Last Name" have a
dataType
of string
and
Age
is described as an
integer
. Both have additional
description
properties that provide additional:
{
"propertyTypes": {
"First Name": {
"dataType": "string",
"description" "This is a person's first name."
},
"Last Name": {
"dataType": "string",
"description": "This is a person's last name."
},
"Age": {
"dataType": "integer",
"description": "This is a person's age, in years."
}
}
}
This very simple example also demonstrates an aspect of Adaptive
Objects that may not seem obvious on the surface. "Object Type"
Person is also an Adaptive Object, and "propertyTypes" here is
also an Adaptive Property, whose value is an object containing
"First Name", "Last Name" and "Age". It's only when we establish
the Object Type relationship between these two that we apply
semantic meaning to this object. In fact, the Person Object Type in
this example also has an Object Type, called
_AdaptiveObjectType_
, which describes how an
Adaptive Object Type is structured. Likewise, the object type
_AdaptivePropertyType_
, is used to describe how
an Adaptive Property Type is structured. These two special objects
are defined by Core as compiled object definitions. We can change
the Person Object Type, because it's an object not defined to core,
but we cannot change "_AdaptiveObjectType_" or
"_AdaptivePropertyType_" without recompiling Adaptive Framework.
Object Types and Property Types
In the previous section, we demonstrated how an Object Type and its Property Types can describe an instance of an Object. We also introduced the idea that Object Types and Property Types are also objects, themselves, described by "_AdaptiveObjectType_" and "_AdaptivePropertyType_" and defined as compiled-in objects to Adaptive Framework Core. Let's first look at what makes an Adaptive Property Type, using the example from the previous section. The Adaptive Property "First Name" had a Property Type definition that included a property called "dataType". The dataType property is an important one that we will get into more details later. Here is a more complete list of properties that define a Property Type:
Property | Description |
---|---|
additionalConstraints | Additional constraint for the value. |
allowQuery | If false, this value can NEVER be queried. If true, this value can be queried if allowed by authorization policy. |
allowWrite | If true, the value can be written if allowed by authorization policy as long as allowChange for the instance is also true. If false, the value can only be written if required is true when adding a new object. |
allowedValues | This is a list of the allowed values for this adaptive value. The dataType and dataTypeParameter of these values is the same as for the adaptive value itself. |
brief | This is a predicate for this value, with the first letter capitalized and without a trailing period. |
collectionURIs | This is the URIs of the collections that this value is a part of and preferably a URIs that can be used to locate an object with objects type _AdaptiveCollection_ that describes the collections. If a collection is used outside of the local instance, it should be a full URI. The URI can also be a local path of the collection object or just the collection's objectId if it resides in the in the same adaptor. |
contextType | For data types that are evaluated (evaluate property true), this is the context type used for the evaluation. |
dataType | Data type of this value. |
dataTypeParameter | See the data type's dataTypeParameterType property to determine how to interpret this. |
dataTypeParameterFormatted | This is the same as dataTypeParameter with possible comments and whitespace. This is especially useful for data type function to document its signature. If this property is not present, dataTypeParameter can be used in its place. |
defaultValue | This is the default value. The dataType and dataTypeParameter properties apply to this value. If needed, this value will be normalized. |
description | The description of this value. |
hints | Hints that can optionally be used by UI to render this value. |
label | Label used to identify this value. |
maxLength | This is maximum length of the to_string() for this value. If not specified, there is no maximum length. |
maxNormalLength | This is maximum normal length of the to_string() for this value. If not specified, maxLength is used. |
maxValue | This is the maximum for this value. If not specified, there is no maximum value. The dataType and dataTypeParameter of this value is the same as for the value. |
minLength | This is minimum length of the to_string() for this value. If not specified, there is no minimum length. |
minValue | This is the minimum for this. If not specified, there is no minimum value. The dataType and dataTypeParameter of this value is the same as for the value. |
originURI | The origin URI of this value meta. Descendant object types should be used for any deviations. This URI may be different from the URI within this instance of Adaptive Framework. |
possibleValues | Possible values of this value. This can be the typed value or the string value. |
referenceURI | URI of more reference information about this value meta. |
required | Indicates that value is required. |
runtime | This is only valid for runtime object types. These are objects that are accessed with adaptorId afw. See afw_runtime.h for more information. |
skeleton | This is a skeleton example that can optionally be used by an application as an initial value. For example, if this is a new data type hybrid value, this can be the text used to prime the edit window with sample Adaptive Script code including comments. |
tags | This is a list of keywords and terms associated with values with the meta. An instance of _AdaptiveTag_ can be used to define and document the purpose of a tag. Adaptive Framework reserves the definition of all tags that begin with "_Adaptive". |
testDataParameter | This contains additional information about values with this meta that is used to produce test data. |
unique | Value of property must be unique within object type. |
valueInfId | This is a runtime property that is the implementation id of the value interface. |
Object Meta
We've now covered Object Types and Property Types and how
useful they are in describing an object or collection of objects by
extracting their "metadata" and storing it in a common place. In
addition to Object Types and Property Types, all objects contain
some additional metadata that is useful for Adaptive Framework
Core, Adaptors, and even clients. As you may have already guessed,
these too are documented and stored in a special Object Type called
_AdaptiveMeta_
, which looks like the following:
Property | Description |
---|---|
allowChange | If false this object is read only. If true, the object can be changed unless denied by authorization policy or by the adaptor. |
allowDelete | If false this object can not be deleted. If true, the object can be deleted unless denied by authorization policy or by the adaptor. |
ancestorPaths | This is all of the associated object's ancestor paths. |
description | The optional description of the object. |
errors | Object errors. |
hasErrors | Indicates that at least one errors property exists in the meta. |
objectId | This the id that uniquely defines the associated object when combined with its adaptor id and object type id within an Adaptive Framework environment. The objectId should be considered opaque unless the associated adaptor or mapping specifies otherwise. |
objectType | This the id of the associated object's object type within the object's adaptor. |
objectTypes | This is a object with a property with a name of the objectType for each _AdaptiveObjectType_ used by this object and all of its embedded objects. |
parentPaths | This is the associated object's direct parent paths. |
path | This is the associated object's path within an Adaptive Framework environment. The path is of the form "/adaptorId/objectType/objectId". |
propertyTypes | This is additional meta information that overrides and supplements property type information for specific associated object's properties. The property name of properties in this object corresponds to properties with the same name in the associated object. |
reconcilable | This strings represents a stateful token, used by the reconcile_object() method, to perform a reconcile request on an object that has been obtained in reconcilable mode. |
resolvedParentPaths | This is the associated object's direct parent paths before they were resolved by object option composite. |
Absolute Object Paths
Object Paths
Every Adaptive Object in Adaptive Framework is uniquely identified
by an Object Path
of the form:
/<adaptorId>/<objectTypeId>/<objectId>
An objectId
is the unique object identifier of
the entity, optionally followed by a slash-separated representation
of embedded properties.
/<adaptorId</<objectType</objectId
/<adaptorId</<objectType</objectId/propertyName
/<adaptorId</<objectType</objectId/propertyNameA/propertyNameB
If the property value is a list, a property name can be followed
with a zero based integer index enclosed in square brackets
([n]
).
/<adaptorId>/<objectTypeId>/<objectId>/<propertyNameA>[<index>]
/<adaptorId>/<objectTypeId>/<objectId>/<propertyNameA>[<index>]/<property name>
/<adaptorId>/<objectTypeId>/<objectId>/<propertyNameA>/<propertyNameB>[<index>]
/<adaptorId>/<objectTypeId>/<objectId>/<propertyNameA>[<index>]/<propertyNameB>[<index>]
Relative Adaptive Object Path
An Object URI
can contain a path as defined
above, a full URI with scheme, or a relative path. If a path is
relative, it must be resolved relative to a supplied path.
If a relative path begins with a /
, its structure
is the same as an absolute path with *
used in
place of <adaptorId>, <objectTypeId>,
and each shashed part of <objectId> to use the
corresponding value from the supplied path. The
<objectId> can also be
**
to indicate that the entire
<objectId> including all slash-separated properties
should be used.
If a relative path does not begin with a /
, the
<adaptorId>
and
<objectTypeId>
from the supplied path
will be used and the relative path will be used as the
/<objectId>
. The character sequence
/*
can be used as a corresponding part from the
supplied path's /<objectId>
.
The following are some examples of relative references using the
given path:
/adaptorId/objectTypeId/objectId/prop1/prop2
:
Relative Path | Resolved Path |
---|---|
objectId2 | /adaptorId/objectTypeId/objectId2 |
objectId2/prop4 | /adaptorId/objectTypeId/objectId2/prop4 |
/*/objectTypeId2/objectId3/prop5 | /adaptorId/objectTypeId2/objectId3/prop5 |
/*/objectTypeId2/*/prop5 | /adaptorId/objectTypeId2/objectId/prop5 |
*/prop6 | /adaptorId/objectTypeId/objectId/prop6 |
*/*/prop7 | /adaptorId/objectTypeId/objectId/prop1/prop7 |
/adaptorId2/*/** | /adaptorId2/objectTypeId/objectId/prop1/prop2 |
/*/*/** | /adaptorId/objectTypeId/objectId/prop1/prop2 |
/*/*/* | /adaptorId/objectTypeId/objectId |
Embedded Objects
Some Adaptive Objects may have properties that also contain
objects. We call these objects Embedded Objects
.
The following object illustrates an example of an Embedded Object,
referenced by the Embedding Property
address:
{
"name": "John Doe",
"address": {
"street": "123 Main St.",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
}
Inheritance
Adaptive Objects also allow for inheritance, so that Adaptive Objects
can borrow properties from other Adaptive Objects. This is done
through a special "meta" property called parentPaths
:
{
"_meta_": {
"parentPaths": [
"/registry/_AdaptiveObjectType_/Person"
]
},
"employeeId": "12345",
"officeAddress": {
"street": "123 Main St.",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
}
When observing an Adaptive Object that contains a parent path, the
Object Option composite
can be specified to
resolve the parent and include their properties in the returned
object. The following is an example of the same object with the
composite
option specified:
{
"first": "John",
"last": "Doe",
"age": 42,
"employeeId": "12345",
"officeAddress": {
"street": "123 Main St.",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
}
Object Options
Adaptive Objects can be provided with Object
Options
that influence how an object should be displayed,
including what metadata should be provided, or how Adaptive Property
values should be interpreted or represented. The options that one
uses is up to the application or client that is consuming or
providing the objects. For example, a UI may require a lot of
metadata to understand how to render properties on a screen, while a
programmatic parser may request property values to be encoded in a
way that's convenient for the client. Below is a table of the
object options that are available.
Property | Description |
---|---|
checkRequired | Indicates that object should be checked for missing required properties. This option implies the normalize option. |
composite | Indicates that both direct and embedded inheritance should be performed. |
debug | This will cause the errors in object meta to include additional debug information. If not specified, only the message will be included. |
includeDefaultValues | This indicates that default property values should be included. This option implies the normalize option. |
includeDescendentObjectTypes | This only applies to retrieve objects requests and indicates that objects with the supplied object type along with objects with any of its descendent object types should be included in the search. |
inheritedFrom | Indicates that the inheritedFrom property in meta propertyTypes.<propertyName>, where <propertyName> is the associated property name, should be set. This option is ignored unless composite option is also set. |
integersAsString | This overrides the largeIntegersAsString option. If neither the integersAsString or large_integer_as_string is specified, integers will remain integers. If this option is specified, all data type integer values will be converted to the string data type.\n\nThis options is useful if a content type is used that represents integers as double (floating point) values. |
largeIntegersAsString | This option is overridden by the integersAsString option.\n\nIf this option is specified, all integers that have a magnitude that exceeds plus or minus 9007199254740991 (2^53-1) will be converted to the string data type.\n\nThis options is useful if integers of a content type are interpreted as double (floating point) values, but integers are normally small enough to be represented properly. An example is Javascript's use of JSON. |
metaFull | This indicates that all meta, including properties that are not part of delta from object type, are to be included. This overrides metaLimited. |
metaLimited | Indicates that only requested and essential (parentPaths) meta is returned. |
normalize | Indicates that each object's object type should be processed, assigned each embedded object's object type, converting any properties to their correct data type, plus computing values when needed. If there is dataType or dataTypeParameter information available during normalization that is not in the associated _AdaptiveObjectType_, it will be added at the appropriate place in the object's meta.\n\nUse the includeDefaultValues option to include default values. |
objectId | Indicates that objectId property should be included in the meta for entity objects. |
objectType | Indicates that objectType property should be included in the meta for entity and embedded objects, if assigned. |
objectTypes | Indicates that the objectTypes property should be added to the meta of the entity containing a property of each object type used by the entity and all of its embedded objects. This option implies normalize. |
path | Indicates that meta path should be included for entity objects. |
pathEmbedded | Indicates that meta path should be included for embedded objects. |
reconcilable | Indicates that meta reconcilable should be included in entity's meta. If this is specified on a get_object or retrieve_objects request and a retrieved object is changed, calling reconcile_object() with the changed object will use the information in meta reconcilable to produce a modify request for only the changes. The reconcilable option assumes the path option and possibly other options as needed. |
resolvedParentPaths | Indicates that meta resolvedParentPaths should be included with a list of parent paths that have been resolved by the composite option. |
typedValues | *** EXPERIMENTAL *** This option indicates that a value's type information (valueType, dataType, and objectType) should be included with each value. See the content type to determines how this is represented. |
whitespace | This option can be optionally supported by a content type implementation. In the case of JSON, this indicates that newline, space, and tab characters should be included to make the output more readable. |