The following document provides an overview of how TPTP's framework can be extended to register a primitive data collection mechanism that launches an agent with limited functionality.
2.0 Design Overview of Data Collectors & Analysis Types
2.1 Creating a Data Collector and an Analysis Type
2.1.1 Associating a Configuration to a Data Collector and an Analysis Type
2.2 Implementing a Launch Delegate
2.3 Implementing a Custom Control Provider
This document will walk through the steps required to create a custom data collector that will be associated with the "Java Application" launch configuration type. It also describes the steps required in associating an analysis type, custom configuration, launch delegate, and a control provider to the data collector registered. Readers that wish not to follow with the article can use the link at the very bottom to download a copy of the sample plug-in.
The reader is assumed to have an intermediate knowledge of TPTP and PDE. The features that will be leveraged in this document are present in TPTP-4.2.0-200603101411 or older. Ensure that a correct driver is downloaded and setup. See TPTP's installation guide for more details.
In TPTP's launch configuration framework, there are extension points that make it possible for contributors
to associate a data collector with a specific launch type. A data collector causes the launch of one or more agents.
The agents are expected to collect and report data that is
understandable by TPTP's loaders. An agent can for example report logging events (a.k.a Common Base Events),
profile events, monitoring events, and etc...
As an example, consider the data collectors that are associated with Java applications: Drop down the
menu of the profile toolbar item > Select Profile... > Double click Java Application to create a new
launch configuration > Switch to the Profile/Monitor tab.
The profile dialog should look similar to figure 2.1. Notice that there are two data collectors registered
with Java application:
- Java Profiling - This data collector will allow the launched Java application to be profiled
- Logging Agent Discoverer - This data collector performs periodic queries to determine if there are any logging agents registered with the process launched. Once a logging agent is discovered, it is automatically attached and monitored.

Figure 2.1 - Associated data collectors and analysis types of Java applications
Notice that in figure 2.1, the "Java Profiling" node has four associated analysis types. The purpose of an analysis type is to scope the data that needs to be collected. As a rule of thumb, a data collector defines how data is collected and its associated analysis types indicate what data should be collected.
Notice that there is a button on the right side of the dialog called "Edit Option". If a data collector of an analysis type has an associated configuration, then this button will be enabled. A configuration is a multi-page wizard that allows users to set custom input on editable options. As an example, select the " Java Profiling" data collector, and click on "Edit Options". Notice that the displayed wizard contains two pages: the first page is used to set the profiling filters, and the second page allows users to set options that limits profiling data.
Figure 2.2 provides an entity diagram that describes the overall relationship between the entities involved in a launch
configuration. A control provider will be further discussed in section 2.3.

