java hosting


JavaRanch Newsletter Articles in this issue :
Apress, Java, a Bunch of New Books and What's to ComeJessica Sant
Printable Version
An Interview with Jacquie Barker, author of Beginning Java ObjectsJessica Sant
Printable Version
Touring the Commons - part 2Jason Menard
Printable Version
The Coffee House - How to Convince Yourself or Your Grumpy Sysadmin to Adopt OpenOffice.orgSolveig Haugland
Printable Version
Book Review of the Month - A look at two popular books on EclipseMichael Yuan
Printable Version
Build a servlet-based application that executes SQL statements against a databaseJoel Murach
Printable Version
Programming Diversions Puzzle - Binary Reflected Gray CodeJason Menard
Printable Version
The Big Moose Saloon Question and Answer of the Month: Why do we define . in the classpath?Dirk Schreckmann
Printable Version
Movin' them Doggies on the Cattle Drive Michael Matola
Printable Version
Book Promotions For August Thomas Paul Printable Version

Apress, Java, a Bunch of New Books and What's to Come

by Jessica Sant

How it all began, and how it doubled over night...

Apress started in 1998 during a phone call between Dan Appleman, author of several top-selling Visual Basic books, and Gary Cornell, co-author of the Core Java books. They were talking about authoring books when one of them suggested "we should just publish our own books". They did just that and Apress, the "Author's Press", was born.

In the spring of 2003, Wrox Press declared bankruptcy. John Wiley & Sons purchased the Wrox Press brand, Wrox.com and many of its best-selling titles. At the same time, Apress more than doubled the number of books they owned by purchasing the remaining 91% of the Wrox titles.

Sorting through all those books...

As Java Editor, it's Craig Berry's job to develop the Java series of books at Apress. He came to the company via Wrox Press. Integrating a catalog as large as the one purchased from Wrox was quite a considerable project. Craig explained that "with the exception of three or four titles, Apress acquired the rights to Wrox's entire Java catalog, so what I've been doing recently is finishing off some of the works-in-progress we had at Wrox. I've also been evaluating which of the Wrox catalog should be reprinted under an Apress cover, which should be revised or updated, and which we should just allow to die gracefully."

Craig said he didn't find there was much overlap between Apress' preexisting Java books and those that had been acquired from Wrox. "The Wrox titles had far more significant subject matter coverage, whereas Apress' titles tended to be more esoteric. There are a couple of titles I need to work around but for the most part I've got a reasonably clean slate to create a new strategy.

"That new strategy includes establishing a strong foundation of titles that gives Apress good, solid coverage of the core areas of Java and then to branch out from there, while still making sure that we don't miss out on any obvious growth areas... The Java book market is quite a tough one; there are a couple of very big players in the form of O'Reilly and Pearson. Plus, Java is quite a mature, stable market now; it's not really volatile like .NET. What I'm looking to do is to carve out a distinctive niche for Apress because so far I think many of their titles have been under most people's radar. I want to take the concept of the 'Expert's voice' (Apress' byline) and help Apress to become recognized as a prestige publisher."

He then explained that the biggest problem with publishing Java books based on a new specification is "trying to figure out when a spec will actually be finalized... Sun is rather vague on release dates... Normally you can't really start writing based on a new spec until it's available for public review and is reasonably stable. So it really comes down to trying to find people who are on the experimental edge and are interested in playing with the latest technologies and then pushing them to try and get something written reasonably quickly."

What makes Apress, Apress?

That strategy and Apress' high standard of selecting expert authors is one of the things that makes them unique. Hollie Fischer, Product Manager at Apress explained, "We publish books for IT professionals, programmers, and developers that have been written by expert IT professionals, programmers, and developers. The Apress editors who are acquiring Apress books are in fact programmers themselves... so, they know what readers want and need. We ask readers what they want and need and, we listen. Apress is a really personable company, too - if a reader or author wants to stop by our office to see what we're all about, or if they just want to have a chat with us at a tradeshow or user group meeting, no problem. Our books are of very high quality - you won't find a lot of fluff in an Apress book."

Wanna write for Apress?

Craig talked about how best to go about getting noticed: "Well, to a certain extent I'm always keeping one eye open on the lookout for potential authors when I'm trawling the web, etc., but if someone wants to take a more active role in becoming an author, then their best bet is to approach us with an idea for a book. If you were to just say 'Hello, I'm interested in writing' that's not really going to get you noticed because we obviously already have lots of writers in our 'family'. What I'd be looking for is an original idea that has a certain degree of market potential."

Coming soon to an Internet near you...

Hollie gave me a little preview of what's to come at Apress, so I thought it only right to pass it along.

The new Apress Forums were opened on August 1st as a place where readers can talk shop and maybe even talk to some of their favorite authors (sounds a bit like they're trying to copy the JavaRanch's Bunkhouse Porch... but we wish them the best of luck *wink*). They will be having weekly contests and gift awards in the form of American Express gift cards.

eBooks and ePublishing is a more and more popular method for publishers to reduce the cost to the reader, or to enhance the reader's experience with a nice searchable electronic copy to go along with their printed book. "Sooner than later, no definite date yet, Apress will be making books available for download. The program will be on a subscription basis, which will include the email address of the subscriber in the actual document, customized for the subscriber. That way, if Apress comes across any illegal copies, we will be able to track the documents back to the original user and the subscriber will lose their privileges. Apress is really open to allowing people to post sample chapters of our books or using our books in tutorials and presentations, so we don't see a lot of problems with copyright infringements.... Currently, Apress books are available for readers with disabilities and any Apress book that is six months old or more is available to Books 24x7 members." If you'd like more information about the program you can contact Apress through their website, Apress.com.

And Finally...

Hollie and Craig are interested in feedback and comments about their titles, feel free to contact them at hollie_fischer@apress.com or craig_berry@apress.com.

Return to Top

An Interview with Jacquie Barker, author of Beginning Java Objects

by Jessica Sant

JavaRanch: Jacquie, let's start with the big question first: What was it like to have your publisher, Wrox, drop out from under you?

Jacquie Barker: Very disturbing, and the worst of it was that I found out indirectly. Wrox hadn't initially notified any of their established authors about the bankruptcy; at first, they only sent email out to those authors with new books under development at the time.

JavaRanch: Wow, that must have been very unnerving.

Jacquie Barker: Yes it was. As a matter of fact, the way that I found out was by receiving an email from none other than Gary Cornell, the President and founder of Apress; his email basically said "In light of the demise of Wrox, I wanted to let you know we would be honored to have you write for us." I said "DEMISE of WROX?" and then hurriedly sent emails to a couple of other Wrox authors/friends; one knew about the bankruptcy, one did not.

My immediate concern, of course, was what the fate of my book was going to be - at that point in time, Beginning Java Objects had become really well established. It was typically in the #1 or #2 slot on Amazon's "beginning Java titles" list, and I was worried that I'd lose ground if another publisher didn't pick it up quickly enough.

