Solstice Enterprise Manager 4.1 Developing C++ Applications Doc Set ContentsPreviousNextIndex


Chapter 10

Developing Object Behaviors

The Object Development Tools (ODT) of Solstice EM provide a simple and automated framework for adding and writing behaviors for managed objects residing in the Solstice EM MIS. You can define objects and their behaviors by using GDMO and ASN.1.

The GDMO definitions formally specify the syntaxes of attributes, actions and notifications. This defines the interface to the object, which is formally specified using ASN.1. The state changes that the object undergoes as a result of the action or operation on the object or as a result of internal changes (perhaps resulting in the creation of notifications) are specified in an informal way in GDMO english text as object behavior. When implementing an object, the developers need to translate this text into a formal state machine in a programming language such as C++.

This chapter explains how to use the Solstice EM object development tools (ODT) to develop object behaviors.

10.1 ODT Overview

The ODT allows you to perform the following operations:

The ODT lets you define behavior for actions or define behavior for generating any event, not just the standard ones. ODT also lets you define behavior when attributes are accessed or when object instances are created and deleted.

10.1.1 Supporting Functions

To provide a useful object implementation, Solstice EM provides the following supporting functions:

These supporting functions are hidden within the Solstice EM platform and are used transparently by the user-defined implementation code generated by ODT.

10.1.2 Object Development Components

FIGURE 10-1 shows the major components and interfaces the ODT provides or uses:


FIGURE 10-1   ODT components

10.2 Object Interfaces

The ODT provides object interfaces for object developers to use when implementing agent or manager-role behaviors using the ODT. The object interfaces are:

10.2.1 Object Behavior Interface

The Object Behavior Interface (OBI) provides functions that allow the MIS to invoke (or request) object behavior functions developed by an API user and receive responses from the user developed functions.

It provides the following functions:

A large part of the software in this interface is generated code. This interface also contains generated stub function interfaces (also referred to as stubs) where you can add your own object behavior code. To write unique object behavior code, you may use the Object Services API or write your own C++ code.

Generated stub function interfaces are provided for the following:

You are required to provide functionality for only the action stub function interface and not for the other stubs functions interfaced. If you do not provide functionality, default behavior functionality is used.

10.2.2 Object Services API

The Object Services API (OSAPI) lets you access services provided by the MIS to implement inter-object behaviors or specialized behaviors. Framework utilities provide capabilities for building, loading, unloading, and instantiating objects.

The decision to use these services depends on the behavior defined for an object. For example, if an action defined for a GDMO object requires the object to check the administrativeState of the log object as part of the action, the user-developed behavior code needs to use the object services interface to issue a get request to obtain the value of the administrativeState attribute of the log object.

The OSAPI provides the following set of services that can be used within an object implementation:

10.3 Object Development Overview

The process for defining and implementing object behavior is as follows:

1. Define object classes.

Define and develop Managed Object Class (MOC) using GDMO and ASN.1 definitions to include the behaviors for the MOC. If you have existing GDMO and ASN.1 documents that define the appropriate behaviors, you can use those existing files.

2. Compile and load MOC into MDR.

Use the GDMO/ASN.1 compiler to compile and load the GDMO and ASN.1 files into the Meta-Data Repository (MDR).

3. Generate object code and develop behavior.

Use the Object Code Generator (OCG) utility to generate the default object implementation for the MOC. The OCG generates function stub interfaces, a Makefile, object loading and unloading utilities, an object instantiation program, and a README file that contains instructions about the generated files and how to extend the default implementation.
To develop additional behavior, add C++ code at insert areas clearly identified in the generated code. The code you add implements behaviors that are defined in GDMO for the MOC.
Refer to section__________

4. Compile and build object implementation source.

Use the OCG-generated Makefile.className to build default or user-extended object implementation. The Makefile builds the object implementation as a dynamic library and a PMI client program for instantiating the object.

5. Load object implementation and restart MIS.

Use the object loading utility, className.load, to load the new object implementation into the platform. Then, restart the MIS (using em_services -start) to read the new object implementation. When the MIS restarts, the new object implementation is loaded dynamically into the em_mis process. Subsequent CMIP operation on an object instance for this object class results in executing the behavior implemented by the user.

6. Debug object implementation [optional]

User-implemented behaviors might contain errors which result in operation failures and, in some instances, MIS crashes. You can use a debugger to attach to the running MIS or directly debug em_mis to debug new object implementations. Using em_debug, you can enable or disable developer-provided object-operation traces at runtime.

For a complete scenario that illustrates this process, see Section10.10 Object Development Scenario Using Chai Object."

10.3.1 Possible Errors

Errors can occur in the following phases of object behavior definition:

The GDMO and ASN.1 compiler identify syntax errors in your GDMO and ASN.1 documents. For the Object Code Generator to generate appropriate code, you must provide complete and syntactically correct GDMO and ASN.1 object definition.

When the MIS restarts, the object class definition and behavior definition are composed and registered. Any errors in this phase display on your screen.

When an instance of a class is created, any problems in creating an instance arising out of an improper object definition are returned as an error for the create request.

If you add any user-defined code to the generated code, you might introduce errors.

10.3.2 Sanity Check Procedure

It might not be possible to detect all GDMO or ASN.1 errors using the GDMO/ASN.1 compiler or the object implementation process, for example, OID registration clashes, name binding and attribute mismatches for initial values, default values, and so on. Sometimes, late in your object development process, you may find errors or failures that result from errors in the GDMO or ASN.1 definition for the MOC. Use the following sanity-check procedure to minimize potential problems:

1. Comment out ACTION definitions in GDMO.

Comment out the ACTION definitions in the GDMO definition for the object class. You must do this because you cannot compose an object class that contains actions without loading the appropriate action implementation in a dynamic library.

2. Compile and load object class in MDR.

The object class definition in GDMO and ASN.1 must be compiled and loaded in the MDR using the following commands:

hostname% em_gdmo -v -f -o 
/var/opt/SUNWconn/em/usr/data/MDR/ 
className.gdmo
hostname% em_asn1 -v -o /var/opt/SUNWconn/em/usr/data/ASN1/ className.asn1

3. Compose object class.

Use the compose program to compose the new object class. This verifies the OIDs, attributes, and syntax and catches such errors as clashes with existing classes, attribute mismatches, and invalid syntax (referring to a different document/syntax label that is valid but not actually desired by the object implementor). Use the following command:

em_compose_oc className


Note – If you find errors in this step, you can often get additional error details by using the oammsg* and mdr* tracing flags with the em_debug utility.

4. Load name bindings.

Use the load name binding utilities to load the defined name bindings in the platform. This detects possible errors in the name binding or naming attribute. Use the following command:

em_load_name_bindings Namebinding

Repeat this for all name bindings specified in the GDMO definition for the object class.


Note – If you find errors in this step, you can often get additional error details by using the oammsg* and mdr* tracing flags with the em_debug utility.

5. Create an instance.

Use OBED or a simple PMI program to create an instance of the MOC. This ensures that the GDMO/ASN.1 definitions are correct and that all CMIP operations can be performed. After you verify this, use OBED or the PMI program to delete the instance.

6. Restore ACTION definitions in GDMO.

Remove the comments to the ACTIONS in the GDMO definition for the MOC. You should now be ready to use ODT.

7. Remove old definitions and prepare to load new object.

