Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 565 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
565
Dung lượng
3,62 MB
Nội dung
LearningJava Pat Niemeyer Jonathan Knudsen Publisher: O'Reilly First Edition May2000 ISBN: 1-56592-718-4, 722 pages Copyright Table of Contents Index Full Description About the Author Reviews Examples Reader reviews Errata For programmers either just migrating to Java or already working steadily in the forefront of Java development, LearningJava gives a clear, systematic overview of the Java Standard Edition It covers the essentials of hot topics like Swing and JFC; describes new tools for signing applets; and shows how to write networked clients and servers, servlets, and JavaBeans as state-of-the-art user interfaces Includes a CD-ROM containing example code and JBuilder for Windows and Solaris LearningJava Preface New Developments Audience Using This Book Getting Wired Conventions Used in This Book How to Contact Us Acknowledgments Yet Another Language? 1.1 Enter Java 1.2 A Virtual Machine 1.3 Java Compared with Other Languages 1.4 Safety of Design 1.5 Safety of Implementation 1.6 Application and User-Level Security 1.7 Java and the World Wide Web 1.8 Java as a General Application Language 1.9 A Java Road Map A First Application 2.1 HelloJava1 2.2 HelloJava2: The Sequel 2.3 HelloJava3: The Button Strikes! 2.4 HelloJava4: Netscape's Revenge Tools of the Trade 3.1 The Java Interpreter 3.2 Policy Files 3.3 The Class Path 3.4 The Java Compiler 3.5 Java Archive (JAR) Files The Java Language 4.1 Text Encoding 4.2 Comments 4.3 Types 4.4 Statements and Expressions 4.5 Exceptions 4.6 Arrays Objects in Java 5.1 Classes 5.2 Methods 5.3 Object Creation 5.4 Object Destruction Relationships Among Classes 6.1 Subclassing and Inheritance 6.2 Interfaces 6.3 Packages and Compilation Units 6.4 Visibility of Variables and Methods 6.5 Arrays and the Class Hierarchy 6.6 Inner Classes Working with Objects and Classes 7.1 The Object Class 7.2 The Class Class 7.3 Reflection Threads 8.1 Introducing Threads 8.2 Threads in Applets 8.3 Synchronization 8.4 Scheduling and Priority 8.5 Thread Groups Basic Utility Classes 9.1 Strings 9.2 Math Utilities 9.3 Dates 9.4 Timers 9.5 Collections 9.6 Properties 9.7 The Security Manager 9.8 Internationalization 10 Input/Output Facilities 10.1 10.2 10.3 10.4 Streams Files Serialization Data Compression 11 Network Programming with Sockets and RMI 11.1 Sockets 11.2 Datagram Sockets 11.3 Simple Serialized Object Protocols 11.4 Remote Method Invocation (RMI) 12 Programming for the Web 12.1 Uniform Resource Locators (URLs) 12.2 The URL Class 12.3 Web Browsers and Handlers 12.4 Talking to CGI Programs and Servlets 12.5 Implementing Servlets 13 Swing 13.1 Components 13.2 Containers 13.3 Events 13.4 Event Summary 13.5 Multithreading in Swing 14 Using Swing Components 14.1 Buttons and Labels 14.2 Checkboxes and Radio Buttons 14.3 Lists and Combo Boxes 14.4 Borders 14.5 Menus 14.6 The PopupMenu Class 14.7 The JScrollPane Class 14.8 The JSplitPane Class 14.9 The JTabbedPane Class 14.10 Scrollbars and Sliders 14.11 Dialogs 15 More Swing Components 15.1 Text Components 15.2 Trees 15.3 Tables 15.4 Desktops 15.5 Pluggable Look-and-Feel 15.6 Creating Custom Components 16 Layout Managers 16.1 FlowLayout 16.2 GridLayout 16.3 BorderLayout 16.4 BoxLayout 16.5 CardLayout 16.6 GridBagLayout 16.7 Nonstandard Layout Managers 16.8 Absolute Positioning 17 Drawing with the 2D API 17.1 The Big Picture 17.2 The Rendering Pipeline 17.3 A Quick Tour of Java 2D 17.4 Filling Shapes 17.5 Stroking Shape Outlines 17.6 Using Fonts 17.7 Displaying Images 17.8 Using Drawing Techniques 17.9 Printing 18 Working with Images and Other Media 18.1 Implementing an ImageObserver 18.2 Using a MediaTracker 18.3 Producing Image Data 18.4 Filtering Image Data 18.5 Working with Audio 18.6 Working with Movies 19 Java Beans 19.1 What's a Bean? 19.2 Building Beans 19.3 Hand-Coding with Beans 19.4 Putting Reflection to Work 19.5 BeanContext and BeanContextServices 19.6 The Java Activation Framework 19.7 Enterprise JavaBeans 20 Applets 20.1 The JApplet Class 20.2 The Tag 20.3 Using the Java Plug-in 20.4 Using Digital Signatures 21 Glossary A Content and Protocol Handlers A.1 Writing a Content Handler A.2 Writing a Protocol Handler B BeanShell: Simple Java Scripting B.1 Running BeanShell B.2 Java Statements and Expressions B.3 BeanShell Commands B.4 Scripted Methods and Objects B.5 Learning More Colophon Preface This book is about the Java™ language and programming environment If you've been at all active on the Internet in the past few years, you've heard a lot about Java It's one of the most exciting developments in the history of the Internet, rivaling the creation of the World Wide Web Java became the darling of the Internet programming community as soon as the alpha version was released Immediately, thousands of people were writing Java applets to add to their web pages Interest in Java only grew with time, and support for Java in Netscape Navigator guaranteed it would be a permanent part of the Net scene What, then, is Java? Java is a network programming language that was developed by Sun Microsystems It's already in widespread use for creating animated and interactive web pages However, this is only the start The Java language and environment are rich enough to support entirely new kinds of applications, like dynamically extensible browsers and mobile agents There are entirely new kinds of computer platforms being developed around Java (handheld devices and network computers) that download all their software over the network In the coming years, we'll see what Java is capable of doing; fancy web pages are fun and interesting, but they certainly aren't the end of the story If Java is successful (and that isn't a foregone conclusion), it could change the way we think about computing in fundamental ways This book gives you a head start on a lot of Java fundamentals LearningJava attempts to live up to its name by mapping out the Java language, its class libraries, programming techniques, and idioms We'll dig deep into interesting areas and at least scratch the surface of the rest Other titles in the O'Reilly & Associates Java Series will pick up where we leave off and provide more comprehensive information on specific areas and applications of Java Whenever possible, we'll provide meaningful, realistic examples and avoid cataloging features The examples are simple but hint at what can be done We won't be developing the next great "killer app" in these pages, but we hope to give you a starting point for many hours of experimentation and tinkering that will lead you to learn more on your own New Developments This book, Learning Java, is actually the third edition—reworked and retitled—of O'Reilly's popular Exploring Java We've de-emphasized web-page applets this time around, reflecting their diminishing role over the past couple of years in creating "smart" web pages Other technologies have filled in the gap: JavaScript on the client side, and Java servlets and Active Server Pages on the server side We cover the most interesting features of Sun's newest release of Java, officially called Java SDK Version 1.3 (In the old days, it would have been called "JDK," for "Java development kit;" we use the newer, officially blessed "SDK," for "software development kit," throughout this book.) These features include servlets, the Java Media Framework ( JMF), timers, the collections, 2D graphics, and image-processing APIs, using the Java security manager, and using Java signed applets Another important change, though not as recent as SDK 1.3, is the ascendancy of Java Swing as the main API for graphical user interface programming Much of the material relating to AWT, Java's original GUI programming interface, has been recast and updated to use Swing facilities Audience This book is for computer professionals, students, technical people, and Finnish hackers It's for everyone who has a need for hands-on experience with the Java language with an eye toward building real applications This book could also be considered a crash course in object-oriented programming; as you learn about Java, you'll also learn a powerful and practical approach to object-oriented software development Superficially, Java looks like C or C++, so you'll be in the best position to use this book if you've some experience with one of these languages If you not, you might want to refer to books like O'Reilly's Practical C Programming for a more thorough treatment of basic C syntax However, don't make too much of the syntactic similarities between Java and C or C++ In many respects, Java acts like more dynamic languages such as Smalltalk and Lisp Knowledge of another objectoriented programming language should certainly help, although you may have to change some ideas and unlearn a few habits Java is considerably simpler than languages like C++ and Smalltalk Although we encourage you to take a broad view, you would have every right to be disappointed if we ignored the Web A substantial part of this book does discuss Java as a language for World Wide Web applications, so you should be familiar with the basic ideas behind web browsers, servers, and web documents Using This Book This book is organized roughly as follows: • • • • • • • • Chapter and Chapter provide a basic introduction to Java concepts and a tutorial to give you a jump start on Java programming Chapter discusses tools for developing with Java (the compiler, the interpreter, the JAR file package) It also covers important concepts such as embedding Java code in HTML support and object signing Chapter through Chapter describe the Java language itself Chapter covers the language's thread facilities, which should be of particular interest to advanced programmers Chapter and Chapter 10 cover much of the core API Chapter describes basic utilities, and Chapter 10 covers I/O facilities Chapter 11 and Chapter 12 cover Java networking, including sockets, URLs, and remote method invocation (RMI) Chapter 13 through Chapter 18 cover the Abstract Window Toolkit (AWT) and Swing, which provide graphical user interface (GUI) and image support Chapter 19 covers the JavaBeans™ component architecture Chapter 20 covers applets, the area in which Java saw its initial success If you're like us, you don't read books from front to back If you're really like us, you usually don't read the preface at all However, on the off chance that you will see this in time, here are a few suggestions If you are an experienced programmer who has to learn Java in the next five minutes, you are probably looking for the examples You might want to start by glancing at the tutorial in Chapter If that doesn't float your boat, you should at least look at the information in Chapter 3, which tells you how to use the compiler and interpreter, and gives you the basics of a standalone Java application This should get you started Chapter 11 and Chapter 12 are essential if you are interested in writing advanced networked applications This is probably the most interesting and important part of Java Chapter 13 though Chapter 19 discuss Java's graphics features and component architecture You should read this carefully if you are interested in Java applications for the Web Getting Wired There are many online sources for information about Java Sun Microsystem's official web site for Java topics is http://java.sun.com; look here for the latest news, updates, and Java releases This is where you'll find the Java Software Development Kit (SDK), which includes the compiler, the interpreter, and other tools Another good source of Java information, including free applets, utility classes, and applications, is the Gamelan site, run by EarthWeb; its URL is http://www.gamelan.com You should also visit O'Reilly & Associates' Java site at http://java.oreilly.com There you'll find information about other books in O'Reilly's Java Series, and a pointer to the home page for Learning Java, http://www.oreilly.com/catalog/learnjava/, where you'll find the source code examples for this book The comp.lang.java newsgroup can be a good source of information and announcements, and a place to ask intelligent questions Conventions Used in This Book The font conventions used in this book are quite simple Italic is used for: • • • Unix pathnames, filenames, and program names Internet addresses, such as domain names and URLs New terms where they are defined Boldface is used for: • Names of GUI buttons and menus Constant width is used for: • • • Anything that might appear in a Java program, including method names, variable names, and class names Command lines and options that should be typed verbatim on the screen Tags that might appear in an HTML document Constant width bold is used for: • In code examples, text that is typed by the user In the main body of text, we always use a pair of empty parentheses after a method name to distinguish methods from variables and other creatures In the Java source listings, we follow the coding conventions most frequently used in the Java community Class names begin with capital letters; variable and method names begin with lowercase All the letters in the names of constants are capitalized We don't use underscores to separate words in a long name; following common practice, we capitalize individual words (after the first) and run the words together For example: thisIsAVariable, thisIsAMethod( ), ThisIsAClass, and THISISACONSTANT How to Contact Us We have tested and verified all the information in this book to the best of our abilities, but you may find that features have changed or that we have let errors slip through the production of the book Please let us know of any errors that you find, as well as suggestions for future editions, by writing to: O'Reilly & Associates, Inc 101 Morris St Sebastopol, CA 95472 1-800-998-9938 (in the U.S or Canada) 1-707-829-0515 (international/local) 1-707-829-0104 (fax) You can also send messages electronically To be put on our mailing list or to request a catalog, send email to: info@oreilly.com To ask technical questions or to comment on the book, send email to: bookquestions@oreilly.com We have a web site for the book, where we'll list examples, errata, and any plans for future editions You can access this page at: http://www.oreilly.com/catalog/learnjava/ For more information about this book and others, see the O'Reilly web site: http://www.oreilly.com Chapter Yet Another Language? The greatest challenges and most exciting opportunities for software developers today lie in harnessing the power of networks Applications created today, whatever their intended scope or audience, will almost certainly be run on machines linked by a global network of computing resources The increasing importance of networks is placing new demands on existing tools and fueling the demand for a rapidly growing list of completely new kinds of applications We want software that works—consistently, anywhere, on any platform—and that plays well with other applications We want dynamic applications that take advantage of a connected world, capable of accessing disparate and distributed information sources We want truly distributed software that can be extended and upgraded seamlessly We want intelligent applications—like autonomous agents that can roam the Net for us, ferreting out information and serving as electronic emissaries We know, to some extent, what we want So why don't we have it? The problem has been that the tools for building these applications have fallen short The requirements of speed and portability have been, for the most part, mutually exclusive, and security has been largely ignored or misunderstood There are truly portable languages, but they are mostly bulky, interpreted, and slow These languages are popular as much for their high-level functionality as for their portability And there are fast languages, but they usually provide speed by binding themselves to particular platforms, so they can meet the portability issue only halfway There are even a few recent safe languages, but they are primarily offshoots of the portable languages and suffer from the same problems 1.1 Enter Java The Java™ programming language, developed at Sun Microsystems under the guidance of Net luminaries James Gosling and Bill Joy, is designed to be a machine-independent programming language that is both safe enough to traverse networks and powerful enough to replace native executable code Java addresses the issues raised here and may help us start building the kinds of applications we want Initially, most of the enthusiasm for Java centered around its capabilities for building embedded applications for the World Wide Web; these applications are called applets Applets could be independent programs in themselves, or sophisticated frontends to programs running on a server More recently, interest has shifted to other areas With Java 2, Java has the most sophisticated toolkit for building graphical user interfaces; this development has allowed Java to become a popular platform for developing traditional application software Java has also become an important platform for server-side applications, using the servlet interface, and for enterprise applications using technologies like Enterprise JavaBeans™ And Java is the platform of choice for modern distributed applications This book shows you how to use Java to accomplish real programming tasks, such as building networked applications and creating functional user interfaces There's still a chapter devoted to applets; they may become more important again when the Java (and subsequent) versions of the Java platform are more widely distributed in web browsers 1.1.1 Java's Origins The seeds of Java were planted in 1990 by Sun Microsystems patriarch and chief researcher, Bill Joy Since Sun's inception in the early '80s, it has steadily pushed one idea: "The network is the computer." At the time though, Sun was competing in a relatively small workstation market, while Microsoft was beginning its domination of the more mainstream, Intel-based PC world When Sun missed the boat on the PC revolution, Joy retreated to Aspen, Colorado, to work on advanced research He was committed to accomplishing complex tasks with simple software, and founded the aptly named Sun Aspen Smallworks Of the original members of the small team of programmers assembled in Aspen, James Gosling is the one who will be remembered as the father of Java Gosling first made a name for himself in the early '80s as the author of Gosling Emacs, the first version of the popular Emacs editor that was written in C and ran under Unix Gosling Emacs became popular, but was soon eclipsed by a free version, GNU Emacs, written by Emacs's original designer By that time, Gosling had moved on to design Sun's NeWS window system, which briefly contended with the X Window System for control of the Unix graphical user interface (GUI) desktop in 1987 While some people would argue that NeWS was superior to X, NeWS lost out because Sun kept it proprietary and didn't publish source code, while the primary developers of X formed the X Consortium and took the opposite approach Designing NeWS taught Gosling the power of integrating an expressive language with a networkaware windowing GUI It also taught Sun that the Internet programming community will refuse to accept proprietary standards, no matter how good they may be The seeds of Java's remarkably permissive licensing scheme were sown by NeWS's failure Gosling brought what he had learned to Bill Joy's nascent Aspen project, and in 1992, work on the project led to the founding of the Sun subsidiary, FirstPerson, Inc Its mission was to lead Sun into the world of consumer electronics The FirstPerson team worked on developing software for information appliances, such as cellular phones and personal digital assistants (PDAs) The goal was to enable the transfer of information and real-time applications over cheap infrared and packet-based networks Memory and bandwidth limitations dictated small and efficient code The nature of the applications also demanded they be safe and robust Gosling and his teammates began programming in C++, but they soon found themselves confounded by a language that was too complex, unwieldy, and insecure for the task They decided to start from scratch, and Gosling began working on something he dubbed "C++ minus minus." With the foundering of the Apple Newton, it became apparent that the PDA's ship had not yet come in, so Sun shifted FirstPerson's efforts to interactive TV (ITV) The programming language of choice for ITV set-top boxes was the near ancestor of Java, a language called Oak Even with its elegance and ability to provide safe interactivity, Oak could not salvage the lost cause of ITV Customers didn't want it, and Sun soon abandoned the concept At that time, Joy and Gosling got together to decide on a new strategy for their language It was 1993, and the explosion of interest in the Internet, and the World Wide Web in particular, presented a new opportunity Oak was small, robust, architecture-independent, and objectoriented As it happens, these are also the requirements for a universal, network-savvy programming language Sun quickly changed focus, and with a little retooling, Oak became Java 1.1.2 Future Buzz? It would not be overdoing it to say that Java has caught on like wildfire Even before its first official release, while Java was still a non-product, nearly every major industry player jumped on the Java bandwagon Java licensees included Microsoft, Intel, IBM, and virtually all major hardware and software vendors (That's not to say that everything has been coming up roses Even with all of this support Java has taken a lot of knocks and had some growing pains during its first few years.) // return the constructed object return( output.toString( ) ); } } That's really all there is to a content handler; it's relatively simple A.1.2.2 The URLConnection The java.net.URLConnection object that getContent( ) receives represents the protocol handler's connection to the remote resource It provides a number of methods for examining information about the URL resource, such as header and type fields, and for determining the kinds of operations the protocol supports However, its most important method is getInputStream( ), which returns an InputStream from the protocol handler Reading this InputStream gives you the raw data for the object the URL addresses In our case, reading the InputStream feeds x_tar the bytes of the tar file it's to process A.1.2.3 Constructing the object The majority of our getContent( ) method is devoted to interpreting the stream of bytes of the tar file and building our output object: the String that lists the contents of the tar file Again, this means that this example involves the particulars of reading tar files, so you shouldn't fret too much about the details After requesting an InputStream from the URLConnection, x_tar loops, gathering information about each file Each archived item is preceded by a header that contains attribute and length fields x_tar interprets each header and then skips over the remaining portion of the item To parse the header, we use the String constructor to read a fixed number of characters from the byte array header[] To convert these bytes into a Java String properly, we specify the character encoding used by web servers: 8859_1, which (for the most part) is equivalent to ASCII Once we have a file's name, size, and time stamp, we accumulate the results (the file listings) in a StringBuffer—one line per file When the listing is complete, getContent( ) returns the StringBuffer as a String object The main while loop continues as long as it's able to read another header record, and as long as the record's "name" field isn't full of ASCII null values (The tar file format calls for the end of the archive to be padded with an empty header record, although most tar implementations don't seem to this.) The while loop retrieves the name, size, and modification times as character strings from fields in the header The most common tar format stores its numeric values in octal, as fixed-length ASCII strings We extract the strings and use Integer.parseInt( ) to parse them After reading and parsing the header, x_tar skips over the data portion of the file and updates the variable count, which keeps track of the offset into the archive The two lines following the initial skip account for tar's "blocking" of the data records In other words, if the data portion of a file doesn't fit precisely into an integral number of blocks of RECORDLEN bytes, tar adds padding to make it fit As we said, the details of parsing tar files are not really our main concern here But x_tar does illustrate a few tricks of data manipulation in Java It may surprise you that we didn't have to provide a constructor; our content handler relies on its default constructor We don't need to provide a constructor because there isn't anything for it to Java doesn't pass the class any argument information when it creates an instance of it You might suspect that the URLConnection object would be a natural thing to provide at that point However, when you are calling the constructor of a class that is loaded at runtime, you can't easily pass it any arguments A.1.2.4 Using our new handler When we began this discussion of content handlers, we showed a brief example of how our x_tar content handler would work for us You can try that code snippet now with your favorite tar file by setting the java.content.handler.pkgs system property to learningjava.contenthandlers and making sure that package is in your class path To make things more exciting, try setting the property in your HotJava properties file (The HotJava properties file usually resides in a hotjava directory in your home directory or in the HotJava installation directory on a Windows machine.) Make sure that the class path is set before you start HotJava Once HotJava is running, go to the Preferences menu, and select Viewer Applications Find the type TAR archive, and set its Action to View in HotJava This tells HotJava to try to use a content handler to display the data in the browser Now, drive HotJava to a URL that contains a tar file The result should look something like that shown in Figure A.1 Figure A.1 Using a content handler to display data in a browser We've just extended our copy of HotJava to understand tar files! In the next section, we'll turn the tables and look at protocol handlers There we'll be building URLConnection objects; someone else will have the pleasure of reconstituting the data A.2 Writing a Protocol Handler A URL object uses a protocol handler to establish a connection with a server and perform whatever protocol is necessary to retrieve data For example, an HTTP protocol handler knows how to talk to an HTTP server and retrieve a document; an FTP protocol handler knows how to talk to an FTP server and retrieve a file All types of URLs use protocol handlers to access their objects Even the lowly "file" type URLs use a special "file" protocol handler that retrieves files from the local filesystem The data a protocol handler retrieves is then fed to an appropriate content handler for interpretation While we refer to a protocol handler as a single entity, it really has two parts: a java.net.URLStreamHandler and a java.net.URLConnection These are both abstract classes that we will subclass to create our protocol handler (Note that these are abstract classes, not interfaces Although they contain abstract methods we are required to implement, they also contain many utility methods we can use or override.) The URL looks up an appropriate URLStreamHandler, based on the protocol component of the URL The URLStreamHandler then finishes parsing the URL and creates a URLConnection when it's time to communicate with the server The URLConnection represents a single connection with a server, and implements the communication protocol itself A.2.1 Locating Protocol Handlers Protocol handlers are organized in a package hierarchy similar to content handlers But unlike content handlers, which are grouped into packages by the MIME types of the objects that they handle, protocol handlers are given individual packages Both parts of the protocol handler (the URLStreamHandler class and the URLConnection class) are located in a package named for the protocol they support For example, if we wrote an FTP protocol handler, we might put it in an learningjava.protocolhandlers.ftp package The URLStreamHandler is placed in this package and given the name Handler; all URLStreamHandlers are named Handler and distinguished by the package in which they reside The URLConnection portion of the protocol handler is placed in the same package and can be given any name There is no need for a naming convention because the corresponding URLStreamHandler is responsible for creating the URLConnection objects it uses As with content handlers, Java locates packages containing protocol handlers using the java.protocol.handler.pkgs system property The value of this property is a list of package names; if more than one package is in the list, use a vertical bar (|) to separate them For our example, we will set this property to include learningjava.protocolhandlers A.2.2 URLs, Stream Handlers, and Connections The URL, URLStreamHandler, URLConnection, and ContentHandler classes work together closely Before diving into an example, let's take a step back, look at the parts a little more, and see how these things communicate Figure A.2 shows how these components relate to each other Figure A.2 The protocol handler machinery We begin with the URL object, which points to the resource we'd like to retrieve The URLStreamHandler helps the URL class parse the URL specification string for its particular protocol For example, consider the following call to the URL constructor: URL url = new URL("protocol://foo.bar.com/file.ext"); The URL class parses only the protocol component; later, a call to the URL class's getContent( ) or openStream( ) method starts the machinery in motion The URL class locates the appropriate protocol handler by looking in the protocol-package hierarchy It then creates an instance of the appropriate URLStreamHandler class The URLStreamHandler is responsible for parsing the rest of the URL string, including hostname and filename, and possibly an alternative port designation This allows different protocols to have their own variations on the format of the URL specification string Note that this step is skipped when a URL is constructed with the "protocol," "host," and "file" components specified explicitly If the protocol is straightforward, its URLStreamHandler class can let Java the parsing and accept the default behavior For this illustration, we'll assume that the URL string requires no special parsing (If we use a nonstandard URL with a strange format, we're responsible for parsing it ourselves, as we'll show shortly.) The URL object next invokes the handler's openConnection( ) method, prompting the handler to create a new URLConnection to the resource The URLConnection performs whatever communications are necessary to talk to the resource and begins to fetch data for the object At that time, it also determines the MIME type of the incoming object data and prepares an InputStream to hand to the appropriate content handler This InputStream must send "pure" data with all traces of the protocol removed The URLConnection also locates an appropriate content handler in the content-handler package hierarchy The URLConnection creates an instance of a content handler; to put the content handler to work, the URLConnection's getContent( ) method calls the content handler's getContent( ) method If this sounds confusing, it is: we have three getContent( ) methods calling each other in a chain The newly created ContentHandler object then acquires the stream of incoming data for the object by calling the URLConnection's getInputStream( ) method (Recall that we acquired an InputStream in our x_tar content handler.) The content handler reads the stream and constructs an object from the data This object is then returned up the getContent( ) chain: from the content handler, the URLConnection, and finally the URL itself Now our application has the desired object in its greedy little hands To summarize, we create a protocol handler by implementing a URLStreamHandler class that creates specialized URLConnection objects to handle our protocol The URLConnection objects implement the getInputStream( ) method, which provides data to a content handler for construction of an object The base URLConnection class implements many of the methods we need; therefore, our URLConnection needs to provide only the methods that generate the data stream and return the MIME type of the object data If you're not thoroughly confused by all that terminology (or even if you are), let's move on to the example It should help to pin down what all these classes are doing A.2.3 The crypt Handler In this section, we'll build a crypt protocol handler It parses URLs of the form: crypt:type://hostname[:port]/location/item type is an identifier that specifies what kind of encryption to use The protocol itself is a simplified version of HTTP; we'll implement the GET command and no more We added the type identifier to the URL to show how to parse a nonstandard URL specification Once the handler has figured out the encryption type, it dynamically loads a class that implements the chosen encryption algorithm and uses it to retrieve the data Obviously, we don't have room to implement a fullblown public-key encryption algorithm, so we'll use the rot13InputStream class from Chapter 10 It should be apparent how the example can be extended by plugging in a more powerful encryption class A.2.3.1 The Encryption class First, we'll lay out our plug-in encryption class We'll define an abstract class called CryptInputStream that provides some essentials for our plug-in encrypted protocol From the CryptInputStream we'll create a subclass called rot13CryptInputStream, that implements our particular kind of encryption: //file: rot13CryptInputStream.java package learningjava.protocolhandlers.crypt; import java.io.*; abstract class CryptInputStream extends InputStream { InputStream in; OutputStream out; abstract public void set( InputStream in, OutputStream out ); } // end of class CryptInputStream class rot13CryptInputStream extends CryptInputStream { public void set( InputStream in, OutputStream out ) { this.in = new learningjava.io.rot13InputStream( in ); } public int read( ) throws IOException { return in.read( ); } } Our CryptInputStream class defines a method called set( ) that passes in the InputStream it's to translate Our URLConnection calls set( ) after creating an instance of the encryption class We need a set( ) method because we want to load the encryption class dynamically, and we aren't allowed to pass arguments to the constructor of a class when it's dynamically loaded (We noticed this same issue in our content handler previously.) In the encryption class, we also provide for the possibility of an OutputStream A more complex kind of encryption might use the OutputStream to transfer public-key information Needless to say, rot13 doesn't, so we'll ignore the OutputStream here The implementation of rot13CryptInputStream is very simple set( ) takes the InputStream it receives and wraps it with the rot13InputStream filter read( ) reads filtered data from the InputStream, throwing an exception if set( ) hasn't been called A.2.3.2 The URLStreamHandler Next we'll build our URLStreamHandler class The class name is Handler; it extends the abstract URLStreamHandler class This is the class the Java URL looks up by converting the protocol name (crypt) into a package name Remember that Java expects this class to be named Handler, and to live in a package named for the protocol type //file: Handler.java package learningjava.protocolhandlers.crypt; import java.io.*; import java.net.*; public class Handler extends URLStreamHandler { protected void parseURL(URL url, String spec, int start, int end) { int slash = spec.indexOf('/'); String crypType = spec.substring(start, slash-1); super.parseURL(url, spec, slash, end); setURL( url, "crypt:"+crypType, url.getHost( ), url.getPort(), url.getFile(), url.getRef( ) ); } protected URLConnection openConnection(URL url) throws IOException { String crypType = url.getProtocol( ).substring(6); return new CryptURLConnection( url, crypType ); } } Java creates an instance of our URLStreamHandler when we create a URL specifying the crypt protocol Handler has two jobs: to assist in parsing the URL specification strings and to create CryptURLConnection objects when it's time to open a connection to the host Our parseURL( ) method overrides the parseURL( ) method in the URLStreamHandler class It's called whenever the URL constructor sees a URL requesting the crypt protocol For example: URL url = new URL("crypt:rot13://foo.bar.com/file.txt"); parseURL( ) is passed a reference to the URL object, the URL specification string, and starting and ending indexes that show what portion of the URL string we're expected to parse The URL class has already identified the simple protocol name; otherwise, it wouldn't have found our protocol handler Our version of parseURL( ) retrieves our type identifier from the specification and stores it temporarily in the variable crypType To find the encryption type, we take everything between the starting index we were given and the character preceding the first slash in the URL string (i.e., everything up to the colon in ://) We then defer to the superclass parseURL( ) method to complete the job of parsing the URL after that point We call super.parseURL( ) with the new start index, so that it points to the character just after the type specifier This tells the superclass parseURL( ) that we've already parsed everything prior to the first slash, and it's responsible for the rest Finally we use the utility method setURL( ) to put together the final URL Almost everything has already been set correctly for us, but we need to call setURL( ) to add our special type to the protocol identifier We'll need this information later when someone wants to open the URL connection Before going on, we'll note two other possibilities If we hadn't hacked the URL string for our own purposes by adding a type specifier, we'd be dealing with a standard URL specification In this case, we wouldn't need to override parseURL( ); the default implementation would have been sufficient It could have sliced the URL into host, port, and filename components normally On the other hand, if we had created a completely bizarre URL format, we would need to parse the entire string There would be no point calling super.parseURL( ); instead, we'd have called the URLStreamHandler's protected method setURL( ) to pass the URL's components back to the URL object The other method in our Handler class is openConnection( ) After the URL has been completely parsed, the URL object calls openConnection( ) to set up the data transfer openConnection( ) calls the constructor for our URLConnection with appropriate arguments In this case, our URLConnection object is named CryptURLConnection, and the constructor requires the URL and the encryption type as arguments parseURL( ) put the encryption type in the protocol identifier of the URL We recognize it and pass the information along openConnection( ) returns the reference to our URLConnection, which the URL object uses to drive the rest of the process A.2.3.3 The URLConnection Finally, we reach the real guts of our protocol handler, the URLConnection class This is the class that opens the socket, talks to the server on the remote host, and implements the protocol itself This class doesn't have to be public, so you can put it in the same file as the Handler class we just defined We call our class CryptURLConnection; it extends the abstract URLConnection class Unlike ContentHandler and StreamURLConnection, whose names are defined by convention, we can call this class anything we want; the only class that needs to know about the URLConnection is the URLStreamHandler, which we wrote ourselves: //file: CryptURLConnection.java import java.io.*; import java.net.*; class CryptURLConnection extends URLConnection { static int defaultPort = 80; CryptInputStream cis; public String getContentType( ) { return guessContentTypeFromName( url.getFile( ) ); } CryptURLConnection ( URL url, String crypType ) throws IOException { super( url ); try { String classname = "learningjava.protocolhandlers.crypt." + crypType + "CryptInputStream"; cis = (CryptInputStream) Class.forName(classname).newInstance( ); } catch ( Exception e ) { throw new IOException("Crypt Class Not Found: "+e); } } public void connect( ) throws IOException { int port = ( url.getPort( ) == -1 ) ? defaultPort : url.getPort( ); Socket s = new Socket( url.getHost( ), port ); // Send the filename in plaintext OutputStream server = s.getOutputStream( ); new PrintWriter( new OutputStreamWriter( server, "8859_1" ), true).println( "GET " + url.getFile( ) ); // Initialize the CryptInputStream cis.set( s.getInputStream( ), server ); connected = true; } public InputStream getInputStream( ) throws IOException { if (!connected) connect( ); return ( cis ); } } The constructor for our CryptURLConnection class takes as arguments the destination URL and the name of an encryption type We pass the URL on to the constructor of our superclass, which saves it in a protected url instance variable We could have saved the URL ourselves, but calling our parent's constructor shields us from possible changes or enhancements to the base class We use crypType to construct the name of an encryption class, using the convention that the encryption class is in the same package as the protocol handler (i.e., learningjava.protocolhandlers.crypt); its name is the encryption type followed by the suffix CryptInputStream Once we have a name, we need to create an instance of the encryption class To so, we use the static method Class.forName( ) to turn the name into a Class object and newInstance( ) to load and instantiate the class (This is how Java loads the content and protocol handlers themselves.) newInstance( ) returns an Object; we need to cast it to something more specific before we can work with it Therefore, we cast it to our CryptInputStream class, the abstract class that rot13CryptInputStream extends If we implement any additional encryption types as extensions to CryptInputStream and name them appropriately, they will fit into our protocol handler without modification We the rest of our setup in the connect( ) method of the URLConnection There, we make sure we have an encryption class and open a Socket to the appropriate port on the remote host getPort( ) returns -1 if the URL doesn't specify a port explicitly; in that case we use the default port for an HTTP connection (port 80) We ask for an OutputStream on the socket, assemble a GET command using the getFile( ) method to discover the filename specified by the URL, and send our request by writing it into the OutputStream (For convenience, we wrap the OutputStream with a PrintWriter and call println( ) to send the message.) We then initialize the CryptInputStream class by calling its set( ) method and passing it an InputStream from the Socket and the OutputStream The last thing connect( ) does is set the boolean variable connected to true connected is a protected variable inherited from the URLConnection class We need to track the state of our connection because connect( ) is a public method It's called by the URLConnection's getInputStream( ) method, but it could also be called by other classes Since we don't want to start a connection if one already exists, we check connected first In a more sophisticated protocol handler, connect( ) would also be responsible for dealing with any protocol headers that come back from the server In particular, it would probably stash any important information it can deduce from the headers (e.g., MIME type, content length, time stamp) in instance variables, where it's available to other methods At a minimum, connect( ) strips the headers from the data so the content handler won't see them I'm being lazy and assuming that we'll connect to a minimal server, like the modified TinyHttpd daemon we discuss below, which doesn't bother with any headers The bulk of the work has been done; a few details remain The URLConnection's getContent( ) method needs to figure out which content handler to invoke for this URL In order to compute the content handler's name, getContent( ) needs to know the resource's MIME type To find out, it calls the URLConnection's getContentType( ) method, which returns the MIME type as a String Our protocol handler overrides getContentType( ), providing our own implementation The URLConnection class provides a number of tools to help determine the MIME type It's possible that the MIME type is conveyed explicitly in a protocol header; in this case, a more sophisticated version of connect( ) would have stored the MIME type in a convenient location for us Some servers don't bother to insert the appropriate headers, though, so you can use the method guess-ContentTypeFromName( ) to examine filename extensions, like gif or html, and map them to MIME types In the worst case, you can use guessContentTypeFromStream( ) to intuit the MIME type from the raw data The Java developers call this method "a disgusting hack" that shouldn't be needed, but that is unfortunately necessary in a world where HTTP servers lie about content types and extensions are often nonstandard We'll take the easy way out and use the guessContentTypeFromName( ) utility of the URLConnection class to determine the MIME type from the filename extension of the URL we are retrieving Once the URLConnection has found a content handler, it calls the content handler's getContent( ) method The content handler then needs to get an InputStream from which to read the data To find an InputStream, it calls the URLConnection's getInputStream( ) method getInputStream( ) returns an InputStream from which its caller can read the data after protocol processing is finished It checks whether a connection is already established; if not, it calls connect( ) to make the connection Then it returns a reference to our CryptInputStream A final note on getting the content type: the URLConnection's default getContentType( ) calls getHeaderField( ), which is presumably supposed to extract the named field from the protocol headers (it would probably spit back information connect( ) had stored away) But the default implementation of getHeaderField( ) just returns null; we would have to override it to make it anything interesting Several other connection attributes use this mechanism, so in a more general implementation, we'd probably override getHeaderField( ) rather than getContentType( ) directly A.2.3.4 Trying it out Let's try out our new protocol! Compile all of the classes and put them in the learningjava.protocolhandlers package somewhere in your class path Now set the java.protocol.handler.pkgs system property in HotJava to include learningjava.protocolhandlers Type a "crypt" style URL for a text document; you should see something like that shown in Figure A.3 Figure A.3 The crypt protocol handler at work This example would be more interesting if we had a rot13 server Since the crypt protocol is nothing more than HTTP with some encryption added, we can make a rot13 server by modifying one line of the TinyHttpd server we developed earlier, so that it spews its files in rot13 Just change the line that reads the data from the file—replace this line: f.read( data ); with a line that reads through a rot13InputStream: new learningjava.io.rot13InputStream( f ).read( data ); We'll assume you placed the rot13InputStream example in a package called learningjava.io, and that it's somewhere in your class path Now recompile and run the server It automatically encodes the files before sending them; our sample application decodes them on the other end We hope that this example has given you some food for thought Content and protocol handlers are among the most exciting ideas in Java It's unfortunate that we have to wait for future releases of HotJava and Netscape to take full advantage of them But in the meantime, you can experiment and implement your own applications Appendix B BeanShell: Simple Java Scripting In this book, I (Pat Niemeyer) have tried to avoid talking about specific software products or tools, other than those that are part of the standard JDK However I'm going to make a small exception here to mention a nifty, free Java tool called BeanShell As its name suggests, BeanShell can be used as a Java "shell." It allows you to type standard Java syntax—statements and expressions—on the command line and see the results immediately With BeanShell, you can try out bits of code as you work through the book You can access all Java APIs and even create graphical user interface components and manipulate them "live" BeanShell uses only reflection, so there is no need to compile class files I wrote BeanShell while developing the examples for this book, and I think it makes a good companion to have along on your journey through Java BeanShell is a free software project, so the source code is included on the CD-ROM that accompanies this book And you can always find the latest updates and more information at its official home: http://www.beanshell.org BeanShell is also distributed with Emacs as part of Paul Kinnucan's Java Development Environment (the JDE) I hope you find it both useful and fun! B.1 Running BeanShell All you need to run BeanShell is the Java runtime system Under Windows, with SDK 1.2 or greater, you may simply double-click the JAR file icon to start the BeanShell desktop More generally, you can simply add the JAR to your class path: Unix: Windows: export CLASSPATH=$CLASSPATH:bsh.jar set classpath %classpath%;bsh.jar and run BeanShell in one of its two basic modes: GUI or on the command line java bsh.Console java bsh.Interpreter // run the graphical desktop // run as text-only on the command line Running BeanShell with the GUI Console brings up a simple desktop that allows you to open multiple shell windows with basic command history, line editing, and cut-and-paste capability There are some other GUI tools available, as well, including a simple text editor and class browser Alternately, you can run BeanShell on the command line, in text-only mode B.2 Java Statements and Expressions At the prompt, you can type standard Java statements and expressions Statements and expressions are all of the normal things that you'd say inside a Java method: e.g., variable declarations and assignments, method calls, loops, and conditionals You can type these exactly as they would appear in Java You also have the option of working with "loosely typed" variables and arguments That is, you can simply be lazy and not declare the types of variables that you use (both primitives and objects) BeanShell will still give you an error if you attempt to misuse the actual contents of the variable If you declare types of variables or primitives, BeanShell will enforce them Here are some examples: foo = "Foo"; four = (2 + 2)*2/2; print( foo + " = " + four ); // print( ) is a bsh command // a loop for (i=0; i