Figure 2.2 - Entity relationship
- Create a plug-in with the default options. Name the plug-in "org.eclipse.tptp.examples.data.collector".
- Open the manifest file of the plug-in and declare a dependency on org.eclipse.debug.core, org.eclipse.jdt.launching, org.eclipse.tptp.platform.models, and org.eclipse.hyades.trace.ui.
- Switch to the extensions page of the manifest file and add the extension point "org.eclipse.hyades.trace.ui.dataCollectionMechanism". This extension will allow the new data collector to be registered.
-
Once the extension has been added, switch to the plugin.xml page and modify the extension's fragment to specify
its required elements and attributes (see below):
The above extension will declare a data collector and associate it with an analysis type with id "org.eclipse.tptp.examples.data.collector.executionAnalysisType". This analysis type will be defined in the next step. Use the following icon that the data collector makes use of:<!-- Declare the data collector -->
<extension point="org.eclipse.hyades.trace.ui.dataCollectionMechanism">
<!-- Declare the custom data collector -->
<collector
id = "org.eclipse.tptp.examples.data.collector.myCustomDataCollector"
name = "My Custom Data Collector"
description = "Here is a new data collector"
icon = "icons/full/etool16/data_collector.gif">
<!-- Associate this data collector with an anlysis type that will be defined later -->
<analysis>
<applicableType id = "org.eclipse.tptp.examples.data.collector.customAnalysisType"/>
</analysis>
</collector>
</extension>
(the icon should be copied in the plug-in and its path
specified as the value of the 'icon' attribute)
-
Use the "org.eclipse.hyades.trace.ui.analysisTypes" extension point to define a custom analysis type (see below):
The analysis type defined above is associated with a configuration that will be declared in section 2.1.1. Use the following icon for the analysis type:<!-- Declare the analysis type -->
<extension point="org.eclipse.hyades.trace.ui.analysisTypes">
<!-- The custom analysis type -->
<analysisType
name="Custom Analysis Type"
icon="icons/full/obj16/exectimeantype_obj.gif"
description= "Here is a new analysis type"
id="org.eclipse.tptp.examples.data.collector.customAnalysisType"
configurationId = "org.eclipse.tptp.examples.data.collector.customAnalysisTypeConfiguration">
</analysisType>
</extension>
. The next step is to associate the custom data collector with a launch configuration
type:
-
Associate the custom data collector with the Java application launch configuration type using the extension defined below:
Notice that the configuration element takes three attributes. The launchDelegate attribute defines a class which will handle the launching of the profile/monitor session, the configurationId attribute is the ID of the configuration extension for the data collector, and the associatedAgent attribute is the ID of the agent declaration extension that will be affiliated with the custom data collector. These attributes will further be explored in later sections. For now, create the class "CustomDelegate" under the package "org.eclipse.tptp.examples.data.collector.launcher". Have the class extend "org.eclipse.tptp.trace.ui.provisional.launcher.AbstractProcessLauncher".<!-- Make the associations between the Java launch configuration and the custom data collector -->
<extension point="org.eclipse.hyades.trace.ui.launchConfigMechanismAssociator">
<!-- Local Java Application -->
<association
launchConfigID = "org.eclipse.jdt.launching.localJavaApplication">
<mechanism mechanismID = "org.eclipse.tptp.examples.data.collector.myCustomDataCollector">
<configuration
launchDelegate = "org.eclipse.tptp.examples.data.collector.launcher.CustomDelegate"
configurationId = "org.eclipse.tptp.examples.data.collector.myCustomDataCollectorConfiguration"
associatedAgent = "org.eclipse.tptp.examples.data.collector.myCustomDataCollectorAgent">
</configuration>
</mechanism>
</association>
</extension>