Run em_services -reload to reinitialize the MDR and MIS. Follow the object development process (see Section10.3 Object Development Overview") to load your new implementation.

10.4 Object Code Generator Utility

The Object Code Generator utility (OCG) provides a set of C++ classes and methods that you use can to implement the behavior for managed objects defined in GDMO. The OCG is external to the MIS. The code generated and the user-defined implementation reside in a dynamic shared library linked to the MIS.

The OCG generates the C++ stubs for attribute access, instance access, and action access for the class. You fill in the behavior in the stubs. The utility hides the process by which user-defined behavior is connected to the framework. In other words, you only change code stubs for:

The generated code also contains debugging information to help you trace what happens at run time.


Note – The Solstice EM MIS must be running locally to generate implementation.

10.4.1 Generated Code Interfaces

The generated code interface provides a set of generated code stubs that can be used to invoke user developed object behavior functions. The interfaces and underlying code are produced by the OCG, which operates on information in the meta data repository (MDR) and on information in a configuration file. The GDMO and ASN.1 definitions for GDMO object need to be loaded into the MDR prior to generating the code and interfaces.

The Object Behavior Interface is shown in FIGURE 10-2, with the generated code interface highlighted:

FIGURE 10-2   ODT Framework, with Generated Code Interface Highlighted

10.4.2 Code Generation Components

FIGURE 10-3 shows the components involved in the agent role behavior code generation portion of the Object Behavior Interface. The OCG generates the appropriate agent role behavior code and code stubs for the GDMO-defined managed object class based on the GDMO definition loaded into the MDR and on parameters you specify in a configuration file.

The OCG also generates a PMI client create program that you can use to instantiate an instance of the new managed object class.

FIGURE 10-3   Code Generation Components

10.4.2.1 Inputs

The Object Code Generator utility takes input from the following sources:

10.4.2.2 Outputs

The Object Code Generator utility provides the following output:

This is called the annotation code. Object implementors should not change any of this code. The annotation OID is unique and is generated automatically.


Note – All the attributes and the object instance are either persistent or volatile. You control volatility on a per-object class basis.

10.4.3 Using the Object Code Generator Utility

Before you use the OCG, you must compile the GDMO and ASN.1 definitions using the GDMO and ASN.1 compiler and restart MIS to load the GDMO and ASN.1 definitions. You then have the following options for the object behavior:

The OCG is a command line function. To run it, use the following command:

% $EM_HOME/bin/em_obcodegen -help filename


Note – $EM_HOME is an environment variable used to designate the directory in which Solstice EM is installed, typically /opt/SUNWconn/em.

TABLE 10-1   OCG Command Line Options
Option Description
-help
Displays a list of command options.
filename
Identifies the class name to generate code for. The GDMO and ASN.1 files must match this file name.


TABLE 10-1 identifies the options available for em_obcodegen.

Example

To generate code for the chai example, you would use the following format:

% $EM_HOME/bin/em_obcodegen chai

10.4.4 Configuring the Object Code Generator Utility

The specific code the OCG generates depends on a number of configuration parameters. You can define these parameters in any of the following locations:

If several developers need to use a standard configuration, use the global configuration file. TABLE 10-2 lists the parameters you can define for ODT configuration.

TABLE 10-2   Object Development Tool Configuration File Parameters
Parameter Default Value Description
CODEGENDIR
.
(Current directory)
Directory for writing the generated code files.
DATASTORAGE
PERSISTENT
Data storage for the object class. Valid values are VOLATILE or PERSISTENT.
OBAPITRACE
YES
Enables runtime functional tracing.
OBAPIDEBUG
YES
Enables runtime debugging output.
HIDDENDIR
.hidden
Indicates where all the hidden annotation and implementation code is generated. Users should not modify files located in this directory.
FILTER_ATTR
DiscriminatorConstruct
If the object class needs to support event discrimination, set this flag to DiscriminatorConstruct. This causes the discrimination secretary to be generated.


10.4.5 How Filter Attributes Affect Code Generation

The GDMO definition for your object class can include following three attributes that affect how code is generated for receiving events:

If these attributes exist in your GDMO definition and FILTER_ATTR is set to DiscriminatorConstruct, then OCG generates the following code:

receive_event(EventType, EventInfo);

If FILTER_ATTR is set to DiscriminatorConstruct and any of these attributes are not defined in your GDMO, then you see a warning message and this line of code is not generated.

10.5 Implementing GDMO Specified Object Behavior

There are 5 important operational aspects to the Generated Interfaces the ODT user must understand:

10.5.1 MIS Object Modeling Concepts

Solstice EM defines object behaviors according to the abstractions described in TABLE 10-3 .

TABLE 10-3   Behavior Abstractions
Behavior Function
Instantiation
object creation and deletion
Containment
management of children
Attribute Management
storage/access to attributes
Actions
action behavior


These four areas have C++ base classes that define interfaces for the functionality listed above. The base C++ classes that implement these behaviors are known collectively as Secretaries. A Secretary is a named component of code that implements a specific functionality. New object behaviors are added to the MIS framework by describing to the MIS the set of secretaries (components of behavior) that will implement the behaviors for a particular GDMO Object Class. This description is called the Object Behavior Definition (OBD). The OBD is a list of the secretaries and is automatically generated by the ODT and is hidden from the ODT user.

The framework by default provides for instantiation, containment, attribute and action support of agent role behavior. The ODT user need only insert behavior code at well defined interfaces to supplement or augment these default behaviors.

New behaviors are created by deriving new C++ object classes from the base C++ secretary classes. The ODT generates these derived classes on behalf of the user for a specific GDMO Managed Object Class. To simplify the problem of creating agent behaviors the ODT has exposed the interfaces listed below.

The following list summarizes the functions or points in the generated code that can be modified by a user of the Object Behavior Interface. For most objects, you will not need to supply additional code for every interface point listed here:

10.5.2 Asynchronous Interface Behavior

Asynchronous behavior is introduced at an interface by providing a callback parameter as part of the interface invocation. The expectation is that the implementor of the interface will only invoke the callback when the interface functionality is complete. Solstice EM provides the following asynchronous interfaces:

These provide interfaces which allow the user an asynchronous interface to fetch data, store data and perform actions in an asynchronous manner. A callback is invoked by using the exec method:

	 cb.exec(parmarater);

The parameter to the exec invocation is one of the ways used to indicate status to the invoker. For more information on this parameter, see Section10.5.4 Propagation of Errors".

The Object Framework uses a state machine model to manage the different phases to complete the different CMIS requests. These requests and the interfaces they invoke are described in TABLE 10-4 and TABLE 10-5 .

TABLE 10-4   Interfaces for CMIS Requests
Interface Action
Fetch
Issue fetch for all operations in request and wait for all Callbacks
Read
Issue read for all attributes in request
Write
Issue write for all attributes in request
Store
Issue store for all attributes in request and wait for all Callbacks


TABLE 10-4 lists the order of interfaces invoked for each CMIS request.

TABLE 10-5   Order of CMIS Request Interfaces
CMIS Request Order of interfaces invoked
M_GET
fetch, read
M_SET
fetch, read, write, store
M_CREATE
write, store


At each phase the framework invokes the appropriate interface for all attributes in the CMIS request. An M_GET with an attribute list with two attributes will invoke fetch twice followed by 2 read requests. An M_SET for three attributes will invoke fetch for each of the three attributes, followed by a read for each of the three attributes followed by a write and a store for each of the listed attributes.

Consider the fetch interface as a simple example of how asynchronous behavior is achieved:

	 ClassName_AttrSecty::fetch(ai,callback)

The invoker of this interface does not expect that when the fetch function returns that the attribute specified by ai has been fetched. The implementation may need to send a request to another entity or agent to fetch the attribute data. However, instead of waiting for the remote entity to respond, the fetch implementation can store the callback parameter and schedule its own callback for when the remote entity provides the attribute data.

On receipt of the attribute data, the fetch interface then invokes the stored callback, indicating to the originator of the fetch invocation that data is now available synchronously. In other words, you can pass a callback to subfetch which, when called, calls the original callback passed in fetch. The invoker can then invoke the ClassName_AttrSecty::read synchronously.

Similarly for storage operation, the ClassName_AttrSecty::store function is passed a callback. Only when the data has been stored should the implementor invoke the passed callback.

The Solstice EM Object Framework invokes the generated Object Behavior Interfaces fetch, read, write and store in a particular order depending on the CMIS request being performed. These interfaces are designed to allow asynchronous requests to be satisfied. The fetch, store and action interfaces are all asynchronous interfaces. FIGURE 10-4 outlines the normal order of operations for a GET request. The framework calls the UserSecty code fetch function for all attributes providing as parameters the attribute identifier and the callback to be invoked when the fetch has been completed. The fetch code is responsible for fetching the attribute data from wherever it is stored.

Once the data has been fetched the UserSecty code must then call the callback provided. The framework maintains a count of all the outstanding callbacks. When all callbacks have been received, the framework enters the read phase. The assumption is that since the (asynchronous) fetch has completed, the (synchronous) read can complete without blocking. Remember that read and write are synchronous operations for accessing memory, while fetch and store are asynchronous and act on disk storage.

In the sequence diagrams below, half arrows indicate asynchronous operations and full arrows denote synchronous operations.

FIGURE 10-4   Sequence Diagram for M_GET operation

FIGURE 10-4 indicates the normal flow for the code that is generated by the ODT. In particular it is important to understand that the subordinate operations do not need to be called unless default behavior is desired. However, once a subordinate fetch function is called, the subsequent read on the fetch attribute should also call the subread function. The use of the sub functions is detailed in the sub operation section following.

The diagrams below outline the sequence flow for M_ACTION and M_SET operations.

FIGURE 10-5   Sequence Diagram for M_ACTION

FIGURE 10-6   Sequence Diagram for M_SET

It is important for the ODT interface implementor to obey the rules of the interface. Essentially the implementor must issue a callback for every asynchronous received. Failure to do so will cause the original request to be suspended. The MIS will continue to operate and service other requests

The default behavior for fetch and store is that the callback is executed immediately from the fetch and substore operations. If the ODT developer does not wish to use this default behavior and decides to delay the invocation of the fetch or store callback the ODT developer must register the object class implementation with the OamAsyncable Interface. To register an object class in the OamAsyncTableIf the oamasynctblif::AppendAsyncTBl method is used:

	 oamasyntblif::AppendAsyncTbl(Oid("1.2.3.4.5.6.7", 
TRUE);

This registers Object Class 1.3.4.5.6.7 as an asynchronous class.


Note – Failure to register the Object Class as asynchronous may result in random MIS code dumps.

10.5.3 Sub Operations: subfetch, subread, subwrite, substore

The interfaces subfetch, subread, subwrite, and substore are used to interface to a service layer coupled to the UserSecty code via a late binding mechanism in the MIS framework. The services currently offered in this manner are Volatile and Persistent. Volatile refers to an in-core storage mechanism for managed objects. Persistent refers to the persistent service component of Solstice EM. Volatile or persistent behavior is defined by configuration. See Section 12.5.6 "Configuring the Object Code Generator" for information on how to configure for volatile or persistent behavior. By obeying the conventions of the sub operations an object class implementation can be switched easily from volatile to persistent.

To use the volatile or persistent services the ODT developer must invoke the sub operations. The rules that apply to the fetch, read, write and store interface apply again. The semantics are the same.

The invocation of sub operations are not mandatory. However the rules of the interfaces must be obeyed. Subfetch must always be called before subread. Subread cannot be called until the callback passed to subfetch has been invoked. Subwrite must always be called before substore. Data is not deemed to be stored until the substore callback has been called.

The default code generated by ODT for fetch is to call subfetch. The subfetch code then invokes the original invoker's callback. If you pass a different callback to subfetch, it must call the original callback to fetch. If the ODT developer chooses not to call the subfetch function then the ODT developer assumes responsibility for invoking the callback supplied as an argument to the fetch call.

ClassName::fetch(ai,framework_cb) 
{
    if ( using_sub_service ) {
      subfetch(ai,framework_cb
    return OK;
    }
   // Set up for my own callback, allocates a Context 
structure
   // which saves the callback, This context is passed 
to ClassName::my_cb
    schedule_my_cb(ai,framework_cb)
    return OK;
}
// Local Callback mechanism invoked when Data has been 
fetched
ClassName::my_cb(Ptr P1, Ptr P2)
{
    MyLocalContext *p_contect = (MyLocalContext*) P1;
   // Invoke original callback with 0 as an indication 
of Success
   p_context->framework_cb.exec((Ptr) 0 );
}

A user may choose to only use persistence for a write through capability. In this case the ODT developer would only need to use subwrite and substore. Once data has been stored to persistence using the subwrite and substore interfaces, the user may subsequently use subfetch and subread to retrieve the data.

10.5.4 Propagation of Errors

The ODT framework has three different means to reflect errors back to the request invoker:

The interface error mechanisms have been designed to allow for maximum flexibility while at the same time offering support to hide the complexity of building a CMIS error PDU. CMIP errors come in two flavors: List Errors and Fatal Errors.

List errors occur on M_SET and M_GET operations and indicate a partial error on a specific attribute or list of attributes. For example, an M_SET operation on an object containing AdminstrativeState and OperationalState would result in a SET_LIST_ERROR response since OperationalState is read-only. An attempt to create an instance of an unknown object class would result in a Fatal Error of NO_SUCH_OBJECT_CLASS.

The Object Framework determines the appropriate error for errors reflected by return value or exceptions. It builds the error PDU and issues the error response. The Operr mechanism allows for complete flexibility to indicate any type of error to the request invoker. The Operr mechanism is used at the fetch and store interfaces only.


Note – The Operr method is the recommended means to generate errors for all operations.

10.5.4.1 Return Value

The Return Value is OK or NOT_OK. The specifics of which error an OK or NOT_OK produces is detailed in the sections specific to each interface.

10.5.4.2 MIS Exceptions

Exceptions are passed back across an interface by using the THROW or VTHROW macros. The specifics of which error is produced for an interface is detailed in the sections specific to each interface.

10.5.4.3 Operr Returns Values

The Operr class has four constructors which will construct different error responses. The types of error responses that can be constructed are:

This will cause the MIS to send an error message, pointed by ErrorMsgp to the original requester. The error message is allocated using the Message::new_message method All fields must be completed in the Error Message.

	 Operr(Oid & errorId, Asn1Value &errorInfo);

This will cause the MIS to send a ProcessFailure message to the original requester. errorId and errorInfo constitute the specific error part of that ProcessFailure message. The syntax for SpecificErrorInfo is:

	 SpecificErrorInfo ::= SEQUENCE {
          errorId         OBJECT IDENTIFIER,
          errorInfo       ANY DEFINED BY errorId
	 }

The errorId parameter must be a valid OID. The errorInfo must be a properly encoded Asn1Value as defined by errorId.

	 Operr(int OperrInt);

This will cause the MIS to send a ProcessFailure message to the original requester. The specific error part of the message is set to probableCause (2.9.3.2.7.18) and the error number indicated by OperrInt.

	 Operr(Oid & OperrOid);

This will cause the MIS to send a ProcessFailure message. The specific error part of the message is set to probableCause (2.9.3.2.7.18) and the error information indicated by OperrOid. In this case, the OperrOid must contain one of the valid OID defined in /SUNWconn/etc/gdmo/dmi.gdmo for probableCause.

To use the Operr format of error reporting the user must allocate an appropriate Operr instance on the heap and then pass it to a fetch or store callback:

Operr *p_err = new Operr(2);	 // Processing 
Failure ProbableCause 2
 
fetch_cb.exec(p_err);	 // Called function will 
delete the Operr
return OK;
 
or
 
Operr *p_err = new Operr("2.9.3.2.0.0.1");	 
	 // Processing Failure ProbableCause 
	 // adaptError, see DMI.ASN1 for
	 // complete ProbableCause Error list
 
store_cb.exec((Ptr)p_err);	 // Called function will 
delete the Operr
return OK;


Note – Fetch and store are called for every attribute. The ODT developer must respond to every fetch and store by issuing a callback for every fetch and store received. The object framework examines these callbacks for errors but only uses the first error reported to generate the requested error response. It will discard any subsequent Operr responses.


Note – The ODT developer must allocate the Operr Data Structure from the heap. The framework deletes the Operr structure when it no longer needs it. Operr data structures can only be used in fetch and store Callbacks. They must not be used for the ::Action result callback.

10.5.5 Serialization of Object Requests

To guarantee consistency within a managed object instance, the object framework employs a simple lock management scheme to lock the object for destructive operations. The locking mechanism locks an object exclusively for M_SET, M_CREATE, M_DELETE and M_ACTION requests. Exclusive locks enforce serialized access to the object and force an operation to complete before the next operation is allowed to start. M_GET requests are honored using a shared lock level, allowing multiple M_GETs to operate on the same managed instance concurrently.

The default lock mode for M_ACTIONs is LOCK_EXCL (exclusive). This mode requires that an action completes before any other operation can be started. Since M_ACTION requests are not necessarily destructive and may execute for a long time, the framework allows the ODT developer to set the lock mode that a specific M_ACTION may be executed at.

To override the default lock level for an action the ODT developer must set the desired action lock level using the oamlockif interface defined in oamlockif.hh. The function set_action_lock_level is used to set the action lock level. The following code example shows how to use the set_action_lock_level function:

	 Oid ActionOid("2.9.2.3.8.1");
	 oamlockif::set_action_lock_level(ActionOid, 
OAM_LOCK_SHARE);

The preceding code example sets the action defined by ActionOid to be shared. This will allow M_GETs and other shareable M_ACTIONs to be performed on the instance supporting these actions while an action is being executed. It will not allow M_SETs to be performed while any M_GETs to M_ACTIONs are in progress.


Note – If M_GET operations seem to block indefinitely and the object implementation supports long running actions set the action level appropriately.

10.6 Debugging Objects

10.6.1 Process

1. Find out the process identifier of the running MIS.

hostname% ps -eaf | grep mis

You should see output similar to the following:

    root  9324     1 80 08:26:00 pts/12   0:59 em_mis -k

2. Run the debugger against the process identifier of the MIS.

hostname% debugger - MIS_pid_from_previous_step

Make sure you put a blank space between the hyphen and the process identifier.
For the output shown in the previous step, you would use the following:

hostname% debugger - 9324

3. When the debugger comes up, go to the debugger line and open the file className_user.cc. This should look similar to the following:

(debugger) file chai_user.cc

4. Set a breakpoint in the className_user.cc file.

(debugger) stop in wherever

5. Continue.

(debugger) cont

10.6.2 Dynamic Loading in Solstice EM

OCG generates a default object implementation for a MOC defined using GDMO and ASN.1 and loaded in the MDR. Application developers can modify the default object implementation. The object implementation is built as a shared library that is loaded dynamically into the MIS at startup (em_services). Similarly, object implementations can be unloaded dynamically at MIS startup.

ODT provides two utilities that are generated as part of OCG:

Because the object implementations are loaded at different address spaces in the MIS when the MIS is started, an application developer cannot set a breakpoint at a well-known location in the dynamically loaded shared library. To enable users to debug object implementation, em_mis provides a well-known breakpoint that you can use before providing other breakpoints in the dynamically-loaded object implementation.

10.6.3 ASN.1 and GDMO Debugging

Solstice EM does not provide specific tools for debugging ASN.1 and GDMO files. For complete information on these syntax definitions, see the following:

10.6.4 Printing ASN.1 Values in Human-Readable Form

To print ASN.1 values (information in Asn1Value form) in human-readable form, first define the following in your .cc file:

Debug_on (className_info);
Asn1Value av;

Then, use the print method of Asn1Value defined in the PMI (asn1_val.hh) as follows:

av.print(className_info);

Where:

10.6.5 Debugging Flags

OCG generates debug agents (className_error and className_info) for every object class. If you specify OBAPIDEBUG as YES in the configuration file, OCG enables these agents at compile time. To enable or disable these agents at runtime, use em_debug and the following commands:

When debugging behaviors that require you to use Object Services API (for example, if implementing inter-object behaviors), you can enable or disable debug agents specifically for Object Services API calls. To enable these agents, use the "objsvc_*" options for the em_debug utility as follows:

$EM_HOME/bin/em_debug -c "on objsvc_test
$EM_HOME/bin/em_debug -c "on objsvc_error

Or use the following command:

$EM_HOME/bin/em_debug -c "on objsvc_*"

To disable these agents, use em_debug -c "off objsvc_*."

10.7 Generated Files

If you have created valid GDMO and ASN.1 definition files and loaded them into the MDR, when you run OCG it creates the files in the target directory specified in your configuration file:

For complete examples of each of these files, see Section10.10 Object Development Scenario Using Chai Object."

10.7.1 Makefile (Makefile.className)

You use the Makefile to create ("make") a dynamic linked library for every object class for either default or user-extended implementation.

10.7.2 Readme File (README.className)

The README file explains how to use the files generated by OCG.

10.7.3 User Header File (className_user.odt.hh)

This header file contains the class definitions for the object class className. OCG generates definitions for the Attribute class, Action class, and Instance class. The Attribute and Action classes contain several helper methods that can be used to access other attributes or actions defined in this file or to perform read/write actions on other attributes or actions defined in this file, while implementing specific behavior for a given attribute or implementing a specific action.

In addition to the class definitions, the user header file defines Action indices, Attribute indices, and OIDs for Attributes, Actions, and Name Bindings.


Note – You are not allowed to modify this file directly. The default object implementation build uses this file, so changes made to it will cause unpredictable results.

To add function prototypes or members in the header file, copy this file to className_user.hh and add your code there.

TABLE 10-6 identifies the Attribute classes OCG defines in this file:

TABLE 10-6   Attribute Class Helper Methods
Attribute Class Name Description
index2AttributeSectyInfo
Converts from AttributeIndex to AttributeInfo
AttributeSectyInfo2index
Converts from AttributeInfo to AttributeIndex
index2ActionSectyInfo
Converts from ActionIndex to ActionSectyInfo
action
Performs action
read/write/fetch/store
Read/Write/Fetch/Store Attribute


TABLE 10-7 identifies the Action classes OCG defines in this file:

TABLE 10-7   Action Class Helper Methods
Action Class Name Description
index2AttrSectyInfo
Converts from AttributeIndex to AttributeInfo
index2ActionSectyInfo
Converts from ActionIndex to ActionInfo
read
Reads attribute
write
Writes attribute
fetch
Fetches attribute
store
Stores attribute


10.7.4 PMI Client Create Program for Object Instantiation (pmi_className.cc)

The PMI client create program file contains PMI client application code that is used to instantiate an instance of the new object class after the dynamic library for the new object class has been linked into the MIS.

10.7.5 User Code File (className_user.odt.cc)

The C++ source file contains the user-level methods defined for Attribute, Action, and Instance classes. The user function stubs that OCG generates include: read, write, fetch, store, action, create_vote, and destroy_vote. In addition, OCG generates a stub for receive_event if discrimination service is used.


Note – You are not allowed to modify this file directly. The default object implementation build uses this file, so changes made to it will cause unpredictable results.

To add user-defined behaviors, copy this file to className_user.cc and add your code in the insertion areas clearly identified.

When implementing intra-object behaviors, you should use only the helper methods defined in Attribute, Action, and Instances classes. When implementing inter-object behavior, you should use the Object Services API calls as needed for behavior implementation.

10.7.6 Dynamic Loading File (className.load)

When you run this utility, the object implementation build is loaded into the platform as a shared library. The new object implementation is read at MIS startup.

10.7.7 Dynamic Unloading File (className.unload)

When you run this utility, the object implementation is removed from the platform. The object implementation is not read at MIS startup.

10.8 TRY Exception Macros

The development environment of Solstice EM includes some exception-handling macros that are used in cases where the C++ compiler does not handle the exception. These exception-handling macros are known as TRY macros. The basic elements of the TRY macros are the TRY block and the Handler block.

10.8.1 Overview

The TRY block brackets the code from which you want to receive exceptions. It must be followed immediately by a Handler block in which you specify how to handle the exception.

Exceptions are scoped dynamically. What this means is that a TRY block establishes a new exception context. When you exit the TRY block, you return to the previous exception context.

10.8.2 Code Structure

The basic structure of a TRY exception is as follows:

TRY {
some block of code that may generate exceptions
}
BEGHANDLERS
CATCH macros that handle various exceptions
ENDHANDLERS

10.8.3 Code Examples

The following example from the chai scenario shows how the TRY macros are used in the generated code:

    TRY 
{
// Fetch attribute specified by (ai)
return subfetch(ai,cb);
    }
BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
    }
ENDHANDLERS
}

10.9 Object Development Examples

Solstice EM comes with several examples that illustrate how to develop object behaviors. All of these examples are located in the $EM_HOME/src/odt directory. This directory includes a README file that explains how to build the examples.

TABLE 10-8 identifies the examples and provides a brief description of what each one includes. A complete scenario that illustrates how to develop an object is included in Section10.10 Object Development Scenario Using Chai Object."

TABLE 10-8   Object Development Examples
Class Name Description
cellSample
Defines a set of intra-object complex behaviors. Basically, it looks at an object and, if its behavior changes then the behavior of its neighboring objects changes.
chai
Looks at an attribute called "chaiReady" to decide whether there is any chai (tea) ready to drink. If not, it sends an action "brewChai" to make more.
demoPing
Defines behavior of a "native agent."
demoregistry
Provides an MIS client function to operate as a "remote agent." This demonstrates how to register an application, similar to a licensing facility.
demoServer
Provides an MIS server function to operate as a "remote agent." This provides required support for demoregistry and diskInfo examples.
diskInfo
Demonstrates behavior to get information from an external (outside the MIS) process.


10.9.1 Compiling All Examples

You can compile and run the object behavior samples shipped with Solstice EM individually or as a group. Instructions for running each of the individual samples are provided in Section10.9.2 cellSample" through Section10.9.6 diskInfo." In addition, Section10.10 Object Development Scenario Using Chai Object" leads you through the entire process for the chai object in detail.

ODT provides a global Makefile that compiles all the object behavior examples. To build these examples, perform the following commands:

hostname# cd $EM_HOME/odt/src
hostname# Make all


Note – This mechanism does not currently compile the cellSample example. You must compile and run cellSample by itself.

10.9.2 cellSample

10.9.2.1 Important Code Functions

The cellSample example illustrates how to use the Object Services API. Specific sections of the code are not specifically identified as being more important than any others. You might want to look at all the code to see how the Object Services API can be used effectively.

To Build the Example

1. Go to the ODT examples directory.

	 hostname% cd $EM_HOME/src/odt/cellSample

2. Copy the cellSample GDMO and ASN.1 files to the appropriate directories.

	 hostname% cp cellSample.gdmo $EM_HOME/etc/gdmo
hostname% cp cellSample.asn1 $EM_HOME/etc/asn1

3. Load the GDMO into the MDR.

	 hostname% em_services -r

4. Generate the code for cellSample.

	 hostname% em_obcodegen cellSample

5. Create the dynamic linked library for the cellSample object class for default implementation.

	 hostname% make -f Makefile.cellSample extended

6. Load the cellSample source into an addressable location in the MIS.

	 hostname% ./cellSample.load

7. Restart the MIS.

hostname% $EM_HOME/bin/em_services

To Execute the Example

1. Create an instance of the cellSample object (instantiate the class).

	 ./cellSample

2. Start OBED and run actions against the cellSample.

10.9.3 demoPing

10.9.3.1 Important Code Functions

The demoPing example shows how you can develop a simple native agent using the ODT.

Action Implementation

//------------------------------------------------------
------------//
// ACTION IMPLEMENTATION //
//----------------------------------------------------------- -------//
// Switch for all actions specified in the GDMO definition of Managed //
// Object Class. Add the Action implementation in individual case //
// statements.//
//  IMPORTANT NOTE:                                      
               //
// --------------- //
// When implementing an Action, Please do not forget to return Action//
// result in cd.result for individual actions in switch statement. //
// //
//  ODT_DEFAULT IMPLEMENTATION:                          
            //
// ----------------------- //
// Default implementation returns a NULL Asn1Value and indicates //
// success by returning CHECK_DONE in CheckData. //
//----------------------------------------------------------- -------//
             switch(ai.local_value() ) 
{
case IDX_pingHost:
#ifdef ODT_EXTENDED
//********* $ODT_EXT_START [ACTION IMPLEMENTATION INSERT] **********//
{
	 	 	 	      DataUnit hostname;
input.decode_octets(hostname);
demoPing_error.print("IS %s\n",hostname.chp());
	 	 	 	      if(!demoping(hostname, 
cb))
{
cd.result = CheckData::CHECK_ERROR;
cb.exec(&cd);
}
return;
}
//*********** $ODT_EXT_END   [ACTION IMPLEMENTATION 
INSERT] ********//
#endif
break;
             };
