/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: piAgentExtension.h,v 1.4 2009/02/26 15:50:00 jcayne Exp $
 * 
 * Contributors: 
 * IBM - Initial API and implementation
 **********************************************************************/

/* 
 * This file contains typedefs and a structure definition for
 * agent extensions to use.
 *

How to write an agent extension to extend the Hyades piAgent:

Your source should #include "piAgentExtension.h" from
o.e.h.datacollectors/collection/collectors/native/java_profiler because
that's where the structures and typedefs below appear.

You use the Agent Controller's plugin/config system to tell
the main piAgent that it should load your extension. Here's how:

In the RASERVER_HOME directory, there is a subdirectory "plugins."
Make a new subdirectory of "plugins" using a name that won't collide
with others - something like "com.sample.myAgentExtension" using your
company's domain name.

Make a subdirectory of your plugin directory called "config."

Put a file in your "config" directory called "pluginconfig.xml."

Put something like this in your pluginconfig.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<PluginConfiguration requires="org.eclipse.hyades.datacollection">
	<Agent configuration="default" name="Java Profiling Agent" extends="default">
		<Option name="piAgentExtension" 
			    type="libraryName" 
			    value="%RASERVER_HOME%\plugins\com.sample.myAgentExtension\lib\myLib.dll"
		/>
	</Agent>
</PluginConfiguration>

The only thing in this example that you should fill in is the value of 
the Option that has the name "piAgentExtension" and the type "libraryName."
All the other element and attribute names have to exactly as shown. You can
add other Option lines and the options you put there will be accessible to 
your agent using ra_getDefaultConfiguration().

Your agent extension library has to export a function called
"agent_extension_init" using standard C calling conventions, and it has
to have this signature:  JNIEXPORT void
agent_extension_init(AgentExtensionInitArgs_t *args);

That function will be called by the main piAgent during the processing
of the JVM_OnLoad function, which is called by JVMPI when it wants to
let the JVMPI agent initialize itself.

These are the meanings of the values in the AgentExtensionInitArgs
structure:

int api_version
	Holds the number '1' today.

	Will increase if there are additions to the args struct.

	Use this in the future to test for additional functionality
	provided by the base piAgent beyond what's described here.

const char* options
	The option string that followed "-XrunpiAgent:" on the Java command line.
	
	The option string passed will be a null string (ie: properly terminated 
	string of length 0) if there are no options (specified with or without a 
	colon).

JavaVM jvm
	The JavaVM* pointer obtained during JVM_OnLoad.

JVMPI_Interface jvmpi_interface
	The JVMPI_Interface* pointer obtained during JVM_OnLoad.

RA_AGENT_HANDLE agent_handle
	The RAC agent handle obtained by piAgent from ra_initializeBindings.
	Use this when calling RAC functions that take a handle argument.

SetCommandHandlerFunction set_command_handler
	Call this function to register your handler for incoming RAC commands.

SetEventHandlerFunction set_event_handler
	Call this function to register your handler for JVMPI events.

event_enable_safety_flag
	This flag is true if it's safe to call set_event_handler()
	from the extension's agent_extension_init function. See
	below about when it's safe to call set_event_handler.
	
The "args" structure will not be preserved after your init function
returns, so copy anything you want from it into your own storage.

REGISTERING FOR JVMPI EVENTS

Your JVMPI event handler functions must have this signature:
void myEventHandler(JVMPI_Event *event);

You register an event handler by calling through the set_event_handler
function pointer:
	(args->set_event_handler)(event_number, my_handler_function);

It's not always safe to call set_event_handler. It can only be called
at a time when a JVMPI agent is permitted to call the JVMPI function
EnableEvent.

If args->enable_event_safety_flag is true (nonzero), then it is
safe to call set_event_handler from inside your agent_extension_init 
function.

If args->enable_event_safety_flag is false (zero), or from outside your
agent_extension_init function, the agent extension is responsible for
making sure it's safe to call EnableEvent. The surest way to do this is
to create a new thread, attach that thread to the JVM, make the enable_event
call, then detach the thread and let it die.

RECEIVING EVENTS

When you register a handler for a JVMPI event and the event occurs, the
JVMPI_Event struct pointer you get is exactly as it came from JVMPI.
Your handler is called before the one in the main piAgent (if any). If
you want to call JNI or JVMPI functions from your handler, call them
directly using the pointers you got in agent_extension_init.

REGISTERING FOR AND RECEIVING RAC COMMANDS

Your RAC command handler function must have this signature:
	void myCommandHandler(ra_command_t *command);

Use the set_command_handler function to register your handler.
After you register it, your handler will be called for all RAC commands
that the piAgent gets.

The command struct you receive is exactly the same as the piAgent sees.
Your command processor runs before the one in the main piAgent. It is
not safe to change the contents of the command struct.

EXAMPLE

Below is a small but complete sample of an agent extension using most of
the features described here.
*/

#if 0
----------------- begin agent extension example; see above ---------------
#include "piAgentExtension.h"

/*
 * This example agent extension exercises some of the features of the
 * piAgent extensibility architecture:
 *
 * It writes a line to stderr when the agent_extension_init function gets called.
 * It registers handlers for two JVMPI events (INIT_DONE and CLASS_LOAD).
 * It registers a handler for RAC commands.
 *
 * The event handler for INIT_DONE just reports that it occurred.
 *
 * The event handler for CLASS_LOAD maintains count of how
 * many classes were loaded and reports the count every
 * time a new class loads.
 *
 * The event handler for RAC commands reports the type of the command received.
 */

void example_init_done_handler(JVMPI_Event *event)
{
	fprintf(stderr, "(Agent extension received init_done event)\n");
}

void example_class_load_handler(JVMPI_Event *event)
{
	/* add one to the class load count */
	class_load_count++;
	fprintf(stderr, "(Load class %s, %d so far)\n", 
			event->u.class_load.class_name, 
			class_load_count);
}

void example_command_handler(ra_command_t *command)
{
	fprintf(stderr, "(Received RAC command, type %d)\n", command->tag);
}

JNIEXPORT void agent_extension_init(AgentExtensionInitArgs *args)
{
	fprintf(stderr, "(agent_extension_init called.)\n");
	(*args->set_command_handler)(example_command_handler);
	(*args->set_event_handler)(JVMPI_EVENT_JVM_INIT_DONE, example_init_done_handler);
	(*args->set_event_handler)(JVMPI_EVENT_CLASS_LOAD, example_class_load_handler);
}
----------------------- end agent extension example ---------------
#endif

/*
 * This is the real start of this header file.
 * Everything above is a comment.
 */

#include "RAComm.h"
#include "jni.h"
#include "jvmpi.h"
#include "RABindings.h"

/* Typedefs for sub-agent handler functions and the setters for them */
typedef void (*AgentExtensionEventHandler)(JVMPI_Event *event, void **sub_agent_slot);
typedef void (*SetEventHandlerFunction)(jint event_type, AgentExtensionEventHandler fn);
typedef void (*AgentExtensionCommandHandler)(ra_command_t *command);
typedef void (*SetCommandHandlerFunction)(AgentExtensionCommandHandler fn);

/* agent extension initialization argument structure */

typedef struct {
	int api_version;
	const char *options;
	JavaVM *jvm;
	JVMPI_Interface *jvmpi_interface;
	RA_AGENT_HANDLE agent_handle;
	SetCommandHandlerFunction set_command_handler;
	SetEventHandlerFunction set_event_handler;
	char event_enable_safety_flag;
} AgentExtensionInitArgs;

typedef void (*AgentExtensionInitFunction)(AgentExtensionInitArgs *args);

