Solved

Applet throws ThreadDeath when using a Socket connection

Posted on 2003-11-04
11
436 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
  • 7
  • 4
11 Comments
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
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
Comment Utility
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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 92

Expert Comment

by:objects
Comment Utility
> 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
Comment Utility
> 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
Comment Utility
> 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
Comment Utility
> 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
Comment Utility
> 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
Comment Utility
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

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 first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.

772 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now