Multiple Applets / Threads / Bashing Buttons :)

S

Stephen RIchardson

Hi I hope someone can help me with this.

Scenario is in a large piece of software my company develops, there is
an html page with lots of hyperlinks. Each link opens a new JApplet
in the main frame. The applet I am currently trying to work with
opens a dialog class that uses a couple of threads to do some stuff
(code to come) and it seems to work ok. If the end user changes the
applet whilst the threads are running, WAITS for the new applet to
load, then returns to the original applet (which then starts from the
beginning again recalling the dialog) all is still well. However, if
the user calls another applet, and then immediately attempts to call
the original one (calling the dialog containing the threads) all hell
breaks loose. First of all the console goes

java.lang.NullPointerException
at sun.applet.AppletPanel.runLoader(Unknown Source)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

and then although the applet functions correctly, it does not display
the animated gif in the dialog anymore (however it does display the
rest of the dialog) I appreciate that the use of 2 threads in this is
probably uneccesary but I had to complete quickly and if I dont use
the 2 threads, I get a lot of priority issues (either display doesnt
update or the url read doesnt work) anyways heres the code, any
suggestions welcome :)

//Code in the primary applet that calls my dialog
void GetURLData(String what)
{
sData = "";
Object parent = getParent();
while (!(parent instanceof Frame))
if (parent != null)
parent = ((Component)parent).getParent();
this.setEnabled(false);
String tempWhat = getDocumentBase().toString() + what;
LoadDialog ld = new LoadDialog(tempWhat,"Stocktake
processing.","network.gif",(Frame)parent,getDocumentBase().toString());
sData = ld.getRes();
ld = null;
this.setEnabled(true);
}

//My Dialog, errors are generated whilst this is working and the
applet is changed to another applet and back to the original applet
that calls this dialog very quickly

import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.text.DecimalFormat;
import java.lang.Math;

public class LoadDialog extends JDialog
{
private String res = "";
private String title = "Please Wait ...";
private Thread displayThread = null;
private Thread readThread = null;
private JLabel l = new JLabel("");
private JLabel g = new JLabel("");
private String url;
private ImageIcon ii;
private Object parent;

public void displayThread()
{
//Thread to manage displaying the dialog
Runnable r = new Runnable() { public void run()
{
getContentPane().setLayout(null);
setSize(400,150);
setResizable(false);
setLocationRelativeTo(null);
//Prevent user killing the dialog and hence bodging the DB
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
l.setText("Please wait.");
if (title != "") { l.setText(title + " Please Wait."); }
FontMetrics fm = getFontMetrics(new Font("Courier", Font.BOLD,
14));
int off = fm.stringWidth(l.getText());
off = (int)(10+((380-off)/2));
l.setBounds(off,80,380,30);
g = new JLabel("");
int x = (int)(((380-ii.getIconWidth())/2)+10);
int y = (int)(((90-ii.getIconHeight())/2)+10);
g.setBounds(x,y,ii.getIconWidth(),ii.getIconHeight());
g.setIcon(ii);
getContentPane().add(l,null);
getContentPane().add(g,null);
}};
//Create and start the thread
if (displayThread == null)
{
displayThread = new Thread(r,"Display");
displayThread.setPriority(Thread.MAX_PRIORITY);
displayThread.start();
}
}

public void readThread()
{
Runnable r = new Runnable() { public void run()
{
try
{
//Thread to manage calling the url and getting the results
URL urlTarg = new URL(url);
BufferedReader input = new BufferedReader(new
InputStreamReader(urlTarg.openStream()));
String line;
StringBuffer buffer = new StringBuffer();
while ((line = input.readLine()) != null)
{
buffer.append(line).append('\n');
displayThread();
}
input.close();
res = new String(buffer);
System.out.println(res);
//Clean up
input = null;
buffer = null;
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent,"Error reading URL " +
url + " " + e.toString());}
//Clean up
//Sleep for 2.5 seconds to prevent "WTF WAS THAT" syndrome
try {Thread.currentThread().sleep(2500);} catch (Exception e) {}
//Fix for buffer overflow on repeated use ?
readThread = null;
displayThread = null;
System.runFinalization();
//Close the dialog hence pass control back to the applet
setVisible(false);
}};
//Create and start the thread
if (readThread == null)
{
readThread = new Thread(r,"Read");
System.out.println("Starting MAIN read thread");
readThread.start();
}
}

//Duh :)
public String getRes() {return res;}

public LoadDialog(String u,String t,String i,Frame f,String base)
{
super(f,true);
//Set up a parent for error dialogs
parent = getParent();
while (!(parent instanceof Frame))
parent = ((Component)parent).getParent();
//Pre cache the image due to latency issues
l.setForeground(Color.black);
l.setFont(new Font("Courier", Font.BOLD, 14));
try {
String img = base;
img = img + "/fclasses/" + i;
System.out.println("Image URL is " + img);
URL imageURL = new URL(img);
ii = new ImageIcon(imageURL);
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent, e.toString());}
//Prevent images BEASTS being used
if ((ii.getIconWidth()>380) || (ii.getIconHeight()>90))
{
JOptionPane.showMessageDialog((Frame)parent,"Image is too large
for use in this context. Using email.gif");
try
{
String temp = base + "/fclasses/email.gif";
URL imageURL = new URL(temp);
ii = new ImageIcon(imageURL);
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent, e.toString());}
}
url = u;
title = t;
//Do threads
System.out.println("Calling main display thread");
displayThread();
try {displayThread.join();} catch (Exception je) {}
readThread();
//Bring up the dialog hence locking us in
setVisible(true);
}
}

