views:

348

answers:

4

We have a program with a main() that parses certain CLPs but does not save them anywhere. I then have my own plug-in code that needs access to the original CLPs (so I can transmit more parameters) for it. However, I cannot change main()

I saw that there is apparently a way to do this in C#, I'm looking for an equivalent Java solution on Linux.

UPDATE: Obviously, I'm aware of how main() works. Unfortunately, I cannot change the existing application or the way it is invoked (except for CLPs). I can only access via a sandboxed plugin code. My question is whether there is a way to get the command line (rather then the environment variables with -D) that the JVM was invoked with.

+1  A: 

Create your own main class. Save the arguments. Call the old main.

It might be easier to use System.getProperty and -Dkey=value on the command line (before main class name or -jar).

Tom Hawtin - tackline
Unfortunately, I cannot change main()... Doing this with the -D is also a problem since I only have control over the standard clps... :(
Uri
This doesn't require changing main, just the command line.
Kathy Van Stone
+4  A: 

The solution is easy once you realize that Java's main method is just another static method that takes a String array as argument.

Create a new class that stores the CLPs, then calls the old class. Later on, you can access your CLPs using the new class:

import NotToBeChangedMainClass;

public MyMainClass {
  public static final String[] ARGUMENTS;
  public static void main(String ... args) {
    ARGUMENTS = args;
    NotToBeChangedMainClass.main(args);
  }

}

Finally, change whatever external caller (e.g. any Batch files) to use MyMainClass instead of NotToBeChangedMainClass. If you are using runable jars or something similar, this requires changing the appropriate configuration file.

nd
Obviously, I'm aware of how main() works. Unfortunately, I cannot change the existing application or the way it is invoked (except for CLPs). I can only access via a sandboxed plugin code.
Uri
+3  A: 

Apart from doing it in main in some way I think the only other option that you have would be to drop to the operating system level and execute some commands to get the arguments.

On linux the cmd line arguments for a running process are stored at /proc/pid/cmdline

So to get them you would have to find the process id. See here:

http://stackoverflow.com/questions/35842/process-id-in-java

Then using this open /proc/pid/cmdline and parse it. The format of this file and an example in c is here:

http://www.unix.com/unix-advanced-expert-users/86740-retrieving-command-line-arguments-particular-pid.html

It might be best to wrap these two calls in one shell script that you call from java.

Please note that this will be extremely non portable and is a bit hacky. But if needs must...

Pablojim
+1  A: 

In case you don't have a choice any you absolutely have to retain all the existing class names with their exact name (as stated in your comment to my previous answer), then you have to go with AspectJ.

Let's consider we have this class:

public class UnmodifyableClassWithMain {
  public static void main(String[] args) {
    System.out.println("In main");
    new ClassUsingArgumentRegistry();
  }
}


First, you need to something that holds the command line arguments. I will use a simple class with a static field for simplicity:

public class ArgumentRegistry {
  public static String[] ARGS;
}

Then, you need you define an Aspect that intercepts calls to main and stores the arguments.

public aspect StoreArgumentsOfMain {

  /**
   * This pointcut intercepts all calls to methods called main with a string array as
   * argument.
   */
  pointcut mainMethod(String[] arguments): execution(void main(String[])) && args(arguments);

  /**
   * Before the original main method gets called, store the arguments in the registry.
   */
  before(String[] arguments): mainMethod(arguments) {
    System.out.println("Storing arguments");
    ArgumentRegistry.ARGS = arguments;
  }

}

For trying it out, I also created a ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

  public ClassUsingArgumentRegistry() {
    System.out.println("Arguments: " + java.util.Arrays.toString(ArgumentRegistry.ARGS));
  }

}


That's it. If I enable AspectJ's compile time weaving and run the result using "java UnmodifyableClassWithMain Foo Bar Baz", I get the follwing output:

Storing arguments
In main
Arguments: [foo, bar, baz]
nd