edmargayao
asked on
Applet throws ThreadDeath when using a Socket connection
I have an applet below that a browser (Using Sun JDK1.4.1 plugin) uses to open a socket connection to a server. It acts as a thread to ensure that it will connect to the server only once. It behaves by waiting for the server to send it a message. Once it receives the message, it displays the message on the browser using javascript by invoking a method of JSObject. The Applet is used across multiple pages (e.g. Login and Home using the sequence: Login->Home).
The Applet Code:
public class webClientAppletThread extends Applet implements Runnable {
private static Socket socket;
private static String serverIP = null;
private static Thread connector = null;
private static String location = null;
/** String representing the default action to be taken upon signalling */
private static String refreshAction = "JavaScript: document.location.reload() ";
/** server socket has to be static because the listener is a global thread */
private static int port = 9090;
/** A generic message for warning the browser user that it cannot accept messages */
public static final String NOT_LISTENING_MSG =
"JavaScript: alert('WARNING: A browser has already been opened for webClientFiles."
+ "\\nThis browser will not be able to receive update messages correctly."
+ "\\n\\nPlease close this browser.'); window.close()";
/**
* A generic message for warning the browser that
* it will no longer receive messages
*/
public static final String CONNECTION_LOST =
"JavaScript: alert('WARNING: The connection to the server has been lost."
+ "\\n\\n\\nPlease close this browser.'); window.close()";
private static Applet globalApplet;
private static final String PORT_PARAM = "Port";
private static final String REFRESH_PARAM = "Refresh";
private static final String SERVER_IP = "ServerIP";
public void init() {
System.out.println("init() ");
System.out.println("Refres h: " + getParameter(REFRESH_PARAM ));
System.out.println("Port: " + getParameter(PORT_PARAM));
System.out.println("Server IP: " + getParameter(SERVER_IP));
refreshAction = getParameter(REFRESH_PARAM );
if ((refreshAction == null) || (refreshAction.equals("")) ) {
refreshAction = "JavaScript: document.location.reload() ";
}
try {
port = Integer.parseInt(getParame ter(PORT_P ARAM));
} catch (NullPointerException e) {
} catch (NumberFormatException e) {
}
System.out.println("defaul t refresh action = \"" + refreshAction + "\""
+ "; port=" + port);
globalApplet = this;
serverIP = getParameter(SERVER_IP);
try{
if (connector==null) {
System.out.println("creati ng new connector thread");
connector = new Thread(new webClientAppletThread());
connector.setDaemon(false) ;
this.port = port;
connector.start();
} else {
System.out.println("using old connector thread");
}
}catch(SecurityException e){
e.printStackTrace();
}
// Initialize global listener will attempt listen:
// start up single global port listener
}
public void start() {
System.out.println("start( )...");
}
public void stop() {
System.out.println("stop() ...");
}
/**
* The run() method does the actual ServerSocket waiting
* and wakes up all threads that need notification when
* when a message is received from the middleware server.
*
* The run() method does the actual Socket connection
* to the server.
*/
public void run() {
// start up the client socket!!!
System.out.println("Inside Run.. "+connector.getThreadGroup ().getName ());
try {
// give microsoft some slack!!!
try {
if (Class.forName("java.secur ity.Access Controller ") != null) {
//PolicyEngine.assertPermi ssion(Perm issionID.S YSTEM);
java.security.AccessContro ller.check Permission (new
SocketPermission(serverIP, "connect, accept"));
//java.security.AccessCont roller.che ckPermissi on(new
//java.lang.RuntimePermiss ion("stopT hread"));
java.security.AccessContro ller.check Permission (new
java.security.AllPermissio n());
//System.out.println("GL: Asserted Permissions...");
} else {
System.out.println("GL: AccessController class not found.");
}
} catch (AccessControlException ace){
System.out.println("GL: Access Control Exception: " + ace.getMessage());
} catch (SecurityException se) {
System.out.println("GL: Throwed Security Exception: " + se.getMessage());
} catch (Throwable e){
System.out.println("GL: Throwed After Permission: " + e.getMessage());
}
System.out.println("Before synch..");
////////////////////////// ////////// ////////// ////////// //
// Listen on port for client connections if no thread
// is currently listening...
//
// In a way, this makes sure that the eMediclApplet class
// thread is a singleton...
synchronized (webClientAppletThread.cla ss) {
if (socket != null) {
// quit! if clientSocket has already been initialized...
return;
}
System.out.println("GL: Connect attempt on port: " + port);
try{
socket = new Socket(serverIP,port);
socket.setSoTimeout(0);
//socket.setKeepAlive(true );
BufferedOutputStream bos = new BufferedOutputStream(socke t.getOutpu tStream()) ;
bos.write(InetAddress.getL ocalHost() .getHostAd dress().to String().g etBytes()) ;
bos.flush();
}catch(UnknownHostExceptio n uhex){
System.out.println("EA: " + uhex.getMessage());
}catch (SecurityException se) {
System.out.println("GL: Sync Throwed Security Exception: " + se.getMessage());
}catch(IOException ioe){
System.out.println("GL: Sync Throwed IO Exception: " + ioe.getMessage());
}
}
System.out.println("After synch..");
////////////////////////// ////////// ////////// ////////// //
// loop for server connections
Thread thisThread = Thread.currentThread();
while (socket.isConnected() && connector == thisThread) {
////////////////////////// ////////// ////////// ////////// //
// try to read data from the socket...
String mes = null;
try {
System.out.println("Before getInputStream.."+socket.i sBound()+" :"+socket. isClosed()
+":"+socket.isConnected()+ ":"+socket .isInputSh utdown()+" :"+socket. isOutputSh utdown());
ObjectInputStream ois = new ObjectInputStream(socket.g etInputStr eam());
System.out.println("After getInputStream.."+Thread.a ctiveCount ());
mes = (String)ois.readObject();
System.out.println("After readUTF.."+ mes);
} catch (IOException e) {
// end of client stream ?
// just ignore the so far received message ;)
System.out.println("IOExce ption: " + e.getMessage());
mes = null;
} catch (SecurityException se) {
System.out.println("GL: While Throwed Security Exception: " + se.getMessage());
}
System.out.println("GL: TCP/IP message received: \"" + mes + "\"");
String appletMessage = mes;
// close client socket...
////////////////////////// ////////// ////////// ////////// //
// Invoke javascript...
jsInvoke((appletMessage.eq uals("")?r efreshActi on:appletM essage));
}
}catch (Throwable t1) {
t1.printStackTrace();
System.out.println("GL: Throwable" + t1+" : "+ connector.isAlive() + Thread.activeCount());
System.out.println("GL: Throwable :" + socket.isConnected()+":" + this.isActive());
System.out.println("Socket State"+socket.isBound()+": "+socket.i sClosed()
+":"+socket.isConnected()+ ":"+socket .isInputSh utdown()+" :"+socket. isOutputSh utdown());
// failure of any kind...
jsInvoke(CONNECTION_LOST);
// try to close socket...
// notify all instances that our socket is no longer valid
// by setting global server socket variable to null...
// set server socket to null so that a browser refresh could recover....
try { socket.close(); } catch (Throwable t2) {}
socket = null;
}
}
private static void jsInvoke(String message) {
try {
System.out.println(">>>>>> > Invoking: " + message);
JSObject.getWindow(globalA pplet).eva l(message) ;
} catch (Throwable t) {
// ignore :(
}
}
}
The problem is that we are getting the following error when the applet receives a message on the succeeding page (e.g. Error occurs at Home in the sequence: Login > Home) :
java.lang.ThreadDeath
at java.lang.Thread.stop(Thre ad.java:63 5)
at java.lang.ThreadGroup.stop OrSuspend( ThreadGrou p.java:633 )
at java.lang.ThreadGroup.stop (ThreadGro up.java:54 7)
at sun.awt.AppContext.dispose (AppContex t.java:382 )
at sun.applet.AppletClassLoad er.release (AppletCla ssLoader.j ava:662)
at sun.plugin.security.Plugin ClassLoade r.release( PluginClas sLoader.ja va:415)
at sun.applet.AppletPanel.rel ease(Apple tPanel.jav a:163)
at sun.applet.AppletPanel.sen dEvent(App letPanel.j ava:260)
at sun.plugin.AppletViewer.on PrivateClo se(AppletV iewer.java :764)
at sun.plugin.AppletViewer$1. run(Applet Viewer.jav a:726)
at java.lang.Thread.run(Threa d.java:536 )
The error above is thrown when the following line of code comes out of a block state "ObjectInputStream ois = new ObjectInputStream(socket.g etInputStr eam());"
I also tried separating the Socket code and Thread into a singleton class to ensure that the Thread and socket persists across different pages but it did not solve the error above.
The Applet Code:
public class webClientAppletThread extends Applet implements Runnable {
private static Socket socket;
private static String serverIP = null;
private static Thread connector = null;
private static String location = null;
/** String representing the default action to be taken upon signalling */
private static String refreshAction = "JavaScript: document.location.reload()
/** server socket has to be static because the listener is a global thread */
private static int port = 9090;
/** A generic message for warning the browser user that it cannot accept messages */
public static final String NOT_LISTENING_MSG =
"JavaScript: alert('WARNING: A browser has already been opened for webClientFiles."
+ "\\nThis browser will not be able to receive update messages correctly."
+ "\\n\\nPlease close this browser.'); window.close()";
/**
* A generic message for warning the browser that
* it will no longer receive messages
*/
public static final String CONNECTION_LOST =
"JavaScript: alert('WARNING: The connection to the server has been lost."
+ "\\n\\n\\nPlease close this browser.'); window.close()";
private static Applet globalApplet;
private static final String PORT_PARAM = "Port";
private static final String REFRESH_PARAM = "Refresh";
private static final String SERVER_IP = "ServerIP";
public void init() {
System.out.println("init()
System.out.println("Refres
System.out.println("Port: " + getParameter(PORT_PARAM));
System.out.println("Server
refreshAction = getParameter(REFRESH_PARAM
if ((refreshAction == null) || (refreshAction.equals(""))
refreshAction = "JavaScript: document.location.reload()
}
try {
port = Integer.parseInt(getParame
} catch (NullPointerException e) {
} catch (NumberFormatException e) {
}
System.out.println("defaul
+ "; port=" + port);
globalApplet = this;
serverIP = getParameter(SERVER_IP);
try{
if (connector==null) {
System.out.println("creati
connector = new Thread(new webClientAppletThread());
connector.setDaemon(false)
this.port = port;
connector.start();
} else {
System.out.println("using old connector thread");
}
}catch(SecurityException e){
e.printStackTrace();
}
// Initialize global listener will attempt listen:
// start up single global port listener
}
public void start() {
System.out.println("start(
}
public void stop() {
System.out.println("stop()
}
/**
* The run() method does the actual ServerSocket waiting
* and wakes up all threads that need notification when
* when a message is received from the middleware server.
*
* The run() method does the actual Socket connection
* to the server.
*/
public void run() {
// start up the client socket!!!
System.out.println("Inside
try {
// give microsoft some slack!!!
try {
if (Class.forName("java.secur
//PolicyEngine.assertPermi
java.security.AccessContro
SocketPermission(serverIP,
//java.security.AccessCont
//java.lang.RuntimePermiss
java.security.AccessContro
java.security.AllPermissio
//System.out.println("GL: Asserted Permissions...");
} else {
System.out.println("GL: AccessController class not found.");
}
} catch (AccessControlException ace){
System.out.println("GL: Access Control Exception: " + ace.getMessage());
} catch (SecurityException se) {
System.out.println("GL: Throwed Security Exception: " + se.getMessage());
} catch (Throwable e){
System.out.println("GL: Throwed After Permission: " + e.getMessage());
}
System.out.println("Before
//////////////////////////
// Listen on port for client connections if no thread
// is currently listening...
//
// In a way, this makes sure that the eMediclApplet class
// thread is a singleton...
synchronized (webClientAppletThread.cla
if (socket != null) {
// quit! if clientSocket has already been initialized...
return;
}
System.out.println("GL: Connect attempt on port: " + port);
try{
socket = new Socket(serverIP,port);
socket.setSoTimeout(0);
//socket.setKeepAlive(true
BufferedOutputStream bos = new BufferedOutputStream(socke
bos.write(InetAddress.getL
bos.flush();
}catch(UnknownHostExceptio
System.out.println("EA: " + uhex.getMessage());
}catch (SecurityException se) {
System.out.println("GL: Sync Throwed Security Exception: " + se.getMessage());
}catch(IOException ioe){
System.out.println("GL: Sync Throwed IO Exception: " + ioe.getMessage());
}
}
System.out.println("After synch..");
//////////////////////////
// loop for server connections
Thread thisThread = Thread.currentThread();
while (socket.isConnected() && connector == thisThread) {
//////////////////////////
// try to read data from the socket...
String mes = null;
try {
System.out.println("Before
+":"+socket.isConnected()+
ObjectInputStream ois = new ObjectInputStream(socket.g
System.out.println("After getInputStream.."+Thread.a
mes = (String)ois.readObject();
System.out.println("After readUTF.."+ mes);
} catch (IOException e) {
// end of client stream ?
// just ignore the so far received message ;)
System.out.println("IOExce
mes = null;
} catch (SecurityException se) {
System.out.println("GL: While Throwed Security Exception: " + se.getMessage());
}
System.out.println("GL: TCP/IP message received: \"" + mes + "\"");
String appletMessage = mes;
// close client socket...
//////////////////////////
// Invoke javascript...
jsInvoke((appletMessage.eq
}
}catch (Throwable t1) {
t1.printStackTrace();
System.out.println("GL: Throwable" + t1+" : "+ connector.isAlive() + Thread.activeCount());
System.out.println("GL: Throwable :" + socket.isConnected()+":" + this.isActive());
System.out.println("Socket
+":"+socket.isConnected()+
// failure of any kind...
jsInvoke(CONNECTION_LOST);
// try to close socket...
// notify all instances that our socket is no longer valid
// by setting global server socket variable to null...
// set server socket to null so that a browser refresh could recover....
try { socket.close(); } catch (Throwable t2) {}
socket = null;
}
}
private static void jsInvoke(String message) {
try {
System.out.println(">>>>>>
JSObject.getWindow(globalA
} catch (Throwable t) {
// ignore :(
}
}
}
The problem is that we are getting the following error when the applet receives a message on the succeeding page (e.g. Error occurs at Home in the sequence: Login > Home) :
java.lang.ThreadDeath
at java.lang.Thread.stop(Thre
at java.lang.ThreadGroup.stop
at java.lang.ThreadGroup.stop
at sun.awt.AppContext.dispose
at sun.applet.AppletClassLoad
at sun.plugin.security.Plugin
at sun.applet.AppletPanel.rel
at sun.applet.AppletPanel.sen
at sun.plugin.AppletViewer.on
at sun.plugin.AppletViewer$1.
at java.lang.Thread.run(Threa
The error above is thrown when the following line of code comes out of a block state "ObjectInputStream ois = new ObjectInputStream(socket.g
I also tried separating the Socket code and Thread into a singleton class to ensure that the Thread and socket persists across different pages but it did not solve the error above.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Whether we separated the thread from the applet and made that thread a singleton or used the code above, our thread never got killed. We even made sure that the thread did not die by logging (look at throwing clause) it's state.
Not sure I understand what you're saying. The ThreadDeath exception is being thrown when your thread is stopped.
Whether it's a singleton or not has nothing to do with it, all threads in the applets ThreadGroup are stopped when the applet is stopped.
Whether it's a singleton or not has nothing to do with it, all threads in the applets ThreadGroup are stopped when the applet is stopped.
ASKER
True. ThreadDeath is thrown when your thread is stopped. We even separated the ThreadGroup of the Applet and the Thread Singleton, and found out that the Thread Singleton would be alive.
>Probable reason is that people would abuse
>this and leave a background thread running
>after you have visited a page containing their
>unfriendly applet.
We intentionally need a background thread running all the time when the web application is being used which is why we made sure the Thread Singleton is kept alive at all times.
Thing is, when the line:
ObjectInputStream ois = new ObjectInputStream(socket.g etInputStr eam());
comes out from the blocked state, the applet throws a ThreadDeath exception and not the Thread Singleton. We are suspecting that the I/O stream in conjunction with the Applet's start() method has something to do with this, and not the Thread Singleton because our debugging already showed proof of the Thread Singleton's life through the isActive() method.
>Probable reason is that people would abuse
>this and leave a background thread running
>after you have visited a page containing their
>unfriendly applet.
We intentionally need a background thread running all the time when the web application is being used which is why we made sure the Thread Singleton is kept alive at all times.
Thing is, when the line:
ObjectInputStream ois = new ObjectInputStream(socket.g
comes out from the blocked state, the applet throws a ThreadDeath exception and not the Thread Singleton. We are suspecting that the I/O stream in conjunction with the Applet's start() method has something to do with this, and not the Thread Singleton because our debugging already showed proof of the Thread Singleton's life through the isActive() method.
> and found out that the Thread Singleton would be alive.
If your thread is still alive then what exactly is the problem?
> comes out from the blocked state, the applet throws a ThreadDeath exception
probably cause thats the first chance it gets to shut things down.
If your thread is still alive then what exactly is the problem?
> comes out from the blocked state, the applet throws a ThreadDeath exception
probably cause thats the first chance it gets to shut things down.
ASKER
> If your thread is still alive then what exactly is the problem?
The applet dies by throwing a ThreadDeath exception for which we cannot trace any further, and we are sure this is not attributed to the Thread Singleton.
The applet dies by throwing a ThreadDeath exception for which we cannot trace any further, and we are sure this is not attributed to the Thread Singleton.
> and we are sure this is not attributed to the Thread Singleton.
If you remove the thread (or stop it when the applet is stopped) does the problem still occur?
If you remove the thread (or stop it when the applet is stopped) does the problem still occur?
ASKER
> If you remove the thread (or stop it when the applet is stopped) does the problem still occur?
We can't stop the Thread Singleton because the thread listens to a socket, which is why we made the Thread a Singleton in the other solution i mentioned above. However, we can try removing the thread, but that would mean that the Applet will just function as any normal applet... init start and stop... etc..
We can't stop the Thread Singleton because the thread listens to a socket, which is why we made the Thread a Singleton in the other solution i mentioned above. However, we can try removing the thread, but that would mean that the Applet will just function as any normal applet... init start and stop... etc..
> We can't stop the Thread Singleton because the thread listens to a socket
Why does that stop you stopping the thread.
> However, we can try removing the thread, but that would mean that the
> Applet will just function as any normal applet... init start and stop... etc..
Doesn't that imply the thread is the cause of the problem.
I'm just trying to isolate the cause of the problem.
If you can post a simple applet that keeps a thread running when you leave the page then I can try it here.
Why does that stop you stopping the thread.
> However, we can try removing the thread, but that would mean that the
> Applet will just function as any normal applet... init start and stop... etc..
Doesn't that imply the thread is the cause of the problem.
I'm just trying to isolate the cause of the problem.
If you can post a simple applet that keeps a thread running when you leave the page then I can try it here.
Probable reason is that people would abuse this and leave a background thread running after you have visited a page containing their unfriendly applet.