#ifdef ODT_DEFAULT
// Default implementation (returns NULL Action Response & Success)
cd.result = CheckData::CHECK_DONE;
cb.exec(&cd);
#endif
}
    BEGHANDLERS
CATCHALL {
#ifdef ODT_EXTENDED
//******* $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//******* $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

demoPing Callback Function

void
demoping_cb(Ptr userdata, Ptr calldata)
{
CheckData cd;
demoping_userdata *d1 = (demoping_userdata *)userdata;
DataUnit hostname = d1->hostname;
    struct sockaddr_in from;
int len;
char buf[1024];
int fromlen=sizeof(from);
	 if ( (len = recvfrom(d1->sockfd, (char *)buf, 
1024 , 0, 
(sockaddr*)&from, &fromlen )) < 0)
{
demoPing_error.print("Failed in recvfrom() for ICMP Packet \n");
cd.result = CheckData::CHECK_ERROR;
d1->cb.exec(&cd);
purge_fd_read_callback(d1->sockfd);
close(d1->sockfd);
delete d1;
return;
}
	 demoPing_debug.print("received %d = 
%s\n",len,buf);
demoPing_debug.print("from %ld\n",from.sin_addr);
	 pingreply_struct prpl;
	 if(!pr_pack( (char *)buf, len, &prpl))
{
post_fd_read_callback(d1->sockfd,
Callback((CallbackHandler)demoping_cb, d1));
return;
}
	 close(d1->sockfd);
	 Asn1Value direply;
if(!make_pingrpl(&prpl,direply))
{
demoPing_error.print("Failed in encoding action reply\n");
cd.result = CheckData::CHECK_ERROR;
d1->cb.exec(&cd);
purge_fd_read_callback(d1->sockfd);
close(d1->sockfd);
delete d1;
return;
}
direply.print(demoPing_error);
	 cd.rv = direply;
cd.result = CheckData::CHECK_DONE;
purge_fd_read_callback(d1->sockfd);
close(d1->sockfd);
d1->cb.exec(&cd);
delete d1;
}

To Build the Example

1. Go to the ODT examples directory.

	 hostname% cd $EM_HOME/src/odt/demoPing

2. Copy the demoPing GDMO and ASN.1 files to the appropriate directories.

	 hostname% cp demoPing.gdmo $EM_HOME/etc/gdmo
hostname% cp demoPing.asn1 $EM_HOME/etc/asn1

3. Load the GDMO into the MDR.

	 hostname% em_services reload

4. Generate the code for demoPing.

	 hostname% em_obcodegen demoPing

5. Create the dynamic linked library for the demoPing object class for default implementation.

	 hostname% make -f Makefile.demoPing extended

6. Load the demoPing source into an addressable location in the MIS.

	 hostname% ./demoPing.load

7. Restart the MIS.

hostname% $EM_HOME/bin/em_services

To Execute the Example

1. Create an instance of the demoPing object (instantiate the class).

	 ./pmi_demoPing

2. Start OBED and run action on instance specifying the hostname you want to ping.

3. Alternatively, you can run the ODT Sample Program driver (odtsamples) and select the Ping option.

10.9.4 demoregistry

10.9.4.1 Important Code Functions

Action Implementation

//------------------------------------------------------
------------//
// ACTION IMPLEMENTATION //
//----------------------------------------------------------- -------//
// Switch for all actions specified in the GDMO definition of Managed //
// Object Class. Add the Action implementation in individual case //
// statements. //
//  IMPORTANT NOTE:                                      
             //
// --------------- //
// When implementing an Action, Please do not forget to return Action//
// result in cd.result for individual actions in switch statement. //
// //
//  ODT_DEFAULT IMPLEMENTATION:                          
            //
// ----------------------- //
// Default implementation returns a NULL Asn1Value and indicates //
// success by returning CHECK_DONE in CheckData. //
//----------------------------------------------------------- -------//
             switch(ai.local_value() ) 
{
case IDX_emDemoRegistryReg:
#ifdef ODT_EXTENDED
//********** $ODT_EXT_START [ACTION IMPLEMENTATION 
INSERT] **********//
{
Asn1Value hostasn1;
Asn1Value appasn1;
Asn1Value appidasn1;
Asn1Value temp;
DataUnit appname;
DataUnit hostname;
I32 appid;
	 	 	 	      
input.first_component(temp);
temp.first_component(hostasn1);
input.next_component(temp,temp);
temp.first_component(appasn1);
input.next_component(temp,temp);
temp.first_component(appidasn1);
	 	 	 	      
hostasn1.decode_octets(hostname);
appasn1.decode_octets(appname);
appidasn1.decode_int(appid);
	 	 	 	      
if(!register_me(appname, hostname, appid, cb))
{
cd.result = CheckData::CHECK_ERROR;
cb.exec(&cd);
}
return;
}
//********** $ODT_EXT_END   [ACTION IMPLEMENTATION 
INSERT] **********//
#endif
break;
case IDX_emDemoRegistryValidateCookie:
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [ACTION IMPLEMENTATION INSERT] *********//
// Use it to implement some good cookie eating in your app
//*********** $ODT_EXT_END [ACTION IMPLEMENTATION INSERT] **********//
#endif
                     break;
case IDX_emDemoRegistryUnreg:
#ifdef ODT_EXTENDED
//********* $ODT_EXT_START [ACTION IMPLEMENTATION INSERT] **********//
{
Asn1Value hostasn1;
Asn1Value appasn1;
Asn1Value appidasn1;
Asn1Value temp;
	 	 	 	      DataUnit appname;
DataUnit hostname;
I32 appid;
	 	 	 	      
input.first_component(temp);
temp.first_component(hostasn1);
input.next_component(temp,temp);
temp.first_component(appasn1);
input.next_component(temp,temp);
temp.first_component(appidasn1);
	 	 	 	      
hostasn1.decode_octets(hostname);
appasn1.decode_octets(appname);
appidasn1.decode_int(appid);
	 	 	 	      
if(!unregister_me(appname, hostname, appid, cb))
{
cd.result = CheckData::CHECK_ERROR;
cb.exec(&cd);
}
return;
}
//********** $ODT_EXT_END   [ACTION IMPLEMENTATION 
INSERT] **********//
#endif
break;
};
#ifdef ODT_DEFAULT
// Default implementation (returns NULL Action Response & Success)
cd.result = CheckData::CHECK_DONE;
cb.exec(&cd);
#endif
        }
