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.
Related
I want to start a webservice via an executible jar I create (so that I can eventually use procrun to have it start up as a Windows Service). The webservice is currently started via the command line by calling the main method on the class.
Here is my code so far:
public class test
{
private static boolean stop = false;
private static Process process;
public static void start(String[] args)
{
String classpath = "my\\classpath\\test.jar";
ProcessBuilder processBuilder = new ProcessBuilder("C:\\java\\jdk1.6.0_43\\bin\\java",
"-cp", classpath,
"com.test.theJavaWebServiceWithAMainMethod");
try
{
process = processBuilder.start();
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public static void stop(String[] args)
{
stop = true;
process.destroy();
}
public static void main(String[] args)
{
if (args != null && args.length > 0)
{
String command = args[0];
if ("start".equals(command))
{
start(args);
}
else if ("stop".equals(command))
{
stop(args);
}
}
else
{
throw new IllegalArgumentException("command missing");
}
}
}
Starting works fine. I see the process start in the task manager and I can now pull up the WSDL. However when I go to kill the process via process.destroy() (by calling the main method with the arguemnt stop), I get a null pointer exception I assume because this is a new instance of the jvm so it doesn't know the process from when I called start. Whats the best way to persist this process object or pid or something so when I go to call stop, I can find and kill the webservice (java process) that is running?
You are executing your 'test' program twice, which results in two completely separate program instances, and they have no reference to each other. So when you call the 'test' program with stop command, theprocess variable is null because one was not created in the current program.
Options:
Rewrite your main method to block, waiting for the "stop" command. This would mean the start/stop were not separate asynchronous program executions though. You would start the program, and it would then wait for you to enter a stop command before exiting.
You could devise a way to signal the other application 'remotely' ...even though it's all running on the same machine. This is easy to do via a simple network socket, and is a very common approach. (Checkout Tomcat's start/stop command handling for an example....though it's more complex than you need.) To summarize... once running, the main program listens on a server socket. The subsequent "stop program" connects to that server socket as client to notify the main program it should stop.
You could use underlying OS tools to find and stop the program. See this answer: How to find and kill running Win-Processes from within Java? . It's hard to do cross platform and generically though.
It's not really clear what it is you want to do though and why you are executing your web service as a separate program via ProcessBuilder. Depending on your requirements, perhaps you could instead do something like this:
public void start(String[] args)
{
try
{
com.test.theJavaWebServiceWithAMainMethod.main(args);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
That would start your service, of course, and then you could control-c to end the program.
Rather than start your runnable jar as you do, you could convert your program to start as a Windows Service. Then it would be able to react to a Windows-based shutdown request.
When I use 4 threads for my program there is usually no problems, but today I increased it to 8 and I noticed 1-3 threads stop working without throwing any exceptions. Is there anyway to find out why they are stopping? is there anyway to make the thread restart?
This is how the structure of my thread is
public void run()
{
Main.logger.info(threadName + ": New Thread started (inside run)");
while (true)
{
try
{
//all my code
//all my code
//all my code
}
catch(Exception e)
{
Main.logger.error("Exception: " + e);
try
{
Thread.sleep(10000);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
}
finally
{
try
{
webClient.closeAllWindows();
Thread.sleep(3000);
Main.logger.info(threadName + ": Closed browser!");
}
catch (Exception e)
{
Main.logger.error("Exception: " + e);
}
}
}// end while
}
Regards!
Note that an Error is not an Exception; it's a Throwable.
So, if you catch Exception, Errors will still get through:
private void m() {
try {
m(); // recursively calling m() will throw a StackOverflowError
} catch (Exception e) {
// this block won't get executed,
// because StackOverflowError is not an Exception!
}
}
to catch "everything", change your code to this:
try {
...
} catch (Throwable e) {
// this block will execute when anything "bad" happens
}
Note that there might be little you can do if an Error occurs. Excerpt from javadoc for Error:
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
Is there anyway to find out why they are stopping?
That's a bit tricky.
A Java thread can terminate for two reasons:
it can return from its run() method,
it can terminate due to an exception being thrown and not caught on the thread's stack.
You can detect the latter case by using an "UncaughtExceptionHandler" for the thread, but the former case can't be positively detected unless you modify your thread's run() method to log the event ... or something like that.
I guess, the other way to figure out what is going on would be to attach a debugger to the JVM and get it to report the uncaught exception to you.
(I suspect that the reason you are not seeing any exceptions is that your threads' run methods are not catching / logging all exceptions, AND they don't have an uncaught exception handler.)
is there anyway to make the thread restart?
No. There is no way to restart a Thread that has terminated.
If you are running from the command line, you can have dump states of all threads to the console. On windows you do this by hitting Ctrl+Break, under linux, by sending the QUIT signal to the process with 'kill'.
Please refer to An Introduction to Java Stack Traces
Sending a signal to the Java Virtual Machine On UNIX platforms you can
send a signal to a program by using the kill command. This is the quit
signal, which is handled by the JVM. For example, on Solaris you can
use the command kill -QUIT process_id, where process_id is the process
number of your Java program.
Alternatively you can enter the key sequence \ in the window
where the Java program was started. Sending this signal instructs a
signal handler in the JVM, to recursively print out all the
information on the threads and monitors inside the JVM.
To generate a stack trace on Windows 95, or Windows NT platforms,
enter the key sequence in the window where the Java
program is running, or click the Close button on the window.
Thread priority on one of them could be too high, try setting them the same level through?
Deadlocking is possible if there is any control on each and other between them.
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
I'm trying to clean up resources in my application before it shuts down, following on from my previous question (Detecting When A Java Application Closes) I have implemented the following code which performs the cleanup operation perfectly.
//Intercept when the application closes
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
//Reclaim resources from MIDI usage
if(_midiInstance.CleanUp())
{
Logger.Add("Closed resources successfully on ShutDown");
}
else
{
Logger.Add("Failed to close all resources on ShutDown");
}
System.exit(0);
}
});
Although the System.exit(0); call is understood and processed the application continues to run, just without a visiable GUI. I've thought about placing the System.exit(0) call just outside of the Thread but then it's out of scope, there aren't any other threads or streams running.
Is there an additional step I need to take when hooking in to the ShutDown event to ensure everything closes?
Thanks for your time, I greatly appreciate it.
After reading your other question, it seems like your are probably not calling dispose() on your window(s). If true, that would explain the cause of your problem.
You need to over ride the windows close button:
//overriding the windowClosing() method will allow the user to click the close button
addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
By doing this the program will close not just become invisible.
How do I stop a Java process gracefully in Linux and Windows?
When does Runtime.getRuntime().addShutdownHook get called, and when does it not?
What about finalizers, do they help here?
Can I send some sort of signal to a Java process from a shell?
I am looking for preferably portable solutions.
Shutdown hooks execute in all cases where the VM is not forcibly killed. So, if you were to issue a "standard" kill (SIGTERM from a kill command) then they will execute. Similarly, they will execute after calling System.exit(int).
However a hard kill (kill -9 or kill -SIGKILL) then they won't execute. Similarly (and obviously) they won't execute if you pull the power from the computer, drop it into a vat of boiling lava, or beat the CPU into pieces with a sledgehammer. You probably already knew that, though.
Finalizers really should run as well, but it's best not to rely on that for shutdown cleanup, but rather rely on your shutdown hooks to stop things cleanly. And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!
Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"
Overview is here
That allows you to control one application from another one in relatively easy way. You can call the controlling application from a script to stop controlled application gracefully before killing it.
Here is the simplified code:
Controlled application:
run it with the folowing VM parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
//ThreadMonitorMBean.java
public interface ThreadMonitorMBean
{
String getName();
void start();
void stop();
boolean isRunning();
}
// ThreadMonitor.java
public class ThreadMonitor implements ThreadMonitorMBean
{
private Thread m_thrd = null;
public ThreadMonitor(Thread thrd)
{
m_thrd = thrd;
}
#Override
public String getName()
{
return "JMX Controlled App";
}
#Override
public void start()
{
// TODO: start application here
System.out.println("remote start called");
}
#Override
public void stop()
{
// TODO: stop application here
System.out.println("remote stop called");
m_thrd.interrupt();
}
public boolean isRunning()
{
return Thread.currentThread().isAlive();
}
public static void main(String[] args)
{
try
{
System.out.println("JMX started");
ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread());
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=ThreadMonitor");
server.registerMBean(monitor, name);
while(!Thread.interrupted())
{
// loop until interrupted
System.out.println(".");
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
// TODO: some final clean up could be here also
System.out.println("JMX stopped");
}
}
}
Controlling application:
run it with the stop or start as the command line argument
public class ThreadMonitorConsole
{
public static void main(String[] args)
{
try
{
// connecting to JMX
System.out.println("Connect to JMX service.");
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
// Construct proxy for the the MBean object
ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor");
ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true);
System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running");
// parse command line arguments
if(args[0].equalsIgnoreCase("start"))
{
System.out.println("Invoke \"start\" method");
mbeanProxy.start();
}
else if(args[0].equalsIgnoreCase("stop"))
{
System.out.println("Invoke \"stop\" method");
mbeanProxy.stop();
}
// clean up and exit
jmxc.close();
System.out.println("Done.");
}
catch(Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
That's it. :-)
An another way: your application can open a server socet and wait for an information arrived to it. For example a string with a "magic" word :) and then react to make shutdown: System.exit(). You can send such information to the socke using an external application like telnet.
Here is a bit tricky, but portable solution:
In your application implement a shutdown hook
When you want to shut down your JVM gracefully, install a Java Agent that calls System.exit() using the Attach API.
I implemented the Java Agent. It is available on Github: https://github.com/everit-org/javaagent-shutdown
Detailed description about the solution is available here: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/
Similar Question Here
Finalizers in Java are bad. They add a lot of overhead to garbage collection. Avoid them whenever possible.
The shutdownHook will only get called when the VM is shutting down. I think it very well may do what you want.
Thanks for you answers. Shutdown hooks seams like something that would work in my case.
But I also bumped into the thing called Monitoring and Management beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
That gives some nice possibilities, for remote monitoring, and manipulation of the java process. (Was introduced in Java 5)
Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. (ps ax | grep java) or something like that, or store the process id when the process gets created (this is used in most linux startup files, see /etc/init.d)
Portable signalling can be done by integrating a SocketServer in your java application. It's not that difficult and gives you the freedom to send any command you want.
If you meant finally clauses in stead of finalizers; they do not get extecuted when System.exit() is called.
Finalizers should work, but shouldn't really do anything more significant but print a debug statement. They're dangerous.