public class Agent extends Object
Agent is a generic solution to greatly simplify the agent programming (see
java.lang.instrument package description for more information about agents
in general).
The main idea is to have a totally separated environment for running agents. This means that
the agent uses its own namespace (i.e. class loader) for its classes. With Agent
a programmer can avoid .jar file version conflicts. That's why the Agent configuration
file has its own classpath element(s). Another advantage is that the XML configuration
file is always similar for different agents. And yet one more advantage is that the programmer
does not need to care about the manifest attributes mentioned in java.lang.instrument
package description. They are already handled for the programmer.
AgentAgent is specified by using Java -javaagent switch like this:
-javaagent:agent-jarpath=path-to-xml-config-file;arg_key_1=arg_value_1;arg_key_2=arg_value_2[;arg_key_N=arg_value_N]
For example:
-javaagent:/users/me/agent/target/jeyzer-agent.jar=/users/me/agent/agent-config.xml;jeyzer-record-agent-profile=test
<agent> as its root element.
<agent> has the following childs:
<variable>, this is an optional element for simplifying the configuration<delegate>, this is a mandatory element to define the agent delegate<classpath>, this is a mandatory element and has at minimum of one (1)
<entry> child element.
<filter>, this is an optional element and can have zero (0)
<include> and/or <exclude> child elements. Filters are regular
expressions patterns to include or exclude classes to be instrumented.
<configuration>, which is an optional element is used to configure
agent delegate.
See /agent/configuration element
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<variable />
<variable />
...
<delegate />
<classpath>
<entry />
<entry />
...
</classpath>
<filter>
<include />
<include />
<exclude />
<exclude />
...
</filter>
<configuration>
<!--
This can be text, a predefined structure or
programmer's own structure
-->
</configuration>
</agent>
/agent/variable element/agent/variable element is optional and it is supposed to be used to simplify
the configuration file. Variables can be anywhere under agent element (i.e. they
need not to be in the beginning of the configuration file).
The /agent/variable element must have (only) name attribute which is used
as a reference in other parts of the configuration file. The name reference is replaced
by the value of the /agent/variable element.
The variable value can contain variable references which will be resolved in this order :
${VARIABLE}
where:
VARIABLE is the name attribute of the /agent/variable element${repo-path} variable reference is replaced with
/users/me/.m2/repository string:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<variable name="repo-path">/users/me/.m2/repository</variable>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
<entry>${repo-path}/asm/asm/3.1/asm-3.1.jar</entry>
<entry>${repo-path}/asm/asm-commons/3.1/asm-commons-3.1.jar</entry>
<entry>${repo-path}/asm/asm-util/3.1/asm-util-3.1.jar</entry>
<entry>${repo-path}/asm/asm-tree/3.1/asm-tree-3.1.jar</entry>
</classpath>
<configuration>...</configuration>
</agent>
Variables can be used more creatively if there is a need for that. This example produces exactly
the same result than the example above but the use of variables are more complex:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<variable name="a">repo</variable>
<variable name="b">path</variable>
<variable name="c">ju</variable>
<variable name="juuri">roo</variable>
<variable name="${${c}uri}t">users</variable>
<variable name="${a}-${b}">/${root}/me/.m2/repository</variable>
<variable name="asm-package">asm</variable>
<variable name="${asm-package}-version">3.1</variable>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
<entry>${repo-path}/${asm-package}/asm/${asm-version}/asm-${asm-version}.jar</entry>
<entry>${repo-path}/${asm-package}/asm-commons/${asm-version}/asm-commons-${asm-version}.jar</entry>
<entry>${repo-path}/${asm-package}/asm-util/${asm-version}/asm-util-${asm-version}.jar</entry>
<entry>${repo-path}/${asm-package}/asm-tree/${asm-version}/asm-tree-${asm-version}.jar</entry>
</classpath>
<configuration>...</configuration>
</agent>
/agent/delegate element/agent/delegate element is mandatory and its value is the name of the delegate class
as a fully qualified name (e.g. com.hapiware.asm.TimeMachineAgentDelegate).
The agent delegate class must have the following method (with the exact signature):
public static void premain(
java.util.regex.Pattern[] includePatterns,
java.util.regex.Pattern[] excludePatterns,
Object config,
Instrumentation instrumentation
)
where:
java.util.regex.Pattern[] includePatterns has a list of regular expression
patterns to be used to include classes for instrumentation.
See /agent/filter
java.util.regex.Pattern[] excludePatterns has a list of regular expression
patterns to be used to set classes not to be instrumented.
See /agent/filter
Object config is the configuration object based on the
/agent/configuration element.
Instrumentation instrumentation has services to provide the instrumentation.static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method can do all the same things as defined for static void premain(String, Instrumentation)
method in the java.lang.instrument package description.
/agent/classpath element/agent/classpath element is mandatory and is used to define the classpath
for the agent delegate class. This means that there is no need to put any of
the used libraries for the agent delegate class in to your environment classpath.
The /agent/classpath element must have at least one <entry> child element
but can have several. The only required classpath entry is the delegate agent (.jar file) itself.
However, usually there are other classpath entries for the libraries needed by the delegate
agent. Here is an example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.agent.TimeMachineAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/timemachine-delegate-1.0.0.jar</entry>
<entry>/usr/local/asm-3.1/lib/all/all-asm-3.1.jar</entry>
</classpath>
<configuration>...</configuration>
</agent>
/agent/filter element/agent/filter is optional and is used to filter classes to be
instrumented.
The /agent/filter element can have several include and/or exclude
elements but can have also none of them. Here is an example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
</classpath>
<filter>
<include>^com/hapiware/.*f[oi]x/.+</include>
<include>^com/mysoft/.+</include>
<exclude>^com/hapiware/.+/CreateCalculationForm</exclude>
</filter>
<configuration>...</configuration>
</agent>
<include> element<include> element can be used for matching the possible candidates for instrumentation.
If none is defined then one pattern containing ".+" is assumed as a default value.
<include> element is a normal Java regular expression.
Notice that the class names are presented in the internal form of fully qualified class
names as defined in The Java Virtual Machine Specification (e.g. "java/util/List"). So, when
you create <include> and <exclude> elements, remember that package names are
separated with slash (/) instead of period (.).
<exclude> element<exclude> can be used to ensure that the instrumentation is not done for some classes.
<exclude> element is a normal Java regular expression.
Notice that the class names are presented in the internal form of fully qualified class
names as defined in The Java Virtual Machine Specification (e.g. "java/util/List"). So, when
you create <include> and <exclude> elements, remember that package names are
separated with slash (/) instead of period (.).
/agent/configuration/ element/agent/configuration/ element is optional and has all the necessary
configuration information for the agent delegate class. The exact structure can depend on
the programmer but there are some predefined structures as well. The configuration object
is delivered to the agent delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument.
All the possible options for configuration object creation are:
nullStringList<String>Map<String, String>null/agent/configuration/ element is not defined at all then null is
delivered to the agent delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument. For example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
</classpath>
</agent>
which sends null to the
MyAgentDelegate.premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument.
String/agent/configuration/ element has only pure text (i.e. String), the
text string is delivered to the delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument. For example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
</classpath>
<configuration>Show me!</configuration>
</agent>
which sends "Show me!" to the
MyAgentDelegate.premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument.
List<String>/agent/configuration/ element has <item> child elements without an
attribute then the List<String> is created which is in turn delivered to the agent
delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument. For example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
</classpath>
<configuration>
<item>One</item>
<item>Two</item>
<item>Three</item>
</configuration>
</agent>
which sends List<String> {"One", "Two", "Three"} to the
MyAgentDelegate.premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument.
Map<String, String>/agent/configuration/ element has <item> child elements with a
key attribute then the Map<String, String> is created which is in turn
delivered to the agent delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument. For example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.test.MyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/my-delegate-1.0.0.jar</entry>
</classpath>
<configuration>
<item key="1">One</item>
<item key="2">Two</item>
<item key="3">Three</item>
</configuration>
</agent>
which sends Map<String, String> {{"1", "One"}, {"2", "Two"}, {"3", "Three"}} to the
MyAgentDelegate.premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument.
/agent/configuration/ element has the custom child element defined,
then public static Object unmarshall(org.w3c.dom.Element configElement) method must
be defined to the agent delegate class in addition to premain() method. The
unmarshall() method is called with the /agent/configuration/custom element
as an argument. The system then delivers the returned Object directly to the agent
delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method as an Object argument. This approach makes it possible to create different configuration
structures for the agent delegate's
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method very flexibly.
public static Object unmarshall(org.w3c.dom.Element configElement) is assumed to return
a programmer's own configuration object. Here is an example:
<?xml version="1.0" encoding="UTF-8" ?>
<agent>
<delegate>com.hapiware.agent.FancyAgentDelegate</delegate>
<classpath>
<entry>/users/me/agent/target/fancy-delegate-1.0.0.jar</entry>
<entry>/usr/local/asm-3.1/lib/all/all-asm-3.1.jar</entry>
</classpath>
<filter>
<include>^com/hapiware/.*f[oi]x/.+</include>
<include>^com/mysoft/.+</include>
<exclude>^com/hapiware/.+/CreateCalculationForm</exclude>
</filter>
<configuration>
<custom>
<message>Hello World!</message>
<date>2010-3-13</date>
</custom>
</configuration>
</agent>
This assumes that com.hapiware.asm.FancyAgentDelegate class has
public static Object unmarshall(org.w3c.dom.Element configElement) method defined
to handle <message> and <date> elements from the <configuration/custom>
element. It is also assumed that the Object the unmarshall() method returns
can be properly handled (and type casted) in the
static void premain(java.util.regex.Pattern[], java.util.regex.Pattern[], Object, Instrumentation)
method.java.lang.instrument| Constructor and Description |
|---|
Agent() |
| Modifier and Type | Method and Description |
|---|---|
static void |
premain(String agentArgs,
Instrumentation instrumentation)
This method is called before the main method call right after the JVM initialisation.
|
static void |
publishAgentVersion() |
public static void premain(String agentArgs, Instrumentation instrumentation)
Notice that this method follows the fail fast idiom and thus throws a runtime exception if there is something wrong in the configuration file.
agentArgs - Same string which was given to -javaagent as options (see the class
description).instrumentation - See java.lang.instrument.InstrumentationConfigurationError - If there is something wrong with the configuration file.java.lang.instrumentpublic static void publishAgentVersion()
Copyright © 2020–2023 Jeyzer. All rights reserved.