Actually i want to developpe a java application witch should instrumentate another java application witch i don't have its source code..
I tried to create an agent and attach it to the jvm.. then i created an mbean and tried to connect to it.. it works when i try to instrumentate a class in my project.. but i don't know how could i instrument a distant application with my application..
here is my code: https://github.com/ammouna8ammouna/Monitoring.git
i am really new at the instrumentation world and i really need help.
If you can get the processID of the VM that you are targeting you can attach your agent using
com.sun.tools.attach.VirtualMachine
For example if you have pid, the path of your JAR target and the loader that handle the JAR you can try something like this:
private static void attach(String pid, String jarPath,
ClassLoader toolLoader) throws Exception {
Class<?> attacherLib = toolLoader.loadClass("com.sun.tools.attach.VirtualMachine");
Class<?> string = toolLoader.loadClass("java.lang.String");
Method attach = attacherLib.getMethod("attach", string);
Object instance = attach.invoke(null, pid);
Method loadAgent = attacherLib.getMethod("loadAgent", string, string);
loadAgent.invoke(instance, jarFilePath, "");
Method detach = attacherLib.getMethod("detach");
detach.invoke(instance);
}
Let me know if it's clear or you need other help.
Related
I have an app that will rely on a 3rd party JAR file to execute some code, this JAR has been developed by our client, we need to include a call to the JAR in our app and they have the hope that we can send the current SQL Connection as a parameter for the JAR
Having no previous experience working with this kind of scenario we all agreed it should be pretty straight-forward, but we overlooked the fact that the main class's main method only receives an array of Strings as parameter
I've googled my head off, but can't find a similar need, is it just completely off the books and impossible to do?
The call I was hoping to implement would look something like this:
final Process command = re.exec("java -jar ./MyClientsJar.jar " + arg1 + " " + arg2 + " " + SQLConnection);
command.waitFor();
But of course, when we try to define a main method like this in the client's source code:
private void MyClientsJARMainClass(String args[], Connection con){}
Eclipse's JAR export tool fails to find the main class
Any ideas other than sending user, url and pass arguments?
You are creating a new process when you call re.exec. Since its a new process you cannot share your connection defined in another process.
Try to use the jar as a library. Import the class and make them a public method that accepts the connection as a parameter. For example:
import MyClientsJARMainClass
...
String[] args = { arg1, arg2 };
MyClientsJARMainClass.mainWithConnection(args, connection);
Your client adds a method like this in their class:
public static void mainWithConnection(String[] args, Connection connection)
I want to create a GUI app in java for signing j2me app which is done by JadTool.jar but it is a Command Line Interface Apps. So I just want to use it as library and pass the parameters in program. How it can be done?
Check out Runtime. It will allow you to execute a command. You can use this to start your command line interface library.
Edit:
Ah, I didn't read care carefully earlier. If you're using a Java library starting a separate process is not the best solution.
Just reference the JadTool jar from your project. If the functionality you need isn't accessible in the library, edit the source and recompile. Make sure JadTool's license allows this.
If you're against editing the source (or not allowed) try using reflection to invoke the private run method you need.
A jar is just a library of classes, the fact that it can be run from the command line is caused by the presence of a main method in a class. As jadtool's source is available it's easy to see its very simple main:
public static void main(String[] args) {
int exitStatus = -1;
try {
new JadTool().run(args);
exitStatus = 0;
} catch (Exception e) {
System.err.println("\n" + e.getMessage() + "\n");
}
System.exit(exitStatus);
}
Unfortunately, that run() method is private, so calling it directly from another class won't work, leading to a reduced set of options:
#WilliamMorrison 's solution of going via Runtime - not really a library call, but it would work.
see Any way to Invoke a private method?
In my main program I am allowing users to create Java classes and storing them in a .java file within the package UserInputs. I am now looking for a way to instantiate the user created class within my main program and also running the public methods within the class.
Here is the code which gets executed when the user presses a JButton to finish creating their class.
public void actionPerformed(ActionEvent e) {
if(e.getSource() == inputButt.getButtons()){
try{
PrintWriter writer = new PrintWriter("C:/Users/human/Desktop/UserInputTest/src/UserInputs/UserCreatedClass.java", "UTF-8");
writer.println(textArea.getText());
writer.close();
}catch(Exception except){
except.printStackTrace();
}
}
}
You need to compile the file at runtime. Maybe this or this post here on SO helps you.
What the first link says is that you should use the Java 6 Compiler API. What you need to do is this:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, fileToCompile);
Where fileToCompile is the path to your file, in your case "C:/Users/human/Desktop/UserInputTest/src/UserInputs/UserCreatedClass.java". Then you can execute the code via Reflection.
I would be very carefully with letting people create and execute their own Java code, though. I don't know what you plan to do but if you are running this code on a server, I would not recommend doing such things. In case this application should run locally on the clients computer (so they can only harm themselves) this should not be a problem. Otherwise I would not let them program what they want.
You might also want to consider Groovy compiler which is almost fully compatible with Java syntax, more functional and has simpler API. Example from a Groovy page:
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(new File("src/test/groovy/script/HelloWorld.groovy"));
// let's call some method on an instance
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Object[] args = {};
groovyObject.invokeMethod("run", args);
I'm working on a project that requires to show the CPU usage as well as other system information of remote machines.
People suggest using SIGAR to achieve this, but I don't know how to use it. The source code didn't quite make sense to me.
Basically, my question is that: how can I register the MBeans provided by SIGAR to the server when host IP and JMX port are provided, and how to fetch the system info from other computer afterward.
Please correct me if I'm wrong with how JMX works. Thanks in advance.
These are the names of the classes that are the Sigar built in MBeans that you can register:
org.hyperic.sigar.jmx.SigarCpu
org.hyperic.sigar.jmx.SigarCpuInfo
org.hyperic.sigar.jmx.SigarCpuPerc
org.hyperic.sigar.jmx.SigarLoadAverage
org.hyperic.sigar.jmx.SigarMem
org.hyperic.sigar.jmx.SigarProcess
org.hyperic.sigar.jmx.SigarRegistry
org.hyperic.sigar.jmx.SigarSwap
However, it will be quite complicated to deploy these remotely since Sigar depends on a native library which must be in the target JVM's lib-path when the MBeans are loaded. This means, you will need to actively load the library and MBeans on each target host you want to monitor.
You might be able to hack a way of making the target JVMs load this through a remote call, but it is non-trivial and will require you to bypass any security setups in the JVMs since by default, this is something you're not supposed to be able to do.
You can sort of hack the system part to get an easy deployment for Sigjar:
private String before;
private Sigar sigar;
/**
* Constructor - don't forget to call unload later!
*/
public SetlogSigar() throws Exception {
before = System.getProperty("java.library.path");
String path = "";
String add = getJarFolder();
if (before.contains(";"))
path = before + ";./;" + add;
else
path = before + ":./:" + add;
setSystemPath(path);
sigar = new Sigar();
}
/**
* This is needed to dynamically update the JAVA Path environment in order to load the needed native library
* Yes -rather an ugly hack...
*/
private String getJarFolder() {
// get name and path
String path = SetlogSigar.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = path;
try {
decodedPath = URLDecoder.decode(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
File f = new File(decodedPath);
String absolutePath = f.getParentFile().getParentFile().getParentFile().getParent()+"/lib";
return absolutePath;
}
/**
* Unloads the JNI bindings
*/
public void unload() {
this.sigar.close();
setSystemPath(before);
}
This hack dynamically adds the folder where sigjar.jar is located to the environment variable. Just place all native libs in there and deployment gets less complicated.
Seems to me that you will have to write some wrapping objects to expose the various SIGAR outputs as JMX mbean attributes. How you do that that depends highly on what you are using to expose your JMX beans. I would write one wrapping object for each of the various different types of SIGAR output: memory, disk, ...
I've written a SimpleJMX library that might help. I'll use its format to provide an example object that you can use to expose the info via JMX. You can adapt it to whatever mechanism you are using to publish JMX means. I'm not familiar with SIGAR enough to know if my sigar code below is correct to get a ProcMem instance.
#JmxResource(description = "Show SIGAR Info", domainName = "foo")
public class SigarProcMem {
private ProcMem procMem;
{
// sorry, I'm not up on sigar so I'm not sure if this works
Sigar sigar = new Sigar();
procMem = sigar.getProcMem(sigar.getPid());
}
#JmxAttributeMethod(description = "Resident memory")
public long residentMemory() {
return procMem.getResident();
}
#JmxAttributeMethod(description = "Get the Total process virtual memory")
public long totalVirtualMemory() {
return procMem.getSize();
}
}
I want to launch a java subprocess, with the same java classpath and dynamically loaded classes as the current java process. The following is not enough, because it doesn't include any dynamically loaded classes:
String classpath = System.getProperty("java.class.path");
Currently I'm searching for each needed class with the code below. However, on some machines this fails for some classes/libs, the source variable is null. Is there a more reliable and simpler way to get the location of libs that are used by the current jvm process?
String stax = ClassFinder.classPath("javax.xml.stream.Location");
public static String classPath(String qualifiedClassName) throws NotFoundException {
try {
Class qc = Class.forName( qualifiedClassName );
CodeSource source = qc.getProtectionDomain().getCodeSource();
if ( source != null ) {
URL location = source.getLocation();
String f = location.getPath();
f = URLDecoder.decode(f, "UTF-8"); // decode URL to avoid spaces being replaced by %20
return f.substring(1);
} else {
throw new ClassFinder().new NotFoundException(qualifiedClassName+" (unknown source, likely rt.jar)");
}
} catch ( Exception e ) {
throw new ClassFinder().new NotFoundException(qualifiedClassName);
}
}
See my previous question which covers getting the classpath as well as how to launch a sub-process.
I want to launch a java subprocess, with the same java classpath and dynamically loaded classes as the current java process.
You mean invoke a new JVM?
Given that...
it is possible to plug in all sorts of agents and instrumentation into a JVM that can transform classes at load time
it is possible to take a byte array and turn it into a class
it is possible to have complex class loader hierarchies with varying visibility between classes and have the same classes loaded multiple times
...there is no general, magic, catch-all and foolproof way to do this. You should design your application and its class loading mechanisms to achieve this goal. If you allow 3rd party plug-ins, you'll have to document how this works and how they have to register their libraries.
If you look at the javadoc for Class.getClassLoader, you'll see that the "bootstrap" classloader is typically represented as the null. "String.class.getClassLoader()" will return null on the normal sun jvm implementations. i think this implementation detail carries over into the CodeSource stuff. As such, I wouldn't imagine you would need to worry about any class which comes from the bootstrap classloader as long as your sub-process uses the same jvm impl as the current process.