?
Solved

Applet throws ThreadDeath when using a Socket connection

Posted on 2003-11-04
11
Medium Priority
?
469 Views
Last Modified: 2008-02-01
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("Refresh: " + getParameter(REFRESH_PARAM));
    System.out.println("Port: " + getParameter(PORT_PARAM));
    System.out.println("ServerIP: " + getParameter(SERVER_IP));

    refreshAction = getParameter(REFRESH_PARAM);
    if ((refreshAction == null) || (refreshAction.equals(""))) {
      refreshAction = "JavaScript: document.location.reload()";
    }

    try {
      port = Integer.parseInt(getParameter(PORT_PARAM));
    } catch (NullPointerException e) {
    } catch (NumberFormatException e) {
    }

    System.out.println("default refresh action = \"" + refreshAction + "\""
      + "; port=" + port);

    globalApplet = this;
    serverIP = getParameter(SERVER_IP);
    try{
    if (connector==null) {
                  System.out.println("creating 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.security.AccessController") != null) {
          //PolicyEngine.assertPermission(PermissionID.SYSTEM);
          java.security.AccessController.checkPermission(new
              SocketPermission(serverIP,"connect, accept"));
          //java.security.AccessController.checkPermission(new
              //java.lang.RuntimePermission("stopThread"));
          java.security.AccessController.checkPermission(new
              java.security.AllPermission());
          //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.class) {
        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(socket.getOutputStream());
        bos.write(InetAddress.getLocalHost().getHostAddress().toString().getBytes());
        bos.flush();
        }catch(UnknownHostException 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.isBound()+":"+socket.isClosed()
              +":"+socket.isConnected()+":"+socket.isInputShutdown()+":"+socket.isOutputShutdown());
          ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

          System.out.println("After getInputStream.."+Thread.activeCount());
          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("IOException: " + 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.equals("")?refreshAction:appletMessage));
      }

    }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.isClosed()
          +":"+socket.isConnected()+":"+socket.isInputShutdown()+":"+socket.isOutputShutdown());

      // 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(globalApplet).eval(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(Thread.java:635)
      at java.lang.ThreadGroup.stopOrSuspend(ThreadGroup.java:633)
      at java.lang.ThreadGroup.stop(ThreadGroup.java:547)
      at sun.awt.AppContext.dispose(AppContext.java:382)
      at sun.applet.AppletClassLoader.release(AppletClassLoader.java:662)
      at sun.plugin.security.PluginClassLoader.release(PluginClassLoader.java:415)
      at sun.applet.AppletPanel.release(AppletPanel.java:163)
      at sun.applet.AppletPanel.sendEvent(AppletPanel.java:260)
      at sun.plugin.AppletViewer.onPrivateClose(AppletViewer.java:764)
      at sun.plugin.AppletViewer$1.run(AppletViewer.java:726)
      at java.lang.Thread.run(Thread.java:536)

The error above is thrown when the following line of code comes out of a block state "ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());"


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.
0
Comment
Question by:edmargayao
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 4
11 Comments
 
LVL 92

Accepted Solution

by:
objects earned 2000 total points
ID: 9684860
The applet will kill any threads when it stops.
You need to stop all threads when the applet is stopped, and restart them when it is started again.
0
 
LVL 92

Expert Comment

by:objects
ID: 9684996
ie. you cannot persist a thread across pages.
Probable reason is that people would abuse this and leave a background thread running after you have visited a page containing their unfriendly applet.
0
 

Author Comment

by:edmargayao
ID: 9691576
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.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 92

Expert Comment

by:objects
ID: 9691634
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.
0
 

Author Comment

by:edmargayao
ID: 9691691
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.getInputStream());

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.

0
 
LVL 92

Expert Comment

by:objects
ID: 9691721
> 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.

0
 

Author Comment

by:edmargayao
ID: 9691783
> 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.
0
 
LVL 92

Expert Comment

by:objects
ID: 9691823
> 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?
0
 

Author Comment

by:edmargayao
ID: 9691849
> 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..
0
 
LVL 92

Expert Comment

by:objects
ID: 9691872
> 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.
0
 
LVL 92

Expert Comment

by:objects
ID: 10230830
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
This video teaches viewers about errors in exception handling.
Suggested Courses
Course of the Month10 days, 4 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question