BEGHANDLERS
CATCHALL {
#ifdef ODT_EXTENDED
//******** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//******** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

Function to Register Application

Result
register_me(DataUnit &appname, DataUnit &hostname, int appid,
Callback &cb)
{
	 demoregistry_userdata *d1=new 
demoregistry_userdata;
emDemoRegister info;
	 strcpy(info.appname,appname.chp());
strcpy(info.hostname,hostname.chp());
	 if(! demoClientSend( &info, DemoRegister, 
d1->sockfd, 
hostname.chp()) )
return(NOT_OK);
	 d1->cb = (Callback *)&cb;
d1->appname = appname;
d1->hostname = hostname;
d1->appid = appid;
	 post_fd_read_callback(d1->sockfd,
Callback((CallbackHandler)demoregistry_cb, d1));
	 return OK;
}

Function to Unregister Application

Result
unregister_me(DataUnit &appname, DataUnit &hostname, int appid,
Callback &cb)
{
	 demoregistry_userdata *d1=new 
demoregistry_userdata;
emDemoRegister info;
	 strcpy(info.appname,appname.chp());
strcpy(info.hostname,hostname.chp());
	 if(! demoClientSend( &info, DemoUnregister, 
d1->sockfd, 
hostname.chp()) )
return(NOT_OK);
	 d1->cb = (Callback *)&cb;
d1->appname = appname;
d1->hostname = hostname;
d1->appid = appid;
	 post_fd_read_callback(d1->sockfd,
Callback((CallbackHandler)demounregistry_cb, d1));
	 return OK;
}

To Build the Example

1. Go to the ODT examples directory.

	 hostname% cd $EM_HOME/src/odt/demoregistry

2. Copy the demoregistry GDMO and ASN.1 files to the appropriate directories.

	 hostname% cp demoregistry.gdmo $EM_HOME/etc/gdmo
hostname% cp demoregistry.asn1 $EM_HOME/etc/asn1

3. Load the GDMO into the MDR.

	 hostname% em_services reload

4. Generate the code for demoregistry.

	 hostname% em_obcodegen demoregistry

5. Create the dynamic linked library for the demoregistry object class for default implementation.

	 hostname% make -f Makefile.demoregistry extended

6. Load the demoregistry source into an addressable location in the MIS.

	 hostname% ./demoregistry.load

7. Restart the MIS.

hostname% $EM_HOME/bin/em_services

10.9.4.2 Running the Example

1. Create an instance of demoregistry class (instantiate the class).

	 ./pmi_demoregistry

2. Run demo_server on your local host or, if running on a remote host make sure Solstice EM is installed on the remote host.

3. Start OBED and find the object instance under EM-MIS.

4. Click on the OI and issue a DemoReg action where the ActionInfo parameter is {"hostname", "ApplicationName", 345}.

5. Alternatively, you can run the ODT Sample Program driver (odtsamples) and run the Register option or the UnRegister option.

10.9.5 demoServer

10.9.5.1 Building the Example

1. Go to the ODT examples directory.

	 hostname% cd $EM_HOME/src/odt/demoServer

2. Create the dynamic linked library for the demoServer object class for default implementation.

	 hostname% make

10.9.5.2 Running the Example

To start the demo_server:

> demo_server

10.9.6 diskInfo

10.9.6.1 Building the Example

1. Go to the ODT examples directory.

	 hostname% cd $EM_HOME/src/odt/diskInfo

2. Copy the diskInfo GDMO and ASN.1 files to the appropriate directories.

	 hostname% cp diskInfo.gdmo $EM_HOME/etc/gdmo
hostname% cp diskInfo.asn1 $EM_HOME/etc/asn1

3. Load the GDMO into the MDR.

	 hostname% em_services reload

4. Generate the code for diskInfo.

	 hostname% em_obcodegen diskInfo

5. Create the dynamic linked library for the diskInfo object class for default implementation.

	 hostname% make -f Makefile.diskInfo extended

6. Load the diskInfo source into an addressable location in the MIS.

	 hostname% ./diskInfo.load

7. Restart the MIS.

hostname% $EM_HOME/bin/em_services

10.9.6.2 Running the Example

1. Create an instance of the diskInfo object (instantiate the class).

	 ./pmi_diskInfo

2. Start OBED and run an action on the object instance, specifying the hostname about which you want to get disk information.

3. Alternatively, you can run the ODT Sample Program driver (odtsamples) and select the DiskInfo of a Host option.

10.10 Object Development Scenario Using Chai Object

The sample files shipped with Solstice EM for object development scenarios provide important information in README files. Although the information in the README files is fairly complete, this section of the documentation provides an expanded view of the object development scenario for the Chai managed object.

10.10.1 Creating Your Own Object Class

1. Load the chai managed object into the Meta Data Repository (MDR).

# em_gdmo 
hostname chai.gdmo
# em_asn1 -o `pwd' chai.asn1
# cp 1.3.6.1.4.1.42.2.2.2.1.96.3.1 /var/opt/SUNWconn/em/usr/data/ASN1
# cp *-ASN1 /var/opt/SUNWconn/em/usr/data/ASN1

2. Define environment variables, if needed.

Location of hidden/intermediate files:
HIDDENDIR=/tmp
Data storage for OC whether PERSISTENT or VOLATILE:
DATASTORAGE=PERSISTENT

3. Go to the directory where you want your code to be generated.

% cd user_directory

4. Generate the C++ code for your objects.

You will see output similar to the following:

hostname% em_obcodegen chai
objdefn_info: Attribute Name is chaiKettleNumber
objdefn_info: Attribute Name is chaiBlend
objdefn_info: Attribute Name is chaiReady
objdefn_info: Attribute Name is discriminatorConstruct
objdefn_info: Attribute Name is administrativeState
objdefn_info: Attribute Name is operationalState
objdefn_info: Total Number Of Attributes is 6
objdefn_info: ********************************
objdefn_info: Action Name is brewChai
objdefn_info: Total Number Of Actions is 1
objdefn_info: *****************************
objdefn_info: Name Binding Name is chai-system
objdefn_info: Name Binding Name is chai-chai
objdefn_info: Total Number Of Name Bindings is 2
objdefn_info: ***********************************

Note that OCG identifies the attributes, actions, and name bindings for which code will be generated.
The following files are generated:

  • Makefile.chai
  • README.chai
  • chai.load
  • chai.unload
  • chai_user.odt.cc
  • chai_user.odt.hh
  • pmi_chai.cc

5. Compile and make the dynamic library for the default implementation.

% make -f Makefile.chai default

This command compiles and makes a dynamic library called chai.so.

6. Create a customized implementation.

To create a customized implementation, you need to first modify the source code. Then, to compile and make a customized library, use the following format:

% make -f Makefile.chai extended

7. Load the new dynamic library.

% chai.load

8. Terminate and restart the MIS.

# em_services

9. Instantiate the new chai object.

% cd chai_Create_program
% make chai
% chai
// This creates the chai object
% chai -g
// This gets attributes of new chai object

10. Run the debugger to verify the object behaves as expected.

% debugger $EM_HOME/bin/em_mis &
stop in DynLoader::DynLoader
run

10.10.2 Debugging Flags

The following code lines that contain the debug agents for the chai object class are included in the chai_user.odt.cc file.

	 Debug_on(cahi_info)
Debug_on(chai_error)

If debug agents are spread across multiple files, the above definitions must only be included in the chai_user.hh file (copied and modified from chai_user.odt.hh). The other files need to contain the following code lines:

	 extern Debug chai_info;
extern Debug chai_error;

10.10.3 Sample Behavior Implementation

The following program implements specialized behavior for the chaiReady attribute. If chaiReady is 0, then set the chaiBlend to "Earl Grey" and send brewAction.

To add this behavior, insert the following piece of code in chai_user.cc at the location of chai_AttrSecty::read after the subread is performed.

// User Behavior Extension: Start 
// Def: If the chaiReady is equal to 0 then
// Set the blend to "Earl Grey" and then send a action
// to brewchai.
// SectyInfo definition 
AttrSectyInfo AttrInfo;
ActionSectyInfo ActionInfo;
	 Asn1Value	   ready, blend, Orig_Blend; 
I32 Is_chai_Ready;
// Get original index of our Attribute 
int org_index = AttrSectyInfo2index(ai);
// Check to see we're reading chaiReady, if yes, then 
specialize 	 
// the behavior
if (org_index == IDX_chaiReady) {
if (av) {
av.decode_int(Is_chai_Ready);
if (!Is_chai_Ready)
{
// We're out of chai.. brew and choose my blend
// Earl Grey
index2AttrSectyInfo(IDX_chaiBlend, AttrInfo);
(void) fetch(AttrInfo, NULL_CALLBACK);
(void) read(AttrInfo, Orig_Blend);
	 	     DataUnit O_blend; 
Asn1Value new_blend;
	 	     Orig_Blend.decode_octets(O_blend); 
chai_debug.print("Read Secretary - chai_Blend is\n");
Orig_Blend.print(chai_debug);
if (O_blend != DataUnit("Earl Grey"))
{
// Special check to blend only Earl Grey
DataUnit chai_blend("Earl Grey");

new_blend.encode_octets(TAG_OCTSTR, chai_blend);
(void) write(AttrInfo, new_blend);
	 	         (void) store(AttrInfo, 
NULL_CALLBACK); 
}
// Go Ahead and Brewchai
index2ActionSectyInfo(IDX_brewchai, ActionInfo);
action(ActionInfo, new_blend, NULL_CALLBACK);
}
}
}

10.10.4 chai Object Class Definitions

The example GDMO and ASN.1 definitions for the chai object class are installed into the $EM_HOME/src/odt/chai directory when you install the ODT onto your system (SUNWemobj package).

The chai.gdmo file defines the following attributes:

The chai.gdmo file also defines the brewChai action.

10.10.4.1 Sample chai.gdmo Definitions File

-- Copyright 03 Apr 1996 Sun Microsystems, Inc. All 
Rights Reserved.--
-- #pragma ident "@(#)chai.gdmo 1.2 96/04/03 Sun Microsystems"
MODULE "EM Chai Document"
basechai MANAGED OBJECT CLASS
DERIVED FROM "Rec. X.721 | ISO/IEC 10165-2 : 1992" : top;
	 CHARACTERIZED BY
chaiPackage;
REGISTERED AS { em-chai-objectClass 0 };
chaiPackage PACKAGE
BEHAVIOUR chaiPackageDefinition BEHAVIOUR DEFINED AS
!This managed object class represents the chai
from the neighbourhood chai shop !;
;
ATTRIBUTES
chaiKettleNumber GET-REPLACE,
chaiBlend GET-REPLACE,
chaiReady GET-REPLACE,
"Rec. X.721 | ISO/IEC 10165-2 : 1992" : discriminatorConstruct
REPLACE-WITH-DEFAULT
DEFAULT VALUE Attribute
ASN1Module.defaultDiscriminatorConstruct
GET-REPLACE,
"Rec. X.721 | ISO/IEC 10165-2 : 1992" : administrativeState
GET-REPLACE,
"Rec. X.721 | ISO/IEC 10165-2 : 1992" : operationalState
GET;
ACTIONS
brewChai;
NOTIFICATIONS
"Rec. X.721 | ISO/IEC 10165-2 : 1992" :
objectCreation,
"Rec. X.721 | ISO/IEC 10165-2 : 1992" :
objectDeletion,
"Rec. X.721 | ISO/IEC 10165-2 : 1992" :
attributeValueChange;
REGISTERED AS { em-chai-package 1 };
chai MANAGED OBJECT CLASS
DERIVED FROM basechai;
REGISTERED AS { em-chai-objectClass 1 };
-- Actions
brewChai ACTION
MODE CONFIRMED;
WITH INFORMATION SYNTAX Chai-ASN1.ChaiString;
WITH REPLY SYNTAX Chai-ASN1.ChaiString;
REGISTERED AS { em-chai-action 1 };
-- Name Bindings
chai-system NAME BINDING
SUBORDINATE OBJECT CLASS chai;
NAMED BY
SUPERIOR OBJECT CLASS "Rec. X.721 | ISO/IEC 10165-2 : 1992" : system;
WITH ATTRIBUTE chaiKettleNumber;
BEHAVIOUR chai-rootBehaviour BEHAVIOUR DEFINED AS
!This name is used to define the chai object
name binding!;
;
CREATE;
DELETE ONLY-IF-NO-CONTAINED-OBJECTS;
REGISTERED AS { em-chai-binding 1 };
chai-chai NAME BINDING
SUBORDINATE OBJECT CLASS chai;
NAMED BY
SUPERIOR OBJECT CLASS chai;
WITH ATTRIBUTE chaiKettleNumber;
BEHAVIOUR chai-systemchai BEHAVIOUR DEFINED AS
!This name is used to define the chai object
name binding under system branch!;
;
CREATE;
DELETE ONLY-IF-NO-CONTAINED-OBJECTS;
REGISTERED AS { em-chai-binding 2 };
-- Attributes
chaiKettleNumber ATTRIBUTE
WITH ATTRIBUTE SYNTAX Chai-ASN1.ChaiInteger;
MATCHES FOR EQUALITY;
BEHAVIOUR chaiKettleNumberBehaviour BEHAVIOUR DEFINED AS
!This is the naming attribute for the chai
object.!;
;
REGISTERED AS { em-chai-attribute 1 };
chaiBlend ATTRIBUTE
WITH ATTRIBUTE SYNTAX Chai-ASN1.ChaiString;
MATCHES FOR EQUALITY;
BEHAVIOUR chaiBlendBehaviour BEHAVIOUR DEFINED AS
!This is the blend of chai that is brewing
in the current Kettle!;
;
REGISTERED AS { em-chai-attribute 2 };
chaiReady ATTRIBUTE
WITH ATTRIBUTE SYNTAX Chai-ASN1.ChaiInteger;
MATCHES FOR EQUALITY;
BEHAVIOUR chaiReadyBehaviour BEHAVIOUR DEFINED AS
!If this attribute is true there is chai in
the Kettle!;
;
REGISTERED AS { em-chai-attribute 3 };
END

10.10.4.2 Sample chai.asn1 Definitions File

-- Copyright 03 Apr 1996 Sun Microsystems, Inc. All 
Rights Reserved.--
-- #pragma ident "@(#)chai.asn1 1.2 96/04/03 Sun Microsystems
Chai-ASN1 
{iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) sun(42)
products(2) management(2) em(2) odt(1) em-chai(96)
asn1Module(2) 0}

