Copyright (c) 1999, 2000 Silicon Graphics, Inc. All Rights Reserved.
Related: Basic Concepts | Architecture | Item & Category |
An Association represents a relationship between an Item and other Item(s) in the same or different Category. For example, the user account Item(s) that are related to a group account Item with selector "bar" could be represented by an Association. The identifying parameters for each Association are a parent Category, selector of an Item in that Category (parent Item) and a child Category. An Association represents an 1-to-n relationship. A 1-to-1 relationship is handled as a special case of 1-to-n relationship.
Association derives from Category and supports the same client mechanisms, using CategoryListener interface, for obtaining dynamic information about the Item(s) in an Association instance. The list of Item(s) in an Association is of the same type as indicated by the (selector of) child Category. An Association can have a set of Attributes that apply to all Item(s) in that relationship. The Association class provides API to support monitoring of Item(s) and Attribute(s) in the specific relationship and notification of current state and state changes to interested clients.
If an Item with the specified parent selector does not exist, the Association will monitor the parent Category for the addition of an Item with that selector. When such an Item is added, the subclasses are notified and subclasses can do whatever is necessary to determine the child Item(s) and Association Attribute(s) and monitor the system for future changes.
If an Item with the specified parent selector existed, but is deleted while a client is monitoring the Association, all Items are removed from the Association and the Association continues monitoring of the parent Category for the addition of an Item with that parent selector.
The concept of an Association is implemented in Java at the client-side and in C++ at the server-side. An application developer writes the logic to determine the set of Item(s) related to a parent Item and Association Attribute(s) and to monitor the system for any changes to the Item(s) and Association Attribute(s) in C++, using the server-side API. The application-specific clients, such as specific Tasks, ItemViews and TreeView are written in Java and use the client-side API to obtain information about Association(s) and Item(s).
The Association class and three subclasses ComputedAssoc, ChildAttrAssoc and ParentAttrAssoc provide support for implementing Association(s) on the server-side.
The most basic support for specifying association is provided by the Association class. This class monitors the parent Item and subclasses are responsible for determining the child Item(s) that added, deleted and changed. The Association class (versus derived classes) is used only when sub-classes require logic very specific to the application to determine when items are added, changed and removed from the association. For example, the relationship may be calculated by queries on a database based on the parent Selector. The derived classes ComputedAssoc, ChildAttrAssoc and ParentAttrAssoc is used when the data requiring for computing the relationship is contained within the Item(s) in the Category(s).
// Provided by infrastructure class Category : public AttrBundle { ... virtual void addItem(const& Item item); virtual void removeItem(const& Item item); virtual void changeItem(const& Item oldItem, const& Item newItem); ... }; // Provided by infrastructure class Association : public Category { ... Association(Category& parentCategory, const String& parentSelector, Category& childCategory); // Association interacts with Category with selector parentCategory // and calls the following methods when the parent Item with // selector parentSelector is added, changed or removed. virtual void parentAdded(const Item& item); virtual void parentChanged(const Item& oldItem, const Item& newItem); virtual void parentRemoved(); ... };Using Association
// Written by application developer class MachinesAssocWithCluster : public Association { MachinesAssocWithCluster(Category& parentCategory, const String& parentSelector, Category& childCategory) : Association(parentCategory, parentSelector, childCategory); virtual void parentAdded(const Item& item); virtual void parentChanged(const Item& oldItem, const Item& newItem); };
The Association class provides trivial implementations of Association::parentAdded() and Association::parentChanged(). Subclasses can override Association::parentAdded() to, for example, register for notifications about Items in the child Category. Subclasses can override Association::parentChanged() to do whatever is necessary to keep the list of child Item(s) and Association Attribute(s) up-to-date. The Association class implements Association::parentRemoved() to remove all Item(s) from its list and notify removal of Item(s) to registered listeners. Most of the rules of subclass interaction with the Category base class apply. The differences are:
Typically a subclass makes zero or more Category::addItem() and AttrBundle::setAttr() calls, followed by a Category::endExists() call followed by zero or more Category::addItem(), Category::changeItem(), Category::removeItem() and Category::setAttr() calls. The Category::endExists() call signals that the subclass has communicated the entire set of Item(s) and Association attributes discovered in the system to the Category base class.
The anticipated use of information in Association is by the client side code. Clients can access Association information using the CategoryListener interface in the same manner as they would obtain information from a Category. The only difference is the call to obtain the handle to an Association. This is covered in detail in the Obtaining information about Association(s) on the client-side section. The information in that section can be applied to server-side components requiring information from an Association via the C++ CategoryListener API.
This is the base class for deriving classes to represent relationships that can be computed from values of Attribute(s) of the monitored parent and child Item(s). This class monitors the parent Item from the parent Category and Item(s) in the child Category that are potential children. The Item(s) that are potential children are indicated by a NotificationFilter that comes in effect when the parent Item is detected by Association. The NotificationFilter can be changed when the parent Item changes or at any arbitrary time.
// Provided by infrastructure class ComputedAssoc : public Association { ... // Monitoring of potential child Item(s) virtual void childCategoryItemAdded(const Item& item); virtual void childCategoryItemChanged(const Item& oldItem, const Item& newItem); virtual void childCategoryItemRemoved(const String& selector); ... // Set NotificationFilter to indicate potential child Item(s) virtual NotificationFilter* createAddedChildNotificationFilter(const Item& parentItem); virtual NotificationFilter* createChangedChildNotificationFilter(const Item& oldItem, const Item& newItem); virtual void adoptAndReplaceChildNotificationFilter(NotificationFilter* filter); ... // ... virtual bool isChild(const Item& potentialChildItem) = 0; };
Subclasses must override the ComputedAssoc::isChild() method to provide logic that determines if the Item of the child Category passed to ComputedAssoc::isChild() is a child of the parent Item.
This class marks all Item(s) of the child Category as potential child Item(s). This class calls ComputedAssoc::isChild() anytime there is a change to the parent or the monitored child Item(s) and forwards notifications about changes in its list of child Item(s) to the listeners on this Association. When the parent Item changes, it gets the current list of child Item(s) and checks if any child Item(s) need to be added/removed from its list based on the computation performed by ComputedAssoc::isChild(). When an Item of the child Category is added, removed or changed, it checks if the Item should be added/removed/updated in its list of child Item(s) based on isChild().
For example, the user account Item(s) belonging to a particular group account Item could be stated as the user account Item(s) that have the same value of Attribute with key uid as the corresponding Attribute in the group account Item. The following code can be used to model this relationship.
// Provided by application developer class UsersAssocWithGroup : public ComputedAssoc { ... bool isChild(const Item& parentItem, const Item& childItem) { if (childItem.getAttr("uid").stringValue() == parentItem.getAttr("uid").stringValue()) { return true; } else { return false; } } ... }
Sub-classes can further fine-tune behaviour by overriding the methods that are called upon notifications related to the parent and child Item(s). For example, subclass ChildAttrAssoc overrides parentChanged() to turn off computation of the list of child Item(s) when the parent Item changes and only does so on changes in the Item(s) of the child Category.
This is the base class for deriving classes to represent relationships in which the child Item(s) store the selectors of one or more parent Item(s) as part of its Attributes.
Subclasses provide the Attribute's key in the constructors. The ParentAttrAssoc class monitors the parent and child Item(s), keeps the list of child Item(s) current and notifies listeners of changes to the list of child Item(s).
ParentAttrAssoc can determine the Item(s) of child category that belong to this Association in two ways depending on the constructor that is used. One constructor is used when there is a 1-to-1 relationship from a child Item to Item(s) of the parent Category. Subclasses specify the Attribute key of the child Item that holds the parent Item selector. Another constructor is used when there is a 1-to-n relationship from a child Item to Item(s) of the parent Category. This is based on the recommended format for representing arrays of values in an Item. Subclasses specify the value of the key of the child Item that holds the number of parent Item selectors and the base name of the Attribute keys which hold the selectors themselves.
For example, if ClustersAssocWithMachine is a relationship where an Item of type ClusterCategory has an array of selectors of Item(s) of MachineCategory, NUM_MACHINES could be the key of ClusterCategory Item(s) that holds number of values in the array. The base name of the attribute keys could be MACHINE. ParentAttrAssoc will monitor Item(s) corresponding to the list of selectors in Attributes of the child ClusterCategory Item(s) with keys CLUSTER0, CLUSTER1, ... CLUSTER<NUM_CLUSTERS - 1>.
ChildAttrAssoc keeps the list of child Item(s) up-to-date based on parent/child changes.
// Provided by infrastructure class ChildAttrAssoc : public ComputedAssoc { ... // Constructor. This version is used for 1-to-n relationships and // takes two attribute names. // "childAttrNumKeys" is the attribute key which holds the number of // parent Item selectors, and "childAttrKey" is the base name of // the attribute keys which hold the selectors themselves. ChildAttrAssoc(Category& parentCategory, const String& parentSelector, Category& childCategory, const String& childAttrNumKeys, const String& childAttrKey); // Constructor. This version is used for 1-to-1 relationships and // takes one attribute name which is the attribute key holding the // parent Item selector. ChildAttrAssoc(Category& parentCategory, const String& parentSelector, Category& childCategory, const String& childAttrKey); ... }
Typically, subclasses only need to call the ChildAttrAssoc constructor with the application specific values of the Attribute keys and do not need to override any methods. For example, if a user account Item has an attribute with key "groupSelector" that refers to the parent group account Item, the following code can be used to model this relationship.
// Provided by application developer class UsersAssocWithGroup : public ChildAttrAssoc { UsersAssocWithGroup(Category& parentCategory, const String& parentSelector, Category& childCategory) : ChildAttrAssoc(parentCategory, parentSelector, childCategory, "groupSelector") { } };
This is the base class for deriving classes to represent relationships in which the parent Item stores the selectors of one or more child Item(s) as part of its Attributes.
Subclasses provide the Attribute's key in the constructors. The ParentAttrAssoc class monitors the parent and child Item(s), keeps the list of child Item(s) current and notifies listeners of changes to the list of child Item(s).
ParentAttrAssoc can determine the Item(s) of child category that belong to this Association in two ways depending on the constructor that is used. One constructor is used when there is a 1-to-1 relationship from a parent Item to Item(s) of the child Category. Subclasses specify the Attribute key of the parent Item that holds the child Item selector. Another constructor is used when there is a 1-to-n relationship from a parent Item to Item(s) of the child Category. This is based on the recommended format for representing arrays of values in an Item. Subclasses specify the value of the key of the parent Item that holds the number of child Item selectors and the base name of the Attribute keys which hold the selectors themselves.
For example, if ClustersAssocWithMachine is a relationship where an Item of type MachineCategory has an array of selectors of Item(s) of ClusterCategory, NUM_CLUSTERS could be the key of MachineCategory Item(s) that holds number of values in the array. The base name of the attribute keys could be CLUSTER. ParentAttrAssoc will monitor Item(s) corresponding to the list of selectors in Attributes of the parent MachineCategory Item with keys CLUSTER0, CLUSTER1, ... CLUSTER<NUM_CLUSTERS - 1>.
ParentAttrAssoc keeps the list of child Item(s) up-to-date based on parent/child changes.
// Provided by infrastructure class ParentAttrAssoc : public ComputedAssoc { ... // Constructor. This version is used for 1-to-n relationships and // takes two attribute names. // "parentAttrNumKeys" is the attribute key which holds the number of // child Item selectors, and "parentAttrKey" is the base name of // the attribute keys which hold the selectors themselves. ParentAttrAssoc(Category& parentCategory, const String& parentSelector, Category& childCategory, const String& parentAttrNumKeys, const String& parentAttrKey); // Constructor. This version is used for 1-to-1 relationships and // takes one attribute name which is the attribute key holding the // child Item selector. ParentAttrAssoc(Category& parentCategory, const String& parentSelector, Category& childCategory, const String& parentAttrKey); ... };
Typically, subclasses only need to call the ParentAttrAssoc constructor with the application specific values of the Attribute keys and do not need to override any methods. For example, if a group account Item has an attribute with key "NUM_USERS" that specifies the number of user account Item(s) belonging to it, USER0, USER1 ... USER<NUM_USERS - 1> would be the keys of the actual selector values, the following code can be used to model this relationship.
// Provided by application developer class UsersAssocWithGroup : public ParentAttrAssoc { UsersAssocWithGroup(Category& parentCategory, const String& parentSelector, Category& childCategory) : ParentAttrAssoc(parentCategory, parentSelector, childCategory, "NUM_USERS", "USER") { } };
AssocFactory is the factory class for Association objects. AssocFactory methods are used by the Association Service (similar to the Category Service described in sysadmd(1M)) to fulfill requests from remote clients. They can also be used by any server-side components that require information from an Association. Association subclasses use the macros defined by AssocFactory.h.
To make information about an Association between any Item of type parentCategorySelector and Item(s) of type childCategorySelector available to the rest of the system the following steps are required:
All application-specific entities are instances of Item. Further, all application-specific associations are instances of Association. No subclassing is required by the developer of specific application. The steps in obtaining information about Association(s) and Item(s) are:
Association instances are obtained via a HostContext object. When writing Task UI interface, a HostContext object will be available for you from the Task infrastructure. The same applies to writing an ItemView etc,.
Internally, the HostContext object is obtained when a user successfully logs in to a server machine.
If the HostContext object is hostContext, then a client can obtain a handle to an Association representing the user account Item(s) belonging to a parent group account Item called foo by using the following code:
Association assoc = hostContext.getCategory("GroupAccountCategory", "foo", "UserAccountCategory");This is an asynchronous call that returns an handle to the Association before it receives a response from the server. The client can use this handle to add CategoryListener instances for obtaining information. If an error is encountered in communication with the server or loading the specific Association instance requested, this is handled as a fatal connection error by the infrastructure and the client will exit after the error message is acknowledged by a user.
All details of Obtaining information about Items from a category apply to obtaining information from an Association.