Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2006

Tip: Looking for answers? Try searching our database.

Can you get any more performance out of this?

Thread view: 
VisionSet - 20 Feb 2006 18:11 GMT
This demo app loads a bunch of URLs into JEditorPanes in a JTabbedPane.
I don't think HTML engine in the JRE is much cop, so this is probably a
non-starter.
But I'd at least expect my interface to remain responsive. Is my code broken
or Suns?
I'm guessing the renderer is just consuming tOo much resources.

TIA
Mike W

compilable example:

import java.net.URL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import java.beans.*;

public class GuiFrame extends JFrame {

private JTabbedPane tabbedPane;
private int idx;

public GuiFrame() {

 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 tabbedPane = new JTabbedPane();
 tabbedPane.setPreferredSize(new Dimension(600,500));
 add(tabbedPane, BorderLayout.CENTER);

 JPanel northPanel = new JPanel(
  new FlowLayout(FlowLayout.CENTER));

 JButton searchButton = new JButton("Load some pages");
 searchButton.addActionListener(searchAction);
 northPanel.add(searchButton);
 add(northPanel, BorderLayout.NORTH);

 pack();
 setVisible(true);
}

private ActionListener searchAction = new ActionListener() {
 public void actionPerformed(ActionEvent evt) {

  SwingUtilities.invokeLater(
   new Runnable() {
    public void run() {
     search();
    }
  });
 }
};

private URL[] someUrls() {

 try {
  return new URL[] {

   new URL("http://openp2p.com"),
   new URL("http://www.p2pnet.net"),
   new URL("http://en.wikipedia.org/wiki/Peer-to-peer"),
   new URL("http://www.limewire.com/english/content/home.shtml"),
   new URL("http://morpheus.com"),
   new URL("http://p2p.wrox.com"),
   new URL("http://www.slyck.com"),
   new URL("http://p2p.weblogsinc.com"),
   new URL("http://p2p-politics.org")
  };
 }
 catch(MalformedURLException ex) {
  ex.printStackTrace();
  return new URL[0];
 }
}

private void search() {

 URL[] urls = someUrls();

 tabbedPane.removeAll();

 idx = 0;

 for (final URL url : urls) {

  System.out.println("adding: " + url);

  Thread pageLoader = new Thread(new Runnable() {
   public void run() {

    PageView view = null;

    try {
     view = new PageView(url);
    }
    catch(IOException ex) {
     return;
    }
    tabbedPane.addTab(
     Integer.toString(++idx), view);
    tabbedPane.revalidate();
   }
  });
  pageLoader.setPriority(Thread.MIN_PRIORITY);
  pageLoader.start();
 }
}

public static void main(String[] args) {

 new GuiFrame();
}
}

class PageView extends JPanel {

private final JScrollPane scrollPane = new JScrollPane();
private final JEditorPane textComp = new JEditorPane();

public PageView(URL url) throws IOException {

 setLayout(new BorderLayout());

 textComp.setContentType("text/html");
 textComp.setPage(url);
 textComp.setEditable(false);
 add(scrollPane);

 Document doc = textComp.getDocument();

 if (doc instanceof AbstractDocument) {
  ((AbstractDocument)doc).setAsynchronousLoadPriority(+1);
 }

 textComp.addPropertyChangeListener(
   new PropertyChangeListener() {

  public void propertyChange(PropertyChangeEvent evt) {

   if (evt.getPropertyName().equals("page")) {

    if(scrollPane.getViewport().getView() != null) return;
    scrollPane.setViewportView(textComp);
    revalidate();
   }
  }
 });

 textComp.addHyperlinkListener(new HyperlinkListener() {

  public void hyperlinkUpdate(HyperlinkEvent evt) {

   try{
    if(HyperlinkEvent.EventType.ACTIVATED
     == evt.getEventType()) textComp.setPage(evt.getURL());
   }
   catch(IOException ex) {
    ex.printStackTrace();
   }
  }
 });
}
}
Chris Uppal - 21 Feb 2006 14:18 GMT
> This demo app loads a bunch of URLs into JEditorPanes in a JTabbedPane.
> I don't think HTML engine in the JRE is much cop, so this is probably a
> non-starter.
> But I'd at least expect my interface to remain responsive. Is my code
> broken or Suns?

I played with this code for a bit.  There seem to be some problems with the way
you use threads and arrange for stuff to happen on the AWT thread, but with
those fixed to the best of my knowlege (I'm do very little with Swing so "best"
is none too good) the basic problem remains.  It seems that the renderer just
spends too much time blocking the input handler.

   -- chris
VisionSet - 21 Feb 2006 18:49 GMT
> I played with this code for a bit.  There seem to be some problems with the way
> you use threads and arrange for stuff to happen on the AWT thread...

Would you be good enough to enlighten me?

Thanks
Mike W
Chris Uppal - 22 Feb 2006 12:30 GMT
[me:]
> > I played with this code for a bit.  There seem to be some problems with
> > the way you use threads and arrange for stuff to happen on the AWT
> > thread...
>
> Would you be good enough to enlighten me?

