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.
Related
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.
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.
I try to set the --ignore-gpu-blacklist argument to JCEF but I can't find a way. The method I should be using is this one: CefApp::onBeforeCommandLineProcessing(String, CefCommandLine). But I can't find an example or good instructions of how to do it. CefCommandLine is an interface and I cannot find any implementation.
All the instructions I found are related to CEF, not JCEF and apparently there are classes that are different. Can anyone post a small example of how to pass Chromium arguments to CEF from a String str = "--ignore-gpu-blacklist"; ?
You have several possibilities to pass over arguments from JCEF to CEF/chromium.
1) The easiest way:
public static void main(String [] args) {
[...]
ArrayList<String> mySwitches = new ArrayList<>();
mySwitches.add("--persist-session-cookies=true");
CefApp app = CefApp.getInstance(mySwitches.toArray(new String[mySwitches.size()]));
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Just create a string array, containing all your switches you want to pass over and assign that array to CefApp.getInstance(..) at the very first call of that static method.
If you have only some simple settings, you can use the class CefSettings as well and pass over the object to getInstance(). Beside that, you can combine both (there are four different "getInstance()" methods).
2) Create your own CefAppHandler implementation to do some advanced stuff.
(a) Create an own AppHandler:
public class MyAppHandler extends CefAppHandlerAdapter {
public MyAppHandler(String [] args) {
super(args);
}
#Override
public void onBeforeCommandLineProcessing(String process_type, CefCommandLine command_line) {
super.onBeforeCommandLineProcessing(process_type, command_line);
if (process_type.isEmpty()) {
command_line.appendSwitchWithValue("persist-session-cookies","true");
}
}
}
(b) Pass AppHandler over to CefApp
public static void main(String [] args) {
[...]
MyAppHandler appHandler = new MyAppHandler(args);
CefApp.addAppHandler(appHandler);
CefApp app = CefApp.getInstance(args);
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Using this approach you'll do two things:
(a) you pass over the program arguments (args) to CefApp and
(b) you take the advantage of having the opportunity to manipulate the complete process of parsing the arguments within onBeforeCommandLineProcessing.
If you open the example code of JCEF detailed main frame, you will find this approach implemented in:
- tests.detailed.MainFrame.MainFrame(boolean, String, String[])
So implementing the onBeforeCommandLineProcessing is equal to CEF but written in Java instead of C/C++.
Regards,
Kai
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");
}
I wrote a small HTTP server in Java and I have a problem passing static variables (server configuration: port, root, etc.) to the thread that handles requests. I do not want my thread to modify these variables and if it extends the server class, it will also inherit its methods which I don't want.
I don't want to use getters for reasons of performance. If I make the static members final, I will have a problem when loading their values from the config file.
here's an example
class HTTPServer {
static int port;
static File root;
etc..
....
//must be public
public void launch() throws HTTPServerException {
loadConfig();
while (!pool.isShutdown()) {
....
//using some config here
...
try {
Socket s = ss.accept();
Worker w = new Worker(s);
pool.execute(w);
}catch () {...}
}
}
private void loadConfig(){ //reading from file};
...
other methods that must be public goes here
}
I also don't want to have the worker as nested class. It's in another package...
What do you propose?
You could put your config in a final AtomicReference. Then it can be referenced by your worker and also updated in a thread-safe manner.
Something like:
class HTTPServer {
public static final AtomicReference<ServerConf> config =
new AtomicReference(new ServerConf());
}
Make the new ServerConf class immutable:
class ServerConf {
final int port;
final File root;
public ServerConf(int port, File root) {
this.port = port;
this.root = root;
}
}
Then your worker can get a reference to the current config via HTTPServer.config.get(). Perhaps something like:
Worker w = new Worker(s, HTTPServer.config.get());
loadConfig() can set new config via something like:
HTTPServer.config.set(new ServerConf(8080, new File("/foo/bar"));
If it's not important for all your config to change at the same time, you could skip the ServerConf class and use AtomicInteger for the port setting, and AtomicReference<File> for the root.
Read the static data into a static 'sharedConfig' object that also has a socket field - you can use that field for the listening socket. When acccpet() returns with a server<> client socket, clone() the 'sharedConfig', shove in the new socket and pass that object to the server<>client worker thread. The thread then gets a copy of the config that it can erad and even modify if it wants to without afecting any other thread or the static config.