How to set/get a value from another JVM - java

I have a class Normal with the following code:
public class Normal {
private static String myStr = "Not working...";
private static boolean running = true;
public static void main(String[] args) {
while(running) {
System.out.println(myStr);
}
}
}
And I have another class named Injector in another project. Its purpose is to change the values of Normal even though they are not in the same JVM:
public class Injector {
public static void main(String[] args) {
String PID = //Gets PID, which works fine
VirtualMachine vm = VirtualMachine.attach(PID);
/*
Set/Get field values for classes in vm?
*/
}
}
What I want to do is change the values myStr and running in the class Normal to "Working!" and false respectively without changing the code in Normal (Only in Injector).
Thanks in advance

You'll need two JARs:
One is Java Agent that uses Reflection to change the field value. Java Agent's main class should have agentmain entry point.
public static void agentmain(String args, Instrumentation instr) throws Exception {
Class normalClass = Class.forName("Normal");
Field myStrField = normalClass.getDeclaredField("myStr");
myStrField.setAccessible(true);
myStrField.set(null, "Working!");
}
You'll have to add MANIFEST.MF with Agent-Class attribute and pack the agent into a jar file.
The second one is a utility that uses Dynamic Attach to inject the agent jar into the running VM. Let pid be the target Java process ID.
import com.sun.tools.attach.VirtualMachine;
...
VirtualMachine vm = VirtualMachine.attach(pid);
try {
vm.loadAgent(agentJarPath, "");
} finally {
vm.detach();
}
A bit more details in the article.

Related

How do I activate the Java class resource lookup cache?

I want to check if the VM property sun.cds.enableSharedLookupCache helps improve the performance of an application that does numerous calls to ClassLoader::getResource(). I found that property in URLClassPath.
I tried to turn it on with -Dsun.cds.enableSharedLookupCache=true or -Dsun.cds.enableSharedLookupCache as VM argument but that did not activate the cache.
I use this simple test program to test the activation :
public class Test {
public static void main(String[] args) {
System.out.println(Test.class.getClassLoader().getResource("java/lang/Exception.class"));
}
}
The value of field lookupCacheEnabled in URLClassPath is false :
private static volatile boolean lookupCacheEnabled
= "true".equals(VM.getSavedProperty("sun.cds.enableSharedLookupCache"));
EDIT: jdk version is jdk8
What am I missing here ?

Second main() class does not see variables initialized in first main() class