The problem is that when an author signs a publishing agreement, he/she sells one's soul to that publisher, and so I had no control in the fate of my book; I had to sit and wait (along with hundreds of other Wrox authors) to learn of my fate.

JavaRanch: Speaking of your book, how does the Apress version of Beginning Java Objects differ from the one published by Wrox?

Jacquie Barker: Actually, it doesn't, and I am glad you asked, because I want to make sure that folks understand the situation. John Wiley and Sons purchased the rights to reprint the top 30 selling books by Wrox out of 400+ titles; mine was #35 on Wrox's list, so Wiley didn't acquire it. As a result of Wiley's purchase of the Wrox brand, none of the other Wrox titles could continue to be marketed with their familiar red covers; so, in effect, my book was technically out of print when Wrox closed their doors! But, it was still in great demand, and so it was important to get it reprinted ASAP, which I am delighted to say was a priority on the part of Apress. However, in order for Apress to reprint my book "as is", they still had to (a) change the cover and (b) assign it a new ISBN, thus technically making it a new book in, for example, Amazon.com's eyes.

We've tried hard to get the word out that it is NOT a new edition, but rather a reprint ... but, I am sure that there is still some confusion on that subject, because a few of the old red cover Wrox copies are still floating around in bookstores, etc.

Gary Cornell and I decided that we didn't need to immediately worry about a new second edition of my book. I wrote my book to be "timeless" -- it is based on basic object/Java language principles that are language version independent -- and so we felt it more important to get the existing book back out on the streets "as is", and to worry about revisions/potential sequels at a later date. If something isn't broken, there's no need to fix it!

JavaRanch: So... are there any new books in the works?

Jacquie Barker: Yes! I am working on a lighthearted career guide for "techies" at the moment, which I am going to attempt to self-publish this Fall or Winter. I'm also talking seriously with Apress about a) a second edition to Beginning Java Objects (BJO), which will incorporate some of the more significant features of Java 1.5 (but which will still remain "language version neutral") and/or b) a C# version of my first book (BC#O). A third possibility is a sequel to BJO, which will address deploying Java-based web apps using selected J2EE component technologies (servlets/JSPs in particular). If readers are interested in following my progress on these various projects, I encourage them to visit my website, objectstart.com. But, my first priority is the techie career guide.

JavaRanch: How do you find the world of Apress vs. the old Wrox Press?

