Server-to-Component Updates
All the representation update requests issued by the server are processed by the representation model interpreter supplied by the Rogue Wave® Server component library.
For each incoming representation update request, this interpreter decodes the representation object identifier as well as the attribute identifier, if any, so as to select the appropriate function to be applied to the representation object.
These functions and their association with runtime representation attributes must have been previously declared to the interpreter.
Just as the server classes are declared to a server model interpreter, the representation object classes —the bridge classes— must be declared to the representation model interpreter using a set of macros. This declaration has to be made only once and should occur in the file tha implements the bridge classes.
Example
The code sample below shows how to declare the TreeR and TreeItemR classes:
ILS_RP_OBJECT_BEGIN(TreeR)
ILS_RP_ATTR_STRING(TreeR,label,setLabel)
ILS_RP_OBJECT_END(TreeR)
ILS_RP_OBJECT_BEGIN(TreeItemR)
ILS_RP_ATTR_STRING(TreeItemR,label,setLabel)
ILS_RP_ATTR_REF(TreeItemR,ownerTree,setOwner,TreeR)
ILS_RP_ATTR_REF(TreeItemR,ownerItem,setOwner,TreeItemR)
ILS_RP_OBJECT_END(TreeItemR)
In this code sample, the two macros ILS_RP_OBJECT_BEGIN declare the following constructors:
TreeR(IlsRepresentation& rp, const IlsRpObjModel& m);
and
TreeItemR(IlsRepresentation& rp, const IlsRpObjModel& m);
to the representation model interpreter. Each time the interpreter receives a request for the creation of a TreeR or TreeItemR object, it executes the corresponding constructor.
Note: If the interpreter receives a request for creation of an object whose type is unknown, it executes the virtual function IlsRepresentation::newRpObject on the representation to which the new object will belong. |
Declaring Runtime Representation Attributes
A runtime attribute of a representation object class is declared to the representation model interpreter through a macro that takes a label and an editing function as parameters. This macro must appear between the BEGIN and END macros of the representation object class.
In our example, the class TreeR declares a string-typed attribute named label, associated with the editing function setLabel. The label attribute does not need to be the identifier of a data member of the class TreeR. This name is used merely to specify representations in dynamic view types.
Each time the server sends a request for the modification of the attribute label of a TreeR representation object, the representation interpreter executes the function setLabel on this representation object. Actually, the label of the attribute is not transmitted with the request but only its internal identifier of type IlsRpAttributeId.
A label attribute is also declared for the TreeItemR part along with two other attributes:
ownerTree: a reference attribute of type
TreeR* associated with the function
setOwner(TreeR*), and
ownerItem: a reference attribute of type
TreeItemR* associated with the function
setOwner(TreeItemR*).
As for the attribute label, each time the server sends a request for the modification of one of the reference attributes ownerTree or ownerItem of a TreeR representation object, the representation interpreter executes the relevant function setOwner on the object, passing the new reference target as the argument.
Note: If the interpreter receives a request for modification of an attribute whose label is unknown, it first looks for a default modifier declared for the type of the attribute (see macro ILS_RP_DEFAULT_XXX in the Rogue Wave Server Reference Manual). If no such default modifier is declared, the interpreter executes the virtual update function declared in the IlsRpObject class that corresponds to the attribute type (see the functions IlsRpObject::setBoolean, setChar, setLong, etc. in the Reference Manual). |
Creating a New Object from a Server Request
This section discusses the whole process of creating a new TreeItemR object from a server request.
First, the constructor TreeItemR is executed and an empty TreeItemR object is created. This object has no label yet (except the default label) and is not attached to its owner.
The creation of a new gadget item in the tree requires to execute the function addItem on the owner tree gadget or tree gadget item. Therefore, the gadget item and the TreeItemR object cannot be created simultaneously. In other words, a new gadget item cannot be created before one of the setOwner functions has been called as a reference to the owner.
A solution is to create the gadget item inside the setOwner functions. Below is an example of how to implement the setOwner function with a TreeItemR as its parameter:
void TreeItemR::setOwner(TreeItemR* owner)
{
assert(owner && owner->getGadgetItem(););
if (!_gadgetItem){
// this is the creation phase
_gadgetItem=owner->getGadgetItem()->addItem("<not yet defined label>");
}
else {
// this is a cut/paste of the tree item tree
....
}
}
In the above example, we assume that the owner is set before the label, so that the gadget item is created with a default label at first. This solution relies on the fact that attributes are notified by the server according to their order in the dynamic-view type specification.
A more common solution is to wait for all the attribute values to be set before creating the graphic object. This implies that these values be buffered until the object is complete. At that time, Rogue Wave Server always calls the virtual function IlsRpObject::endS2CUpdate on the representation object. This is the empty function implemented by the class IlsRpObject by default, but you can override it for your own purpose.
Thus, the TreeItemR class is completed as follows:
class TreeItemR {
...
void endS2CUpdate(IlsS2CTransStatus,IlsTransactionId);
private:
static TreeR* _curtTreeOwner;
static TreeItemR* _curtItemOwner;
static IlsString _curtLabel;
};
The static data members _curtTreeOwner, _curtItemOwner and _curtLabel are used to buffer the current attribute values set by the setOwner and setLabel functions in the context of new object creation.
For instance, the code for the function setOwner is then:
void TreeItemR::setOwner(TreeItemR* owner)
{
if (!_gadgetItem){
// this is the creation phase
_curtItemOwner=owner;
}
else {
// this is a cut/paste
....
}
}l
Note: This very simple implementation is not multithread safe. A safer solution would be to store this data at the representation level. See Deriving a Tree Representation Type for details. |
The gadget item is created by the endS2CUpdate function, as shown by the following code sample:
void TreeItemR::endS2CUpdate(IlsS2CTransStatus status,
IlsTransactionId)
{
if (status==ILS_S2C_NOTIFY_CREATION){
// we are in a notification of creation
assert(!_gadgetItem);
assert(_curtTreeOwner || _curtItemOwner);
if (_curtTreeOwner){
_gadgetItem=_curtTreeOwner->getGadget()->addItem(_curtLabel);
}
else {
assert(_curtItemOwner);
_gadgetItem=
_curtItemOwner->getGadgetItem()->addItem(_curtLabel);
}
_curtTreeOwner=0;_curtItemOwner=0;_curtLabel=0;
}
}
Version 6.3
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.