DEFINITIONS ::=
BEGIN
em-chai OBJECT IDENTIFIER ::=
{iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) sun(42)
products(2) management(2) em(2) odt(1) em-chai(96)}
em-chai-objectClass  OBJECT IDENTIFIER ::= { em-chai 3 
}
em-chai-package OBJECT IDENTIFIER ::= { em-chai 4 }
em-chai-binding OBJECT IDENTIFIER ::= { em-chai 6 }
em-chai-attribute OBJECT IDENTIFIER ::= { em-chai 7 }
em-chai-action OBJECT IDENTIFIER ::= { em-chai 9 }
ChaiInteger ::= INTEGER
ChaiString ::= GraphicString
ChaiBoolean ::= BOOLEAN
END

10.10.5 Sample PMI Program to Create a New chai Object Instance

/*
"This file is generated using Solstice EM (2.0) - Object Development Tools" Code Generator
*/
#include <hi.hh>
#include <error.hh>
#include <sys/types.h>
#include <unistd.h>
#ifdef HPUX
#include <sys/param.h>
#else
#include <sys/systeminfo.h>
#endif
void create_chai( DU &dn);
main(int argc, char **argv)
{
printf("MODIFY THE GENERATED CODE FILE ./pmi_chai.cc \n");
exit(0);
	 Platform plat(duEM);
	 if (plat.get_error_type() != PMI_SUCCESS) 
{
printf("Platform constructor failed...\n");
printf("Reason: %s\n", plat.get_error_string());
exit(1);
}
	 // Initialize to the dn of object
	 // dn can be a name starting from local root or 
fully distinguished name
DU dn; /* DISTINIGUISHED NAME OF OBJECT HERE*/
	 // Connect to the mis running on the local host
if (!plat.connect("localhost", "chai_sample"))
{
printf("Connecting to platform Failed \n");
printf("Reason: %s\n", plat.get_error_string());
exit(2);
}
	 // Create the object
create_chai(dn);

}
void
display_attributes(Image &im)
{
// Get all the attribute names in an Array of 
DataUnits.
// Perform a get on each attribute to get its value
// Note we have stripped off the document name to make
// the attribute value pairs more readable
// the chp() method of the DataUnit is necessary to null
// terminate the DataUnit.
//
    Array(DU) attr_names = im.get_attr_names();
fprintf(stdout, "Attribute\tValue\n---------\t-----\n");
for (int i=0; i<attr_names.size; i++) {
DU& name = attr_names[i];
// note: next to lines use chp() function to convert a
// DataUnit into char *.
char *short_name = strrchr(attr_names[i].chp(),':');
fprintf(stdout, "%s: \t%s \n", ++short_name,
im.get_str(name,USE_EXPLICIT_CHOICE|OMIT_NEWLINES).chp());
}
fprintf(stdout, "\n\n");
fflush(stdout);
}
void
create_chai(DU &dn)
{
	 Image im;
im = Image(dn,DU("chai"));
	 if (!im.boot()) 
{
printf("Image::boot Failed %s\n",im.get_error_string());
exit(3);
}
	 /* UNCOMMENT AND MODIFY THE APPROPRIATE LINES IF YOU 
WANT TO CREATE
* OBJECT WITH SOME ATTRIBUTE VALUES
if (!im.set_str("chaiKettleNumber", "None"))
{
printf("Image::set_str() failed for chaiKettleNumber: %s %d\n",
im.get_error_string(), im.get_error_type());
exit(4);
}
if (!im.set_str("chaiBlend", "None"))
{
printf("Image::set_str() failed for chaiBlend: %s %d\n",
im.get_error_string(), im.get_error_type());
exit(4);
}
if (!im.set_str("chaiReady", "None"))
{
printf("Image::set_str() failed for chaiReady: %s %d\n",
im.get_error_string(), im.get_error_type());
exit(4);
}
*
*/
if (im.get_error_type() != PMI_SUCCESS)
{
printf("Image::set_str Failed %s\n",im.get_error_string());
exit(5);
}
	 if (!im.create()) 
{
printf("Create Failed %s\n",im.get_error_string());
exit(6);
}
printf("Created instance %s\n", dn.chp());
display_attributes(im);
}