Jacquie Barker: Apress has been far more organized/responsive to me than Wrox was for most of the time that I worked with them. (The individual people at Wrox were great, but somehow the corporate "glue" just wasn't there to make things flow smoothly.) I am impressed with the professionalism of everyone that I've dealt with at Apress. I wasn't very familiar with Apress before they acquired my title, because their initial focus (as a relatively new publisher) was on C# and Microsoft technologies overall, and of course I've been dedicated to the Java/open source arena for many years. But, Apress (which stands for "the Author's Press"), with the acquisition of a wide variety of formerly Wrox titles, is definitely expanding their vision.

It's also impressive that the founder of Apress, Gary Cornell, is a noted author himself! I first became acquainted with him when he co-authored several of Prentice Hall/Sun Microsystems' Core Java titles.

So, I have high hopes that Apress will do great things for my book!

JavaRanch: Ahhh that's where I recognize that name -- I see it on my desk every day

Jacquie Barker: Yes! And, the funny thing is that when Gary first contacted me about writing for Apress, I didn't make the connection either; and, he is so modest, that it didn't come out until our second or third phone chat (and even then, it was only mentioned indirectly). He said something about having been a Java author, and I glanced up at my bookshelf and said, "You are THE Gary Cornell?" It was quite a fun discovery!

JavaRanch: I think I'm about out of questions, is there anything else you'd like to add?

Jacquie Barker: Hmmm ... let's see ... I'm passionate about the fact that people who want to do justice to an object oriented programming language must learn about objects first. Most programmers dive right into Java from a non-OOP background, thinking that learning yet another language cannot be that tough; they focus on Java language syntax, but miss the boat on its object oriented "bone structure".

Now that J2EE is mainstream, there are many legacy programmers who (a) missed the object technology wave in the early 90's, (b) missed the Java wave in the mid 90's, and (c) are now trying to play "catch up" in a BIG way! I hope that my book will continue to be a launching point for folks trying to get from (a) => (b) => (c).

I welcome reader inquiries, and encourage folks to contact me via email at jjbarker@objectstart.com (or via my website) if I can be of help to them in any way in their "Java journey"!

Lastly, if any instructors are interested in potentially adopting my book as a textbook, I have lots of supporting materials -- PowerPoint presentations, exam questions, and homework assignments -- that I am happy to share.

JavaRanch: Excellent, thanks for taking the time to chat with me.

Jacquie Barker: Jessica, thanks to you (and JavaRanch) for giving me the opportunity!

Return to Top

Touring the Commons - part 2

by Jason Menard (jason@javaranch.com)

This is the second in a three part series discussing elements of the Jakarta Commons project. The first part discussed the Commons BeanUtils package, the second part discusses the Commons Digester package, and the final part will demonstrate using these packages together to build a framework for dynamically generating data transfer objects.

Introduction

Last month we took a look at using the Jakarta Commons BeanUtils package to dynamically create and manipulate JavaBeans. This month we take a look at another very useful component of the Commons project - Digester. Digester is a component that facilitates the easy mapping of XML documents to Java objects.

The reasons why you might want to map an XML document to a set of Java objects are nearly limitless. A primary reason you might do this is to extract configuration information stored in an XML file to use in your own classes. Maybe you need this capability simply because "that's where the data is". XML is a popular format for storing a large variety of information, and having the ability to easily map this data to your own set of application specific objects is nothing to sneeze at. Regardless what your motivation is, it's very likely that Digester is just what you've been looking for.

The Problem: A Collection of Book Reviews

We have an XML file containing the book reviews here at JavaRanch, along with information about the books being reviewed. We want to write a Swing application to add new reviews and edit existing reviews. It is obvious to us that we need a way to import the XML data and have it mapped to a set of Java classes which we will use within our application. We decide to use Digester to handle the object mapping for us.

First, let's take a look at a snippet of our XML. See reviews.xml for the entire file.

<books>
  <book>
    <title>Design Patterns</title>
    <category>Design Patterns, UML, and Refactoring</category>
    <edition number="1">
      <author>
        <lastName>Gamma</lastName>
        <firstName>Erich</firstName>
      </author>
      <author>
        <lastName>Helm</lastName>
        <firstName>Richard</firstName>
      </author>
      <author>
        <lastName>Johnson</lastName>
        <firstName>Ralph</firstName>
      </author>
      <author>
        <lastName>Vlissides</lastName>
        <firstName>John</firstName>
      </author>
      <isbn>0201633612</isbn>
      <review>
        <rating>8</rating>
        <content>The most popular computer science book of all time...</content>
        <reviewer>Paul Wheaton</reviewer>
	<ranchCategory>trailboss</ranchCategory>
        <reviewDate>
          <month>1</month>
          <year>2000</year>
        </reviewDate>
      </review>
    </edition>
  </book>
</books>

This looks straightforward enough. We have a collection of books, each of which has a title, a category for the type of book it is, and one or more editions. We see that each edition has one or more authors (each having first and last names), an ISBN number, and one or more reviews. Taking a look at the reviews, we can see that each review is given a rating, has the month and year the review was done, the text of the review, and the name and JavaRanch category of the person who did the review. Based on this information we come up with Books.java, Book.java, Edition.java, Author.java, and Review.java. Since the review month and review year are one-to-one mappings with Review, we made them properties of Review since there was no need for a separate class just to store those two pieces of information.

Let's take a look at our Book class.

public class Book {
    private String title;
    private ArrayList editions = new ArrayList();

    public Book() {
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List getEditions() {
        return editions;
    }

    public void addEdition(Edition edition) {
        editions.add(edition);
    }
}

The only thing to really note here is that there is an addEdition() method for adding an Edition object to an instance of Book. This is done throughout the classes we wrote where a class is maintaining a collection of objects, just like Book has a collection of Editions. We will need to have methods like this when we start working with Digester.

Now that we have some XML and some classes to map the XML to, let's take a look at using Digester.

Inside Digester

Digester uses three main concepts that must be understood in order to effectively make use of it: the object stack, element matching patterns, and processing rules.

The Object Stack

The Digester class maintains an internal stack of objects. Typically objects are pushed onto the stack or popped off of the stack according to processing rules. The Digester class contains the typical operations for manipulating the stack: clear(), peek(), push(), and pop().

  • clear() - removes all objects from the stack
  • peek() - gets a reference to the top object on the stack, but doesn't remove it
  • push() - places an object on top of the stack
  • pop() - removes the top object from the stack

Just to make sure we are all clear on how a stack works, let's walk through a quick example. I have a stack 'S' which is currently empty. I will represent it like so:

===
 S

Next let's push an Object 'A' onto the stack using the push() method. Our stack now looks like the following:

 A
===
 S

After pushing two more objects on the stack, 'B' and 'C' in that order, the stack is in the following state:

 C
 B
 A
===
 S

A call to peek() would return a reference to 'C', but the stack would remain in its current state. If we were to now pop() the stack, we would get a reference to 'C' and our stack would be left in the following state:

 B
 A
===
 S

Calling clear() would naturally remove all objects from the stack:

===
 S

Element Matching Patterns

Digester uses element matching patterns to describe the location of elements of your XML document relative to each other. You can think of it as similar to a directory hierarchy. Looking back at our XML document we can see that the first element in the document is the <books> element. The element matching pattern for the <books> element is simply:

books

Getting back to the analogy of our XML document as a directory tree, if we can imagine our XML document as being the "directory" that we are currently in, then referencing the <books> element with the element matching pattern that is simply "books" seems to make sense.

Well how about the <book> element? Our XML document lays it out like this:

<books>
  <book>
The element matching pattern for this structure is:

books/book

Once again, if we could imagine our XML document as a directory tree structure, this makes perfect sense. Let's try one more. What would the element matching pattern be for the author's last name? If you said...

books/book/edition/author/lastName

...then you are absolutely correct. Nothing too fancy here. It's a fairly straightforward concept.

Processing Rules

Processing rules are used by Digester to determine what actions need to be taken when the parser encounters a given element matching pattern. Processing rules typically are used to manipulate the stack (for example, popping an object off of the stack), create objects, and manipulate objects on the stack. Digester's processing rules are classes that implement the Rule interface.

Processing rules are fired when the parser matches the rule's element matching pattern. In other words, when the parser encounters the specified element in the XML document, the rule is triggered. Just like an XML element has a beginning tag, body content, and a closing tag, a Rule has a begin() method, a body() method, and an end() method. The begin() method of the Rule is called when the beginning of the XML element is encountered, the body() method is called when the body of the XML element is encountered, and the end() method is called when the end of the XML element is encountered. When parsing is complete, the finish() method of the rule is called, in order to take care of any resources which might need to be cleaned up.

While you may write your own rules, and in fact may often need to do so, the Digester package comes with several common Rule implementations. The Digester class has methods to register these processing rules. We'll take a look at a few of the more common processing rules and the Digester methods which register them.

ObjectCreateRule - This rule is used to create an instance of an object. The object is created by callings its no-argument constructor and pushed onto the stack when the begin() method is called. When the end() method is called, the object is popped off of the stack. To register an ObjectCreateRule that creates a new Book object whenever the <book> element is encountered, we make a call to Digester's addObjectCreate() method:

Digester digester = new Digester();
digester.addObjectCreate("books/book", Book.class);

We can see that addObjectCreate() take an element matching pattern and the class of the Java object to be created. In fact, every Digester method we'll look at that creates a Rule will take an element matching pattern as its first parameter.

BeanPropertySetRule - Sets a property of the bean that is the top object in the stack. By default, the property of the bean set is the same as the name of the current XML element being examined. The value set is the body content of the XML element.

digester.addBeanPropertySetter("books/book/title");

In the above example, setTitle() will be called on the bean on top of the object stack, setting that property with the body content of the <title> tag.

SetPropertiesRule - Sets a property of the bean that is the top object in the stack to the value of an XML attribute.

digester.addSetProperties("books/book/edition", "number", "number");

This example registers a SetPropertiesRule that calls the method setNumber()(the third argument of addSetProperties()) of the object on top of the stack, setting the value to the number attribute (the second argument of addSetProperties()) of the <edition> element.

SetPropertyRule - Sets a property of the bean on top of the stack to a value of an XML attribute. The property of the bean to be set is specified by another XML attribute.

For example, given the XML element <set-property property="name" value="jason"/>...

digester.addSetProperty("some/pattern/set-property", "property", "value");

...would call the setName() method of the object on top of the stack, passing the value "jason" as the argument.

CallMethodRule and CallParamRule - These two rules used in conjunction with each other allow the execution of arbitrary methods of the top bean on the stack. A CallMethodRule specifies the name of the method to call, the number of arguments that the method expects, and of course when it should be called as indicated by the element matching pattern. The method is called when the CallMethodRule's end() method executes. A CallParamRule indicates the values to be passed to method specified by the CallMethodRule. Values for the CallParamRule may be taken from either the character data of an XML element, or from an attribute of an XML element.

digester.addCallMethod("books/book/edition/isbn", "setIsbn", 1);
digester.addCallParam("books/book/edition/isbn", 0);

The first line in the above code specifies that the setIsbn() method should be called on the object on top of the stack, and that it takes one argument. The second line states that the character data of the <isbn> element should be passed as the first parameter (parameters are indexed zero-relative, so the first parameter has an index of 0) to the setIsbn() method. If we wanted to pass a parameter value from an XML element's attribute instead of its character data, our addCallParam() method might look something like this:

digester.addCallParam("books/book/edition", 0, "number");

In this case, the value passed will be taken from the number attribute of the <edition> element.

Looking back at the addCallMethod() method of Digester, one might think that to call a method that takes no attributes then we would use "0" as the value of the method's third argument. This is not the case however.

digester.addCallMethod("books/book/edition/isbn", "setIsbn", 0);

This example is a shorthand for the previous example where we used both addCallMethod() and addCallParam(). What this says is that we will call setIsbn() and pass the character data of the <isbn> element as the value of the argument to the method.

If these examples look like they accomplish essentially the same thing as a similar call to addBeanPropertySetter(), that is absolutely correct! The combination of addCallMethod() and addCallParam()do give us the flexibility to invoke arbitrary method calls however, which addBeanPropertySetter() does not provide for.

But what if we want to invoke a method that takes no arguments? In that case we can use the signature of addCallMethod() which takes only two methods - the element matching pattern and the name of the method, as in the following example:

digester.addCallMethod("some/pattern", "someMethod");

SetNextRule - This rule sets a property of the object that is next from the top of the stack, passing the object that is at the top of the stack as the value of the property being set. When the end() method is called, the object on top of the stack is popped and set to a property of the newly exposed top object. Typically a SetNextRule will be used to add one or more child objects to a parent object.

digester.addSetNext("books/book/edition/review", "addReview");

The example code shown here will call the addReview() method of the object that is next from the top of the stack, passing the object that is at the top of the stack as an argument. It is important to keep in mind that the stack is popped by this rule.

Using Digester

Once you understand the concepts outlined in the preceding sections, actually using Digester is really rather easy. All we need to do is follow a few simple steps and we are on our way.

The first thing we must do is create a new instance of Digester.

Digester digester = new Digester();

Now that we have our instance of Digester, we need to set any configuration properties that we might need. Configuration operations include whether or not the XML document should be validated against a DTD, the class loader to use for loading objects created by an ObjectCreateRule, and whether or not namespace aware parsing is enabled. There are a host of other configuration options, and I would urge you to read the API documents for further information.

digester.setValidating(false);

Next we must register our processing rules.

digester.addObjectCreate("books", Books.class);
digester.addObjectCreate("books/book", Book.class);
digester.addBeanPropertySetter("books/book/title");
digester.addObjectCreate("books/book/edition", Edition.class);
digester.addSetProperties("books/book/edition", "number", "number");
digester.addBeanPropertySetter("books/book/edition/isbn");
digester.addObjectCreate("books/book/edition/author", Author.class);
digester.addBeanPropertySetter("books/book/edition/author/lastName");
digester.addBeanPropertySetter("books/book/edition/author/firstName");
digester.addSetNext("books/book/edition/author", "addAuthor");
digester.addObjectCreate("books/book/edition/review", Review.class);
digester.addBeanPropertySetter("books/book/edition/review/rating");
digester.addBeanPropertySetter("books/book/edition/review/content");
digester.addBeanPropertySetter("books/book/edition/review/reviewer");
digester.addBeanPropertySetter("books/book/edition/review/reviewDate/month");
digester.addBeanPropertySetter("books/book/edition/review/reviewDate/year");
digester.addSetNext("books/book/edition/review", "addReview");
digester.addSetNext("books/book/edition", "addEdition");
digester.addSetNext("books/book", "addBook");

Once we register our processing rules we are almost home. In order to proceed we must identify our input XML document. In this example we are specifying a File, but the API specifies several other suitable input sources.

File input = new File(REVIEWS_XML);

If necessary, push any objects onto the stack that we need to. Finally all we need to do is call parse(), which returns the root object of the stack.

Books books = (Books)digester.parse(input);

That's all there is to it!. See ReviewDigester.java for the complete source code.

Conclusion

In this article we've seen just how easy it can be to create a mapping between an XML document and a hierarchy of Java objects. We focused on using the Rule implementations that Digester provides for us. Next month we will learn how to write our own Rule implementations, as well as what to do when you want to create an object using a constructor that takes arguments.

Digester has a few other tricks up its sleeve that we won't have time to look at. These include specifying our processing rules in XML and pluggable rules processing, among others. Take a look at the API documentation for more information.

Resources

Please feel free to email me with any questions or comments concerning this article.


Return to Top

Sid, the Depressed Cowboy

The Coffee House

by Solveig Haugland

This Month's Story: How to Convince Yourself or Your Grumpy Sysadmin to Adopt OpenOffice.org


 
"You know," said Lacey, "I know in my heart it's wrong to be using Microsoft Office here in the coffee shop. But I'm just scared to death of what would happen if we switched over to OpenOffice.org. What about our beautifully formatted menus? Would OpenOffice.org screw up the formatting? What about them budgets we send over to the bank and all our forms?"

"I'm a little afeared myself," admitted Brenda. "Guess this is one of them things they make movies about, ordinary people facing extraordinary challenges and courage and all that stuff."

Just then, like it happens in the movies, the swinging doors of the coffee house flung open and a tall, dark, handsome, and very very tired cowboy walked on into the coffee house and kinda slumped over the bar.

"Espresso...triple shot...please..." he gasped.

"Brenda, get this man a shot, pronto!" The women swung into action and before you could say JavaBeans, they had him perked up and feelin' good on espresso, with a cafe au lait chaser.

"Thank you, ladies! I can't say as I've ever had a finer Egyptian roast, 'cept maybe in Kansas City a few years ago in the height of the coffee boom."

Brenda blushed and could hardly respond, since she was the one who roasted the beans herself.

"And you know, I thought I overheard you gals talkin' about making the big courageous switch to OpenOffice.org. Did I hear right?"

Brenda and Lacey nodded. "You know somethin' about it, mister?"

"Call me Sam. Why yes I do, ladies. I ride my horse Ned throughout the West, stoppin' wherever people need a helpin' hand to make the switch from Microsoft Office to OpenOffice.org. I show folks how to do it smart, and that it ain't as hard as the Microsoft Folks make out."

"That would be just dandy, mister! I mean Sam." And before they could say 'Richard Stallman', the stranger had a couple of laptops set up with a projector, and had a clipboard out on his knee.

"All righty. Now there's usually about five things folks are afeared of when they want to switch from Microsoft Office to OpenOffice.org. Here's one of'em."

1. General fear of the unknown, fear of going to something that?s open source and potentially flaky or unsupported.

"Now I don't know about you ladies, but I ain't exactly had a fabulous time with the support you gotta pay for. You gals  need to go on the users@openoffice.org list (just look on the www.openoffice.org site) and talk to other folks who?ve switched. You mighta heard of Cassens Transport in Illinois, Ernie Ball Guit-tar in Washington, and Jefferson County government in Golden, Colorado, just down west apiece. Once you've talked to other folks who've done it, succeeded, and liked it, there'll be less general fear of the unknown."

"That's mighty true," Brenda admitted. "I sure would like to talk to other folks; that'd make me feel better for sure."

Sam nodded. "The folks on the users@openoffice.org list, by the way, are not only a font of information but they are as prompt and courteous as a lady could want."

"So let's take another look at something else y'all will have to do."

2. Converting existing documents.

"This can be a big ol' job, but it might be not so bad. All depends on what's in your documents. You could probably get some folks who come in here regular to help convert a few test documents to just see what all happens when you switch over. You got some guys who just sit here at the bar all day long who would help you switch over your spreadsheets and invoices and stuff to OpenOffice.org to see what would happen?"

"We sure do! Lefty and Sid, and Zeke too I think, have been itching to take their ranches Open Source. They'd sure help us out, that's a great idea."

"Dandy, that's dandy," replied Sam. "All righty. Here's the third thing."

3. Training

"This isn?t trivial-like," Sam began, "but it?s certainly manageable. If you take a look at the programs, you'll see they look a heck of a lot alike. You drive on into Dodge for a couple days, get yourself a couple days of training, get a couple books to take back, and you'll be surprised how much you can do. . Do the training early and often and in manageable chunks, Oh, and OpenOffice.org is just a bit weird with some things, you'll take a long time trying to find out how to do them. so make sure you get them books. I use them myself, this Norwegian feller is the one who wrote my "OpenOffice.org Resource Kit" and I like it real fine. Big index. Oh, and the whole OpenOffice.org CD is tucked real neat in the back, so you don't gotta download it. That's kinda nice."

"Well, OK," said Lacey, "that sounds like it could work. It doesn't sound like it would be all that expensive to head into Dodge. And I shore think it would be tax deductible."

4. Ya gotta commit.

"Here's the thing. If you gals keep Microsoft Office on your computers, you ain't never going to learn OpenOffice.org proper. You gotta take off the Awfice after a month or two and just use OpenOffice.org. Just like when you go to France for a trip -- you ain't never learnin' no French if you hang out with your American buddies."

5. It's just too much work, ain't it?

"It's finally just the effort of doing it. It seems intimidating, but think about it. Think about when you've done some test documents, and you've got some learnin' under your belt, and you've talked to other folks. It'll seem real easy at that point, once you've got your mental obstacles overcome- like."

"And I just wanna mention a couple dandy things. OpenOffice.org file sizes are tiny. If you're concerned about disk space that files take up on servers or going through email, OpenOffice.org will be a dandy change. And if you ladies have a lot of licenses for Canvas, Illustrator, or Visio, you might be able to get rid of those too and just use OpenOffice.org Draw. It's got them connector lines from Visio, the object and text manipulation things you can do in Illustrator, and the general types of things you can do in Canvas. Plus it's the easiest thing to use in the whole  OpenOffice.org program, I think."

Brenda and Lacey sighed happily and looked at each other. Brenda exclaimed "Dang, I can hardly wait to put that OpenOffice.org program on our computer! We can sure save a lot of money, not sendin' in to Uncle Bill for the upgrades and support and stuff. And I kinda like the idea of a nice drawing program tucked into it too. I could sure do a lot with that Draw thing."

"We should ask Sam if he could show us a couple things before he leaves. Sam--?? What in tarnation? He was here a second ago!"

But the swinging doors of the coffee house told the story clearly -- Sam had cleared out. Onto another town, to free people from their fears and from Uncle Bill.

Riding, always riding, into the west. Every day, one mile closer to Redmond.



 

Solveig Haugland is an independent writer and trainer based in Colorado. You can contact her through her myriad Web sites, www.getopenoffice.org, www.datingdesignpatterns.com, www.cafepress.com/datingpatterns, and www.cafepress.com/techspeak.

If you or your organization are leaning toward learning OpenOffice.org, Solveig can provide you with training, learning materials, and consulting. Contact her through solveig@getopenoffice.org.


Return to Top
Book Review of the Month

A look at two popular books on Eclipse
Michael Yuan - Bartender,  July 2002

Eclipse has generated a lot of buzz among developers these days. It seems to get everything right:
  • It is small, fast and cross-platform;
  • It is code-centric with support for as-you-type error highlighting, auto code completion, refactoring and common stub generation;
  • It is extensible with many plugins and features an open architecture for plugin development;
  • It supports agile methodologies and collaborative development;
  • Best of all, it is Open Source.
Although it is easy to get started, few developers can appreciate the full power of Eclipse as both an IDE and a complete development platform. Good guide books on this subject can empower users to explore more features in the platform and maybe even contribute back to the Eclipse community as a plugin developer someday. Two Eclipse books caught my eye as the best sellers on Amazon: From the surface, the Addison-Wesley book seems to be a better bargain: It has 854 pages with a CDROM, sells for $49.99 and is written by members of the IBM Eclipse Jumpstart team. Addison-Wesley is actually publishing an entire book series on Eclipse. A draft of the second book in the series "Eclipse Modeling Framework" is in my hands as I write this review. On the other hand, the Manning book is "merely" 383 pages and costs a rather steep $44.95. However, after reading both books in the past week, I come to the conclusion that the two books serve very different purposes. I would like to have them both on my desk. Now, let’s start from the Manning book.
Eclipse In Action
David Gallardo, Ed Burnette, Robert McGovern

Manning Publications Company
Published: 15 May, 2003
The "Eclipse in Action" book covers much more than the Eclipse IDE or the Eclipse Framework. It should be accurately named "How to use Eclipse to develop agile software". Using a single project as the example throughout the book, the authors cover the Eclipse core IDE (e.g. editor, project manager and debugger) and important add-on tools such as ant, log4j, junit and cvs. The book also covers advanced topics such as how to develop and use Eclipse plug-ins.

After spending a little time studying the example project itself, the reader forms a concrete idea on how the development should proceed. Given this context, it is easy to understand how the directories are laid out; how to construct ant build files; how to auto generate test cases or JavaBean wrappers; and how to manage the CVS. Most importantly, the authors discussed adequately why and how to apply test-driven development methodologies in the application. They even refactored example application multiple times to demonstrate Eclipse’s superior code refactoring support. Overall, it is an excellent guide book on how to use Eclipse in your projects. After reading it, you can learn a lot about Eclipse as well as agile methodologies.

However, due to the limitations of the single example, the book cannot cover all the features in Eclipse. This book is a very smooth read from cover to cover. But if you are looking for description of a particular feature or menu item, you might be disappointed since the example application just does not go that far. The "plug in development" chapters of this book also only scratch the surface.
More info at Amazon.com || More info at Amazon.co.uk

Java Developer's Guide To Eclipse
Sherry Shavor, Jim D'Anjou, Dan Kehn, Scott Fairbrother, John Kellerman, Pat McCarthy

Addison Wesley
Published: 19 May, 2003
"The Java developer's Guide to Eclipse" book is almost exactly the opposite to "Eclipse in Action". It focuses on the Eclipse tool and platform, not any particular sample application. That allows the authors to describe almost all the menu items and details of supported features. However, without context, those descriptions are hard to understand or remember. I think this book makes a great reference book or textbook if supplemented with classroom and lab teaching. In fact, since the authors develop teaching materials for living, the book includes 7 chapters of "Exercises". Those materials are very good for serious learners but may not be suitable for casual readers who just want to get started with Eclipse quickly. The Addison-Wesley book really shines when it comes to Eclipse platform development materials. It presents basic and advanced tutorials on plugin development. It also describes how to build plugins into features that can be managed by the Eclipse update manager. A major characteristic of the Eclipse platform is its tight integration with the native platform. A chapter in the book is dedicated to COM interoperation on the Windows platform. Another chapter covers interoperating the native-based SWT toolkit with the standard Swing UI toolkit. If you are using Eclipse as a platform to develop your own tools, "Java Developer’s Guide to Eclipse" is a must-have book.
More info at Amazon.com || More info at Amazon.co.uk


Other books reviewed in July :

Java Extreme Programming Cookbook by Eric M. Burke and Brian M. Coyner
Design for Community, the art of connecting real people in virtual places by Derek M. Powazek
Java Web Services Architecture by James McGovern, Sameer Tyagi, Michael Stevens, Sunil Mathew
JDBC API Tutorial and Reference by Maydene Fisher, Jon Ellis, Jonathan Bruce
Unit Testing in Java by Johannes Link, Peter Froehlich
Java Web Services in a Nutshell by Kim Topley
MIDP 2.0 Style Guide for the Java 2 Platform, Micro Edition by Cynthia Bloch, Annette Wagner
The Art of Interactive Design by Chris Crawford
Sams Teach Yourself Extreme Programming in 24 Hours by Stewart Baird
Blogging - Genius Strategies for Instant Web Content by Biz Stone
Building Embedded Linux Systems by Karim Yaghmour
Java Development on PDAs: Building Applications for Pocket PC and Palm Devices by Daryl Wilding, McBride
Google Pocket Guide by Tara Calishain, Rael Dornfest , D. J. Adams
Web Services and Service-Oriented Architecture: The Savvy Manager's Guide by Douglas K. Barry
Secure Coding by Mark G. Graff, Kenneth R. van Wyk

Return to Top

Build a servlet-based application that executes SQL statements against a database

by Joel Murach - (While he may not be a JavaRanch regular, yet, he did provide us with this article to be included in our Newsletter.)

This tutorial shows how to use a Java servlet, a JavaServer Page (JSP), and a static Java class to create an application that can be used to interactively execute any standard SQL statement against a database that's running on a server. You can use an application like this one to work with a database as you're developing an application. In this article, this application will be referred to as the SQL Gateway application.

If you're working with a database that's hosted by an Internet Service Provider (ISP), the ISP will usually include an HTML-based way to work with the database that's similar to this application. If not, you can upload this application to work with the database. Either way, this application shows how to use JDBC within a servlet to work with a database that's running on a server.

Prerequisites

This tutorial is an excerpt from chapter 11 of Murach's Java Servlets and JSP by Andrea Steelman and Joel Murach. It assumes that you have a basic understanding of the Java language, servlets, and JavaServer Pages. If you don't, you might be interested in Murach's Beginning Java 2 or Murach's Java Servlets and JSP.

This tutorial also assumes that an appropriate servlet/JSP container and database server are available on the server that you're using. The source code for this tutorial has been tested using Tomcat 4.0 and MySQL, but it should work with other servlet/JSP containers, and it should work for most database servers if you supply a valid driver and connection string for that database.

Source code

Before you begin this tutorial, you may want to download the source code for this application. That way, you can open the source code in your favorite text editor to see how it all fits together.

The user interface

Here's the user interface for the SQL Gateway application after it has executed an INSERT statement:

As you can see, the bottom of the page shows a message that indicates the number of rows that were affected by the statement. If the SQL statement is a SELECT statement that runs successfully, the result set will be displayed within an HTML table as shown here:

Of course, if the SQL statement doesn't execute successfully, the result will be a message that displays information about the exception that was thrown.

The code for the JSP

The code for the JSP starts with a scriptlet that contains Java code that retrieves two attributes from the session object:

<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<%
   String sqlStatement =
      (String) session.getAttribute("sqlStatement");
   if (sqlStatement == null)
      sqlStatement = "";
   String message =
      (String) session.getAttribute("message");
   if (message == null)
      message = "";
%>

The first attribute is the string that contains the SQL statement, and the second attribute is the string that contains the result message. If these attributes contain null values, they haven't been set yet so this code sets the sqlStatement and message variables to empty strings.

This JSP also contains an HTML form that contains a text area and a submit button:

<form action="../servlet/murach.sql.SQLGatewayServlet" method="post">
   <b>SQL statement:</b><br>
   <textarea name="sqlStatement" cols=60 rows=8>
      <%= sqlStatement %>
   <textarea><br>
   <br>
   <input type="submit" value="Execute">
<form>

Here, the text area allows the user to enter the SQL statement. This code creates a text area that's approximately 60 characters wide and 8 lines tall. Within this area, the sqlStatement variable is displayed, which is empty the first time this JSP is run. Then, when the user clicks the submit button, this JSP calls the SQLGatewayServlet that's described later in this article.

The table near the end of the JSP displays the message string that contains the result of the SQL statement:

<b>SQL result:</b><br>
<table cellpadding="5" border="1">
  <%= message %>
<table>

Since this message contains the rows and columns for an HTML table, it's coded within the Table tags.

The code for the servlet

The SQLGatewayServlet, which is stored in the murach.sql package, starts by importing the java.sql package so it can use the JDBC classes. In addition, it declares a Connection object so the database connection can be used by all of the methods in the servlet:

package murach.sql;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;

public class SQLGatewayServlet extends HttpServlet{

    private Connection connection;

When the servlet engine places this servlet into service, the init method opens the connection to the database.

    public void init() throws ServletException{
        try{
            Class.forName("org.gjt.mm.mysql.Driver");
            String dbURL = "jdbc:mysql://localhost/murach";
            String username = "root";
            String password = "";
            connection = DriverManager.getConnection(
                dbURL, username, password);
        }
        catch(ClassNotFoundException e){
            System.out.println("Database driver not found.");
        }
        catch(SQLException e){
            System.out.println(
              "Error opening the db connection: "
                + e.getMessage());
        }
    }

Usually, this occurs when the first user uses the application. That way, the database connection will be open and available for all subsequent users. Then, a new thread is spawned for each user that uses this servlet.

In this example, the servlet uses a driver for the MySQL database to open a connection to a database named "murach" that's running on the same server as the servlet. In addition, this servlet uses MySQL's default username of "root" and a blank password. However, you can modify this code to connect to just about any type of database running on any type of server. Either way, you'll need to make sure that an appropriate driver for the database is installed on the server. For more information about getting, installing, and configuring MySQL, you can go to www.mysql.com. In addition, there's an introduction to MySQL in chapter 10 of Murach's Java Servlets and JSP.

Before the servlet engine takes a servlet out of service, the destroy method closes the database connection and frees up the resources required by the connection.

    public void destroy() {
        try{
            connection.close();
        }
        catch(SQLException e){
            System.out.println(
              "Error closing the db connection: "
                + e.getMessage());
        }
    }

When the JSP shown earlier calls the doPost method, this method calls the doGet method.

    public void doPost(HttpServletRequest request,
                    HttpServletResponse response)
                    throws IOException, ServletException{
        doGet(request, response);
    }

Within the doGet method, the first statement gets the SQL statement that the user entered in the JSP, and the second statement declares the message variable.

    public void doGet(HttpServletRequest request,
                     HttpServletResponse response)
                     throws IOException, ServletException{

        String sqlStatement =
            request.getParameter("sqlStatement");
        String message = "";

Then, within the try block, the first statement uses the Connection object to create a Statement object, and the next two statements use the trim and substring methods of a String object to return the first six letters of the SQL statement that the user entered.

    try{
        Statement statement = connection.createStatement();
        sqlStatement = sqlStatement.trim();
        String sqlType = sqlStatement.substring(0, 6);

If the first six letters of the SQL statement are "select", the executeQuery method of the Statement object returns a ResultSet object. Then, this object is passed to the getHtmlRows method of the SQLUtil class that's shown later in this article, and it returns the result set formatted with the HTML tags for rows and columns.

    if (sqlType.equalsIgnoreCase("select")){
        ResultSet resultSet =
            statement.executeQuery(sqlStatement);
        message =
            SQLUtil.getHtmlRows(resultSet);
    }

However, if the first six letters of the SQL statement aren't "select", the executeUpdate method of the Statement object is called, which returns the number of rows that were affected. If the number of rows is 0, the SQL statement was a DDL statement like a DROP TABLE or CREATE TABLE statement. Otherwise, the SQL statement was an INSERT, UPDATE, or DELETE statement. Either way, the code sets the message variable to an appropriate message.

    else{
        int i = statement.executeUpdate(sqlStatement);
        if (i == 0) // this is a DDL statement
          message =
            "<tr><td>" +
              "The statement executed successfully." +
            "</td></tr>";
        else        // this is a DML statement
          message =
            "<tr><td>" +
              "The statement executed successfully.<br>" +
              i + " row(s) affected." +
            "</td></tr>";
        }
        statement.close();
    }

If any of the statements within the try block throw an SQLException, the catch block sets the message variable to display information about the SQLException. If, for example, you enter an SQL statement that contains incorrect syntax, this message will help you troubleshoot your syntax problem.

    catch(SQLException e){
        message = "Error executing the SQL statement: <br>"
                + e.getMessage();
    }

After the catch block, the next three statements get the session object and set the sqlStatement and message variables as attributes of that object.

        HttpSession session = request.getSession();
        session.setAttribute("message", message);
        session.setAttribute("sqlStatement", sqlStatement);

Then, the last two statements return a RequestDispatcher object that forwards the request and response objects to the JSP shown earlier in this article.

        RequestDispatcher dispatcher =
            getServletContext().getRequestDispatcher(
                "/sql/sql_gateway.jsp");
        dispatcher.forward(request, response);
    }
}

The code for the utility class

The code for the utility class named SQLUtil is shown below. This class contains a static method named getHtmlRows that is called by the servlet shown eariler. Like the SQLGatewayServlet, this class is stored in the murach.sql package.

package murach.sql;

import java.sql.*;

public class SQLUtil{

The getHtmlRows method accepts a ResultSet object and returns a String object that contains the HTML code for all of the column headings and rows in the result set. To build the information for that String object, the getHtmlRows declares a StringBuffer object named htmlRows and appends data to it as the method is executed. At the end of the method, the toString method is used to convert the StringBuffer object to the String object that is returned to the servlet.

    public static synchronized String
    getHtmlRows(ResultSet results) throws SQLException{
        StringBuffer htmlRows = new StringBuffer();
        ResultSetMetaData metaData = results.getMetaData();
        int columnCount = metaData.getColumnCount();

        htmlRows.append("<tr>");
        for (int i = 1; i <= columnCount; i++)
            htmlRows.append("<td><b>"
                + metaData.getColumnName(i) + "</td>");
        htmlRows.append("</tr>");

        while (results.next()){
            htmlRows.append("<tr>");
            for (int i = 1; i <= columnCount; i++)
                htmlRows.append("<td>"
                    + results.getString(i) + "</td>");
        }
        htmlRows.append("</tr>");
        return htmlRows.toString();
    }
}

To get the column headings that are returned, the getHtmlRows method uses the getMetaData method of the ResultSet object to create a ResultSetMetaData object. This type of object contains information about the result set including the number of columns and the names of the columns. To get that information, the getHtmlRows method uses the getHtmlRows and getColumnName methods of the ResultSetMetaData object.

To get the data from the result set, the getHtmlRows method uses a for loop within a while loop to get the data for each column in each row. Within these loops, the code uses the getString method of the result set to get the data for each field. That converts the data to a string no matter what data type the field is.

Please note that this method is declared with the synchronized keyword. This prevents two or more threads of a servlet from executing this method at the same time.

Thanks for reading. Please let me know if you found this tutorial helpful.

Joel Murach
joelmurach@yahoo.com

Related Downloads and Resources

Source Code - Free Download
http://www.murach.com/books/jsps/download_sql_gateway.htm
Feel free to download the code for this application. Then, you can install and configure it to work on your system.

Murach's Java Servlets and JSP
http://www.murach.com/books/jsps
If you want to learn more about servlet and JSP development using a MySQL database, JDBC, and connection pooling, this book uses a unique format to methodically present these topics. In addition, it presents other essential topics such as JavaBeans, custom JSP tags, JavaMail, SSL, security, and XML.

Murach's Beginning Java 2
http://www.murach.com/books/java
If you had any trouble understanding the Java syntax presented in this tutorial, this book provides great introduction to the Java language and also makes a great reference.


Return to Top

Programming Diversions Puzzle

by Jason Menard

Binary Reflected Gray Code

Background

A Gray code is an ordered set of binary numbers such that only one bit changes from one element to the next. Any n-bit Gray code will have 2n elements. {000, 001, 011, 010, 110, 111, 101, 100} and {000, 010, 011, 001, 101, 100, 110, 111} are both examples of 3-bit Gray codes. Note that only one bit changes between each element and each set has 8 (23) elements.

A binary reflected Gray code (BRGC) is a particular encoding for non-negative integers. To find a BRGC of n bits, take the BRGC of ( n - 1 ) bits, writing it forward and then backward. Prefix the first half of the binary numbers with 0, and prefix the second half of the binary numbers with 1. The binary reflected Gray code of 1 bit (integer values 0 and 1) is:

Integer   BRGC
=======   ====
      0      0
      1      1

To find the BRCG up through 2-bit integers (0, 1, 2, 3), write the BRCG of 1 bit going forward (0, 1), then backwards (1, 0), to get (0, 1, 1, 0). Prefix the first half of those numbers with 0 and the second half with 1, giving us:

Integer   BRGC
=======   ====
      0     00
      1     01
      2     11
      3     10

Looking at the above chart we came up with, we can see that the BRCG encoding for the integer 2 is 11.

Let's try it one more time, finding the BRCG for integers up to 3-bits (0, 1, 2, 3, 4, 5, 6, 7). First we write the 2 bit BRGC forward then backwards (00, 01, 11, 10, 10, 11, 01, 00). Finally we prefix the first half of those numbers with 0, and the second half with 1:

Integer   BRGC
=======   ====
      0    000
      1    001
      2    011
      3    010
      4    110
      5    111
      6    101
      7    100

Looking that the chart above tells us that the BRGC encoding for the integer 7 is 100.

The Challenge

Write a class BRGC containing three static methods. The first method displays a table of long integers and their BRGC encoded values up to n-bits. It should have the following signature:

public static void displayBRCG(long n)

Calling the method...

BRGC.displayBRGC(3);

...should produce something similar to the following output:

Integer   BRGC
=======   ====
      0    000
      1    001
      2    011
      3    010
      4    110
      5    111
      6    101
      7    100

The second method returns the BRGC encoded representation of an input non-negative long integer. It should have the following signature:

public static String encode(long n)

Calling the method...

System.out.println(BRGC.encode(5));

...should display 111 on the console.

The third method returns the long integer representation of an input BRGC encoding. It should have the following signature...

public static long decode(String brgc)

Calling the method...

System.out.println(BRGC.decode("111"));

...should display 5 on the console.

See the thread August Newsletter Puzzle in the Programming Diversions forum to post your answer and discuss this problem.


Return to Top
The Big Moose Saloon Question and Answer of the Month

Mosey on in and pull up a stool. The JavaRanch Big Moose Saloon is the place to get your Java questions answered. Our bartenders keep the peace, and folks are pretty friendly anyways, so don't be shy!

Over in The Java In General (Beginner) Forum, JavaRanch's founder, Kathy Sierra, did a heck of a job tellin' folks about that dot in the whole CLASSPATH thing. Following is an excerpt from the original forum thread.

Question: Why do we define . in the Java classpath environment setting?

Answer: Both the compiler and the JVM need to find any of the classes that you're using in your code. If those classes are from the standard edition API, then no problem -- both java and javac know where *those* are. But they don't know about your *own* classes... the ones you're writing.

So... if you have a class that you just wrote, in a directory "foo", and the class is NOT in a package, then you cd to directory "foo" and then compile from that directory. That's the simplest way, to start out with. Including the dot "." in your classpath is the way you tell they system to "when you're looking for classes, be sure to look in the current directory (i.e. the one you cd to)."

Where to put that "."? You can add it permanently to your classpath as an environment variable in DOS (via autoexec.bat, if you're still on Windows 98!), or a property in Windows NT (I think -- can't remember it's been so long since I've seen NT). Or if you're on some flavor of Unix (including Mac OSX), you can put it in one of several places, including your .cshrc file (or whatever your initialization file is for your particular shell).

That's my preferred way... I never have to think about the current directory that way. (And you can still override that if you do NOT want the current directory to be included, which is sometimes necessary with RMI, but that's another story...)

Or, you can make sure that you have the "." by using the -classpath flag with java and javac:

java -classpath . MyClass

Or, you can do it just for your current terminal session, by using whatever it is you have to do for your particular shell. Something like:

%SET CLASSPATH = ${CLASSPATH}:.

(this says, "Take the current classpath, and add the current directory (.) to it, and then make that the new classpath setting for as long as this terminal is active.")

%java MyClass

(this is not necessarily *real* syntax)

If you use packages, it gets a little more complicated, although you'll still need the "." on the classpath.

What has troubled some programmers is that they are using an IDE which makes all kinds of settings for the classpath, and which may NOT include the current directory. That's when it's probably easiest to just use the -classpath flag:

javac -classpath . MyClass.java

There is of course more to the story than this, but if you're just starting out, this should work fine.


Return to Top
Movin' them doggies on the Cattle Drive

It's where you come to learn Java, and just like the cattle drivers of the old west, you're expected to pull your weight along the way.

The Cattle Drive forum is where the drivers get together to complain, uh rather, discuss their assignments and encourage each other. Thanks to the enthusiastic initiative of Johannes de Jong, you can keep track of your progress on the drive with the Assignment Log. If you're tough enough to get through the nitpicking, you'll start collecting moose heads at the Cattle Drive Hall of Fame.

Fresh riders on the Drive...
Got us three new ranchers this month signed up for that wild bronco ride known 'round here as the Cattle Drive. Tip your ten-gallon to Marie Mazerolle, Craig Thomas, and Greg Neef -- our latest pardners on the trail.

Another moose on the wall for...
Yep, that's right, you make it through, you get yerself a nice little moose to hang on the wall. Well, OK, so it's a virtual moose on a virtual wall, but you can be right proud of 'em! Thanks to the efforts of Marilyn deQueiroz, you can now proudly admire your codin' accomplishments at the Cattle Drive Hall of Fame. Check it out, pardner, it's worth a wink.

Ol' timer Greg Harris bagged himself a moose for the servlets assignments and is hard at work on that mean varmint known as JDBC. Sherry Cuenco's got herself a moose this month for completin' the first set of Cattle Drive assignments. And whoa, Nelly! Chuck "just call me Chuck" Wannall's servin' up mooseburgers after finishin' up them OOP assignments.

Back in the saddle...
Hadn't heard from Cattle Driver Adalberto Altamirante for a spell, but he's back in the saddle, wrasslin' down them cattle (and codin' some Java assignments too!).