Figure 2.3 - The results of the contribution
-
Use the "org.eclipse.hyades.trace.ui.configuration" extension point to define the configurations:
<!-- Define the configuration wizard that will be associated with the custom data collector and analysis type -->
<extension point = "org.eclipse.hyades.trace.ui.configuration">
<!-- Data collector configuration -->
<configuration
id = "org.eclipse.tptp.examples.data.collector.myCustomDataCollectorConfiguration"
class = "org.eclipse.tptp.examples.data.collector.configuration.CustomDataCollectorConfiguration"
dialogTitle = "Custom Data Collector Configuration">
</configuration>
<!-- Analysis type configuration -->
<configuration
id = "org.eclipse.tptp.examples.data.collector.customAnalysisTypeConfiguration"
class = "org.eclipse.tptp.examples.data.collector.configuration.CustomAnalysisTypeConfiguration"
dialogTitle = "Custom Analysis Type Configuration">
</configuration>
</extension>
- Define the classes AbstractConfiguration, CustomDataCollectorConfiguration, and CustomAnalysisTypeConfiguration under the package name "org.eclipse.tptp.examples.data.collector.configuration".
-
Open AbstractConfiguration and replace its content with:
package org.eclipse.tptp.examples.data.collector.configuration; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.tptp.trace.ui.provisional.launcher.DataCollectionEngineAttribute; import org.eclipse.tptp.trace.ui.provisional.launcher.IConfiguration; import org.eclipse.tptp.trace.ui.provisional.launcher.IConfigurationPage; import org.eclipse.tptp.trace.ui.provisional.launcher.IStatusListener; /** * An abstract configuration that will only display a single page with a label. */ public abstract class AbstractConfiguration implements IConfiguration { private IConfigurationPage configurationPage; /** * Here is our chance to initialize the configuration pages */ public void initialize() { /* Create the configuration page if it has not yet been created */ if (configurationPage == null) { configurationPage = new IConfigurationPage() { public void reset(ILaunchConfiguration launchConfiguration) { } public void createControl(Composite parent) { Composite result = new Composite (parent, SWT.NONE); result.setLayout(new GridLayout()); result.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Label titleLabel = new Label(result, SWT.NULL); titleLabel.setText(getLabelText()); titleLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Font font = titleLabel.getFont(); if (font != null) { FontData[] fonts = font.getFontData(); if (fonts != null && fonts.length >= 1) { titleLabel.setFont(new Font(Display.getDefault(), fonts[0].getName(), fonts[0].getHeight() + 3, SWT.BOLD)); } } } public String getPageName() { return this.getClass().getName(); } public String getTitle() { return "Title of the Configuration Wizard"; } public ImageDescriptor getWizardBanner() { return null; } public String getDescription() { return "Here is the description of the configuration wizard"; } public void addErrorListener(IStatusListener statusListener) { } }; } } /** * Return the configuration pages of this configuration. */ public IConfigurationPage[] getConfigurationPages() { return new IConfigurationPage[]{configurationPage}; } /** * Normally client would use this to write the selected options of the configuration wizard to * the launch configuration. */ public boolean finishConfiguration(ILaunchConfigurationWorkingCopy workingCopy) { return true; } /** * Normally this is used to return the attributes that is understandable by the back end engine * that starts the profile/monitor session. */ public DataCollectionEngineAttribute[] getAttributes() { return new DataCollectionEngineAttribute[]{}; } /** * Return the label text that will be displayed in the single page * configuration wizard. */ public abstract String getLabelText(); } -
Open CustomDataCollectorConfiguration and replace its content with:
package org.eclipse.tptp.examples.data.collector.configuration; /** * This data collector configuration */ public class CustomDataCollectorConfiguration extends AbstractConfiguration { public String getLabelText() { return "Data Collector Configuration"; } } -
Open CustomAnalysisTypeConfiguration and replace its content with:
package org.eclipse.tptp.examples.data.collector.configuration; /** * The analysis type configuration */ public class CustomAnalysisTypeConfiguration extends AbstractConfiguration { public String getLabelText() { return "Analysis Type Configuration"; } }

Figure 2.4 - The configuration of the custom data collector
Recall that in section 2.1 a launch delegate, "org.eclipse.tptp.examples.data.collector.launcher.CustomDelegate" was specified
for the custom data collector. Within TPTP's framework, a launch configuration type (e.g. Java application) is associated with a primary launch delegate
called org.eclipse.tptp.trace.ui.provisional.launcher.PrimaryLaunchDelegate. The primary launch delegate looks up the data collectors selected and invokes
their respective launch delegate. There are three different kinds of launchers that can be associated with a data collector (see table 2.1):
| Launch Delegate Type | Description |
|---|---|
| A self manageable launcher | This type of launcher benefits the least from the abstract launch classes available. A self manageable launcher will manage its own creation of data model entities. The general launcher in place will do nothing more than invoking the launch method of a self manageable launcher. |
| A process launcher | A type of launcher that will launch an actual process on the target machine where a profile/monitor session will begin. |
| An agent launcher | This type of launcher doesn’t need an actual process to be launched. It only creates and feeds an agent. The process that the agent is associated with will either be a dummy process OR one that’s created by a process launcher. |
Figure 2.5 is the decision tree that the primary launch delegate will use to determine the sequence of method invocations.
Figure 2.6 describes the relationship between the classes and interfaces involved. The delgate class that will be defined for the
custom data collector will extend AbstractProcessLauncher. The class will launch a Java process with an associated dummy agent that will not collect any
type of data.