10.10.6 Example Generated Code in .cc File

The following generated code stub examples are based on the chai example object. A complete scenario for defining the chai object is provided in Section10.10 Object Development Scenario Using Chai Object." The actual code that OCG generates can contain additional comments not reflected in this book.


Note – Throughout these examples and in any code generated by OCG, there are lines that are similar to the following:
//********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//**********
$ODT_EXT_END [LOCAL VARIABLE INSERT] ************//
These lines indicate areas in the code where you can safely add your own code to the generated code to further customize object behaviors.

10.10.6.1 Generated Asynchronous Read Stub Function (FETCH)

Function

chai_AttrSecty::fetch (Const AttrSectyInfo &ai, Const callback
	 &cb)

Description

This function is an asynchronous interface for reading attributes. For every attribute requested in a GET or SET request, the MIS Framework calls fetch for that attribute, followed by a read of the same attribute. The fetch function can reflect status back to the invoker by:

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Errors

The Operr data structure is passed to the Object Framework by invoking the passed exec with the parameter set to a pointer to the allocated Operr data structure. The default behavior is for the subordinate secretary to invoke the callback.


Note – A NULL parameter to the invocation of the callback indicates a POSITIVE status e.g cb.exec((Ptr) 0); If the ODT developer wishes to return an error, an Operr Data structure must be allocated from the heap and passed to the callback function.

