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
2
Terminology
2.1
Command Protocol:
3
Client API
3.1
NodeFactory
3.2
INode
3.3
AgentController
3.4
Agent
3.5
Process
3.6
Console
3.7
Collector
3.8
IDataProcessor
3.9
ICommandHandler
3.10
CommandElement
3.11
Example Client Development
4
Agent Base Classes
4.1
General Class Definitions
4.1.1
Class VariableProvider
4.1.2
Class MsgBlock
4.1.3
Class CmdBlock.
4.1.4
BaseAgentImpl Class.
4.1.5
DataProviderImpl class
4.1.6
BaseCollectorImpl Class
4.1.7
Events
4.1.8
Agent Configuration
Revision History
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
2
Terminology
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="https://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>
This section describes the client
API. The convention used in this document is that the names of classes are the
same as the component they
represent
on the target machine. For
example, the Agent class represents and provides access to an Agent
object on the target machine. Client writers must use this set of classes to
build clients to consume Agent Controller and Agent services. The client side
objects are denoted in blue color, example,
AgentController
represents the client side agent controller
object. The target objects are represented as
bold, example AgentController
is the
actual AgentController object.
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 I
Node::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 I
DataProcessor
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. |
I
CommandHandler
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.