I'm developing an application that requires two main() classes, first one for the actual application, and a second one for the JMX connectivity and management. The issue I'm facing is even after ensuring the first main() is executed and initializes the variables, when the second main() runs but does not see those variables and throws null exception.
Application main():
public class GatewayCore {
private static Logger logger = Logger.getLogger(GatewayCore.class);
private static ThreadedSocketInitiator threadedSocketInitiator;**
private static boolean keepAlive = true;
//private static Thread mqConnectionManager;
public static void main(String args[]) throws Exception {
__init_system();
__init_jmx();
__init_mq();
while(keepAlive) {}
}
private static void __init_system() {
try {
logger.debug("__init_system:: loading configuration file 'sessionSettings.txt'");
SessionSettings sessionSettings = new SessionSettings(new FileInputStream("sessionSettings.txt"));
logger.info("\n" + sessionSettings);
MessageStoreFactory messageStoreFactory = new FileStoreFactory(sessionSettings);
LogFactory logFactory = new FileLogFactory(sessionSettings);
MessageFactory messageFactory = new DefaultMessageFactory();
Application sessionManager = new SessionManager();
threadedSocketInitiator = new ThreadedSocketInitiator(sessionManager, messageStoreFactory, sessionSettings, logFactory, messageFactory);
...
public static ThreadedSocketInitiator getThreadedSocketInitiator() {
return threadedSocketInitiator; }
Secondary main() class, meant to be invoked for JMX-Mbean purpose:
public class RemoteCommandLine {
private static Logger logger = Logger.getLogger(RemoteCommandLine.class);
private static final String JMX_SERVICE_URL_PREFIX = "service:jmx:rmi:///jndi/rmi://";
private static final String HOST = "localhost";
private static String PORT = "24365";
private static JMXConnectionInstance jmxConnectionInstance;
private static boolean keepAlive = true;
public static void main(String[] args) throws IOException, MalformedObjectNameException, ConfigError {
logger.debug(GatewayCore.getThreadedSocketInitiator());
...
From command line, I first run:
java -classpath etdfix.jar:slf4j-api-1.7.25.jar:mina-core-2.0.16.jar:quickfixj-all-2.0.0.jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=24365 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false com.scb.etdfix.GatewayCore sessionSettings.txt
Wait for the inits to complete, ensuring threadedSocketInitiator has been assigned, then:
java -classpath etdfix.jar:slf4j-api-1.7.25.jar:mina-core-2.0.16.jar:quickfixj-all-2.0.0.jar com.scb.etdfix.JMX.RemoteCommandLine
Which ultimately throws a null pointer exception for the line:
logger.debug(GatewayCore.getThreadedSocketInitiator());
My plan is to have the first main() initialize the object, then pass to the second main() to do further method calls using the same object (it must be the same instance) when it is manually invoked. Both classes are compiled together into the same JAR. Please advise on how I can get around this issue or anything I can do to debug this further.
In fact, I'm thinking that this may not be possible as when the 2nd main() is invoked, from its POV the first main() isn't initialized. Therefore I should approach this by considering that they are two separate entities.
Each process (each java command) is completely separate, whether they run the same main() or not. This is a feature—the alternative would be to have unrelated parts of the system collide whenever they used a common utility.
That said, nothing stops you from calling GatewayCore.main() yourself (with the real command line or whatever other argument list) if you want to reuse its logic. It might be a good idea, though, to factor out the common code as another function: main() has many special responsibilities and programmers do not usually expect it to be called within a program.

Static Variable becomes null after class completed

I Have three classes
StaticHolder.java - Which holds a static variable.
StaticInitializer.java -Responsible only for initializing the variable through a static method.
Application.java - Retrieves the static variables value through getter method.
I thought initializing a static variable once in JVM will not go until we stop the JVM. So I called ran StaticInitializer once which will do the initialization. And tired to access its value from another class which is not working and returning null. Can anyone explain why. Thanks In Advance.
public class StaticHolder {
private static String hello;
public static void ini() {
hello = "Hello World";
}
public static String getHello() {
return hello;
}
public static void setHello(String hello) {
StaticHolder.hello = hello;
}
}
class StaticInitializer {
public static void main(String[] args) {
StaticHolder.ini();
while (true) {
Thread.sleep(1000);
}
}
}
public class Application {
public static void main(String[] args) {
System.out.println(StaticHolder.getHello());
}
}
static does not mean that this value is there forever!
It is only theree for the current java session.
Invocing the java command at the command line starts a new java session where the value needs to be initialized again.
Actually I have a daemon thread which does the initialization and stays alive.And I have another stand alone java program which tries to get the value.
Without knowing that other code involved my gueass is that you did not establish inter process communication.
The easiest way it that you "deamon" opens a server socket and your "stand alone java program" connects to it an queries the desired data through it.
So there is only one main method that can be executed as entry point for the entire application for each JVM run.
When the JVM is executed you can specify which class has to be loaded at start. The Classloader take care to load that class and then the JVM can execute the only one public static void main(String[] args) method.
In Java you need to have at least one class with a public static method named main. I suggest to read this post to understand why it is public static.
The Java Classloader is a part of the Java Runtime Environment that
dynamically loads Java classes into the Java Virtual Machine.
Usually classes are only loaded on demand.
So returning to your question, given that when Application.main is running there is no way to execute StaticHolder.init(), I suggest to change your main in this way:
public class Application {
public static void main(String[] args) {
StaticHolder.init();
System.out.println(StaticHolder.getHello());
}
}
or change StaticHolder in this way and remove the init:
public class StaticHolder {
private static String hello;
static {
hello = "Hello World";
}
public static String getHello() {
return hello;
}
public static void setHello(String hello) {
StaticHolder.hello = hello;
}
}
On the other hand, just to be clear if you run the StaticInitializer.main this has no effect on Application.main execution.
In your program , when main method of StaticInitializer is first executed, a String named hello is initalized. and as ini() method is called, the value 'Hello world' is assigned to hello. Then jvm exists main method, and then stops working. Again when we compile application class,instead of the previous hello variable , a new hello string variable is created with no value assigned(null valued) . That's why you're getting null as output. Thankyou.

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();
}

Java: How to determine startup arguments without the main line access?

I'm curious to know if it is possible to determine the startup arguments of a Java application when you don't have access to the arguments array from the main line.
public static void main(String[] args)
{
// Invokes my code without providing arguments.
mycode();
}
public static void mycode()
{
// Attempting to determine arguments here.
// TODO GetArgs()
}
I'm in this situation by doing some plugin work and the core application does not provide a list of startup arguments. Any thoughts?
Not unless the plugin is given them, but that kind of goes without saying (at least in Java).
If you need to set some options specifically for your plugin, but can't access the command line, there are at least two options:
Options file (several mechanisms)
Set system params on the command line
For the second option, just use the normal -D option and namespace the param name, like:
java -Dcom.davelnewton.plugins.foo.bar=anOptionValue etc...
Retrieve them via System.getProperty(anOptionName) or one of its cousins.
IMO an options file is a better (ahem) option, even if you're specifying the file path on the command line, but if you only have an option or two, maybe not--just depends.
Pass the arguments to the function?
public static void main(String[] args)
{
mycode(args);
}
public static void mycode(String[] args)
{
String arg1 = args[0];
}
You could do:
public static void main(String[] args)
{
System.setProperty("cmdArgs", args);
mycode();
}
public static void mycode()
{
// Attempting to determine arguments here.
String[] args = System.getProperty("cmdArgs");
}

Categories