Bit of a mess I know, but anything appreciated :)
 
M

Missaka Wijekoon

Try to implement a stop method to quickly shutdown the applet as soon as
the user offloads the applet. This may help the speed at which a user
can switch between applets.

-Misk
 
M

Matt Humphrey

Stephen RIchardson said:
Hi I hope someone can help me with this.

Scenario is in a large piece of software my company develops, there is
an html page with lots of hyperlinks. Each link opens a new JApplet
in the main frame. The applet I am currently trying to work with
opens a dialog class that uses a couple of threads to do some stuff
(code to come) and it seems to work ok. If the end user changes the
applet whilst the threads are running, WAITS for the new applet to
load, then returns to the original applet (which then starts from the
beginning again recalling the dialog) all is still well. However, if
the user calls another applet, and then immediately attempts to call
the original one (calling the dialog containing the threads) all hell
breaks loose. First of all the console goes

java.lang.NullPointerException
at sun.applet.AppletPanel.runLoader(Unknown Source)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

and then although the applet functions correctly, it does not display
the animated gif in the dialog anymore (however it does display the
rest of the dialog) I appreciate that the use of 2 threads in this is
probably uneccesary but I had to complete quickly and if I dont use
the 2 threads, I get a lot of priority issues (either display doesnt
update or the url read doesnt work) anyways heres the code, any
suggestions welcome :)

