How can I "capture" System.exit(-1) from different thread? - java

I have the following
System.setSecurityManager(new SecurityManager() {
#Override
public void checkExit(int status) {
super.checkExit(status);
//custom exception extends SecurityException
throw new SystemExitCalledException();
}
});
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
//never reaches here somehow...
//maybe some3rdPartyStaticMethod sets this, too?
}
});
try {
//this method spawns threads and some call System.exit().
some3rdPartyStaticMethod.invoke(null, new Object[]{args});
} catch (SystemExitCalledException e) {
//it never reaches here because
//SystemExitCalledException is thrown on different thread??
//
}
Is there a way to prevent some3rdPartyStaticMethod's spawned thread's System.exit() call from halting jvm?

You can start the code in a separate process and communicate with it using RMI. If the third party code calls System.exit and kills its process, your process can continue to run and recreate the child process if necessary.
Note that there are some caveats with this approach:
The two processes don't share the same heap space.
You will need to marshal all data that is passed between the two processes. This means that the data must be serializable.
There will be a considerable overhead for every method call. This may give performance problems if you need to make many calls per second.

Writing a custom SecurityManager policy should help -- I've never done this myself :)
According to this post (scroll down to the bottom):
However, when anything in the VM tries to call System.exit(), the VM exits. Since this includes a brutal shotdown of mvn, the normal mvn process is interrupted. A SecurityManager can be used to prevent code from calling System.exit(), but nobody mentions the side-effects.
A colleague of mine mentioned that you can setup your policies system-wide, per-user and as a system-property when starting the VM and after a quick test this has proven to solve my problem. I've since managed to figure out how to set my own policy from my code (before setting up the SecurityManager) and this solves my problems.
I used the following code:
//Setup security to prevent System.exit()
SecurityManager sm = System.getSecurityManager();
URL policy = getClass().getClassLoader().getResource("jsdoc.policy");
System.setProperty("java.security.policy", policy.toString());
System.setSecurityManager(new JSDocSecurityManager(getLog()));
With a simple, wide-open, policy file reading this:
grant {
permission java.security.AllPermission;
};
If it works it supposed to capture the System.exit() request and throw a SecurityException instead

Related

How to Ensure Method is called before Object is Destroyed?

I've written a custom logging Class that behaves very similarly to a PrintWriter like System.out or System.err. The main difference is that when myLogger.printf("Hello World!\n"); is called, the data isn't written directly to the log file, but instead to an internal queue, and this queue only gets flushed to the output file via the flush(); method. So use of the code looks like this:
myLogger.println("Line 1.");
myLogger.println("Line 3.");
myLogger.println("Actually that was Line 2. THIS is Line 3!");
myLogger.flush();
Which should give an output that (sort of) looks like this:
2016-03-30 15:44:45::389> Line 1.
2016-03-30 15:44:45::390> Line 3.
2016-03-30 15:44:45::395> Actually that was Line 2. THIS is Line 3!
However, the problem I have is when users make mistakes. Namely, they forget to call flush(), and the data they've written to the logger never gets dumped to the file, and the program closes without ever flushing the data.
I can't flush after every single call, because it would defeat the purpose of writing this class in the first place. And having the system manage automatic flushing would be similarly self-defeating.
My idea was to put a call to flush() inside the finalize() method of the object, but as I've read from several other articles on this site, there's no guarantee that finalize() will ever be called.
Just for clarity's sake, this is what the flush() method looks like:
public void flush() {
open();
while(!unwrittenLogs.isEmpty()) {
String line = unwrittenLogs.poll();
log.print(line);
}
close();
}
private void open() {
if(log == null) {
try {
log = new PrintWriter(new FileOutputStream(logFile, true));
} catch (FileNotFoundException e) {
System.err.printf("Unable to open Log File.\n%s\n",e.getMessage());
e.printStackTrace(System.err);
}
}
}
private void close() {
if(log != null) {
log.close();
log = null;
}
}
So what is my best option to ensure that the logger is flushed before the program quits?
Put your method into the finalize method, like this:
#Override protected void finalize() throws Throwable {
// TODO Auto-generated method stub
// do some crazy stuff here
super.finalize();
}
This is and example for object destruction.
For saving the data before the JVM gets shut down, use shutdown hooks:
public static void main(final String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override public void run() {
// TODO Auto-generated method stub
// do the other crazy stuff in here
super.run();
}
});
}
But both will not be a 100% safe to use.
1) You can close the JVM without all finalizers being run
2) If you kill the JVM process via task manager / kill signal, the shutdown hooks wont be triggered
You've asked two different questions: how to ensure that your loggers' flush() method is invoked before that object is collected, and how to ensure that it is invoked before the program quits. As you gathered from your research, the logger might not be collected before the program quits, therefore a finalizer cannot guarantee that the method will be called.
If you would be satisfied with the logger being ineligible for GC prior to VM shutdown, then you could register a shutdown hook with the runtime, that flushes the logger. Such a hook would need to hold a reference to the logger, and the runtime will hold on to a reference to the hook (an unstarted Thread) until it shuts down, so the logger will remain ineligible for GC until the runtime executes its shutdown hooks.
An alternative approach to a flushable writer:
use a TransferQueue<LogItem> implementation
create a separate log writer thread
do a take() on the queue. [blocking]
open log file, optionally do truncation and log rotation as desired at this point
write taken item, drain additional items with poll() [non-blocking]
flush and close log file
if(application still running) then goto 3
This approach has several advantages:
the log thread will suffer the IO and flush costs, not the threads executing your business logic
it's thread-safe as there is only one writing thread
log item submission is lock-free as long as the TransferQueue implementation is, such as LinkedTransferQueue
the logger thread will keep the VM alive until logs are written, assuming thread.setDaemon(false), which is the default.

