SMILA/Documentation/Usage of Blackboard Service
What is Blackboard
Purpose of the Blackboard Service is management of SMILA record data during processing in SMILA component (Connectivity, Workflow Processor). Complete record data is stored only on a Blackboard which is not pushed through the workflow engine itself. Blackboard service hides handling of record persistence from the services. Clients should generally manipulate records using Blackboard API methods in most cases so records will be completely under control of the Blackboard.
Usage of Blackboard Service
Record lifecycle on the Blackboard
Record can be put onto Blackboard with one of the following operations:
- Creates a new record with a given Id. No data is loaded from persistence. If record with this Id already exists in the storages it will be overwritten when the created record will be committed. E.g. used by Connectivity to initialize the record from incoming data.
- Loads record data for the given Id from persistence. Used by a client to indicate that it wants to process this record.
- split(Id, String);
- Creates a fragment of a given record, i.e. the record content is copied to a new Id derived from the given by adding a frament name (see Id Concept for details).
- Puts record on the Blackboard, saves record attachments to BinStorage and replaces actual record attachments values with null.
- Assumes that record with the same Id as of given record already exists on Blackboard or in storage. Loads record from the storage if needed and updates it's properties with properties of the given record.
Record is removed from the blackboard with one of these operations:
- Saves record and attachments to storages and removes record from the Blackboard.
- Record is removed from the Blackboard. If the record was created new (not overwritten) on the Blackboard it will be removed completely.
There are following methods for working with Record attachments in the Blackboard:
- setAttachment(id, name, byte);
- setAttachmentFromStream(id, name, InputStream);
- byte getAttachment(id, name);
- InputStream getAttachmentAsStream(id, name);
- boolean hasAttachment(id, name);
Attachments are not stored anywhere in the Blackboard, they are saved to BinStorage directly and the actual attachment value in the corresponding Record is replaced with Template:Null. It is highly recommended to use only Stream methods to manage attachments because loading the whole attachments in memory will cause great memory consumption and can be cause for application crash.
Usage of Blackboard Notes
Notes is additional temporary data created by pipelets to be used in later pipelets in the same workflow, but not to be persisted in the storages. Notes can be either global or record specific (associated with a record Id). Record specific notes are copied on record splits and removed when the associated record is removed from the Blackboard. Each Note has a String name and Serialaizable value. There are following methods for working with Notes:
- boolean hasGlobalNote(name);
- Serializable getGlobalNote(name);
- setGlobalNote(name, value);
- boolean hasRecordNote(id, name);
- getRecordNote(id, name);
- setRecordNote(id, name, value);
Usage of Path with Blackboard methods
Some methods of Blackboard accept Path as an argument, for example getAttributeNames(Id, Path). Path represents the attribute path in the Record and is somewhat similar to XPath. String format of Path looks like "attributeName1[index1]/attributeName2[index2]/...". The specification of index is optional and defaults to 0. Index can refer to a literal or a sub-object that depends on methods getting the argument.
Consider the following example Record structure:
<Record> <A n="AccessTreeExpanded"> <O> <A n="account"> <O> <A n="sub"> <O> <A n="sid"> <L> <V>Value1</V> </L> <L> <V>Value2</V> </L> </A> </O> <O> <A n="sid"> <L> <V>Value3</V> </L> </A> </O> </A> </O> </A> </O> </A> </Record>
The correct path to access first MObject (<O>) of the first sub attribute is AccessTreeExpanded/account/sub/. Here indexes in each step mean the number of MObject inside the attribute. That is, to get second sub attribute you should use the path AccessTreeExpanded/account/sub/.
There are some cases when index of last step has a different meaning: - in the getLiteral(Id, Path) method the index of last step means the number of literal inside the attribute. That is, path for getting literal value from second sid attribute will be AccessTreeExpanded/account/sub/sid and path for getting the second literal of first sid attribute will be: AccessTreeExpanded/account/sub/sid. Path is used that way in getLiteral(Id id, Path path) - in the getLiterals(Id, Path) method index of last step is irrelevant, that means this method will return all literals of the attribute found at the given path; - in the setLiteral(Id, Path, Value) and addLiteral(Id, Path, Value) methods index of last step is irrelevant, that means that literal will be set or added to the attribute found on specified path - in the methods that modify annotations, null, , or empty path should be used to access root annotations of the record