Figure 2.5 - The interaction between the launch delegate classes and interfaces. Methods
marked by '+' will only be invoked once by the first delegate that is detected (e.g. if two data collectors are selected, then only one of the delegates will
have its '+' methods invoked by the primary delegate).

Figure 2.6 - The relationship between the launch delegate classes and interfaces
Open CustomDelegate and replace its content with the following code:
package org.eclipse.tptp.examples.data.collector.launcher;
import java.io.File;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.hyades.internal.execution.local.common.CommandElement;
import org.eclipse.hyades.internal.execution.local.common.Constants;
import org.eclipse.hyades.internal.execution.local.common.ControlMessage;
import org.eclipse.hyades.internal.execution.local.common.QueryProcessListCommand;
import org.eclipse.hyades.internal.execution.local.common.RegisteredProcessListCommand;
import org.eclipse.hyades.internal.execution.local.control.Agent;
import org.eclipse.hyades.internal.execution.local.control.AgentConfiguration;
import org.eclipse.hyades.internal.execution.local.control.AgentConfigurationEntry;
import org.eclipse.hyades.internal.execution.local.control.CommandHandler;
import org.eclipse.hyades.internal.execution.local.control.Node;
import org.eclipse.hyades.internal.execution.local.control.Process;
import org.eclipse.hyades.internal.execution.local.control.ProcessListener;
import org.eclipse.hyades.models.hierarchy.HierarchyFactory;
import org.eclipse.hyades.models.hierarchy.TRCAgent;
import org.eclipse.hyades.models.hierarchy.TRCAgentProxy;
import org.eclipse.hyades.models.hierarchy.TRCConfiguration;
import org.eclipse.hyades.models.hierarchy.TRCOption;
import org.eclipse.hyades.models.hierarchy.TRCProcessProxy;
import org.eclipse.hyades.models.hierarchy.util.SaveUtil;
import org.eclipse.hyades.trace.ui.ProfileEvent;
import org.eclipse.hyades.trace.ui.UIPlugin;
import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tptp.trace.ui.internal.launcher.core.LauncherConstants;
import org.eclipse.tptp.trace.ui.provisional.launcher.AbstractProcessLauncher;
/**
* The launcher class for the custom data collector
*/
public class CustomDelegate extends AbstractProcessLauncher
{
/** The agent name */
private static final String AGENT_NAME = "org.eclipse.tptp.examples.data.collector.agent";
/** The agent type */
private static final String AGENT_TYPE = "Custom Agent Type";
/** This is an extended version of the JDT launch configuration delegate that will be used as a helper to
* extract some required attributes from the configuration. */
protected JavaConfigurationExtended javaLaunchConfigurationDelegate;
public CustomDelegate()
{
super(AGENT_NAME, AGENT_TYPE);
javaLaunchConfigurationDelegate = new JavaConfigurationExtended();
}
/**
* Retrieve the working directory from the configuration
*/
protected String getWorkingDirectory(ILaunchConfiguration conf)
{
try
{
File workingDirectory = javaLaunchConfigurationDelegate.getWorkingDirectory(conf);
if (workingDirectory != null)
return workingDirectory.getAbsolutePath();
return null;
}
catch (CoreException e)
{
return null;
}
}
/**
* Retrieve the program arguments from the configuration
*/
protected String getProgramArguments(ILaunchConfiguration conf)
{
try
{
return javaLaunchConfigurationDelegate.getProgramArguments(conf);
} catch (CoreException e)
{
return null;
}
}
/**
* Retrieve the main type from the configuration
*/
protected String getMainTypeName(ILaunchConfiguration conf)
{
try
{
return javaLaunchConfigurationDelegate.getMainTypeName(conf);
} catch (CoreException e)
{
return null;
}
}
/**
* Retrieve the VM arguments from the configuration
*/
protected String getVMArguments(ILaunchConfiguration conf)
{
try
{
return javaLaunchConfigurationDelegate.getVMArguments(conf);
} catch (CoreException e)
{
return null;
}
}
/**
* Retrieve the classpath from the configuration
*/
protected String[] getClasspath(ILaunchConfiguration conf)
{
try
{
return javaLaunchConfigurationDelegate.getClasspath(conf);
} catch (CoreException e)
{
return null;
}
}
public Agent createAgent(Process process, final TRCProcessProxy trcProcessProxy) throws CoreException
{
final Agent agent = super.createAgent(process, trcProcessProxy);
process.addProcessListener(new ProcessListener()
{
/** The model entity represeting an agent */
private TRCAgentProxy trcAgentProxy;
public void processLaunched(final Process process)
{
long processId = 0;
try
{
processId = Long.parseLong(process.getProcessId());
}
catch (Exception e)
{
/* Ignore silently */
}
new Thread(new ProcessStateNotifier(new IProcessStateChangeListener(){
public void processStateChanged(boolean alive)
{
updateAgentStatus(alive);
}}, process, processId)).start();
String pPath = trcProcessProxy.eResource().getURI().toString();
IPath path = new Path(pPath);
if (path.segmentCount() > 1) {
pPath = path.removeLastSegments(1).toString();
}
String fileName = "MyAgentFileName.trcaxmi";
IPath filePath = new Path(pPath).append(fileName);
URI uri = SaveUtil.createURI(filePath.toString()+"#").trimFragment();
Resource agDoc = Resource.Factory.Registry.INSTANCE.getFactory(uri).createResource(uri);
EList agExt = agDoc.getContents();
UIPlugin.getDefault().getResourceSet().getResources().add(agDoc); // prevents reloading later
HierarchyFactory factory = UIPlugin.getDefault().getPerftraceFactory();
trcAgentProxy = factory.createTRCAgentProxy();
trcAgentProxy.setName(AGENT_NAME);
trcAgentProxy.setType(AGENT_TYPE);
trcAgentProxy.setProcessProxy(trcProcessProxy);
/* We need to close the configuration of the execution agent and include it as part of the agent proxy */
AgentConfiguration agentConfiguration = agent.getConfiguration();
int agentConfigurationCount = agentConfiguration == null ? 0 : agentConfiguration.size();
/* For each configuration */
TRCConfiguration agentProxyConfiguration = null;
for (int i = 0; i < agentConfigurationCount; i++)
{
AgentConfigurationEntry agentConfigurationEntry = agentConfiguration.getEntryAt(i);
String configuraitonEntryName = agentConfigurationEntry.getName();
TRCOption agentProxyConfigurationEntry = factory.createTRCOption();
agentProxyConfigurationEntry.setKey(configuraitonEntryName);
agentProxyConfigurationEntry.setValue(agentConfigurationEntry.getValue());
/* Create the agent proxy configuration */
if (agentProxyConfiguration == null)
{
agentProxyConfiguration = factory.createTRCConfiguration();
agentProxyConfiguration.setName(configuraitonEntryName);
agentProxyConfiguration.setActive(true);
agentProxyConfiguration.setAgentProxy(trcAgentProxy);
trcAgentProxy.getConfigurations().add(agentProxyConfiguration);
}
agentProxyConfigurationEntry.setConfiguration(agentProxyConfiguration);
}
TRCAgent iAgent = factory.createTRCAgent();
iAgent.setAgentProxy(trcAgentProxy);
agExt.add(iAgent);
iAgent.setName(trcAgentProxy.getName());
iAgent.setRuntimeId(trcAgentProxy.getRuntimeId());
iAgent.setType(trcAgentProxy.getType());
iAgent.setCollectionMode(trcAgentProxy.getCollectionMode());
updateAgentStatus(true);
}
public void processExited(Process process)
{
updateAgentStatus(false);
}
/**
* Activate the model entity representing the agent
*/
private void updateAgentStatus(boolean activate)
{
/* Set the attributes of the agent */
trcAgentProxy.setAttached(activate);
trcAgentProxy.setActive(activate);
trcAgentProxy.setMonitored(activate);
trcProcessProxy.setActive(activate);
/* Update the UI to indicate a refresh */
updateAgentStatus(ProfileEvent.START_MONITOR);
}
/**
* Update the status of the agent.
*/
private void updateAgentStatus(final int status)
{
Display d = Display.getDefault();
d.asyncExec(new Runnable() {
public void run() {
ProfileEvent event = UIPlugin.getDefault().getProfileEvent();
event.setSource(trcAgentProxy);
event.setType(status);
UIPlugin.getDefault().notifyProfileEventListener(event);
}
});
}
});
return agent;
}
/**
* Extend the JDT Java launch configuration delegate
*/
protected class JavaConfigurationExtended extends AbstractJavaLaunchConfigurationDelegate
{
public void setDefaultSourceLocator(ILaunch launch, ILaunchConfiguration configuration) throws CoreException {
super.setDefaultSourceLocator(launch, configuration);
}
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException
{
/* Doesn't need to be implemented */
}
}
/**
* This runnable periodically checks to ensure that a given process is alive
*/
private class ProcessStateNotifier implements Runnable
{
/** The process whose state is periodically checked */
private Process process;
/** A flag that indicates when a message sent to the Agent Controller has been processed */
private boolean isMessageProcessed;
/** The list of active processes */
private long[] activeProcesses;
/** The process id of the process launched */
private long processId;
/** The state listener registered */
private IProcessStateChangeListener stateListener;
private ProcessStateNotifier (IProcessStateChangeListener stateListener, Process process, long processId)
{
this.stateListener = stateListener;
this.process = process;
this.processId = processId;
}
public void run()
{
while (true)
{
waitFor(500);
ControlMessage message = new ControlMessage();
QueryProcessListCommand qplCommand = new QueryProcessListCommand();
message.appendCommand(qplCommand);
isMessageProcessed = false;
try
{
process.getNode().getConnection().sendMessage(message, new CommandHandler(){
public void incommingCommand(Node node, CommandElement command)
{
int tag = (int) command.getTag();
switch (tag)
{
/* Queries for meta data of agents (just the names) */
case (int) Constants.RA_PROCESS_LIST:
RegisteredProcessListCommand rplCmd = (RegisteredProcessListCommand) command;
activeProcesses = rplCmd.getProcessList();
break;
}
isMessageProcessed = true;
}});
}
catch (Exception e)
{
isMessageProcessed = true;
}
/* Wait until we get a response */
while (!isMessageProcessed)
{
waitFor(500);
}
boolean foundProcess = false;
if (activeProcesses != null)
{
for (int i = 0; i < activeProcesses.length; i++)
{
if (activeProcesses[i] == processId)
{
foundProcess = true;
break;
}
}
}
if (!foundProcess)
{
stateListener.processStateChanged(false);
break;
}
}
}
private void waitFor(long waitPeriod)
{
synchronized(this)
{
try
{
this.wait(waitPeriod);
}
catch (Exception e)
{
return;
}
}
}
};
private interface IProcessStateChangeListener
{
public void processStateChanged(boolean alive);
}
}
|
Self-host a workbench to test drive the new launch delegate: In the self-hosted workbench, create a Java project with a classic HelloWorld class > Switch to the profile and logging perspective > Open the profile launch dialog > Create a new launch configuration of type Java application > Specify the HelloWorld class as the main class > Select the custom data collector that appears under the profile/monitor tab > Click on Profile. The HelloWorld process should be launched and the model entities for the process and the agent should appear in the profiling monitor view - see figure 2.7.

