Programming 101
By Way of Java
Instructor: T. Boutell
Transcript for 1/9/97
Stimulants Anonymous
Welcome to the Java programmers' roasteria. A wide variety of stimulating beverages are consumed among the whirring virtual machines.
You say, "welcome to the ninth meeting of the java class. Thanks for coming."
You say, "please access the following URL in your browser:"
You say, "http://boutell.com/~boutell/class"
You say, "and click on the 'talk client/server' link."
You say, "this page offers the source code for all four of the classes that make up the chat server we began discussing last week."
You say, "last week, we looked at the talk.Client class, and at much of the talk.ChatFrame class."
You say, "roughly speaking, talk.Client does the communicating, and talk.ChatFrame just presents a user interface and takes advantage of talk.Client."
You say, "as I mentioned last week, these four classes are all part of the 'talk' package. So, to run them on your own system, you need to put them in a subdirectory named 'talk' beneath the directory where the web page displaying the applet is."
You say, "Netscape and appletviewer both will generally oblige by considering subdirectories of the current directory as possible places where packages might be hiding."
You say, "now, I'm going to continue talking about the ChatFrame class. First, I'd like to ask if there are any questions about last week's material before I go on."
You say, "okay..."
You say, "feel free to shoot if you have any, of course..."
You say, "now, please take a look at the source code to the talk.ChatFrame class. Please let me know when you have that source code on your screen."
You say, "scroll down to the 'action' method once you have it open."
You say, "we've seen the action() method before in a lot of classes that are descended from the Component class. It responds to button clicks, the 'return' keystroke in text fields, and so on."
You say, "in a previous class there was some frustration because I didn't do anything with the 'Object arg' argument. This time, it turns out to be very handy..."
You say, "when the user hits the 'return' key in a text field, an action event is generated, and the 'arg' parameter is a String object containing the text in that field."
You say, "just thought I'd point that out for your amusement."
You say, "now, the inputLine method isn't very interesting; it just passes the line of text up to the Client object that created this frame."
You say, "outputLine is a bit more interesting. That's because, although TextArea is a useful class, it unfortunately doesn't provide us with word wrap."
You say, "needless to say, chatting on IRC while scrolling horizontally all the time would get very old, very quickly."
You say, "now, I won't go into agonizing detail, but what this function does is break the text into short lines that fit in the text area."
You say, "the first criteria is that the line be less than a certain width in characters."
You say, "the second is that the line be broken at a space. So, if there is at least one space before that width, we break the line at the space and forget the space altogether."
You say, "if there isn't, we give up and just snap the (ridiculously long) word in half."
You say, "at the end of this method, we call deleteOldScrollback, the task of which is to make sure the TextArea doesn't keep building up text forever."
You say, "a lot of programmers don't bother with this sort of thing, because it is inconvenient and java will let you keep allocating memory."
You say, "but that can lead to unhappy computers and unhappy users. Bloat Is Bad."
jsam nods.
You say, "the approach we take here isn't too complicated. We check to see whether there's more than 'Y' characters of text in the TextArea. If there are, we lop off lines from the top until there are fewer than 'X' characters left."
You say, "now, if I made 'X' and 'Y' the same, it would work all right, but the program would be forced to do this work every time the user entered a new line once the TextArea filled up."
You say, "to keep the program snappy, we make 'X' considerably smaller than Y, so the text will not immediately hit the limit again for a little while."
You say, "the end of this method is the most interesting part, as you may have noted from my egotistical comments in the code..."
You say, "as we went along, we diligently removed text from the top of the string we received from the TextArea. But we also kept track of how many characters we removed."
You say, "at the end, we could just set the text of the TextArea to the resulting string."
You say, "but we don't want to do that, because it turns out to be slow and flickery, at least on some Java platforms."
You say, "instead, we use the replaceText method to 'replace' the unwanted text with an empty string."
You say, "in Windows, java uses a 'real' Windows text control, and windows text controls have built-in support for replacing text efficiently. Other platforms might as well. So by calling 'replace', we save time and keep a clean display."
You say, "finally, we call scrollOutputToEnd. This is another problem with TextArea -- there is no obvious way provided to make sure the cursor, and therefore the part of the text the user can see, is all the way at the end."
You say, "fortunately, it is possible to control what part of the text is selected. It turns out that all operating systems I've tried so far consider the cursor to be at the end of the currently selected text."
You say, "by making an empty selection at the end of the text, we scroll to the bottom so the user always sees the latest material when new stuff rolls in."
You say, "any questions on the talk.ChatFrame class?"
jsam wonders why the textarea on his screen has scroll bars, if it doesn't under other operating systems. You say, "this brings up a relevant point about the java AWT (abstract window toolkit)."
You say, "the AWT is 'high level.' That euphemism means that it is built on top of controls, such as text fields, that are already built into the operating systems java runs under."
You say, "sam: what operating system?"
jsam // netscape 3.01, mac.
You say, "because the AWT is high level, often there is little or no direct access to the 'guts' of controls. For example, java does not even specify whether a TextArea should have scrollbars, and it provides no way to get at them directly from your java code. But it *does* specify that the text area must support more text than can fit in the window at once, and that it should be possible to select (and scroll to) any part of the text."
You say, "whether scrollbars in TextArea will be present when needed, present all the time, or not present at all with arrow keys instead is entirely up to the person who implements the AWT on that operating system."
You say, "whether they did a good job on the Mac is for you to decide."
jsam says, "are there choices other than TextArea?"
You say, "sam: TextField is a single-line text entry area."
jsam nods. "Okay."
You say, "sam: TextArea is multiline text entry. That's it for text entry controls built in..."
You say, "sam: you can subclass Canvas yourself and write a text control. In Java 1.0, you wouldn't be able to implement copy and paste with the same clipboard other apps use, but in Java 1.1, you can do that."
jsam says, "Hmmm. I've heard that Java Beans and the Java 1.1 AWT are richer, but I don't know details. "
Malus says, "Is there some concern that if you're using a package that simplifies making windows that it won't be as platform independent as 'straight' AWT?"
You say, "Malus: it depends whether that package is built on top of the AWT or not."
You say, "Malus: if native code is involved, that's clearly a red flag unless it's done by Sun or Netscape."
You say, "now, I'm going to move on from the client applet, and talk about the server."
You say, "We've come to an important transition point."
You say, "up until this point, we have been writing java applets, intended to run within a web browser."
You say, "applets have a limited set of things they are allowed to do, but as we've seen, they are useful or at the very least entertaining."
You say, "applets can't manipulate files or contact sites other than the one they were downloaded from. They are deliberately restricted in many ways, for security reasons: you should be able to trust that a web page you casually visit won't format your hard drive."
You say, "however, java itself is not at all limited to creating applets."
You say, "java can also be used to write full-fledged 'applications' in the normal sense of the word."
You say, "for instance, as you may be aware, the java compiler 'javac' is itself a java application."
You say, "on most systems, 'javac' is a script that tells 'java.exe', the java virtual machine interpreter, to start running the java compiler application."
You say, "please take a look at the source code to the talk.Server class."
You say, "this class is the source for an application, not an applet. It implements the chat server that you are talking to."
You say, "please direct your attention to the following line:"
You say, "public static void main(String argv[]) "
You say, "this is the starting point for our java application."
You say, "if you are familiar with C or C++, this will look surprisingly familiar."
You say, "the rule for applications is this:"
You say, "to write a java application, you must write a public class with a 'public static void main(String argv[])' method. When you type 'java myclassname', the java interpreter will load the class and execute that method. The argv[] array contains any arguments you passed on the command line."
You say, "notice that the 'main' method is static. That is because, at this point, we haven't created an object of the class. Also, it is a bit more familiar for C and C++ programmers."
jsam says, "are java applications identified in any external manner?"
You say, "sam: no. When you try to run a class as a java application, the java interpreter will complain and stop if there is no static main method."
You say, "sam: java applications are not assembled into special executable files or anything of that sort."
jsam nods.
You say, "now, you can write a perfectly correct java application without creating any objects of your own at all."
You say, "here's a short example:"
public class MyApp {
public static void main(String argv[]) {
System.out.println("Hello World.");
}
}
You say, "this will run and exit just fine. Not very interesting, though, is it."kristen is still trying to figure out what makes an app different from an applet.
You say, "kristen: a good question."
You say, "kristen: applets live inside web browsers, or the appletviewer, and they live with many restrictions. They are loaded off the net, and they always have a little window they reside in, even if they don't do anything with that. They are always subclassed from java.awt.Applet."
You say, "kristen: apps are quite different. Any public java class that has a public static void main(String argv[]) method can be started up from the command line as an application, like so:"
You say, "java myclassname"
kristen says, "ah."
Malus says, "and the same class can be both an applet and an application, right, Tom?"
Malus says, "that is, they can somehow tell what context they're being run in..."
You say, "Malus: I don't want to suggest that this is all that useful or necessary, but you could write an applet with a public static void main(String argv[]) method, which would only run if it was started from the command line; it gets hairier after that, though. I don't recommend this approach."
You say, "on the Macintosh, apps are a bit different. One might say that java apps are downright silly on the mac, but that's another ball of wax."
Malus is interested in the other ball of wax, too.
jsam smiles.
You say, "Malus: well, java applications tend to think the world looks quite a lot like Unix. That's true under Unix and Windows 95/NT, to some extent. But Macs are really different -- files have file types and resource forks and so forth. Java applications don't know what to make of that."
Malus says, "ah."
jsam notes that Apple's stated plans are to make the mac an attractive place for java work; java applications on the mac should become much nicer.
You say, "now, java applications can be used to interact with the command line in a simple way, like Unix or DOS command line tools. 'javac' does that, for instance."
You say, "our chat server also talks to the command line. I don't want you to think that you can't have a graphical interface in an app; you can. You can subclass stuff from java.awt.Frame and create frames for your components to reside in, a lot like applets."
You say, "but for a server application like the chat server, we don't want to require the user to have a graphical display around. The server should be a 'start me and forget me' affair."
jsam says, "I have a question about public methods. What if I didn't specify public? The default is private, right?"
You say, "sam: now you've done it. Here's the answer:"
You say, "sam: 'default' protection is a bit different from public or private."
You say, "sam: if you don't specify protection, then other classes in the same package can use that method without restriction; no one else can."
You say, "sam: if the method is private, no one else can use it, period."
jsam says, "every time I ask a silly question, I get such an interesting answer."
Tom laughs.
You say, "now, let's take a look at the code of the main method."
if (argv.length != 1) {
usage();
}
You say, "I believe I have mentioned earlier that arrays, like argv, are objects."You say, "in particular, they have one data member, 'length', which contains the size that array was allocated for."
You say, "this application expects one argument: the port number it should listen for connections on. So we test here to see if there is exactly one argument. If not, we complain bitterly and go away."
You say, "next, we parse the argument to see if it is a reasonable integer:"
You say, "port = Integer.parseInt(argv[0]); "
You say, "this statement is in a try/catch block to catch a possible NumberFormatException, which lets us know it's not a proper number. In this case, we also complain bitterly and die."
You say, "now, we're through examining the command line, and we know we were started in a reasonable way. The next thing we do is actually create a Server object."
You say, "I should mention that we could skip that. We could have made all the member variables static. But I prefer not to do that, partly because there's no reason to write the code for apps and applets in completely different styles if you don't have to."
You say, "now, execution moves to the Server() constructor."
You say, "consider that the server takes connections from many different users, not just one."
You say, "so we create a Vector to keep these Connection objects in."
You say, "the Connection class, by the way, is nearly a mirror image of the Client class which we looked at last week. It has the same basic goal: accept input from and send output to the far end, in independent threads, so the server won't have to wait for a particular user at any time."
You say, "next, we create a special kind of socket, a ServerSocket. ServerSocket objects listen for connections on a particular port. Instead of reading and writing data through them, we just ask them for the next connection, typically in an endless loop."
You say, "listener = new ServerSocket(port); "
You say, "if this fails with an IOException, it is likely that another server is already listening on that port. Which is pretty common if you are testing a server and forget you already started a copy."
You say, "so we suggest that possible problem and go away."
You say, "notice the call to System.exit(). The exit method of the System class, which is static like most methods in that class, accepts a 'result code' for the operating system's benefit. It is a bit pointless to worry about the 'correct' result code because not every operating system is going to act like Unix."
You say, "so I tend to just specify zero. Strictly speaking, for an error, it is traditional in Unix and DOS to output something other than zero."
You say, "but it's not worth fretting over."
You say, "now, if all goes well to this point, we create a thread to do the actual listening."
You say, "then we return from the constructor."
You say, "you might notice that, after returning from the constructor, we return from main(). You might expect the program to end. And it would, if we had no threads."
You say, "if a program has threads, though, to simplify a bit, it won't end until we explicitly call System.exit, which we don't do in this program unless something goes wrong. This is a server, after all, and should run forever."
You say, "the listenerRun() method is where the actual listening for connections takes place."
You say, "Socket s = listener.accept(); "
You say, "this method call waits until a new connection is available. When a connection is ready (a user has connected), the accept method returns an ordinary Socket."
You say, "we can use that Socket object to talk to the user."
You say, "next, we create a Connection object which will take care of talking to this particular user:"
You say, "Connection c = new Connection(this, s); "
You say, "we pass a reference to the Server object because, when something interesting happens, we may want the connection to tell us about it. For instance, if the user hangs up, or says something that should go to the other users, the connection will call methods in the Server object to let us know about it."
You say, "once we have a new connection, we add it to the vector of connections. We keep that list for the same reason: because sometimes we want to communicate something to all of the connections."
You say, "we continue to accept new connnections in an endless loop."
You say, "now, if a user hangs up, the forgetConnection method will be called."
You say, "actually, let me back up a moment: let's look at outputLine first. Sorry."
You say, "the Connection class, as I mentioned, is a great deal like the Client class. When it receives a String from the client, it calls outputLine, and passes a reference to itself and the new String."
You say, "we then walk through our list of Connection objects, and call inputLine on each one of them -- except for the one we got the string from."
You say, "as I mentioned when we looked at the client code, there's no need to send the string back to the user it came from; the client shows it to the user right away to make the whole thing seem a bit less laggy."
You say, "now, let me explain how we go about examining every element of the Vector, because I don't think we've talked about this before."
You say, "there are several classes that can be used to store collections of objects."
You say, "the Vector class, which we've used a lot, contains a simple array or list of objects, one after the other."
You say, "the Hashtable class, on the other hand, lets us typically use a String to refer to each object in the collection. This is a lot like associative arrays in Perl."
You say, "but one thing they have in common is that we often want to examine every single element in the collection, for one reason or another."
You say, "the Enumeration class gives us a consistent, simple way to look at every element in a collection."
You say, "Enumeration enum = connections.elements();"
You say, "this call gives us a new enumeration that contains all of the elements in the vector."
You say, "while (enum.hasMoreElements())"
You say, "'while there are more to look at...'"
You say, "Connection c = (Connection) enum.nextElement();"
You say, "this call fetches the next element from the enumeration."
You say, "Notice that I have synchronized this loop with regard to the connections vector." You say, "That was done to make sure that elements will not be removed from the vector while we are in the process of iterating through it. Defensive programming of this sort is important when threads are involved." You say, "finally, the forgetConnection method is pretty straightforward."
You say, "first, we remove the connection from our list."
You say, "second, we call outputLine to tell all of the other users about its demise."
You say, "that brings us to the end of the Server class. And, because the Connection class is very similar to the Client class, we have in a sense covered the server entirely. But I'll review the Connection class next week for good measure."
You say, "since we're almost out of time, I'm going to stop at this point and answer questions."
jsam says, "Does connections.removeElement(c) change Enumerations that were derived from connections.elements() by replacing c with null ?"
You say, "sam: no, it should remove that element from the vector entirely and neatly move the others down."
You say, "sam: the trouble is that, after hasMoreElements succeeds, removeElements might remove the last element..."
You say, "sam: and by the time we call nextElement, there isn't one there anymore. By synchronizing on the connections vector, we force any attempt to alter the vector to wait patiently until we're through."
jsam says, "no, wait: is an Enumeration a view on a changeable object or a snapshot from when it was created?"
You say, "sam: an enumeration is merely a view."
You say, "sam: they are implemented using interfaces and smoke and mirrors and such, so you can write your own collection classes that allow Enumeration."
jsam nods. "Okay, cool. Thank you for the class, Tom; I'm learning more tcp!"
You say, "thanks for attending."
Next | Up to the Index
Follow us on Twitter | Contact Us
Copyright 1994-2012 Boutell.Com, Inc. All Rights Reserved.
