#12 Oids
Posted: Fri Nov 04, 2011 3:04 pm
This bulletin is a compilation of questions answered by Jade Support in regard to oids and their usage.
A schema is available upon request from Jade Support that contains coded examples for all of the questions discussed below.
Class Number and Class ID
An oid may not be quite what you think it is…
To most developers, an oid exists in the following format: <class number>.<instance number>
…however internally oids are represented as: <class ID>.<instance number>
The class ID is an encoded number based on the class number and other information such as the persistence of the object.
It is important to understand which representation is being used\given from the context.
For example:
More generally, why is it preferable to use String::asObject() rather than String::asOid() and Object::getObjectStringForObject() rather than Object::getOidString()? They seem to return exactly the same.
Context
This question comes from JADE par #38081 where the user had used a hard coded string based on a class number to retrieve an object but unexpectedly incurred error 4, Object not found. The code used was:
In JADE 6.0.19 the range of available class numbers for user defined classes was extended. Prior to JADE 6.0.19 the range was from 2048 to 16384. At the time of writing (current release is 6.3.09) the range of available user class numbers is 2048 to 19978 (excluding transient only classes, which are discussed below). Note the use of a class having number 16385 in the examples below; this is the number of the first class in the extended range.
The existing methods (getOidStringForObject(), asOid()) have not changed in their behaviour. However, you will obtain unexpected results when using these methods on oids where the class number is greater than the old class number limit (16384).
Unexpected behaviour can result if anything other than a class number is passed to asObject(), and unexpected behaviour can result if anything other than a class ID is passed to asOid()*.
This is due to the coding system applied to object identifiers that affects existing methods String::asOid() and Object::getOidStringForObject().
The new methods function such that they always take and produce 'literal' (un-encoded) class numbers (i.e. class numbers that match those you observe in the Class Browser).
How Does the Encoding Between Class Number and Class ID Work?
The encoding can be implied by noting such things as:
Is it Safe to Store Oids as Strings For Later Use?
It is not safe practice to use oids explicitly in your code other than for debugging purposes. As described above, the internal mechanism for coding oids are subject to change* and if the recommended interfaces are used then it is not necessary to understand the internal encoding mechanisms.
It is much safer to:
Two-Part (short), Three-Part (mid) and Five-Part (long) Oids
Simple objects (objects that are not collections or collection block structures) are represented by a two part oid, as described above.
Exclusive collections (and slobs and blobs) are represented by a five part oid:
<class ID>.<instance ID>.<parent class ID>.<sub level>.<sub ID>
Where Class ID represents the class of the child object (zero for a slob or blob), Instance ID is the instance of the parent object, Parent class Id is the class Id of the parent object, Sub level and sub Id describe the location where the reference parent->child is defined in the class hierarchy. Sub level describes the number of classes from Object to Parent in the class hierarchy and sub Id defines the position of the reference in the list of references for the parent class.
Collection blocks are represented by a three part oid and constitute the infrastructure associated with a collection. The form of a collection block oid is:
<class ID>.<instance ID>.<parent class ID>
Where Class ID represents the type of collection block (for example DictBlock). If the block is for an exclusive collection, the parent class ID is the class ID of the collection’s owner. If the block is for a shared collection, the parent class ID is the class ID of the collection.
What is the Maximum Number of Classes That Can be Defined?
At the time of writing 17,931 user-defined classes may be created. This number is increased if you include transient only classes. This topic is discussed next.
(19978-2047=17,931 where the first 2047 are reserved for use by JADE)
How Do I Make the Most of the Number of Classes Available?
Transient-only classes extend the number of classes available in your entire JADE system. If your JADE system has exhausted the number of normal classes, converting some of these to transientsOnly can provide an additional 10,800 classes (User Guide, section Transient-Only Classes).
Note that transient-only class numbers are encoded to a process specific class ID. This means that two processes can have instances of different transient-only classes with the same oid! It also means that the oid of the same transient-only class can differ for a process each time the application is run.
There are some runtime restrictions and performance ramifications associated with using this feature. Please consult documentation for further information regarding this feature or contact Jade Support if you have a support contract.
If a Persistent Object is Deleted Can Its oid be Re-Used?
JADE stores the instance number of the object last created for each class and the next object created of that type in the same database session will have an instance number one higher than this stored value.
If however objects for a class are created and deleted, and then the database restarted, the instance number of the next object created will resume one greater than the highest remaining instance number. For example:
2^32 (4,294,967,296) for JADE 6.3 or earlier
2^64 (~18*10^18) for 64-bit JADE 7.0+
What Happens When the Instance Limit is Reached?
If the instance number for a class reaches the maximum value and a request is made to create a new instance, a 1288 exception is raised ("No more instances can be created because the instance ID is at the maximum value")
How Does JadeAuditAccess Deal With Oids?
The oid returned (for example, following a call to getNextRecord()) is the oid as it appears in the audited record. It is an oid string using a class ID, not an ‘oid-like’ string that uses a class number.
When extended class numbers are in use, the class number portion of the oid consists of multiple bit fields which when simply interrogated as an integral value does not yield the correct class number. In other words, does not match the class number as you see it in the class browser.
Where extended class numbers can exist and the oid strings are to be stored or used, the string representation of the oid as audited should be transformed into a natural or pure string representation of the oid as follows:
For example, the creation of a HighClass instance where class HighClass has class number 16385 will appear in the audit as a create of 32769.x (in JADE 6.3.09). When the above line of code is run, the resultant string is 16385.x
How Are Oids Represented in the Object Inspector?
The following two scenarios refer to the same instance of class HighClass having class number 16385.
Oids appear in an exception dialog (e.g. receiver oid) where the class number part of the oid matches the class number of the class as it appears in the class browser. I.e. it appears in the un-encoded, human readable format.
It would therefore be appropriate to use the String::asObject() method with this oid to obtain the object from the ‘oid-like’ string. Using the String::asObject() method would have avoided the unexpected error 4 described in the opening question above.
A schema is available upon request from Jade Support that contains coded examples for all of the questions discussed below.
Class Number and Class ID
An oid may not be quite what you think it is…
To most developers, an oid exists in the following format: <class number>.<instance number>
…however internally oids are represented as: <class ID>.<instance number>
The class ID is an encoded number based on the class number and other information such as the persistence of the object.
- “<class ID>.<instance number>” is an oid string
- “<class number>.<instance number>” is an ‘oid-like’ string
It is important to understand which representation is being used\given from the context.
For example:
- When performing journal analysis using the JadeAuditAccess class,
- When inspecting an object in the object inspector
- When reading an exception log
- When using RootSchema APIs - some expect/return a class number, others a class Id.
Why is it preferable to use String::asObject rather than String::asOid?Tip: In addition to being able to locate a class by entering its name in the Find Class dialog, you can also enter the number of the class.
More generally, why is it preferable to use String::asObject() rather than String::asOid() and Object::getObjectStringForObject() rather than Object::getOidString()? They seem to return exactly the same.
Context
This question comes from JADE par #38081 where the user had used a hard coded string based on a class number to retrieve an object but unexpectedly incurred error 4, Object not found. The code used was:
Code: Select all
'16401.1'.asOid.inspectModal
The existing methods (getOidStringForObject(), asOid()) have not changed in their behaviour. However, you will obtain unexpected results when using these methods on oids where the class number is greater than the old class number limit (16384).
Unexpected behaviour can result if anything other than a class number is passed to asObject(), and unexpected behaviour can result if anything other than a class ID is passed to asOid()*.
This is due to the coding system applied to object identifiers that affects existing methods String::asOid() and Object::getOidStringForObject().
The new methods function such that they always take and produce 'literal' (un-encoded) class numbers (i.e. class numbers that match those you observe in the Class Browser).
For class numbers less than the old upper limit, the old and new methods are equivalent.
*Please note the section below regarding JadeAuditAccess where it is appropriate to use the String::asOid method since class Ids are audited, not class numbers."For instances of classes with large class numbers, the class identifier and parent class identifier parts of the string are not the same as the class number returned by the String primitive type asObject method." (p98 EncycloPrim.pdf)
How Does the Encoding Between Class Number and Class ID Work?
The encoding can be implied by noting such things as:
- “Transient-only classes have class numbers in the range 20,480 through 31,279” (JADE 6.3 Release Info)
- The difference between oid string returned by Object::getOidString() and Object::getObjectStringForObject()
- Comparing oid strings for persistent and transient instances
- 1-2047 for system classes;
2048-19978 user classes;
19979-20379 report writer;
20380-20479 transient classes;
20480-31279 user transient-only classes;
31280+ system transient-only classes.
Is it Safe to Store Oids as Strings For Later Use?
It is not safe practice to use oids explicitly in your code other than for debugging purposes. As described above, the internal mechanism for coding oids are subject to change* and if the recommended interfaces are used then it is not necessary to understand the internal encoding mechanisms.
It is much safer to:
- 1) Have a unique property value in your object that you can use to find the object again. This is the recommended approach.
2) Use the getObjectStringForObject() (and the corresponding inverse asObject()) where the object is encoded using the class number and instance id, possibly along with a (t) for transients or (s) for shared transients.
Two-Part (short), Three-Part (mid) and Five-Part (long) Oids
Simple objects (objects that are not collections or collection block structures) are represented by a two part oid, as described above.
Exclusive collections (and slobs and blobs) are represented by a five part oid:
<class ID>.<instance ID>.<parent class ID>.<sub level>.<sub ID>
Where Class ID represents the class of the child object (zero for a slob or blob), Instance ID is the instance of the parent object, Parent class Id is the class Id of the parent object, Sub level and sub Id describe the location where the reference parent->child is defined in the class hierarchy. Sub level describes the number of classes from Object to Parent in the class hierarchy and sub Id defines the position of the reference in the list of references for the parent class.
Collection blocks are represented by a three part oid and constitute the infrastructure associated with a collection. The form of a collection block oid is:
<class ID>.<instance ID>.<parent class ID>
Where Class ID represents the type of collection block (for example DictBlock). If the block is for an exclusive collection, the parent class ID is the class ID of the collection’s owner. If the block is for a shared collection, the parent class ID is the class ID of the collection.
What is the Maximum Number of Classes That Can be Defined?
At the time of writing 17,931 user-defined classes may be created. This number is increased if you include transient only classes. This topic is discussed next.
(19978-2047=17,931 where the first 2047 are reserved for use by JADE)
How Do I Make the Most of the Number of Classes Available?
Transient-only classes extend the number of classes available in your entire JADE system. If your JADE system has exhausted the number of normal classes, converting some of these to transientsOnly can provide an additional 10,800 classes (User Guide, section Transient-Only Classes).
Note that transient-only class numbers are encoded to a process specific class ID. This means that two processes can have instances of different transient-only classes with the same oid! It also means that the oid of the same transient-only class can differ for a process each time the application is run.
There are some runtime restrictions and performance ramifications associated with using this feature. Please consult documentation for further information regarding this feature or contact Jade Support if you have a support contract.
If a Persistent Object is Deleted Can Its oid be Re-Used?
JADE stores the instance number of the object last created for each class and the next object created of that type in the same database session will have an instance number one higher than this stored value.
If however objects for a class are created and deleted, and then the database restarted, the instance number of the next object created will resume one greater than the highest remaining instance number. For example:
- 1) Create instance of class 2069 -> oid is 2069.1
2) Create another instance of class 2069 -> oid is 2069.2
3) Delete instance 2069.2
4) Create another instance of class 2069 -> oid is 2069.3
5) Delete instance 2069.3
6) Restart the database
7) Create another instance of class 2069 -> oid is 2069.2
2^32 (4,294,967,296) for JADE 6.3 or earlier
2^64 (~18*10^18) for 64-bit JADE 7.0+
What Happens When the Instance Limit is Reached?
If the instance number for a class reaches the maximum value and a request is made to create a new instance, a 1288 exception is raised ("No more instances can be created because the instance ID is at the maximum value")
How Does JadeAuditAccess Deal With Oids?
The oid returned (for example, following a call to getNextRecord()) is the oid as it appears in the audited record. It is an oid string using a class ID, not an ‘oid-like’ string that uses a class number.
When extended class numbers are in use, the class number portion of the oid consists of multiple bit fields which when simply interrogated as an integral value does not yield the correct class number. In other words, does not match the class number as you see it in the class browser.
Where extended class numbers can exist and the oid strings are to be stored or used, the string representation of the oid as audited should be transformed into a natural or pure string representation of the oid as follows:
Code: Select all
oidLikeString := getObjectStringForObject(pOid.asOid); //where pOid is the audited oid.
How Are Oids Represented in the Object Inspector?
The following two scenarios refer to the same instance of class HighClass having class number 16385.
- 1) The ‘oid-like’ string that appears in the object inspector title bar uses the class number.
For example, if you inspect a specific object, e.g. by executing:…or by executing:Code: Select all
HighClass.firstInstance.inspectModal;
The title bar of the inspector will display the string [16385.1]Code: Select all
“16385.1”.asObject.inspect;//uses a class number therefore should use asObject() method
- 2) When inspecting a collection, a selected instance shows the class Id in the right-hand pane.
If you select a class in the class browser and you then select option “Inspect instances”, the resulting inspector dialog will display class instances. When a class instance is selected, the oid that appears in the right-hand pane uses the class Id (not the class number). Its class part will not match the class number if the class number exists in the extended range. The first instance of HighClass inspected in this manner will be displayed as:Code: Select all
---HighClass/32769.1---
Oids appear in an exception dialog (e.g. receiver oid) where the class number part of the oid matches the class number of the class as it appears in the class browser. I.e. it appears in the un-encoded, human readable format.
It would therefore be appropriate to use the String::asObject() method with this oid to obtain the object from the ‘oid-like’ string. Using the String::asObject() method would have avoided the unexpected error 4 described in the opening question above.
The asObject method is useful for debugging from a Workspace method to inspect a specific oid; for example, an oid returned in an exception dialog (EncycloPrim, String::asObject)