Code Example

Result
chai_AttrSecty::fetch(const AttrSectyInfo &ai, const Callback &cb)
{
TRACE(Tracer TR(chai_trace, "chai_AttrSecty::fetch",
"this = 0x%lx, const AttrSectyInfo &ai = 0x%lx, const Callback &cb = "
"0x%lx", (void*)this, &ai, (void*)cb));
#ifdef ODT_EXTENDED
//********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//********** $ODT_EXT_END [LOCAL VARIABLE INSERT] ************//
#endif
    TRY 
{
// Fetch attribute specified by (ai)
return subfetch(ai,cb);
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [FETCH BEHAVIOUR SPECIALIZATION INSERT ] **//
//***** $ODT_EXT_END [FETCH BEHAVIOUR SPECIALIZATION INSERT ] **//
#endif
    }
BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.2 Generated Asynchronous Write Stub Function (STORE)

Function

chai_AttrSecty::store (Const AttrSectyInfo &ai, Const callback
	 &cb)

Description

This function is an asynchronous interface for storing attributes. For every attribute requested in a SET request, MIS Framework calls write for that attribute, followed by a store of the same attribute. The store function can reflect status back to the invoker by:

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Errors

The Operr data structure is passed to the Object Framework by invoking the passed exec with the parameter set to a pointer to the allocated Operr data structure. The default behavior is for the subordinate secretary to invoke the callback.


Note – A NULL parameter to the invocation of the callback indicates a POSITIVE status e.g cb.exec((Ptr) 0); If the ODT developer wishes to return an error, an Operr Data structure must be allocated from the heap and passed to the callback function.

Code Example

Result
chai_AttrSecty::store(const AttrSectyInfo &ai, const Callback &cb)
{
TRACE(Tracer TR(chai_trace, "chai_AttrSecty::store",
"this = 0x%lx, const AttrSectyInfo &ai = 0x%lx, const Callback &cb = "
"0x%lx", (void*)this, &ai, (void*)cb));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] ************//
#endif
    TRY 
{
// store attribute to DATASTORAGE specified by (ai)
return substore(ai,cb);
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [STORE BEHAVIOUR SPECIALIZATION INSERT ] **//
//***** $ODT_EXT_END [STORE BEHAVIOUR SPECIALIZATION INSERT ] **//
#endif
    }
BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.3 Generated Synchronous Read Stub Function (READ)

Function

chai_AttrSecty::read (Const AttrSectyInfo &ai, Asn1Value 
&av)

Description

This function is a synchronous interface for reading attributes. For every attribute requested in a GET or SET request, MIS Framework calls read for that attribute. The read function can reflect status back to the invoker by:

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Errors
Code Example

Result
chai_AttrSecty::read(const AttrSectyInfo &ai, Asn1Value &av)
{
TRACE(Tracer TR(chai_trace, "chai_AttrSecty::read",
"this = 0x%lx, const AttrSectyInfo &ai = 0x%lx, Asn1Value &av = "
"0x%lx", (void*)this, &ai, (void*)av));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] *************//
#endif
    TRY 
{
int index = AttrSectyInfo2index(ai);
        // Validate passed attribute index
if(!is_valid_index(index))
{
return NOT_OK;
}
        // Read in-memory value of attribute specified 
by (ai)
TRYRES (subread(ai,av));
        // Assign read attribute value 
index2lhsvalue(index) = av ;
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [READ BEHAVIOUR SPECIALIZATION INSERT] ****//
//***** $ODT_EXT_END [READ BEHAVIOUR SPECIALIZATION INSERT] ****//
#endif
return(OK);
}
BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.4 Generated Synchronous Write Stub Function (WRITE)

Function

chai_AttrSecty::write (Const AttrSectyInfo &ai, Const Asn1Value
	 &av)

Description

This function is a synchronous interface for writing attributes. For every attribute requested in a SET request, MIS Framework calls write for that attribute. The write function can reflect status back to the invoker by:

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Errors
Code Example

Result
chai_AttrSecty::write(const AttrSectyInfo &ai,
const Asn1Value &av)
{
TRACE(Tracer TR(chai_trace, "chai_AttrSecty::write",
"this = 0x%lx, const AttrSectyInfo &ai = 0x%lx, const Asn1Value "
"&av = 0x%lx", (void*)this, &ai, (void*)av));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] *************//
#endif
    TRY 
{
int index = AttrSectyInfo2index(ai);
        // Validate passed attribute index
if(!is_valid_index(index))
{
return NOT_OK;
}
        // Assign written attribute value
index2lhsvalue(index) = av ;
        // Execute Write thru
TRYRES (subwrite(ai,av));
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [WRITE BEHAVIOUR SPECIALIZATION INSERT ] **//
//***** $ODT_EXT_END [WRITE BEHAVIOUR SPECIALIZATION INSERT ] **//
#endif
        return(OK);
}
    BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.5 Generated Action Stub Function (ACTION)

Function

chai_AttrSecty::action (Const AttrSectyInfo &ai, Const Asn1Value 
	 &input, Const callback 
&cb)

Description

This function is an asynchronous interface for handling CMIP ACTIONS. The CMIP actions handled are those specified in the Managed Object Class definition in the GDMO. The action stub function can issue status to the invoker using 2 methods:

Arguments

This function uses the following arguments:

Return Value

This function returns no values aside from those passed back in the cb argument. CheckData return values are:

Sample Error Generating Code

The following code illustrates how to build an Action Response message. The action_type Oid is found in the ai and needs to be encoded using CONTEXT(2) as the tag. The object instance and object class information can be found from the moi reference. The action_reply is an any defined by the action_type. This needs to be encoded according to the syntax of the action_reply_syntax:

// Encode the action Type using Oid from the ai 
parameter
Asn1Value action_type;
action_type.encode_oid(TAG_CONT(2), ai.id);
 
// allocate and fill in Error Resp, need
// to complete the OI, OC, action_Type and action reply 
fields
ActionRes *resp;
if ( !(resp = (ActionRes 
*)Message::new_message(ACTION_RES)) ||
        !(resp->action_type = action_type) ||
        resp->oc.encode_oid(TAG_CONT(0), 
moi->object_class()) !=OK ||
                        !(resp->oi = moi->fdn())) 
{
	 	 THROW(ResourceLimX);
	 }
Asn1Value action_reply;
// Here we need to encode the action reply, consider a 
reply syntax
// of
// INTEGER ::= {
//	 noerror(0),
//	 nobandwidth(1)
//}
// To encode a nobandwidth error
action_reply.encode_int(TAG_INT,1);
resp->action_reply = action_reply;
cd.error = (ResMess *) resp;
cd.result = CHECK_ERROR;
cb.exec(&cd);

The same method above could be used to create any response message defined in message.hh that would make sense for this action request.

Code Example

void
chai_ActionSecty::action(const ActionSectyInfo &ai,
const Asn1Value &input,
const Callback &cb)
{
TRACE(Tracer TR(chai_trace, "chai_ActionSecty::action",
"this = 0x%lx, const ActionSectyInfo &ai = 0x%lx, const Asn1Value "
"&input = 0x%lx, const Callback &cb = 0x%lx",
(void*)this, &ai, (void*)input, (void*)cb ));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] ************//
#endif
    TRY 
{
        CheckData cd;              // CheckData (cd) - 
Action Response value //

switch(ai.local_value() )
{
case IDX_brewChai:
#ifdef ODT_EXTENDED
//********* $ODT_EXT_START [ACTION IMPLEMENTATION INSERT] *******//
//********* $ODT_EXT_END [ACTION IMPLEMENTATION INSERT] ********//
#endif
break;
             };
#ifdef ODT_DEFAULT
// Default implementation (returns NULL Action Response & Success)
cd.result = CheckData::CHECK_DONE;
cb.exec(&cd);
#endif
        }
    BEGHANDLERS
CATCHALL {
#ifdef ODT_EXTENDED
//****** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] ****//
//****** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] ****//
#endif
    }
ENDHANDLERS
}

10.10.6.6 Generated Instance Create Stub Function (CREATE)

Function

chai_AttrSecty::create_vote (Const Asn1Value &fdn,
	 Const Asn1Value &av)

