Eclipse™ TPTP Data Collection Subsystem External Specification
Client and Agent API
Eclipse TPTP Platform Project
Revision 0.9
November 6, 2005
Content is provided under the terms and conditions of the Eclipse Public License
Version 1.0.
Eclipse is a trademark of Eclipse Foundation, Inc.
Intel and the Intel logo are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries
* Other names and brands may be claimed as the property of others.
Copyright © 2005, 2006 Intel Corporation.
Table of Contents
1 Eclipse TPTP Data Collection Subsystem External Specification
3.11 Example Client Development
Revision History
Rev. |
Date |
Author |
Company |
Summary of Changes |
The Test and Performance Tools Platform (TPTP) data collection sub-component
provides a framework that defines the architecture for agents and clients, and
provides the basic building blocks to create and consume data collection
services. An Agent is a reusable binary file that provides
services to the host process (example: application under profile or test),
provides a mechanism by which application data can be forwarded to clients. An
agent registers with the Agent controller to be consumed by
clients. The Agent Controller is a standalone component independent of the TPTP
Client (Eclipse workbench). It is a daemon that resides on each local or remote
deployment host. The primary service of the agent controller is to launch new
processes and attach to agents that externalize the process data to clients. The
agent controller provides extensible agent architecture for control capabilities
and data collection. Agents hosted within the Agent Controller may communicate
data back to monitoring clients (e.g. TPTP/Eclipse workbench). A Client
is a local or remote application (example: Eclipse Workbench) that is the
terminal destination of host process data that is externalized by an agent. The
data collection framework consists of a set of abstract and concrete classes.
This document describes the framework for developing agents and clients.
Figure 1 - Agent Controller Diagram
Command: An instruction to the recipient (client, agent or the AC) calling for an action. A command is the primary mechanism for message passing in the AC and is represented using XML elements. See the command protocol changes for further information.
Interface: Basically, a token used as an identifier to logically group services. Example: An interface serviced by the Agent controller is "agentManager", these token groups’ together services provided by the AC.
Agent Manager:
The Agent Manager is a service provided by the AC that enables the interface
that allows clients and agents to get information about agents and
process/consume agent instance services.
Process Controller:
The Process Controller service is a "System" Agent (system agents are specific
agents that are required by the AgentController to service requests) that is
started by the Agent Controller during its start-up. It may be used by the
Agent Controller to launch other agents and by clients/agents to launch
applications to be monitored. (System agents by default are shared and used by
multiple clients/agents. System agents are dependent on the configuration of the
AgentController - see documentation for additional details)
The basic command protocol has been modified in the AC to allow extensibility and portability by the use of XML. The schema for the command protocol is as described below. The command element must have a root of "<Cmd>" that contains the attributes destination (dest), source (src) and, context (ctxt). The destination is the connection identifier of the recipient, and the source is the connection identifier of the sender. Connection identifier is a token given by the agent manager in the AC to either a client or agent on its completion of a successful connection. The child element of a command is the name of the actual command, for example registerAgent in the example below. This command is serviced by the agent manager as described in the attribute interface identifier (iid). All elements encapsulated in the child element of the command are elements that comprise the necessary data elements for the command. This is extensible and can contain elements that have to be processed by the command recipient.
Command Schema:
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xsd:complexType name="CmdType">
<!-- The cmdName is a placeholder for the actual command name. Example, a commandName could be registerAgent or startProcess. -->
<xsd:sequence>
<xsd:element name="cmdName" type="xsd:string" minOccurs=1 maxOccurs=1>
<xsd:attribute name="iid" type="xsd:string"/>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="dest" type="xsd:int"/>
<xsd:attribute name="src" type="xsd:int"/>
<xsd:attribute name="ctxt" type="xsd:int"/>
</xsd:complexType>
</xsd:schema>
Example:
<Cmd dest=”100” src="102" ctxt="10001">
<registerAgent iid="org.eclipse.tptp.agentManager">
<agentID>102</agentID>
<processID>4067</processID>
<agentName>TimeCollector</agentName>
</registerAgent>
</Cmd>
The diagram below shows the classes that will be described in this section.
**Please refer to the actual class implementations for all the method names
Figure 2. Client Class Diagram
The NodeFactory class provides a static method (createNode) to create instances of the Node class. A parameter to the createNode method specifies the host name or IP address of the node to be created.
Method Signature |
Description |
INode* createNode(char* address) |
Creates a Node with the hostname or IP Address as an input. Returns a reference to the INode object. |
void deleteNode(Inode* node) |
Destroys the node object. |
The INode class represents a physical node on the network. This object represents either a local machine or a remote machine hosting the AgentController, depending upon the name provided in the createNode call, as described above. The connect call provided by this object establishes the connection to the AgentController.
Interface Signature |
Description |
char* getName() |
Returns the Host Name of the Node. |
Char* getINetAddress() |
Returns the IP address of the Node. |
AgentController* connect(int port) |
Connects to an AgentController using the port number as an input. Returns a reference to an instance of AgentController |
void disconnect() |
Disconnects from the Node. Returns success or failure |
AgentController* getAC(int port) |
Returns the AgentController instance running at the specified port to which the client is connected to. |
The INode::connect method returns an instance of the AgentController class. The AgentController class provides the client with access to the services provided by the Agent Controller component on the target system. This object also provides for the object instantiations of Agent and Process.
Interface Signature |
Description |
char* getName() |
Returns the Host Name of the target machine on which the AgentController is running. |
INode* getNode() |
Returns the instance of INode, the node on which AgentController is running. |
int getAgent(Agent* agent, int flags); |
Obtain an Agent instance and reference to the actual Agent The second parameter can be a combination (only if valid) of the following values. An agent reference is required to communicate and control the agent TPTP_CONTROLLER_ACCESS - Request Control Access on the Agent TPTP_OBSERVER_ACCESS - Request Observer Access on the Agent TPTP_CREATE_INSTANCE - Creates a new instance even if an existing instance is available TPTP_RUNNING_AGENTS_ONLY - Request only the running agents TPTP_LOCK_AGENT - Request exclusive usage and others can't share this agent |
int getAgentByProcessID(Agent* agent, int pid, int flags); |
Obtain an agent reference to an agent for the input Process id. An agent reference is required to communicate and control the agent
Flags used as an input can be a combination (only if a valid combination) of the following values. TPTP_CONTROLLER_ACCESS - Request Control Access on the Agent TPTP_OBSERVER_ACCESS - Request Observer Access on the Agent TPTP_LOCK_AGENT - Request exclusive usage and others can't share this agent |
char** queryAvailableAgents(char* interfaceName) |
Obtain a list of available agents on the AgentController filtered by the interface name. This includes agents that are deployed (available to be run) and the running agents |
Char* queryRunningAgents(int processID, char* interfaceName) |
Returns the list of all the running agents (Agent instances already created and available for use by clients) on the AgentController machine filtered by interface name. |
char* getAgentMetadata(char* agentName) |
Returns the Agent metadata (in XML string format) of the given input Agent name . |
int addEventListener(char* listenerID, int interfaceID) |
Adds an event listener that listens to event notifications (interface ID parameter) from the AgentController.
|
void sendCommand(char* cmd, int destID, ICommandHandler* handler); |
Used to send a command to the AgentController. The AgentController will process this command (if it belongs to itself or forward to the specified destination. The parameters include an input XML command string, destination ID and Command Handler required to handle any responses to this command. The second parameter (Destination ID, For e.g. Agent ID) specifies the intended recipient of the command. The destID is a unique identifier that identifies a component instance registered with the AgentController. Example: A client on completion of a successful connection with the AgentController obtains a connection id that is its unique identifier. |
IProcess* createNewProcess() |
Obtain a new IProcess instance. This instance can be used to launch and control the process |
The Agent class provides a local representation of actual agents running on the target system. Clients can sub-class the Agent class as detailed in the Collector class.
Interface Signature |
Description |
long addEventListener(char* interfaceID, ICommandHandler* listener) |
This adds the input listener as the listener of Agent events that are sent by the Agent object. Events sent by the Agent on being received by the client will notify the listener in context about the Event. A listener has to implement the CommandHandler abstract class in order to register and process the event. The interface ID parameter defines the list of interested events that the client wants to register. Returns the listener ID (an identity of the listener object) of the listener . |
void removeEventListener(char* interfaceid, long listenerid) |
Removes the specified Agent Listener |
char* getName() |
Returns the Name of the Agent. |
char* getAgentID() |
Returns the connection identifier of the Agent. The Agent ID is a unique identifier of an actual Agent instance that is hosted by the AgentController. |
void sendCommand(char* command, ICommandHandler* handler) |
Sends a Command to the agent running on the target machine. The input command handler is registered to receive any responses for the command sent to the agent. |
int createDataConnection(int direction); |
Establishes a data path between Client and Agent that can be used for transferring the data between them. The direction specifies if the data path needs to be created in forward, reverse or both directions. The possible values are
DATA_PATH_SEND DATA_PATH_RECEIVE DATA_PATH_TWOWAY |
int addDataListener(IDataProcessor* dataProcessor) |
Add a listener for incoming data. Once the listener is added, the data received over the data channel can be forwarded to the listener. The listener needs to implement the IDataProcessor interface to be able to receive and process data. |
int removeDataListener(IDataProcessor* dataProcessor) |
Removes the data processor. |
int destroyDataConnection(); |
Destroys the data connection that was established previously. |
virtual int sendData(char buffer[], int bufferLength); |
Sends data to the agent using the data channel. |
int sendData(char buffer[], int bufferLength, char dimeHeader[], int dimeLength) |
Sends data to the agent after adding the dime headers passed. In order to process large data buffers – the message can be broken into parts and headers can be associated with it to reassemble the message. This header associated is the dime header information.
|
void releaseAgent(); |
Release the agent reference |
bool requestControl(int flags); |
This method can be used to request control of the agent. See Agent access modes as described in the AgentController::getAgent call. |
void releaseControl(); |
Release agent control. Note that following this call the access mode defaults to being an observer. ReleaseAgent must be called to release the agent. |
The IProcess class represents a process that is to be launched or already launched on the target machine. This class provides the methods to launch and control the process running on the remote machine. A Process object instance is obtained by calling the createNewProcess method defined in the AgentController class. This class provides methods that allow a client to launch processes on the target system and receive notification of events concerning these processes.
Interface Signature |
Description |
void launch() |
This launches a process with the specified input parameters on the target machine |
Void kill() |
Kills the process that was launched. |
char* getProcessId() |
Returns the Process id |
bool validateProcessToLaunch() |
Validates the process launch information is correct or not. For e.g. checks if the executable is available at the specified working directory. Returns true if the validation is successful otherwise false. |
bool isActive() |
Returns true if the Process is active or false if inactive. |
IConsole* getConsole() |
Returns the console for this process. The IConsole instance can be used to write/read the std-in, std-out and std-err data of the target process. |
The IConsole class defines the methods that can be used to write (std-in) and read (std-out and std-err) to the launched target process.
Interface Signature |
Description |
void setDataProcessor(IDataProcessor* processor) |
Sets the Data Processor passed as the Console Data Processor. The Console Data Processor needs to implement the IDataProcessor interface. |
IDataProcessor* getDataProcessor() |
Returns the dataprocessor associated with the console |
void write(char* data) |
Writes to the process console (std-in) |
void close() |
Closed the console for the process to which the Console instance is associated with. |
The Collector class is a subclass of the Agent class. A collector is a type of an agent characterized by simple abstract methods for data collection as shown below. This class will be used when the client requests access to an agent on the target system that implements the collector command interface. The Collector class provides methods to send standard collector commands to the agent. The client may further subclass this class if the agent itself supports additional commands.
Interface Signature |
Description |
void run() |
Runs the collector. |
bool stop() |
Performs the stop operation on the collector. Stops the collector activity. |
void pause() |
Pauses the collector and it will not |
void resume() |
Resumes the previously paused collector. And the collector will start collecting the data again. |
void cancel() |
Cancels the collector activity and the data collected so far, is abandoned. |
int sendData(char buffer[], int bufferLength); |
This method should be called by client applications to send data to the agent over the data channel. NOTE: This is a new API to support bi-directional data transfer between client and agents. |
Clients must provide a concrete class that implements the IDataProcessor in order to register and receive data from an agent. The client library provides the basic functionality of reading the data and forwarding the data to the input Data processor.
Interface Signature |
Description |
void incomingData(char[] buffer, int length) |
This is invoked when data is received over the data channel. |
void waitingForData() |
This method is invoked if there is no data available on the data channel |
void invalidDataType(char data[], int length) |
This method is called by the client library if the data received is not valid. |
ICommandHandler defines the abstract class for processing incoming commands. Clients must provide their own implementation of this interface to receive commands in a variety of situations, including agent-initiated commands, asynchronous events, and responses to outgoing commands.
Interface Signature |
Description |
void incomingCommand(INode* node, CommandElement* command) |
A handler is required for processing the incoming commands as responses to commands or events sent either by the AgentController or the Agent. |
The CommandElement abstract class defines the structure of the commands that are sent by the client to either the AgentController or the Agent on the target system. Clients must extend this class to build a command to be sent to the AgentController or Agent and also process commands received from the AgentController or Agent. The object itself will then be responsible for writing its content to a buffer (or reading it from a buffer in the case of incoming commands). The client library provides classes, which do this for standard commands, but if a client uses custom commands, it must provide its own implementations.
Interface Signature |
Description |
Void setSource(unsigned long source) |
Set the source of the command i.e. Connection Identifier of the client |
void setContext(unsigned long context); |
Set the context of the command, this enables the incoming command to be mapped to the appropriate CommandHandler. |
void setDestination(unsigned long dest); |
Set the destination of the command, example AgentController or an Agent |
void setCommandName(char *commandName); |
Set the name of the command |
virtual void buildCommand()=0; |
Clients must implement this function. |
See the samples provided in the agent controller sdk
package.
The UML diagram below shows the TPTP agent class hierarchy. There are several abstract classes and their implementation classes defined. IBaseAgent and IBaseCollector provide the basic definitions for agents and one general type of agent, a collector. IBaseCollector extends IBaseAgent as every collector is also an agent. IVariableProvider, IDataProvider and their implementations provide additional useful classes for agents. An agent can extend from these classes to consume this behavior depending on the need and behavior of the agent itself. The BaseAgentImpl class is the top most class in the hierarchy and implements basic operations required of all agents such as registering with the Agent Controller. The BaseCollectorImpl class has been implemented for the group of agents that are collectors. These are agents which can make use of a general set of commands used in controlling the collection of data, such as start and stop. Developers can create an agent by extending from one of the base implementation classes in the hierarchy, using the default implementation or providing their own version of a method as needed.
Figure 3. The TPTP Agent Class Hierarchy
This section gives details about general class definitions. All these classes are available as external API and may be used during agent development.
The VariableProvider class is designed to allow an agent to expose the variables it uses to do its work. In effect, it allows an external entity to define what the agent does by directly manipulating its own internal set of variables. For convenience, variables can be combined and accessed in sets called VariableGroups.
Method Signature |
Description |
int listVariables(CmdBlock* cmdBlock) |
Sends the list of variables that the agent wants to expose to the requestor specified in the cmdBlock. |
int listVariableGroups(CmdBlock* cmdBlock) |
Sends the list of variable groups which have been previously defined to the requestor specified in the cmdBlock. |
int getVariable(int varID, CmdBlock* cmdBlock) |
Sends the variable specified by the varID to the requestor specified in the cmdBlock. |
int getVariableGroup(int varGroupID, CmdBlock* cmdBlock) |
Sends the variable group specified by the varGroupID to the requestor specified in the cmdBlock. |
int setVariable(Variable* varNode, CmdBlock* cmdBlock) |
Changes the variable specified by the varNode and sends a notice to the requestor specified in the cmdBlock. |
int setVariableGroup(VariableGroup* varGrp, CmdBlock* cmdBlock) |
Changes the variable group specified by the varGrp and sends a notice to the requestor specified in the cmdBlock. |
int processVariableProviderCommands(CmdBlock* cmd) |
Handles incoming requests for the VariableProvider interface (i.e., set of commands) |
This class represents the structure of a command message exchanged between the Agent Controller and agents. The contents (payload) of a message is typically an XML fragment in a command format that resolves to a CmdBlock as defined below.
Method Signature |
Description |
void setMagicNumber(unsigned int magNum) |
Sets the magic number for the message |
void setFlags(unsigned int flags) |
Sets message flags |
void setPayLoadLength(unsigned int length) |
Sets the length of the message (pMsg) in bytes. |
void setMsg(unsigned char* pMsg, int count) |
Sets the contents of the message. |
unsigned int getMagicNumber() |
Gets the magic number |
unsigned int getFlags() |
Gets the flags |
unsigned int getPayLoadLength() |
Gets the length of the message in bytes. |
unsigned char* getMsg() |
Gets the message. |
This class defines the generic structure of commands sent to an agent. Whenever a command is received by the agent, the base agent class parses the XML command fragment into an instance of a CmdBlock which can then be consumed the processCommand() method of agents which results in acting on the command.
Method Signature |
Description |
void setSourceID(int srcID) |
Sets the source ID from the command (i.e., who sent the command). Responses to this command should be sent to this ID. |
void setDestID(int destID) |
Sets the destination ID from the command. This will be this agent’s own ID. |
void setContextID(int contextID) |
Sets the context value from the command. The context value should be returned unchanged in any replies to the sender. |
void setIID(char* iid) |
Sets the interface ID for the command. The interface ID is the name of the set of commands the agent is expected to know, of which this command is a part. |
void setCommandName(char* commandName) |
Sets the command name string. |
void setParamList(tptp_list_t* paramList) |
Sets the command parameter list. All parameters are name/value pairs. The value can be of any type, but gets stored as a string. There can be zero or more parameters. |
int getSourceID() |
Returns the source ID for the command. |
int getDestID() |
Returns the destination ID for the command. |
int getContextID() |
Returns the context value for the command. |
char* getIID() |
Returns the interface ID for the command. |
char* getCommandName() |
Returns the command name. |
tptp_list_t* getParamList() |
Returns the command parameter list. |
The BaseAgentImpl class provides the default implementation for the basic needs of all agents.
Method Signature |
Description |
int registerAgent() |
Sends a registration request to the Agent Controller thereby making itself available to receive requests from a client. It also establishes a command channel with the Agent Controller, then starts a thread to handle messages coming in on the channel, calling on processCommand() to act on the command. |
int deRegisterAgent() |
Tells the Agent Controller it will no longer receive requests from clients. |
void waitForTermination() |
Waits for a termination notice from the Agent Controller. The agent should cleanup and exit when returning from this call. |
char* getAgentName() |
Returns the name of this agent. |
int getAgentID() |
Returns the connection ID of this agent which was obtained from the Agent Controller during the registration process. Use this as the source ID when sending commands from this agent. |
int getAgentControllerID() |
Returns the connection ID of the Agent Controller. Use this as the destination ID when sending commands to the Agent Controller. |
int getNextContext() |
Generates an arbitrary context value for this agent to use in sending commands that are not replies. When sending replies, should use the context value found in the original request. |
int terminate() |
Cleanup and exit. |
int processCommand(CmdBlock* cmd) |
Acts on the command in the CmdBlock if it chooses to. An agent handles its own command set, calling on the base class implementation to handle basic commands. |
void addClient(tptp_int32 clientID, tptp_clientAccessLevel accessLevel) |
Adds the connection ID of a client that has requested access to the agent to an internal list, along with its access level (controller, observer) |
void removeClient(tptp_int32 clientID) |
Removes the client connection ID from its internal list when the client no longer wants access to this agent. |
bool checkClientAccess(int clientID, tptp_clientAccessLevel accessLevel) |
Allows the agent to check incoming requests against its internal list to see if the requesting client ID has the correct access rights for this command. |
int sendCommand(char *pMessage) |
Sends a command to the Agent Controller. |
int sendErrorCommand(const int destID, const int ctxt, const int tptpErrCode, char *errInfo) |
Sends a TPTP_ERROR error response command to the specified destination ID. |
An agent that collects or generates data to be sent to the client would use the DataProviderImpl class. This class provides implementation for methods to set the data path, get the data path and send and receive data.
Method Signature |
Description |
int sendData(int destinationID, char buffer[], int bufferLength) |
Sends the contents of the buffer to the specified destination connection ID using a previously established data channel. |
int sendData(int destinationID, char buffer[], int bufferLength, DIME_HEADER_PTR_T dimeHeader, int dimeHeaderLength) |
Sends the contents of the buffer to the specified destination connection ID using a previously established data channel, attaching the specified DIME header to the buffer before sending. The contents of the header is used by the receiving side to identify the data or re-assemble it in a particular order. |
int receiveData(int sourceID, char buffer[], int bytesRead, DIME_HEADER_PTR_T dimeHeader) |
Handles data coming to the agent from the client identified by sourceID. There is no default implementation for this method. |
The BaseCollectorImpl class provides a common command set (interface) for agents that collect data.
Method Signature |
Description |
int run(CmdBlock* cmd) |
Causes data collection to begin. |
int pause(CmdBlock* cmd) |
Stop data collection temporarily. |
int resume(CmdBlock* cmd) |
Continue data collection from having been paused. |
int cancel(CmdBlock* cmd) |
Stop data collection and discard any unsent data. |
int stop(CmdBlock* cmd) |
Stop data collection and return any unsent data. |
Agents can send commands in direct response to requests from a client or as a result of some condition it has detected at some later time. Commands which are not a one-to-one response to a request are considered events. For example, an agent may send an error command to the client if it detects a problem while collecting data. This error command is considered an event. An agent defines the events it may send to a client in the same way it defines its command set and the responses to those commands.
During startup its startup, the Agent Controller discovers the agents it might launch by examining the directories contained within the “agents” directory as specified in its serviceconfig.xml file. The name of the directory indicates the name of the agent and must be unique. Inside each agent’s directory there must be an agent.xml file which specifies how to launch and manage the agent. The description of the contents of the agent.xml file is found in the user documentation.