Java Shutdown hook is getting called without exitVM.0 from permission.getName()

In my application I have written the shut down hook. But some third party code is calling that shut down hook.
This shut down hook should not be called by any third party code.
I have written the code to block shut down hook by third party but it did not help. (This code worked in my standalone test program. but did not worked in my application.)
Below are the code where something different behaviour is occurring:
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission(Permission permission) {
System.out.println("In checkPermission:{" + permission.getName() + "}");
if ("exitVM.0".equals(permission.getName())) {
throw new ExitTrappedException();
}
}
};
When I execute this code in Test program then when shut down being called its giving me "In checkPermission:{exitVM.0}". So that it comes in if condition and my shut down hook gets blocked.
Now when I tried same thing in my application then this "exitVM.0" is not getting printed and shut down hook is getting called.
Any suggestions? Is there any different permission.getName() which can call shutdown hook?
It could be exitVM.1, exitVM.2, etc, since the number is just the shutdown code. The actual permission is called exitVM. (see http://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html). So you could use permission.getName().startsWith("exitVM").
But what you're trying to do (prevent application being shut down) sounds like it might not be the best idea. What's the context?

Is there an easy way to investigate if AccessController.doPrivileged() is really needed?

I have this code that attaches a JavaServer to the RMIRegistry, which is done in a PrivilegedAction
//start javaengineserver
AccessController.doPrivileged(new PrivilegedAction()
{
public Object run()
{
try
{
startServer(port, getSession());
} catch (RmiException e)
{
e.printStackTrace();
AWTSwingErrorDialog.show(e, "Error while attaching JavaEngineServer to rmiregistry.exe");
}
return null;
}
});
I found some other Questions about the doPrivileged method, and they all say that there are some comands that need the extra permissions like getting Environment Variables.
So i looked threw the code behind the startServer(port, session) method and i haven't found anything that looks like it needs extra permissions, but is there a way to confirm that, other than Test all the usages and functionality by hand?
Thank you.
I don't think there is a (reliable) easy way. There is an unreliable way though: temporarily replace that code with something that just calls startServer, and try running it in a security sandbox.
I suspect that the doPrivileged call is needed though. A method with that name and a port parameter is likely to try to create / bind / listen on a ServerSocket. The latter will fail if the SecurityManager.checkListen method does not allow the operation ... which it won't do in a typical sandbox. (We don't normally want untrusted code to be able to start stealth network services ...)

How to ensure the scheduled executor runs even after a runtime Exception

I have a very long running task that periodically polls a web service for XML content. I am using a Scheduled executor for these periodic runs and everything works fine.
The JavaDoc of ScheduledExecutorService scheduleAtFixedRate state that
... If any execution of the task encounters an exception, subsequent executions are suppressed ...*
This clearly implies that in case of unhandled exceptions, The application even though running , is effectively in a stopped state and doing nothing. I want to ensure that the task execution does not stop, Apart from catching all exceptions, is there any other way to deal with this?
#Override
public void run() {
try {
// fetch xml feed from network,
// parse the feed and dump to file the json.
} catch (Exception e) {
logger.error("Unhandled exception " + e);}
}
}
I don't think that there is another way around other than catching all Exceptions in the run method.
If you don't mind using 3rd party libraries, you could use Quartz. Take a look at here.
hth

How to quit / terminate / stop a j2me midlet?

Surprisingly terminating a midlet doesn't work in my application. Maybe it is because I'm using Threads, but destroyApp() and notifyDestroyed() are not sufficient.
Take for example the following code:
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
System.out.println("destroying");
notifyDestroyed();
}
protected void startApp() throws MIDletStateChangeException {
try {
// init modules
controller.initialize();
}catch (Exception e) {
viewer.showAlert("error in startApp() init controller");
destroyApp(true);
}
}
You are specifically calling notifyDestroyed() from inside startApp().
My best guess is that the handset (or emulator) you are trying this on doesn't handle it too well.
Try this instead:
When controller.initialize() throws an exception, display a simple Form with a single "Exit" Command and a StringItem error message.
Call notifyDestroyed() from a CommandListener.commandAction() callback.
As far as threads are concerned, it is up to you to have them nicely terminate when the user wants to exit your application.
Most MIDP runtimes will be able to deal with some threads not terminating nicely but leaving system resources not properly cleaned may cause problems, especially on platforms that try to never terminate the Java Virtual Machine process itself.
you should call 'notifyDestroyed' method to exit your application not 'destroyApp' method.

Categories

Resources