![]() ![]() 16 October 2001 ![]() |
![]() |
Into Java, Part 21
|
||||||||||||||||
A better Java browser
There is not much to say this time as we will
use ready made classes from the standard Java and Swing libraries. Admittedly, details aren't
always clearly spelled out in the Java API and hence, many times it is hard to see how to
make use of hidden resources. Most of the time you'll find information in Java news letters,
at Java web pages, from Java books or from friends. |
|
This browser will not be multithreaded as the
last time. Of course you can easily add Java capabilities, such as multithreading, remembering
pages visited and such stuff but that would expand this article into more than I want it to
be.
The topmost area is the text field to enter
URLs into. We add a listener to it so that a hit on Enter will make the browser grab the page.
This time we make no use of such things as JOptionPane dialogs, but it is not hard to add
one.
The next text area is new to us, the JEditorPane.
I will not say anything about it, other than that it is a powerful class and you are free
to explore it's capacity on your own. Anyway, as you can see it has one useful method, the
addHyperlinkListener, which we feed with another listener. Finally we add the GUI stuff to
the frame.
The next thing to do is the two listeners.
Until now we have always used ready made listeners from adapter classes, but we are perfectly
free to make listeners on our own.
|
Making your own listener is not hard as you
can see. But it can be confusing to see another two classes inside another class. This
technique is called inner classes. Remember though that every time we have used an adapter
it has always produced a class file named xxx$1.class, numbered sequentially. That is an anonymous
inner class. But this one differs slightly, it will result in classes like Browser$URLListener.class,
that is not that anonymous. "But", you may argue, "the name of the adapter
inner class is WindowAdapter, isn't it?" No, actually WindowAdapter is the super class
and our anonymous class inherits from its' ancestor and overrides one or more of the ancestor's
methods.
Inner classes are used due to convenience,
not that they are really necessary. Any inner class may be implemented as a regular class,
but not always as elegant as this time and sometimes it can be really cumbersome. The foremost
reason to use inner classes is that they have full access to the instance that made them,
any method or variable no matter if it is declared private or not. This simple browser is
an obvious example of that, they immediately refer to the GUI parts of the Browser object.
The only drawback is that you cannot supply parameters to its constructor when the inner class
implements an interface such as our two inner classes.
However, the URLListener tells the JEditorPane
to set a new page, and also feeds that method with the URL you typed into the text field.
Reading the Java API says that the string given to setPage will be parsed for which type of
parser to use. If the string of your URL is a valid URL the JEditorPane will determine what
to do with it. Confusing? Yes, a bit. It is not that clear that a lot of stuff will be done
automatically. Unfortunately the JEditorPane does not support the PNG image format, so it
is hard to read the OS/2 eZine web site with this browser.
The next inner class implements the HyperLinkListener
interface of the javax.swing.event package. That interface has only one method that we need
to implement, the hyperlinkUpdate(HyperlinkEvent e) method. That is, The JEditorPane,
or any of its subcomponents, can distinguish a hyperlink from other text and if a link is
clicked this inner class is notified. The code might looks confusing, but please, view the
Java API and some clouds will vanish.
If everything with the link clicked is okay,
a new page will be set by the JEditorPane mechanism and the URL text field will also be updated
to reflect the new page viewed.
Let us finish with the driver method, lean
as usual.
|
So far you have a better browser. Still there
are lots of features to add, and I suppose you will not do that. Still the idea with JEditorPane,
the HyperLinkListener interface, and how to make neat inner classes is exposed through this
short example.
Anyway, there are four steps we need to follow
when using the obtained URLConnection object:
URLConnection may be instantiated in two ways,
by the constructor that takes a URL object as a parameter, or by getting a URLConnection object
from an existing URL object using the url.openConnection() method. We will use the latter
but the two ways are equal.
This time we will add to the Browser and use
URLConnection whenever we want to connect and query the resource. As the Browser class is
not multithreaded, this enhanced version will stay single-threaded since we want to keep it
simple.
We will add two import lines, one new GUI feature,
add to the inner class URLListener and finally add a new method. Let's start from the top.
|
We have to add the two bottom import lines,
java.util and java.net since we will use StringBuffer from the former and both URL and URLConnection
from the latter.
Further we declare a JCheckBox to be used when
we want to view the information on a resource. This check box is instantiated and added to
the GUI as follows. The top and bottom lines are from the former Browser constructor, only
the middle two lines are new.
|
So far so good. You can very well compile and
see the outcome, but no feature is yet implemented. Let us start with expanding the inner
class URLListener with a few lines.
|
Now we have added an if-else control, either
the new check box is selected, or not. If it is selected we make a call to the new but not
yet implemented method, feeding it with the URL written in the text input field. Otherwise
we will use the former, ready-made implementation. And this is it. Let us move on to the new
method.
|
This is only a helper method, hence it is private.
As I said, it gets the URL text string as an argument. On the next line, a well known convenience
string, the end-of-line character.
Next comes a new line, somewhat confusing.
If, and only if, we have earlier used the JEditorPane to view a web page, its inner EditorKit
is set to one that can handle html. That kit can handle plain text, but not very well, comment
out this line and watch. The solution is to set an EditorKit that can handle text/plain
before adding text to the pane. And of course we will clear the pane.
We are used to the URL class from last month
but here we only use the URL object to get us an URLConnection object. At the same time the
fresh connection queries for the header information. Let us look at the continued method.
|
We will start with a few lines with variable
declarations and instantiation of a StringBuffer. Recall that a long time ago we discussed
how much computer resources we saved by not concatenating String objects, that is by far the
CPU hungriest way to deal with character arrays. Instead we will use a StringBuffer and append
shorter strings to it. Finally we will, as seen at the bottom code line, get its content as
a String and feed the JEditorPane object with that one.
Another reason is that JEditorPane does not
have an "append" method as JTextArea does, there is only the setText method that
has to get the full text at once. Or worse, adding new concatenated text strings growing bigger
and bigger until there is nothing more to concatenate to it (I shudder at the thought.)
Starting with the first header field line we
append both the line and its key word to the buffer. And that loop will continue until there
is no more to read from the resource's header. During this looping around, nothing is added
to the pane, but do not worry, the looping is done within hundredths of a second. That is
because the header is already downloaded upon connection time.
Surfing around watching resource header fields
will disclose that there is no given order to the lines of a header, nor do all keywords need
to be used. Some of them are used but do not carry a value. Also try to connect to non-existent
resources, or resources you are not allowed to get to and so forth. That way you will see
different replies, all of them must be parsed and taken care of by a full blown browser or
whatever application you will build or it will malfunction sooner or later.
A final word in this method. As you can see
we do not take care of any exception here, on the contrary, we throw such ones to the method
that called this method. Why? Only because that method promised to take care of such things
as exceptions. And why multiply existing code? Lazy programming is nice sometimes.
Now we are done for today. Next time we will
look at sockets, what a socket is and briefly how to use it. But we will also build ourselves
a little multi-multi-threaded chat-server. Why a server before the client? Because a client
needs to have a server, but a server does not necessarily need a client, although that seems
boring. How will we solve that and keep it busy? Stay tuned.
I must finally admit that there has not been
that much Java for me the last few weeks since I took an advanced C++ course that really tires
me. I now realize that I love Java a lot more than I thought. For example, I estimate the
time for a beginner to do the exercise we did today to about two days with a lot of hints.
At least if it is going to be correctly made with correct use of pointers, references, function
pointers and so forth. Not forgetting the destructors. With Java less than one day is sufficient,
with sparse hints.
Implementing today's example took me no more
than three hours (including taking the screen shots and reducing their file sizes), and the
only error I made was forgetting to import two packages when extending with the URLConnection
part. Shame on me <grin>. I take that as an example of how easily things are done in
Java, any experienced Java developer shall be able to make such small applications within
a few hours. But I really doubt I would have done this that fast in C++, by far "no!"
Not even with a mere and humble terminal based application.
But admittedly, C++ is much faster on heavy,
mathematical computations since you have (if you have) full control of what is taking
place. And it starts a lot faster than the JVM does. But again, what is your purpose with
the application? Fast implementation, or fast computations, or GUI, or secure applications
not leaking memory? There are a lot more languages other than Java and C++ to choose from.
Pick the one best suited for the stuff you are working with. But rest assured, Java will stay
alive for many years to come.
CU around.
Previous Article |
|
Next Article |