Figure 2.7 - The profile monitor view
Notice that there are toolbar and context menu options associated with the custom agent that do not apply in our context. TPTP's framework
will associate a default set of options to an agent that does not have a control provider. Using the
org.eclipse.hyades.trace.ui.controllableEntity extension point, clients can associate control providers on 4 different controllable entities:
the process, agent, analysis type, and the toolbar. The relationship of the classes and interfaces involved when defining a control provider
is depicted in figure 2.8. This section will associate a custom control provider to the custom agent. The provider
will only be used to associate actions to options that will appear in the context menu of the agent. The control provider class will extend
org.eclipse.tptp.trace.ui.provisional.control.provider.AbstractAgentControlProvider and will only associate actions to the
resume/pause/attach/detach options.

Figure 2.8 - Control provider class diagram
Follow the steps below to associate a custom control provider to the agent:
- Open the plugin.xml of the org.eclipse.tptp.examples.data.collector plug-in
- One of the first steps of associating a control provider is to declare the agent that the provider will be affiliated with.
Use the org.eclipse.hyades.trace.ui.agentDeclaration extension point to declare an agent:
<!-- Declare the custom agent -->
<extension point = "org.eclipse.hyades.trace.ui.agentDeclaration">
<agent
id = "org.eclipse.tptp.examples.data.collector.myCustomDataCollectorAgent"
name = "org.eclipse.tptp.examples.data.collector.agent"
type = "Custom Agent Type">
</agent>
</extension>
- Define the control provider:
<!-- Associate a custom control provider to the agent declared. -->
<extension point = "org.eclipse.hyades.trace.ui.controllableEntity">
<!-- The custom agent -->
<control associatedAgentId = "org.eclipse.tptp.examples.data.collector.myCustomDataCollectorAgent">
<entity type = "agent"
class = "org.eclipse.tptp.examples.data.collector.controls.CustomAgentControlProvider"/>
</control>
</extension>
- Create a new class called CustomAgentControlProvider under the new package: org.eclipse.tptp.examples.data.collector.controls. The
content of the file appears below:
package org.eclipse.tptp.examples.data.collector.controls; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.tptp.examples.data.collector.Activator; import org.eclipse.tptp.trace.ui.provisional.control.provider.AbstractAgentControlProvider; import org.eclipse.tptp.trace.ui.provisional.control.provider.IAgentStateModifier; /** * A custom control provider that will associate actions to the resume/pause/attach/detach * options that appear in the context menu of the custom agent. */ public class CustomAgentControlProvider extends AbstractAgentControlProvider { /* The state modifier for the custom agent */ private IAgentStateModifier stateModifier; public IAgentStateModifier getAgentStateModifier() { if (stateModifier != null) return stateModifier; stateModifier = new IAgentStateModifier() { /** * Display a message that indicates that the detach option * has been invoked. */ public void detach() throws CoreException { showMessage("Detach option is invoked"); } /** * Display a message that indicates that the attach option * has been invoked. */ public void attach() throws CoreException { showMessage("Attach option is invoked"); } /** * Display a message that indicates that the resume option * has been invoked. */ public void startMonitoring() throws CoreException { showMessage("Resume option is invoked"); } /** * Display a message that indicates that the pause option * has been invoked. */ public void pauseMonitoring() throws CoreException { showMessage("Pause option is invoked"); } /** * Returning true will always ensure that teh attach * option will always be enabled. */ public boolean canAttach() { return true; } /** * Returning true will always ensure that teh attach * option will always be enabled. */ public boolean canDetach() { return true; } /** * Returning true will always ensure that teh attach * option will always be enabled. */ public boolean canResume() { return true; } /** * Returning true will always ensure that teh attach * option will always be enabled. */ public boolean canPause() { return true; } public void setInput(StructuredSelection input) { } /** * Opens a message dialog with the message passed in. */ private void showMessage(String message) { MessageDialog.openInformation( Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(), "", message); } }; return stateModifier; } }

Figure 2.9 - The results of selecting the attach option
This conlcudes this article. The source code of the plug-in created can be downloaded here.