Description

This function lets you validate a CMIP CREATE request before the infrastructure creates the object instance. The function is passed a resolved attribute list and FDN, which you can validate before voting OK or NOT_OK.

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Code Example

Result 
chai_InstanceSecty::create_vote(const Asn1Value &fdn,
const Asn1Value &av)
{
TRACE(Tracer TR(chai_trace, "chai_InstanceSecty::create",
"this = 0x%lx, const Asn1Value &fdn = 0x%lx, const Asn1Value "
"&av = 0x%lx", (void*)this, &ai, (void*)fdn, (void*)av ));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] *************//
#endif
    TRY 
{
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [CREATE VOTE SPECIALIZATION INSERT ] ******//
//***** $ODT_EXT_END [CREATE VOTE SPECIALIZATION INSERT ] ******//
#endif
        return OK;
}
    BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.7 Generated Instance Destroy Stub Function (DELETE)

Function

chai_AttrSecty::destroy_vote()

Description

This function lets you validate a CMIP DELETE request before the infrastructure deletes the object instance.

Arguments

This function uses no arguments.

Return Value

This function returns the following values:

Code Example

Result 
chai_AttrSecty::destroy_vote()
{
TRACE(Tracer TR(chai_trace, "chai_InstanceSecty::destroy_vote",
"this = 0x%lx", (void*)this));
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] *************//
#endif
    TRY 
{
#ifdef ODT_EXTENDED
//****** $ODT_EXT_START [DELETE VOTE SPECIALIZATION INSERT ] *****//
//****** $ODT_EXT_END [DELETE VOTE SPECIALIZATION INSERT ] *****//
#endif
        return OK;
}
    BEGHANDLERS
CATCHALL {
#ifdef ODT_DEFAULT
return (NOT_OK);
#endif
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.6.8 Generated Receive Event Stub Function (RECEIVE_EVENT)

Function

chai_AttrSecty::receive_event (Asn1Value &event_type,
	 Asn1Value &event_info)

Description

This function lets you receive events and notifications specified in event_type and event_info. You would provide specialized processing depending on event_type and event_info which have been received as the discriminatorConstruct specified in the object instance.


Note – The receive_event function only allow the user to access the event_type and event_info. This is a known problem. To access the complete event message place code in the invoke_moi function in the ObjectClassimpl.cc file which lives in the.hidden directory. In the cmd == discriminator_match section the developer can access the complete event message by casting parm to be an EventReq *. See example below.

Result chai_MOI::invoke_moi( void * s, const Command 
&cmd, void  *parm )
{
        if (cmd == discriminator_match)
        {
            // INSERT YOUR CODE HERE and cast parm to be 
an
            // and EventReq Message.
            Eventreq *p_event = (EvenReq *) parm;
            // Use p_event to access 
oi,oc,event_time,event_type 
            // and event_info
            // Decide if receive_event needs to be 
Called
            TRYRES(attrsecty->receive_event(
	 ((EventReq *)parm)->event_type,
                   ((EventReq *)parm)->event_info) ) 
;
                return OK;
        }
        return NOT_OK;
}


Note – This function is generated only if you specify the three discriminator attributes (DiscriminatorConstruct, OperationalState, and AdministrativeState) in your GDMO file and specify FILTER_ATTR: DiscriminatorConstruct in your configuration file.

Arguments

This function uses the following arguments:

Return Value

This function returns the following values:

Code Example

Result chai_AttrSecty::receive_event( 
Asn1Value &event_type, Asn1Value &event_info)
{
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [LOCAL VARIABLE INSERT] ************//
//*********** $ODT_EXT_END [LOCAL VARIABLE INSERT] ************//
#endif
    TRY 
{
#ifdef ODT_DEFAULT
return OK;
#endif
#ifdef ODT_EXTENDED
//*********** $ODT_EXT_START [EVENT PROCESSING INSERT] **********//
//*********** $ODT_EXT_END [EVENT PROCESSING INSERT] ***********//
#endif
    }
BEGHANDLERS
CATCHALL {
        return (NOT_OK);
#ifdef ODT_EXTENDED
//***** $ODT_EXT_START [ EXCEPTION HANDLING CATCHALL INSERT] *****//
//***** $ODT_EXT_END [ EXCEPTION HANDLING CATCHALL INSERT] *****//
#endif
    }
ENDHANDLERS
}

10.10.7 Example Generated Code in .hh File

The chai_user.hh file contains class definitions required for implementing behaviors. The object framework uses the methods defined in this file to perform CMIS operations on the managed object instance. The following secretaries are defined in this file:

10.10.7.1 Generated Object Definitions

//------------------------------------------------------
-----//
// OBJECT ATTRIBUTES ENUMERATION //
//----------------------------------------------------------- //
enum chai_ATTR_INDEX{
IDX_chaiKettleNumber,
IDX_chaiBlend,
IDX_chaiReady,
NUM_chai_ATTR
};
//------------------------------------------------------
-----//
// OBJECT ACTIONS ENUMERATION //
//----------------------------------------------------------- //
enum chai_ACTION_INDEX {
IDX_brewChai,
NUM_chai_ACTION
};

10.10.7.2 Generated OIDs

//------------------------------------------------------
-----//
// ATTRIBUTE OBJECT IDENTIFIERS (OID) //
//----------------------------------------------------------- //
#define OID_chai_chaiKettleNumber "1.3.6.1.4.1.42.2.2.2.1.96.7.1"
#define OID_chai_chaiBlend "1.3.6.1.4.1.42.2.2.2.1.96.7.2"
#define OID_chai_chaiReady "1.3.6.1.4.1.42.2.2.2.1.96.7.3"
//------------------------------------------------------
-----//
// ACTION OBJECT INDENTIFIERS (OID) //
//----------------------------------------------------------- //
#define OID_chai_brewChai "1.3.6.1.4.1.42.2.2.2.1.96.9.1"
//------------------------------------------------------
-----//
// NAME BINDING OBJECT IDENTIFIERS (OID) //
//----------------------------------------------------------- //
#define OID_chai_chai_system "1.3.6.1.4.1.42.2.2.2.1.96.6.1"
#define OID_chai_chai_chai "1.3.6.1.4.1.42.2.2.2.1.96.6.2"

10.10.7.3 Attribute Class Definition

class chai_AttrSecty: public AttrSecty 
{
private:
protected:
// Constructor ODT RESERVED
chai_AttrSecty(ObjMethMOI &m, const AttrSecty *sp,
const AttrSectyTmpl &t);
// Destructor ODT RESERVED
~chai_AttrSecty();
public:
// Local storage for MOI's Attributes
Asn1Value chaiKettleNumber;
Asn1Value chaiBlend;
Asn1Value chaiReady;
        // User Methods
Result read(const AttrSectyInfo &ai, Asn1Value &av);
Result write(const AttrSectyInfo &ai, const Asn1Value &av);
Result fetch(const AttrSectyInfo &ai, const Callback &cb);
Result store(const AttrSectyInfo &ai, const Callback &cb);
Result destroy_vote();
Result receive_event(Asn1Value &event_type, Asn1Value &event_info);
        void    action(const ActionSectyInfo &ai, 
const Asn1Value &input, 
const Callback &cb);
        static  int     AttrSectyInfo2index(const 
AttrSectyInfo &ai);
Result index2AttrSectyInfo(int index, AttrSectyInfo &ai);
Result index2ActionSectyInfo(int index, ActionSectyInfo &ai);
	     // ODT RESERVED METHODS
static AttrSecty *new_secty(ObjMethMOI &m, const AttrSecty *sp,
const AttrSectyTmpl &t);
Asn1Value &index2lhsvalue(int attrindex);
Result delete_prepare(DeleteType type);
static Result is_valid_index(int index);
static Oid index2Oid(int attrindex);
chai_ActionSecty *get_actionsecty()
{
chai_MOI *mm = (chai_MOI *)&moi;
chai_ActionSecty *actionsecty = mm->actionsecty;
return actionsecty;
}
#ifdef ODT_EXTENDED
//******* $ODT_EXT_START [MEMBER FUNCTION/PROTOTYPE INSERT] *****//
//******* $ODT_EXT_END [MEMBER FUNCTION/PROTOTYPE INSERT] ******//
#endif
};

10.10.7.4 Action Class Definition

class chai_ActionSecty: public ActionSecty 
{
protected:
chai_ActionSecty(ObjMethMOI &m, const ActionSecty *sp,
const ActionSectyTmpl &t) ;
public:
// USER METHODS
void action(const ActionSectyInfo &ai, const Asn1Value &input,
const Callback &cb);
        // INTRA-OBJECT CONV. METHODS
Result read(const AttrSectyInfo &ai, Asn1Value &av);
Result write(const AttrSectyInfo &ai, const Asn1Value &av);
Result fetch(const AttrSectyInfo &ai, const Callback &cb);
Result store(const AttrSectyInfo &ai, const Callback &cb);
Result index2AttrSectyInfo(int index, AttrSectyInfo &ai);
Result index2ActionSectyInfo(int index, ActionSectyInfo &ai);
	     // ODT RESERVED METHODS
static ActionSecty *new_secty(ObjMethMOI &m, const ActionSecty *sp,
const ActionSectyTmpl &t)
{
return (ActionSecty *)new chai_ActionSecty(m, sp, t);
}
static Result is_valid_index(int index);
static Oid index2Oid(int attrindex);
chai_AttrSecty *get_attrsecty()
{
chai_MOI *mm = (chai_MOI *)&moi;
chai_AttrSecty *attrsecty = mm->attrsecty;
return attrsecty;
}
virtual void check(const ActionSectyInfo &ai,
const ActionInfo *t,
const Asn1Value &av, const Callback &cb);
#ifdef ODT_EXTENDED
//******* $ODT_EXT_START [MEMBER FUNCTION/PROTOTYPE INSERT] *****//
//******* $ODT_EXT_END [MEMBER FUNCTION/PROTOTYPE INSERT] *****//
#endif
};


Sun Microsystems, Inc.
Copyright information. All rights reserved.
Doc Set  |   Contents   |   Previous   |   Next   |   Index