Nitpicking is hard work too...
We know they're workin' reeeeeally hard, after all, we've seen what those assignments look like once the nitpickers have combed through 'em. Hats off to Marilyn deQueiroz, Pauline McNamara, and Jason Adam for their dedication and patience with the pesky vermin that always manage to make their way into those assignments.

Those gentlemen behind the bar...
Notice the fellas wipin' the bar and shinin' up the sarsparila glasses? Updating that assignment log is tough work too. Big thanks to Michael Matola and Barry Gaunt. Mosey up and place yer orders. Rumor has it Michael keeps some special stuff under the bar, if you know what to ask fer.

Joinin' the Drive
You think ya got what it takes? You ready for some work and some good learnin'? Then pull up a stool and read up on Joinin' the Drive. Good luck!

Content and format adapted from Ol' Timer Pauline McNamara's original column. -Michael Matola.


Return to Top
Scheduled Book Promotions for August (and early September) :
August 5 EJB Cookbook Benjamin G. Sullins Manning EJB
August 12 Bitter EJB Bob Lee Manning EJB
August 19 Eclipse: Step by Step Joe Pluta MC Press IDE's and other tools
August 26 Core J2EE Patterns: Best Practices and Design Strategies, Second Edition Deepak Alur, John Crupi, Dan Malks Prentice Hall EJB
September 2 Jess in Action Ernest Friedman-Hill Manning Other Java APIs

Return to Top
Managing Editor: Dirk Schreckmann

Comments or suggestions for JavaRanch's NewsLetter can be sent to the Newsletter Staff.

For advertising opportunities contact the Newsletter Advertising Staff.