//Code in the primary applet that calls my dialog
void GetURLData(String what)
{
sData = "";
Object parent = getParent();
while (!(parent instanceof Frame))
if (parent != null)
parent = ((Component)parent).getParent();
this.setEnabled(false);
String tempWhat = getDocumentBase().toString() + what;
LoadDialog ld = new LoadDialog(tempWhat,"Stocktake
processing.","network.gif",(Frame)parent,getDocumentBase().toString());
sData = ld.getRes();
ld = null;
this.setEnabled(true);
}

//My Dialog, errors are generated whilst this is working and the
applet is changed to another applet and back to the original applet
that calls this dialog very quickly

import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.text.DecimalFormat;
import java.lang.Math;

public class LoadDialog extends JDialog
{
private String res = "";
private String title = "Please Wait ...";
private Thread displayThread = null;
private Thread readThread = null;
private JLabel l = new JLabel("");
private JLabel g = new JLabel("");
private String url;
private ImageIcon ii;
private Object parent;

public void displayThread()
{
//Thread to manage displaying the dialog
Runnable r = new Runnable() { public void run()
{
getContentPane().setLayout(null);
setSize(400,150);
setResizable(false);
setLocationRelativeTo(null);
//Prevent user killing the dialog and hence bodging the DB
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
l.setText("Please wait.");
if (title != "") { l.setText(title + " Please Wait."); }
FontMetrics fm = getFontMetrics(new Font("Courier", Font.BOLD,
14));
int off = fm.stringWidth(l.getText());
off = (int)(10+((380-off)/2));
l.setBounds(off,80,380,30);
g = new JLabel("");
int x = (int)(((380-ii.getIconWidth())/2)+10);
int y = (int)(((90-ii.getIconHeight())/2)+10);
g.setBounds(x,y,ii.getIconWidth(),ii.getIconHeight());
g.setIcon(ii);
getContentPane().add(l,null);
getContentPane().add(g,null);
}};
//Create and start the thread
if (displayThread == null)
{
displayThread = new Thread(r,"Display");
displayThread.setPriority(Thread.MAX_PRIORITY);
displayThread.start();
}
}

public void readThread()
{
Runnable r = new Runnable() { public void run()
{
try
{
//Thread to manage calling the url and getting the results
URL urlTarg = new URL(url);
BufferedReader input = new BufferedReader(new
InputStreamReader(urlTarg.openStream()));
String line;
StringBuffer buffer = new StringBuffer();
while ((line = input.readLine()) != null)
{
buffer.append(line).append('\n');
displayThread();
}
input.close();
res = new String(buffer);
System.out.println(res);
//Clean up
input = null;
buffer = null;
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent,"Error reading URL " +
url + " " + e.toString());}
//Clean up
//Sleep for 2.5 seconds to prevent "WTF WAS THAT" syndrome
try {Thread.currentThread().sleep(2500);} catch (Exception e) {}
//Fix for buffer overflow on repeated use ?
readThread = null;
displayThread = null;
System.runFinalization();
//Close the dialog hence pass control back to the applet
setVisible(false);
}};
//Create and start the thread
if (readThread == null)
{
readThread = new Thread(r,"Read");
System.out.println("Starting MAIN read thread");
readThread.start();
}
}

//Duh :)
public String getRes() {return res;}

public LoadDialog(String u,String t,String i,Frame f,String base)
{
super(f,true);
//Set up a parent for error dialogs
parent = getParent();
while (!(parent instanceof Frame))
parent = ((Component)parent).getParent();
//Pre cache the image due to latency issues
l.setForeground(Color.black);
l.setFont(new Font("Courier", Font.BOLD, 14));
try {
String img = base;
img = img + "/fclasses/" + i;
System.out.println("Image URL is " + img);
URL imageURL = new URL(img);
ii = new ImageIcon(imageURL);
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent, e.toString());}
//Prevent images BEASTS being used
if ((ii.getIconWidth()>380) || (ii.getIconHeight()>90))
{
JOptionPane.showMessageDialog((Frame)parent,"Image is too large
for use in this context. Using email.gif");
try
{
String temp = base + "/fclasses/email.gif";
URL imageURL = new URL(temp);
ii = new ImageIcon(imageURL);
} catch (Exception e)
{JOptionPane.showMessageDialog((Frame)parent, e.toString());}
}
url = u;
title = t;
//Do threads
System.out.println("Calling main display thread");
displayThread();
try {displayThread.join();} catch (Exception je) {}
readThread();
//Bring up the dialog hence locking us in
setVisible(true);
}
}

Bit of a mess I know, but anything appreciated :)

I get the impression that your processing threads are updating the Swing UI.
This is not good. UI updates need to take place from the UI thread because
(for performance reasons) Swing is not threadsafe. Look at the
SwingUtilities.InvokeLater method to transfer execution from your processing
thread to the UI thread. Also, I'm not sure that it's such a good idea to
do the runFinalization. I'm pretty sure you should just leave that to the
system, although it's not something I normally have to deal with.

Good luck,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top