java instrumentation jar in eclipse - failure in manifest.mf - java

I am trying to use the java.lang.instrument.Instrumentation class which requires usage of the 'premain' class - a good descrip can be found on stack here.
The problem is that I have done this and am having trouble using it in another program. My class looks like this:
public class InstrumentationWrapper {
private static final String INSTR_KEY = "test.instrumentation";
private static Instrumentation instrumentation;
public static void premain(String options, Instrumentation inst) {
Properties props = System.getProperties();
if(props.get(INSTR_KEY) == null)
props.put(INSTR_KEY, inst);
}
public static Instrumentation getInstrumentation() {
if (instrumentation == null) {
instrumentation = (Instrumentation) System.getProperties().get(INSTR_KEY);
}
return instrumentation;
}
public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
public static long getSizeOfObjects (Collection<?> col) {
long cumSize = 0;
for (Object o : col) {
cumSize = getObjectSize (o);
}
return cumSize;
}
}
The manifest is in the Jar file as such:
$ jar -tf target/instrumentator-1.0.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/testTools/
com/testTools/instrumentation/
com/testTools/instrumentation/InstrumentationWrapper.class
META-INF/maven/
META-INF/maven/com.netrecon.testTools/
META-INF/maven/com.netrecon.testTools/instrumentator/
META-INF/maven/com.netrecon.testTools/instrumentator/pom.xml
META-INF/maven/com.netrecon.testTools/instrumentator/pom.properties
and the MANIFEST.MF is just:
$ more src/resources/META-INF/MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: com.testTools.instrumentation.InstrumentationWrapper
In the launch configuration in eclipse I get the following problem
Failed to find Premain-Class manifest attribute in Z:\workspace\<project>\testTools\instrumentor\target\instrumentator-1.0.jar
and the option is -javaagent:${workspace_loc:instrumentator}\target\instrumentator-1.0.jar
I am really unsure how I can get this to work - All I really need to do is have a test harness that will let me look at the memory foot print of an array. Any ideas?

Nothing jumps out at me, but if you want to inspect further you can write a quick class to open up your Jar file with java.util.jar.JarFile and programatically inspect the manifest. This will indicate whether the issue is somehow in the way you wrote your manifest (maybe a space in the wrong place or something) or the way it's getting loaded (Maybe there is a typo in the specification of the premain class?).

Related

AspectJ Load Time Weaving - Command Line Project