Oh, yes.  Sorry.  I wasn't trying to be coy, I just didn't think that criticism
(however constructively intended) would be all that welcome from a
non-expert -- especially when it didn't actually solve (or even help with) the
problem at hand.

Anyway, and in no special order...

There's no need to use invokeLater() in your button's action listener.  You are
already on the right (AWT) thread.

In your search() method, you start threads for each URL.  That means that you
end up doing AWT/Swing operations off the AWT thread -- which is illegal (or so
Sun have suddenly decided -- in preference to fixing their own bugs).

Oh, BTW, the code invoked from main() will also execute on a non-AWT thread,
which again is a no-no.  But I assume that's just because this is only a simple
test rather than production code ;-)  I didn't bother to change it either...

Those threads don't add anything anyway. The lengthy operation is downloading
data to populate the JEditorPane, and that happens in yet another thread
(stared internally by the implementation, as you are aware since you arrange
for that to happen explicitly).

Not really to do with threading, but there are several unnecessary (I think)
calls to revalidate().

The call to setAsynchronousLoadPriority() is unnecessary for two reasons.  One
is that it happens /after/ the lengthy call of getCocument() and the call of
setPage() which is where it that property is used.  The other is that the
Document already has an AsynchronousLoadPriority that will cause setPage() to
use a background thread to do the downloading.

I'll append my own modified version of your code.  It's quite a lot simpler,
and works just as badly ;-)   (I've moved some stuff around to suit my own
tastes better; I also removed the HyperlinkListener stuff just because it was
getting in my way and didn't help diagnose this /specific/ problem).  The only
slight oddity (apart from the fact that it doesn't work) is that I use
invokeLater() to call the setPage() operation -- that allows the constructor to
return quickly and so the tabs list gets populated more-or-less immediately.
Oh, and I also changed some of the URLs since the HTML rendered was throwing
exceptions as it tried to handle their content.

Maybe there is a way to make this work smoothly, but I can't think of one.  In
fact I can't see how it's possible since the HTML rendering /has/ to happen on
the AWT thread, but it's that which is (apparently) blocking input processing
for unacceptably long periods.  I could be missing something, though.

   -- chris

===========================
import java.net.URL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import java.beans.*;

public class GuiFrame
extends JFrame
{
  private JTabbedPane tabbedPane;

  public GuiFrame()
  {
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

     tabbedPane = new JTabbedPane();
     tabbedPane.setPreferredSize(new Dimension(600,500));
     add(tabbedPane, BorderLayout.CENTER);

     JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
     add(northPanel, BorderLayout.NORTH);

     JButton searchButton = new JButton("Load some pages");
     searchButton.addActionListener(searchAction);
     northPanel.add(searchButton);

     pack();
     setVisible(true);
  }

  private ActionListener searchAction
        = new ActionListener()
           {
              public void
              actionPerformed(ActionEvent evt)
              {
                 search();
              }
           };

  private URL[]
  someUrls()
  {
     try
     {
        return new URL[]
           {
           new URL("http://java.sun.com"),
           new URL("http://openp2p.com"),
           new URL("http://www.slyck.com"),
           new URL("http://p2p.weblogsinc.com"),
           new URL("http://p2p-politics.org")
           };
     }
     catch(MalformedURLException ex)
     {
        ex.printStackTrace();
        return new URL[0];
     }
  }

  private void
  search()
  {
     tabbedPane.removeAll();

     int idx  = 0;
     for (URL url : someUrls())
     {
        PageView view = new PageView(url);
        tabbedPane.addTab(Integer.toString(++idx), view);
     }
  }

  public static void
  main(String[] args)
  {
     new GuiFrame();
  }
}

class PageView
extends JPanel
{
  private final JScrollPane scrollPane = new JScrollPane();
  private final JEditorPane textComp = new JEditorPane();

  PageView(final URL url)
  {
     setLayout(new BorderLayout());
     add(scrollPane);

     textComp.addPropertyChangeListener
     (
        new PropertyChangeListener()
        {
           public void
           propertyChange(PropertyChangeEvent evt)
           {
              if (evt.getPropertyName().equals("page")
              &&  scrollPane.getViewport().getView() == null)
              {
                 scrollPane.setViewportView(textComp);
              }
           }
        }
     );
     textComp.setContentType("text/html");

     // postpone setPage() so that the ctor can return without delay
     SwingUtilities.invokeLater
     (
        new Runnable()
        {
           public void
           run()
           {
              try
              {
                 textComp.setPage(url);
              }
              catch(IOException ex)
              {
                 ex.printStackTrace();
              }
           }
        }
     );
  }
}
===========================
VisionSet - 22 Feb 2006 21:02 GMT
> Oh, yes.  Sorry.  I wasn't trying to be coy, I just didn't think that criticism
> (however constructively intended) would be all that welcome from a
> non-expert -- especially when it didn't actually solve (or even help with) the
> problem at hand.

Thanks for that Chris.

Mike W


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.