i am struggling since days on a simple project that i just can't get to run.
My goal is to extend the functionality of a .jar-File in order to get more information about the inner workings of that jar. The .jar is not open source.
I came accross a lot of different concepts to "inject" my own code into the jvm like the "ASM"-Library, BECL, Javassist and finally AspectJ.
AspectJ caught my attention as it seems to be easier to use and more high level. To try how AspectJ is working before using it with the closed source .jar, i set up Test-Projects:
Project1:
To test it, i wanted to create a simply project containing one Class that should be compiled and packed to a .jar-File. This class should later be monitored using the Aspect. I took the Source Code of this Class from an example on the internet: https://github.com/Nosfert/AspectJ-Tutorial-jayway
The file content of the class looks like this:
YourClass.java:
package com.test.java.instrumentation;
public class YourClass {
public static void main(String[] args) {
YourClass yourClass = new YourClass();
yourClass.yourMethodBefore();
yourClass.yourMethodAfter();
yourClass.yourMethodAround(1);
yourClass.yourMethodAround(1,"Test");
}
public void yourMethodBefore() {
System.out.println("Executing TestTarget.yourMethodBefore()");
}
public void yourMethodAfter(){
System.out.println("Executing TestTarget.yourMethodAfter()");
}
public void yourMethodAround(Integer i){
System.out.println("Executing TestTarget.yourMethodAround()");
System.out.println("i : "+i);
}
public void yourMethodAround(Integer i,String x){
System.out.println("Executing TestTarget.yourMethodAround()");
System.out.println("i : "+i);
System.out.println("x : "+x);
}
}
I compile the code with the following command:
javac -d bin -cp ./src/ ./src/com/test/java/instrumentation/YourClass.java
The command runs without errors.
In the next step i created a Manifest file containing the necessary information to run the Class in a .jar-File:
MANIFEST.MF:
Manifest-Version: 1.0
Main-Class: com.test.java.instrumentation.YourClass
Built-By: Me
Build-Jdk: 1.8.0_131
In the next step i create a .jar:
cd bin\
jar cvfm program.jar ..\meta-inf\manifest.mf .
The .jar can be successfully executed via:
java -jar program.jar
The output looks like this:
Executing TestTarget.yourMethodBefore()
Executing TestTarget.yourMethodAfter()
Executing TestTarget.yourMethodAround()
i : 1
Executing TestTarget.yourMethodAround()
i : 1
x : Test
So far so good. Step 1 is completed. This is the example-application that should later be expanded with additional functionality using AspectJ's Load Time Weaving.
Project2:
In the next step i want to create the AspectJ .jar-File containing my code to expand the functionality of Project1:
The contents of Priject2 (YourAspect.java) is the following:
package com.test.java.instrumentation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.JoinPoint;
#Aspect
public class YourAspect {
//Patterns
//blank = modifier (public/private/protected or default(blank) should be looked for
//* = return type to look for. Void/Object/Primitive type
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
#Before("execution (* com.test.java.instrumentation.YourClass.yourMethodBefore(..))")
//JointPoint = the reference of the call to the method
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("YourAspect's BeforeAdvice's body is now executed Before yourMethodBefore is called.");
}
//Patterns
//public = look for the specific modifier named public
//!Object = Basically we are looking for void or primitives. But if we specified Object we could get a good pattern
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
#After("execution (public !Object com.test.java.instrumentation.YourClass.yourMethodAfter(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("YourAspect's afterAdvice's body is now executed After yourMethodAfter is called.");
}
//Patterns
//!private = look for any modifier that's not private
//void = looking for method with void
//com.jayway.YourClass.yourMethodBefore(..) = PackageName . ClassName . methodName (parameters)
#Around("execution (!private void com.test.java.instrumentation.YourClass.yourMethodAround(Integer,..))")
//ProceedingJointPoint = the reference of the call to the method.
//The difference between ProceedingJointPoint and JointPoint is that a JointPoint can't be continued (proceeded)
//A ProceedingJointPoint can be continued (proceeded) and is needed for an Around advice
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
//Default Object that we can use to return to the consumer
Object returnObject = null;
try {
System.out.println("YourAspect's aroundAdvice's body is now executed Before yourMethodAround is called.");
//We choose to continue the call to the method in question
returnObject = joinPoint.proceed();
//If no exception is thrown we should land here and we can modify the returnObject, if we want to.
} catch (Throwable throwable) {
//Here we can catch and modify any exceptions that are called
//We could potentially not throw the exception to the caller and instead return "null" or a default object.
throw throwable;
}
finally {
//If we want to be sure that some of our code is executed even if we get an exception
System.out.println("YourAspect's aroundAdvice's body is now executed After yourMethodAround is called.");
}
return returnObject;
}
//Patterns
//blank = modifier (public/private/protected or default(blank) should be looked for
//* = return type to look for. Void/Object/Primitive type
//com.jayway.YourClass.yourMethod*(..) = PackageName . ClassName . * (parameters)
//Where the "*" will catch any method name
#After("execution ( * com.test.java.instrumentation.YourClass.*(..))")
//JointPoint = the reference of the call to the method
public void printNewLine(JoinPoint pointcut){
//Just prints new lines after each method that's executed in
System.out.print("\n\r");
}
}
I also created a MANIFEST.FM:
Manifest-Version: 1.0
Main-Class: com.test.java.instrumentation.YourAspect
Built-By: Me
Build-Jdk: 1.8.0_131
And a aop.xml:
<aspectj>
<aspects>
<aspect name="com.test.java.instrumentation.YourAspect"/>
</aspects>
<weaver options="-XlazyTjp">
<include within="com.test.java.instrumentation..*"/>
</weaver>
</aspectj>
I can compile the class successfully with the following command:
javac -cp ./lib/aspectjrt.jar;.lib/aspejctjweaver.jar;./src;. -d ./bin/ ./src/com/test/java/instrumentation/YourAspect.java
The resulting classfile is packaged together with the Manifest and the aop.xml into a .jar:
cd bin\
jar cvfm aspect.jar ..\meta-inf\manifest.mf ..\meta-inf\aop.xml .
When i try to run the example-program (Project1) and try to weave the aspect (Project2), i am using the following command:
java -Daj.weaving.verbose=true -Dorg.aspectj.weaver.showWeaveInfo=true -javaagent:./Aspect/lib/aspectjweaver.jar -cp ./Aspect/lib/aspectjrt.jar;./Aspect/lib/aspejctjtools.jar;. -jar ./JavaProgram/bin/program.jar
The load fails and the resulting error is the following:
[AppClassLoader#18b4aac2] info AspectJ Weaver Version 1.8.10 built on Monday Dec 12, 2016 at 19:07:48 GMT
[AppClassLoader#18b4aac2] info register classloader sun.misc.Launcher$AppClassLoader#18b4aac2
[AppClassLoader#18b4aac2] info no configuration found. Disabling weaver for class loader sun.misc.Launcher$AppClassLoader#18b4aac2
Executing TestTarget.yourMethodBefore()
Executing TestTarget.yourMethodAfter()
Executing TestTarget.yourMethodAround()
i : 1
Executing TestTarget.yourMethodAround()
i : 1
x : Test
How can i injecte my aspect (Project2) into the running program.jar (Project1)?
Do you have any ideas?
I attached all the files including Sourcecode and Manifests that i created (Both projects) as a .zip-File in the following link, so you can also try out what i did so far. This might help you to spot my errors easier. The project is designed to run on windows commandline.
Link: Downloadlink of my Projects
Thank you very much for your Ideas!

Can different Java applications use the same javaagent?

I hava a javaagent Jar simpleAgent.jar. I used it to redifine classes in it and I cached some classes to avoid redifine
public class Premain {
private static Instrumentation instrumentation;
private static final Map<String, Class> allLoadClassesMap = new ConcurrentHashMap<>();
public static void premain(String agentArgs, Instrumentation inst) {
instrumentation = inst;
cacheAllLoadedClasses("com.example");
}
public static void cacheAllLoadedClasses(String prfixName) {
try {
Class[] allLoadClasses = instrumentation.getAllLoadedClasses();
for (Class loadedClass : allLoadClasses) {
if (loadedClass.getName().startsWith(prfixName)) {
allLoadClassesMap.put(loadedClass.getName(), loadedClass);
}
}
logger.warn("Loaded Class Count " + allLoadClassesMap.size());
} catch (Exception e) {
logger.error("", e);
}
}
}
I have three different application app1.jar, app2.jar, app3.jar, so when I start the three application can I use the same agent jar? Eg.:
java -javaagent:simpleAgent.jar -jar app1.jar
java -javaagent:simpleAgent.jar -jar app2.jar
java -javaagent:simpleAgent.jar -jar app3.jar
I don't know the javaagent's implementation, so I was scared that using the same javaagent can trigger in app1 or app2 or app3 crash.
Each JVM instance is separate and does not "know" about other JVMs unless you do something in application level. So, generally the answer is "yes, you can use the same jar either javaagent or not for as many JVM instances as you want."
A Javaaget is treated by the VM similarly to jar files on the class path. Those files are read only, all state is contained in the running VM such that they are safely shared among multiple processes.

Cannot expose Java Instrumentation for tomcat jvm

I am using a tomcat7 instance to run a Java application. My application needs the Java instrumentation exposed. This is done with a javaagent and I pass the agent at startup to the JVM in the setenv.bat script.
set JAVA_OPTS=%JAVA_OPTS% -javaagent:"C:\path\to\agent.jar"
In the manifest file I have the required section:
Premain-Class: package.name.agent.ExposeInstrumentation
In the premain method of the agent class assign the instrumentation provided by the JVM to a static variable accessible through a static method
public final class ExposeInstrumentation {
private static Instrumentation s_instrumentation;
public static void premain(String arguments, Instrumentation instrumentation) {
s_instrumentation = instrumentation;
}
public static Instrumentation getInstrumentation() {
return s_instrumentation;
}
}
But in my code when I do this:
Instrumentation instrumentation = ExposeInstrumentation.getInstrumentation();
getInstrumentation() returns null;
What is the problem?
UPDATE
I did some further debugging and premain gets executed and s_instrumentation receives the instrumentation, but when I call getInstrumentation later on in my code s_instumentation is set to null. This is strange I tought the value remains valid thought the life of the program.
I assume that you are loading the class ExposeInstrumentation twice. Once by the application class loader which is child-first (reverse-order) and once via the Java agent where the class is automatically loaded by the system class loader. As a result, the ExposeInstrumentation class is loaded twice where you access the one from your application where the field is not set.
You can solve this by explicitly accessing the class loaded by the system class loader:
class ExposeInstrumentation {
// public to assure accessability
public static Instrumentation s_instrumentation;
public static void premain(String arguments, Instrumentation inst) {
s_instrumentation = inst;
}
public static Instrumentation getInstrumentation() {
try {
return (Instrumentation) ClassLoader.getSystemClassLoader()
.loadClass(ExposeInstrumentation.class.getName())
.getDeclaredField("s_instrumentation")
.get(null);
} catch(Exception e) {
return null;
}
}
}
You can also check out the Byte Buddy Agent project that offers this functionality and more (runtime installation) of an agent. With Byte Buddy, you can simply call ByteBuddyAgent.getInstrumentation().

save file from unit test to project tree

In the unit tests as a side effect I am creating screenshots for various parts of the GUI.
I want to use these screenshots when compiling the documentation.
Therefore I want to save them to a directory within the source tree.
Is there any reliable way to get the source directory root when running a junit test?
If not, how can I make sure that unit tests run with cwd=project root when using eclipse, and when using maven?
wether you execute tests on eclipse or using maven, if you don't specify a path when you create the file it's automatically created at project root directory.
so if you specify a relative folder your files will go there :
public class TestFileCreation {
#Test
public void testFileCreation() throws IOException {
File f = new File("src/main/resources/hello.txt");
OutputStream ostream = new FileOutputStream(f);
String data = "Hello there !";
ostream.write(data.getBytes());
ostream.close();
}
}
will create a file inside the $PROJECT/src/main/resources.
Hope my answer helps
You can base on your classes location. Proposed solution here is to use class that will surely be in classpath. Then you can use class.getResource(""). Example
public class ResouceRoot {
public static String get() {
String s = ResouceRoot.class.getResource("").toString();
if (s.startsWith("jar:")) {
s = s.replace("jar:", "").replaceAll("!.*", "");
} else {
s = s.replaceAll("classes.*", "classes");
}
File f = new File(s.replace("file:", ""));
return f.getParentFile().getParentFile().getAbsolutePath();
}
public static void main(String[] args) throws IOException {
System.out.println(get());
}
}
(this code will give base dir for netbeans projects if they are launched from netbeans or by java -jar ... )

Recompiling the object during runtime

I am developing a project in java in which ,after running main file , some java files get altered and if i run that file again during the same execution the output does not show the changes done in the java file
For example there are 2 files. Main.java and file1.java
main.java
public static void main(string[] argv)
{
file1 obj = new file1();
obj.view();
Scanner in = new Scanner(System.in);
String x = in.nextLine();
//before entering any value i manually updated the content of file1.java
obj = new file1();
obj.view();
}
file1.java (Before updation)
public class file1
{
public void view()
{
system.out.println("This is test code!!");
}
}
file1.java (After updation)
public class file1
{
public void view()
{
system.out.println("That was done for Testing!!");
}
}
Output :
This is test code!!
This is test code!!
You have to recompile the code in order to see the changes.
What you can do is compile a string (after reading it from the file) with java and call methods of classes through reflection.
HERE is a step by step guide on how to compile a string programatically.
Updating a Java file will not impact the runtime instructions executed by the JVM.
When the compile a Java application the .java source code files are compiled into .class files containing byte code instructions which are in turn interpreted by the JVM. When the JVM requires a class it loads the appropriate .class file into memory via a special object known as a classloader.
Applying this to your example - when you first reference the class File1 the JVM will load the File1 class into memory. This in memory representation of the class will persist until either the classloader is destroyed or the JVM is restarted. No change to the file1.java class is visible to the JVM - firstly because the classloader wont reload the definition and secondly because the definition wont change until the file1.java class is recompiled.
To change an object's behaviour at runtime you can use the reflection API see here.
You don't need to compile source code to accomplish anything close to your example.
public class MyView
{
String the_string;
public MyView (String string) { the_string = string; }
public void setString (String string) { the_string = string; }
public void view () { system.out.println (the_string); }
}
public static void main(string[] argv)
{
MyView obj = new MyView("This is test code!!");
obj.view();
Scanner in = new Scanner(System.in);
obj.setString (in.nextLine());
obj.view();
}

Categories