From root@bulkmail1.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Sun Jun 23 07:13:20 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g5NCDJu03050 for ; Sun, 23 Jun 2002 07:13:19 -0500 (EST) Received: from bulkmail1.sun.com (sunmail1.sun.com [64.124.140.171]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with ESMTP id g5NCEjHZ000418 for ; Sun, 23 Jun 2002 07:14:46 -0500 (EST) Received: (from root@localhost) by bulkmail1.sun.com (8.9.3+Sun/8.9.1) id MAA23748; Sun, 23 Jun 2002 12:14:41 GMT Date: Sun, 23 Jun 2002 12:14:41 GMT Message-Id: <200206231214.MAA23748@bulkmail1.sun.com> From: "Java Developer Connection" To: gcf@indiana.edu Subject: Subscription Opt-In Request Content-Length: 492 Dear Subscriber, You recently subscribed to the following Java Developer Connection newsletters: Online Surveys Sun Promotional Info To start receiving your newsletters, you must confirm your subscriptions. Click on the url below to activate your subscriptions. http://bulkmail.sun.com/optin?id=1473416719540902170 We look forward to hearing from you. Thank You. Java Developer Connection http://developer.java.sun.com Sun Microsystems Privacy Policy http://www.sun.com/privacy From root@bulkmail1.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Sun Jun 23 07:13:23 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g5NCDMu03054 for ; Sun, 23 Jun 2002 07:13:22 -0500 (EST) Received: from bulkmail1.sun.com (sunmail1.sun.com [64.124.140.171]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with ESMTP id g5NCEhHZ000412 for ; Sun, 23 Jun 2002 07:14:43 -0500 (EST) Received: (from root@localhost) by bulkmail1.sun.com (8.9.3+Sun/8.9.1) id MAA23745; Sun, 23 Jun 2002 12:14:39 GMT Date: Sun, 23 Jun 2002 12:14:39 GMT Message-Id: <200206231214.MAA23745@bulkmail1.sun.com> From: "Java Developer Connection" To: gcf@indiana.edu Subject: Subscription Opt-In Request Content-Length: 743 Dear Subscriber, You recently subscribed to the following Java Developer Connection newsletters: JDC Regional Bulletin Wireless Developer Tech Tips JDC Tech Tips Wireless Developer Newsletter JDC Newsletter Enterprise Java Technologies Tech Tips Enterprise Java Technologies Newsletter Wireless Developer Bulletin Java Learning Center Java Technology Fundamentals Newsletter To start receiving your newsletters, you must confirm your subscriptions. Click on the url below to activate your subscriptions. http://bulkmail.sun.com/optin?id=-1064798617977415460 We look forward to hearing from you. Thank You. Java Developer Connection http://developer.java.sun.com Sun Microsystems Privacy Policy http://www.sun.com/privacy From env_17549909479909100@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Jun 26 18:32:17 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g5QNWHu29562 for ; Wed, 26 Jun 2002 18:32:17 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g5QNXcd5023478 for ; Wed, 26 Jun 2002 18:33:49 -0500 (EST) Date: Wed, 26 Jun 2002 14:09:11 GMT-08:00 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <17549909479909100@hermes.sun.com> Subject: June 2002 JDC Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 25219 JDC Newsletter: June 26, 2002
    June 26, 2002        

New on the JDC
Articles
Bookshelf
Tech Tips
More...

Product News: Product Release Software
JavaTM 2 Standard Edition v1.4.1 Beta
Java Web Start 1.2 Beta
More...

Developer Programs and Resources
New Newsletters: Enterprise Java Technology
SunNetworkSM Conference
Free Book Download: "CodeNotes for J2EETM"
Missed JavaOne? Visit the JavaSM Learning Center
New Code Camps: Advanced JSPTM and Servlets
WebCast: Java 2 Platform, Micro Edition (J2METM platform)

Java Developer Marketplace
SunTM One Studio Tools Release and Competitive Upgrade Program

Pixel

Articles
June 12, 2002
Deploying Web Services on the JavaTM 2 Platform, Enterprise Edition (J2EETM platform)
This article shows how to integrate Web services with the J2EE environment, using step-by-step instructions.

June 6, 2002
Building an Application, Part 4
Learn how to create scroll bars, pop-up option boxes, and how to read from and write to files

Bookshelf
June 13, 2002
JXTA: Java P2P Programming
Provides an invaluable introduction to this new technology, and is filled with practical examples to introduce developers to the JXTA implementation written in the Java programming language.

JDC Tech Tips
June 18, 2002
Learn how to read what you write to an output stream, and how to blend images using the Java 2DTM API.

Newsletters
June 20, 2002
June Java Technology Fundamentals Newsletter
Learn how to connect to a database using JDBCTM technology, and then test yourself to see how much you learned.

To access the JDC, go to: http://java.sun.com/jdc/

Pixel
Pixel

Product and Technology Release Software
The following Java platform software and technology releases are now available for download:

June 20, 2002
Java 2 Standard Edition (J2SETM) v1.4.1 Beta
Available for Windows, Linux, and SolarisTM, this version has additional Early Access 64-bit releases for Itanium processors for both Linux and Windows. In addition to new features and enhanced performance, version 1.4.1 addresses key customer issues and is fully compatible with previous J2SE software releases.

June 20, 2002
Java Web Start v1.2 Beta
Version 1.2 Beta is now available for download with J2SE. Java Web Start gives you the power to launch full-featured applications with a single click from your Web browser.

June 20, 2002
JSR-000130 OSS IP Billing API Public Review Draft Specification v0.6
Provides an API via the OSS through Java initiative that allows telecom network management applications to be developed and integrated with Java technology-enabled IP Billing systems.

June 20, 2002
Java CardTM Platform Specification and Java Card Development Kit v2.2
Java Card 2.2 Platform Specification offers a set of enhancements to facilitate the design and deployment of innovative secure services. The Java Card 2.2 Development Kit, available for download, enables developers to write applications according to the Java Card 2.2 Specification and provides several enhancements to the existing tool set.

June 18, 2002
Enterprise JavaBeansTM Specification Public Draft 2.1
Enhances the EJBTM architecture with support for Web services. Additionally, EJB 2.1 provides a container-managed Timer Service; enhancements to EJB QL, the declarative language for container-managed persistence, to support, aggregate and order-by operations; and a generalization of message-driven beans to support additional messaging types.

June 11, 2002
Java Web Services Developer Pack v1.0
Provides Java standard implementations of existing key Web services standards including WSDL, SOAP, ebXML, and UDDI as well as important Java standard implementations for Web application development such as JavaServer PagesTM (JSPTM pages) and the JSP Standard Tag Library.

June 10, 2002
Java XML Pack Summer, 2002 Release
The Java XML Pack is an all-in-one download of Java technologies for XML. It includes current, publicly-available releases of Java APIs and Architectures for XML. Includes Java API for XML Messaging, v1.1, Java API for XML Processing v1.2, Java API for XML Registries v1.0_01, Java API for XML-based RPC v1.0, SOAP with Attachments API for Java (SAAJ) v1.1.

June 10, 2002
JSR-000052 JavaServer Pages Standard Tag Library
Final Release Specification v.1.0
Provides a standard tag library for JSPTM pages.

Pixel
Pixel

New Newsletters: Enterprise Java Technology
Learn about the latest enterprise Java technology releases, products, tools, resources, and events in the new Enterprise Java Technologies Newsletter. Get tips and coding examples on using enterprise Java technologies in the new Enterprise Java Technologies Tech Tips. Subscribe on the page linked below.

SunNetworkSM Conference
Join us September 18th to 20th, 2002 at the Moscone Center in San Francisco, California for the SunNetwork Conference. Learn where the industry is heading, get decisive technical insight on system architecture, management and services development for network computing not available anywhere else, participate in discussions, and hear keynotes from some of the biggest names in technology.

JDC members, register on or before August 17, 2002 and pay the discounted price of $695 when you use the code JDC334.

Free Book Download: "CodeNotes for J2EETM"
"CodeNotes for J2EE: EJB, JDBC, JSP and Servlets" introduces Java developers to key database and web development technologies of the Java 2 Platform, Enterprise Edition.

Missed JavaOne? Visit the JavaSM Learning Center
Home of the multimedia JavaOneSM conference sessions, there are more than 300 sessions available with complete presentations, synchronized audio, and text transcription. It's the next best thing to attending one of the leading worldwide Java developer conferences.

New Code Camps: Advanced JSPTM and Servlets
Check out the new Code Camps on Advanced JSP and Servlets, and iPlanetTM Application Server 6.5, Architecture, Installation and Administration. Also, see the new demos section with 13 new demos, including JSP and XSLT, Dukes Bookstore and Message Driven Beans EJB 2.0

WebCast: Java 2 Platform, Micro Edition (J2METM)
AT&T Wireless and Sun are pleased to present a web cast on July 16 and 24 detailing the use of J2ME on the AT&T Wireless mMode data platform. To be included in the web cast, visit the AT&T Wireless Data Developer's program and register for the program. Web cast attendees have a chance to win a Java technology-enabled wireless device. Membership is free and invitations for the web cast will be distributed to program members.

Pixel
Pixel

SunTM One Studio Tools Release and Competitive Upgrade Program
Sun Microsystems, Inc. recently released the Sun ONE Studio development tools for the Java platform. The products are available for immediate purchase and download.

As an additional incentive for developers who own earlier releases of ForteTM for Java, Enterprise Edition, or selected products from Borland, IBM, Microsoft or WebGain, Sun is offering a special price of US$995 to upgrade to Sun ONE Studio 4, Enterprise Edition for Java, representing a savings of US$1,000 over the full purchase price of US$1,995. For details on the upgrade program.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JDC Newsletter to: JDC_Newsletter@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Developer Connection Newsletter archives at:
http://developer.java.sun.com/developer/techDocs/Newsletters/jdc_newsletters.html

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA. 95054 USA.

Sun, Sun Microsystems, Java Developer Connection, Java, Java Learning Center, Java 2D, JavaServer Pages, Enterprise JavaBeans, Java Card, EJB, JDBC, JSP, JDK, J2SE, J2ME, J2EE, JavaOne, SunNetwork Conference, Solaris, Forte and iPlanet are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_1792470113078640@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Jul 10 17:07:19 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6AM7Ju17045 for ; Wed, 10 Jul 2002 17:07:19 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6AM8tI3009875 for ; Wed, 10 Jul 2002 17:09:13 -0500 (EST) Date: Wed, 10 Jul 2002 12:49:17 GMT-08:00 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <1792470113078640@hermes.sun.com> Subject: JDC Tech Tips, July 9, 2002 (LinkedHashMap Class, RandomAccess Interface) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 30677 Technical Tips
   View this issue as simple text July 9, 2002        

Using the LinkedHashMap Class
The RandomAccess Interface
Correction to last month's tip on Using the CharSequence Interface

These tips were developed using javaTM 2 SDK, Standard Edition, v 1.4.

This issue of the JDC Tech Tips is written by Glen McCluskey.

Pixel

Using the LinkedHashMap Class

Imagine that you are writing a Java application that makes use of a dictionary of words, for example, as part of a scheme to tabulate word frequencies. The application inserts the words into a hash table at program startup. Then as each word is used, the application looks up the word in the table, and increments its frequency count.

Here's some code that illustrates this approach:

    import java.util.*;
    
    class Counter {
        private int count;
    
        // initialize a Counter
        public Counter() {
            count = 0;
        }
    
        // increment counter
        public void bumpCount() {
            count++;
        }
    
        // retrieve the current count
        public int getCount() {
            return count;
        }
    
        // convert to a string
        public String toString() {
            return Integer.toString(count);
        }
    }
    
    public class MapDemo1 {
        static Map map = new HashMap();
        //static Map map = new LinkedHashMap();
    
        // initialize the map
        static void initMap() {
            map.put("able", new Counter());
            map.put("baker", new Counter());
            map.put("computer", new Counter());
        }
    
        // increment the count of a word
        static void useWord(String key) {
            Counter ctr = (Counter)map.get(key);
            ctr.bumpCount();
        }
    
        // display the contents of the map
        static void displayMap() {
            Iterator iter = map.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = 
                                (Map.Entry)iter.next();
                System.out.println(entry.getKey() + 
                               " " + entry.getValue());
            }
        }
    
        public static void main(String args[]) {
    
            // initialize the map
    
            initMap();
    
            // look up some words and 
            // bump their use counts
    
            useWord("able");
            useWord("baker");
            useWord("computer");
            useWord("baker");
    
            // display the contents of the map
    
            displayMap();
        }
    }

When you run this program, the result is:

     computer 1
     able 1
     baker 2

So "computer" is used one time, and "baker" two times.

These results are correct, but there's a potential problem: the words are displayed in a different order than originally inserted into the hash table. This problem is intrinsic to the way hash tables work. The ordering within such a table appears to be random.

You might not care about a scrambled ordering because the basic functioning of the hash table is not affected by the order of key/value pairs. But if you do care, is there anything you can do? One answer to this question is to use a LinkedHashMap instead of a HashMap. You can do this by changing one line in the previous example program, that is, the line that sets up the HashMap object at the beginning of the MapDemo1 class definition. In other words, comment out the line:

	static Map map = new HashMap();

Then uncomment the line:

	static Map map = new LinkedHashMap();

A LinkedHashMap is like a HashMap, except that it superimposes a linked list structure on top of the map (hash table). The list structure keeps track of the order of map entry insertions. The list is used when you iterate over the map.

After making the one-line change to MapDemo1, the output of the program is:

    able 1
    baker 2
    computer 1

The entries are now in alphabetical order because that is the order they were inserted into the hash table. A LinkedHashMap does not sort its entries. It simply keeps track of their insertion order.

Let's look at another example. Suppose that you're writing a method that needs to make a copy of a map, and then operate on the copy. In this case it might be important to preserve the order of entries in the map copy. That way, the results of your map operations are predictable. Here's a program that illustrates this idea:

    import java.util.*;
    
    public class MapDemo2 {
    
        // copy a map
        static Map copyMap(Map map) {
            return new HashMap(map);
            //return new LinkedHashMap(map);
        }
    
        public static void main(String args[]) {
    
            // create TreeMap and 
            // add some key/value pairs
    
            Map map_tree = new TreeMap();
            map_tree.put("able", "value1");
            map_tree.put("baker", "value2");
            map_tree.put("computer", "value3");
    
            // copy the map
    
            Map map_copy = copyMap(map_tree);
    
            // display the map contents
    
            Iterator iter = 
                          map_copy.keySet().iterator();
            while (iter.hasNext()) {
                System.out.println(iter.next());
            }
        }
    }

This example again uses a dictionary application. In this code, the words of the dictionary are added to a TreeMap, a class that guarantees that its entries will be sorted in ascending key order.

Suppose that you'd like to make a copy of the TreeMap, and preserve the ordering. But you don't really need all the overhead of a TreeMap structure -- implemented in J2SETM v 1.4 using "red-black trees". (If you're unfamiliar with red-black trees, see the book Introduction to Algorithms by Cormen, Leiserson, and Rivest.) How can you make such a copy?

The first approach in MapDemo2 uses a HashMap, that is:

   static Map copyMap(Map map) {
               return new HashMap(map);           
        }

The result is:

    computer
    able
    baker

The problem here is the same as illustrated earlier -- a hash table stores its entries in apparent random order. The entries in the TreeMap are in order, but when the entries are copied to the HashMap, the order is scrambled.

If the MapDemo2 code is changed to use a LinkedHashMap, like this:

   static Map copyMap(Map map) {
               return new LinkedHashMap(map);           
        }

then the result is:

    able
    baker
    computer

The hash table still scrambles its entries, but there's also a linked list that keeps track of the entry insertion order. This is the list that is used to iterate across the entries.

There's another way you can use a LinkedHashMap. If you create a map with "true" passed as the third argument to the constructor, like this:

    Map map = new LinkedHashMap(16, 0.75f, true);

then the map will keep track of access order instead of insertion order. Each get or put call on the map represents an access, and the iteration order is from oldest to newest. Let's look at an example:

    import java.util.*;
    
    public class MapDemo3 {
        public static void main(String args[]) {
    
            // create a map and 
            // add some key/value pairs
    
            Map map = new LinkedHashMap(
                                      16, 0.75f, true);
            map.put("able", "value1");
            map.put("baker", "value2");
            map.put("computer", "value3");
    
            // display the map contents
    
            Iterator iter1 = map.keySet().iterator();
            while (iter1.hasNext()) {
                System.out.println(iter1.next());
            }
    
            // use the map entries
    
            map.get("baker");
            map.get("able");
            map.get("computer");
    
            // display the map contents again
    
            System.out.println();
            Iterator iter2 = map.keySet().iterator();
            while (iter2.hasNext()) {
                System.out.println(iter2.next());
            }
        }
    }

When you run this program, the result is:

    able
    baker
    computer

    baker
    able
    computer

The first part of the results reflects the sequence of put calls. The put call for "able" is older than the put call for "computer". Then a sequence of get calls is made. The first get call is for "baker", followed by get calls for "able" and "computer".

Retrieving map entries in access order is quite useful in some applications, for example if you're working with a cache, and you want to flush old entries. If you place the cache entries in a LinkedHashMap, each map access will automatically update the access order. So at any time you can determine which entries are the oldest, and remove them if desired. This scheme is often called an LRU or "least recently used" cache.

For more information about LinkedHashMap, see the class description.

Pixel
Pixel

The RandomAccess Interface

Suppose you are writing a method that takes a List parameter. The List is composed of Integer object references, and your method computes the sum of the values in the list. Here's some code that illustrates this idea:

    import java.util.*;
    
    public class RandomDemo1 {
        static final int N = 25000;
    
        // create a List of Integer objects
        static void buildList(List lst) {
            for (int i = 1; i <= N; i++) {
                lst.add(new Integer(i));
            }
        }
    
        // sum a List of Integer objects, using get()
        static long sumList(List lst) {
            long sum = 0;
            for (int i = 0, size = lst.size(); 
                                       i < size; i++) {
                Integer iobj = (Integer)lst.get(i);
                sum += iobj.intValue();
            }
            return sum;
        }
    
        // sum a List of Integer objects,
        // using get() or iterators
        static long newsumList(List lst) {
            long sum = 0;
            if (lst instanceof RandomAccess) {
                for (int i = 0, size = lst.size(); 
                                       i < size; i++) {
                    Integer iobj = (Integer)lst.get(i);
                    sum += iobj.intValue();
                }
            }
            else {
                for (Iterator i = lst.iterator(); 
                                       i.hasNext(); ) {
                    Integer iobj = (Integer)i.next();
                    sum += iobj.intValue();
                }
            }
            return sum;
        }
    
        public static void main(String args[]) {
    
            // create a List as an ArrayList
    
            List lst_array = new ArrayList();
            buildList(lst_array);
    
            // sum the contents of the list
    
            long start_time_array = 
                            System.currentTimeMillis();
            long sum_array = sumList(lst_array);
    
            // display the sum and elapsed time
    
            System.out.println(
                    "sum of ArrayList = " + sum_array);
            System.out.println("sum time = " +
                (System.currentTimeMillis() - 
                                    start_time_array));
    
            // create a List as a LinkedList
    
            List lst_link = new LinkedList();
            buildList(lst_link);
    
            // sum the contents of the list
    
            long start_time_link = 
                            System.currentTimeMillis();
            long sum_link = sumList(lst_link);
    
            // display the sum and elapsed time
    
            System.out.println(
                    "sum of LinkedList = " + sum_link);
            System.out.println("sum time = " +
                (System.currentTimeMillis() - 
                                     start_time_link));
        }
    }

The sumList method does the obvious thing. It obtains the size of the list. Then it calls the get method to retrieve each list element in turn, and extracts the integer value.

The results of running the program look something like this:

    sum of ArrayList = 312512500
    sum time = 16
    sum of LinkedList = 312512500
    sum time = 12969

Notice the sum time for the ArrayList as compared to that for the LinkedList. The sumList method works well for the ArrayList, but for the LinkedList, the performance is nearly a thousand times slower.

What is wrong? The problem is that it's a bad choice to use the get method for a linked list. That's because there is no fast way to access a random element in a linked list. For example, if you want to access the 379th element of such a list, you need to start at the beginning or end of the list, and then iterate to the proper element. There's no alternative approach. By contrast, an ArrayList is backed by a Java array, so accessing a particular array element is inexpensive.

This difference in cost doesn't prove that ArrayList is always a better choice than LinkedList. It depends on what operations are done on the lists. For example, inserting in the middle of an ArrayList is expensive, because elements with indices above the insertion point must be moved.

If you change the calls of sumList to newsumList in the RandomDemo1 example, the behavior changes dramatically. You should see results that look something like this:

    sum of ArrayList = 312512500
    sum time = 16
    sum of LinkedList = 312512500
    sum time = 16

How is newsumList different than sumList? It checks whether the passed-in List object is an instance of the RandomAccess interface, that is, whether the class of the object implements the RandomAccess interface. RandomAccess is an empty marker interface. It is used to give an implementing class a specific property.

In this particular case, the desired property is that a List implementation supports fast random access. In J2SE v 1.4, ArrayList and Vector implement the RandomAccess interface. LinkedList does not. If a List implementation does not implement RandomAccess, then it's better to traverse the list using iterators instead of using get method calls.

You can use the RandomAccess marker interface both in List implementation classes that you define, and in programming with existing List classes such as ArrayList, LinkedList, and Vector.

Another example where RandomAccess is used is in the reverse(List) method in the java.util.Collections class. For small lists and for list objects whose class implements RandomAccess, a loop involving Collections.swap is used. The swap method is based on get/put. By contrast, for larger lists that do not support fast random access, a scheme based on two iterators is used. Here, one iterator goes forward through the list, and the other goes backward from the end of the list.

It pays to be cautious in your use of List implementations such as ArrayList and LinkedList, given the big performance tradeoffs. The RandomAccess interface can help you in writing code that will work efficiently for any type of List.

For more information about the RandomAccess interface, see the interface description.

Pixel
Pixel

Correction to last month's tip on Using the CharSequence Interface

In the June 4, 2002 Tech Tips, there was a tip about the use of the CharSequence interface. The CSDemo2 program in that tip demonstrated a class called CharArrayWrapper for wrapping char arrays. Two lines in that class need to be changed as follows:

Change:

    return vec[index];

to:

    return vec[index + off];

and:

    return new CharArrayWrapper(
                              vec, start, end - start);

to:

    return new CharArrayWrapper(
                        vec, start + off, end - start);

In casual use of the CharArrayWrapper class, "off" will be 0, and this change will have no effect. But if subSequence() is called, and then a further operation is applied to the subsequence, the original code will not work. Here's a test case that fails with the original code:

    if (cs.subSequence(2, 4).charAt(0) != 'c')
        System.out.println("*** error ***");
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Developer Technical Tips to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:
http://developer.java.sun.com/developer/JDCTechTips/

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_18329194623871540@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Jul 18 08:36:00 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6IDa0u04416 for ; Thu, 18 Jul 2002 08:36:00 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6IDc60r000533 for ; Thu, 18 Jul 2002 08:38:08 -0500 (EST) Date: Thu, 18 Jul 2002 05:35:58 GMT-08:00 From: "Wireless Developer J2ME Tech Tips" To: gcf@indiana.edu Message-Id: <18329194623871540@hermes.sun.com> Subject: J2ME Tech Tips, July 18, 2002 (Introduction to the Personal Basis Profile, MIDP Canvas Repainting) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 24703 Wireless Technical Tips: July 18, 2002
    July 18, 2002        

WELCOME to the Wireless Developer Java[tm] 2 Platform, Micro Edition (J2ME[tm]) Tech Tips, for July 18, 2002.

Introduction to the Personal Basis Profile
MIDP Canvas Repainting

You can view these J2ME Tech Tips on the Web, Introduction to the Personal Basis Profile and MIDP Canvas Repainting

Pixel

INTRODUCTION TO THE PERSONAL BASIS PROFILE

by Eric Giguere
July 18, 2002

Although the Mobile Information Device Profile (MIDP) was the first J2ME[tm] profile to be released via the Java[tm] Community Process[sm](JCP), other profiles have also been under development. Recently, Sun released one called the Personal Basis Profile (PBP). The PBP specifies a subset of the functionality of the Personal Profile, which is still under development.

The PBP uses the Connected Device Configuration (CDC) as its base, not the Connected Limited Device Configuration (CLDC) that the MIDP uses. The CDC requires a complete Java 2 virtual machine (VM) implementation, so PBP applications can use floating-point values, object finalization, and other features missing from the CLDC. Of course, the PBP requires significantly more memory and a faster processor than the MIDP: at least 2MB of ROM and 1MB of RAM, plus the processing horsepower to support all the functionality of a complete VM, including class verification.

The PBP also incorporates all the features of the Foundation Profile (FP), including the many core J2SE classes the FP adds to the smaller set that the CDC specifies.

The Personal Basis Profile adds classes to the CDC and the FP in two crucial areas: a subset of the Abstract Windowing Toolkit (AWT) and a new application model.

If you've written user-interface (UI) code in Java, you'll recall that AWT components come in two flavors: heavyweight and lightweight.

The heavyweight components are the original UI components. Each maps directly onto a native UI component, and the underlying system is responsible for drawing and controlling the native component. Advantages in speed and look and feel result, but heavyweight components have disadvantages as well. Applications must limit themselves to components that are available on all platforms, and cannot control many aspects of the components' behavior.

Version 1.1 of the Java platform introduced the concept of lightweight components, as typified by the Swing API. Because they're drawn and controlled entirely by Java code, all aspects of their look and feel can be controlled consistently across all platforms. The PBP AWT subset includes all the support necessary to build lightweight components. The only heavyweight component classes it includes are the top-level window classes java.awt.Frame and java.awt.Window.

Note that the PBP does not specify familiar UI components like buttons, menus, or listboxes - and the leanness of the specification is quite intentional. The PBP is meant to support a wide variety of UI component sets, on devices of many different kinds. The expectation is that applications will rely on toolkits that provide lightweight components appropriate to a target category of devices, such as the HAVi toolkit for set-top boxes, or will provide their own lightweight components based on the PBP's subset of the AWT. The PBP thus provides the support structure for building many different kinds of user interfaces.

While the AWT subset is familiar to most Java programmers, the new application model defined by the PBP is not. The PBP does support launching traditional applications (those with a static main method as their entry point), but it also defines a new type of application called an Xlet, an application model that originated with the Java TV API.

An Xlet is a class that implements the Xlet interface, which is defined thus:

    package javax.microedition.xlet;

    public interface Xlet {
        void destroyXlet( boolean unconditional )
                  throws XletStateChangeException;
        void initXlet( XletContext context )
                  throws XletStateChangeException;
        void pauseXlet();
        void startXlet() throws XletStateChangeException;
    }

If you've done any MIDP programming, this definition will look familiar; it resembles the MIDlet class. Like a MIDlet, an Xlet is loaded by the system and notified of state changes through callback methods. (The PBP does not specify the loading mechanism, leaving that to each implementation.) The startXlet(), pauseXlet(), and destroyXlet() methods of the Xlet interface are analogous to the startApp(), pauseApp(), and destroyApp() methods of javax.microedition.midlet.MIDlet. Note that the Xlet interface includes a fourth method with no MIDlet equivalent, initXlet(). You call this method explicitly to initialize the Xlet after it's constructed, instead of performing initialization implicitly on the first call to startApp(), as in the MIDlet model.

You use the Xlet interface in conjunction with another, XletContext:

    package javax.microedition.xlet;

    import java.awt.Container;

    public interface XletContext {
        String ARGS = new String();

        Container getContainer() throws
                    UnavailableContainerException;
        Object getXletProperty( String key );
        void notifyDestroyed();
        void notifyPaused();
        void resumeRequest();
    }

Again, the methods in XletContext will remind you of their MIDlet equivalents. The Xlet uses notifyDestroyed(), notifyPaused(), and resumeRequest() methods to communicate state changes to the system, and getXletProperty() returns the requested initialization property. The only genuinely new method is getContainer(), which returns the AWT container that the Xlet must use as its main window. Note that the Xlet receives a reference to an instance of XletContext when it is initialized: it should store this reference for later use.

A bare-bones Xlet looks like this:

    import javax.microedition.xlet.*;

    public class MyXlet implements Xlet {
        private XletContext context;

        public MyXlet(){
        }

        public void destroyXlet( boolean unconditional )
                    throws XletStateChangeException {
        }

        public void initXlet( XletContext context )
                    throws XletStateChangeException {
            this.context = context;
        }

        public void pauseXlet(){
        }

        public void startXlet() throws
            XletStateChangeException {
            context.notifyDestroyed(); // immediately quit
        }
    }

A complete Xlet would create and initialize a user interface, of course, and then interact with the user. How you implement your application's UI will depend entirely on the toolkit you use. You can even build your own rudimentary UI classes based solely on the AWT subset specified by the PBP.

Along with the concept of Xlets, the PBP also formally defines the concept of inter-Xlet communication (IXC), modeled on standard Remote Method Invocation (RMI). The PBP includes a very small subset of RMI classes to allow an Xlet to make remote method calls into another Xlet (within the same VM). Conventional RMI support (multiple VM's) is available only if the device supports the RMI Optional Package (JSR-66).

To learn more about the PBP, download the specification and class documentation from the main PBP page on the JCP site. A reference implementation of the PBP will shortly be available from there as well.

Pixel
Pixel

MIDP CANVAS REPAINTING

by Eric Giguere
July 18, 2002

The low-level user-interface APIs of the Mobile Information Device Profile (MIDP) allow you to control exactly what is drawn on the screen through the Canvas class. Sometimes, though, you also want to have control over when the drawing occurs, or to be notified when the drawing is complete. Before exploring either topic, I should recap how canvas painting works in a general sense.

Generally, it is the device that controls when painting occurs. A painting event is triggered when any of a number of things occur -- the canvas is shown for the first time, a menu that was hiding part of the canvas is withdrawn, or an alert is dismissed. The device then invokes the canvas's paint method, passing it a Graphics object initialized to draw on the correct parts of the display. The method does the drawing and returns as quickly as possible. Note that no key or pointer events are processed while the painting occurs -- execution of events, including repaint notifications, is always serialized.

The simplest way to handle repaints is to let the system schedule them. All you do is tell the system that the canvas needs repainting by calling the Canvas.repaint() method:

    Canvas c = ...

    c.repaint( 20, 20, 50, 50 ); // x, y, w, h

The system queues a paint request for the given area. (Another version of the repaint method takes no arguments and queues a paint request for the entire canvas.) If you mark two or more areas for repainting within a short span of time, the system may combine the paint requests into a single request to paint the union of the two areas (the smallest rectangle containing both). At some point the system invokes the canvas's paint method, passing it a Graphics object whose clipping area is set to the area that needs repainting.

You can call the repaint method from any thread, because the MIDP user-interface classes are all thread-safe, unlike the J2SE[tm] Swing classes you may already be familiar with.

Sometimes, though, waiting for the system to call the paint method is not good enough. Perhaps you want to update the display immediately in response to some user input. You can force an update to occur at any point by calling the serviceRepaints() method:

    Canvas c = .....

    c.repaint( 0, 0, 20, 30 );
    c.serviceRepaints(); // paint it now

If the canvas is visible and one or more paint requests are queued, serviceRepaints() causes the system to invoke the canvas's paint method as soon as possible. serviceRepaints() does not return until the paint method returns.

Note that you have no way to control -- or even know -- which thread the system uses when it invokes the canvas's paint method. Often, it uses the same thread that called serviceRepaints(). The system may choose to use a different thread, however, and block the initiating thread until the painting is finished. A deadlock can occur if the paint method requires access to an object that the initiating thread has locked. You must therefore be careful about accessing synchronized objects in your paint() method.

What if you want to execute some code after the display is repainted? Calling the code from the canvas's paint method may not work as you expect it -- the display may be updated only after the paint method returns, especially if the system does automatic double-buffering for flicker-free output. A better tactic is to use the Display.callSerially() method, passing it an object that implements the standard java.lang.Runnable interface:

    Runnable r = ....
    Display d = ....

    d.callSerially( r );

Each callSerially() invocation adds the given object to a system-maintained list. As it processes events, the system removes an object from the list and invokes its run method, effectively serializing the call with system-generated events. Furthermore, if a repaint is pending when the object is added to the list, its run method is not invoked until after the display has been repainted -- this order is guaranteed by the MIDP specification. You can use this feature to animate images, as in this example adapted from the MIDP specification:

public class Animation extends Canvas
                       implements Runnable {
    private Image[] frames;
    private int     next = 0;
    private boolean go = false;

    public Animation( Image[] frames ){
        this.frames = frames;
    }

    protected void paint( Graphics g ){
        g.drawImage( frames[next], 0, 0,
                     g.TOP | g.LEFT );
    }

    public void startAnimation(){
        go = true;
        repaint();
        callSerially( this );
    }

    public void stopAnimation(){
        go = false;
    }

    public void run() { // called after previous repaint is
    finished
        if( go ){
            if( ++next >= frames.length ) next = 0;
            repaint();
            callSerially( this );
        }
    }
}

One problem with this approach to animation, however, is that the animation rate -- the number of frames painted per second -- is device-dependent. It may be better to use a timer-based approach.

Pixel
Pixel

About the Author:

Eric Giguere is a software developer for iAnywhere Solutions, a subsidiary of Sybase, where he works on Java technologies for handheld and wireless computing. He holds BMath and MMath degrees in Computer Science from the University of Waterloo and has written extensively on computing topics.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Wireless Technologies Newsletter to: wd-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allttips/

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2ME, JAIN, and PersonalJava are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_18567908546431466@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Jul 18 19:02:12 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6J02Bu13542 for ; Thu, 18 Jul 2002 19:02:11 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6J0481H013177 for ; Thu, 18 Jul 2002 19:04:18 -0500 (EST) Date: Thu, 18 Jul 2002 15:54:50 GMT-08:00 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <18567908546431466@hermes.sun.com> Subject: Updates to the Java Developer Newsletters Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 11423 JDC Newsletter: July 17, 2002
    July 17, 2002        
Updates to the Java Developer Newsletters

You are receiving this announcement because you currently subscribe to a JDC newsletter. We'd like to alert you to some enhancements we've made to the newsletters.

If you've recently looked at the subscription list for the newsletters, or recently received a newsletter from us, you probably noticed some important changes:

  • New newsletters that focus on enterprise Java technologies.
  • New names and a more specific focus for some newsletters.
  • An option to receive newsletters in HTML.

These changes let you receive information tailored to a specific Java platform, with a new choice of HTML or text format. The changes also allow us to enhance the information you receive.

Sun now offers newsletters specific to enterprise Java technologies, such as those in JavaTM 2 Platform, Enterprise Edition (J2EETM); core Java technologies such as those in JavaTM 2 Platform, Standard Edition (J2SETM); and mobile/wireless Java technologies such as those in JavaTM 2 Platform, Micro Edition.

Pixel
Pixel

New Enterprise Java Technologies Newsletters

Two new newsletters are available:

  • Enterprise Java Technologies Newsletter

    This newsletter links you to the latest enterprise Java technology releases, products, tools, resources, and events. Here you'll also get the latest news and views about enterprise Java and its direction.


  • Enterprise Java Technologies Tech Tips

    This newsletter presents mini-tutorials with examples that demonstrate effective coding techniques using enterprise Java technologies and APIs.
Pixel
Pixel

Refocused Core Java Technology Newsletters

Two existing newsletters have been refocused:

  • Core Java Technologies Newsletter (formerly the JDC Newsletter)

    This newsletter links you to the latest core Java technology releases, products, tools, resources, and events. It also adds new sections that highlight successful deployments of core Java technologies, "hot" (most frequently downloaded) core Java technologies, and more. If you were subscribed to the JDC Newsletter, you are automatically subscribed to the Core Java Technologies Newsletter.


  • Core Java Technologies Tech Tips (formerly, the JDC Tech Tips)

    This newsletter presents mini-tutorials with examples that demonstrate effective coding techniques using core Java technologies and APIs. If you were subscribed to the JDC Tech Tips, you are automatically subscribed to the Core Java Technologies Tech Tips.
Pixel
Pixel

Newsletters in HTML

Checking the "Send me newsletters in HTML whenever possible" checkbox on the subscription page starts you off receiving newsletters in HTML. The checkbox is checked by default, so you'll automatically receive newsletters in HTML. Some newsletters might not be available in HTML (most are) -- you'll receive those newsletters in text. Of course, you can unselect the checkbox if you want to receive newsletters in text. Alternatively, you can select the "Please send me newsletters in text" link at the bottom of an HTML newsletter.

You'll find that the HTML format isn't just a change in presentation style; it also allows us to present additional content (such as illustrations) and offer better navigation through graphical items like search buttons.

Pixel
Pixel

Subscribe Now

Subscribe to any or all of the Java developer newsletters. As always, you can unsubscribe from a newsletter by unchecking the checkbox for the newsletter on the subscription page, or click the unsubscribe link at the bottom of the newsletter.

Please send your feedback about these changes to: jdc-webmaster@sun.com

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_190226541993924311@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Jul 23 17:31:36 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6NMVau06214 for ; Tue, 23 Jul 2002 17:31:36 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6NMWd1H000494 for ; Tue, 23 Jul 2002 17:33:00 -0500 (EST) Date: Tue, 23 Jul 2002 12:58:28 GMT-08:00 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <190226541993924311@hermes.sun.com> Subject: Core Java Technologies Tech Tips (Converting Numeric Entries, Displaying Multiline Text) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 39535 Technical Tips
   View this issue as simple text July 23, 2002        

Converting Numeric Entries
Displaying Multiline Text

These tips were developed using javaTM 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski.

Pixel

Converting Numeric Entries

Numbers entered from the console into a computer are not entered as their decimal value. Internally, a number entered from the keyboard is represented by a Unicode value of the numerical representation for the locale-specific character of that number. In other words, if an American user enters the number 1 on an English language system, the computer represents it as the Unicode value 49. The Unicode value is the the American-English, numerical representation of the character 1. This numerical representation then maps to a physical representation of the number 1, based on the font being used. At no point is this character 1 thought of as the numerical value of 1.

There are two mechanisms in the standard Java libraries that you can use to convert a user's "number" input into actual numeric values. Which mechanism you use depends on your personal preferences and desired feature support. For example, if you want to convert the user entry "3.14" to the value 3.14, there is a way to directly convert the string. Converting locale-specific input, such as "$5,000.12" to the value 5000.12, requires a little more work. You'll learn how to do both types of conversions in this tip.

To convert from a string to a number, use the wrapper classes. These classes offer parsing methods that do the conversion. Which method you use depends on the data type of the intended result:

  • String to byte -- Byte.parseByte(string)
  • String to short -- Short.parseShort(string)
  • String to int -- Integer.parseInt(string)
  • String to long -- Long.parseLong(string)
  • String to float -- Float.parseFloat(string)
  • String to double -- Double.parseDouble(string)

The integer types (byte, short, int, and long) also offer an overridden version of the associated parse method. The overridden version includes an input base as a second argument to the method. So, for example, if the input is in base 2, you don't have to manually calculate that "100" is 4.

  • String to byte -- Byte.parseByte(string, base)
  • String to short -- Short.parseShort(string, base)
  • String to int -- Integer.parseInt(string, base)
  • String to long -- Long.parseLong(string, base)

The following program demonstrates these two conversion mechanisms. The program prompts for two numbers. When you run the program, and respond to the prompts, the first number you enter is converted to a double datatype. Be sure to try entering input with scientific notation, too, as in "1.3E4" to indicate 13000. The second prompt is for a hex value. Here, you can enter a hex value such as "FFFFFF" to indicate 16777215 in base 10.

import java.io.*;

public class Input {
  public static void main(String args[]) 
      throws IOException {
    InputStreamReader isr = 
      new InputStreamReader(System.in);
    BufferedReader input = new BufferedReader(isr);

    System.out.println("Enter a double: ");
    String doubleString = input.readLine();
    if (doubleString != null) {
      try {
        double d = Double.parseDouble(doubleString);
        System.out.println("Double: " + d);
      } catch (NumberFormatException e) {
        System.err.println("Bad input: " + 
                                         doubleString);
      }
    }

    System.out.println("Enter a hex value: ");
    String hexString = input.readLine();
    if (hexString != null) {
      try {
        long l = Long.parseLong(hexString, 16);
        System.out.println("Converted Hex: " + l);
      } catch (NumberFormatException e) {
        System.err.println("Bad input: " + hexString);
      }
    }
  }
}

Note: The previous example is for demonstration purposes only. Under no circumstances should a properly created internationalized program accept input from the user without using the NumberFormat capabilities described below. Also, in a similar way, under no circumstances should a text message be hard-coded into a println statement. You should use a ResourceBundle for maintaining locale-specific messages.

When you run the program, the interaction should look something like this:

    Enter a double: 
    1.3E4
    Double: 13000.0
    Enter a hex value: 
    FFFFFF
    Hex: 16777215

If the input cannot be converted, the program throws a NumberFormatException (which is indicated in this program by "Bad input:").

To convert formatted input, use the NumberFormat class of the java.text package. NumberFormat allows you to accept input in a locale-specific way, while dealing with such things as currency symbols, grouping separators (for example, the comma in the US or the period in Germany), decimal separators (for example, the period in the US or the comma in Germany), and percentages.

The NumberFormat class is abstract. It works by using the Factory design pattern. You provide the details of the format you want. NumberFormat then returns an instance of a subclass that implements the desired input pattern. By using the returned instance of NumberFormat, you can translate the requested input format.

NumberFormat provides a number of methods that return a specific format for the current default locale:

  • Numbers -- NumberFormat.getNumberInstance()
  • Currency -- NumberFormat.getCurrencyInstance()
  • Percentages -- NumberFormat.getPercentInstance()
  • Integers -- NumberFormat.getIntegerInstance()

If these methods don't return the format you want, you can define the format yourself by creating an instance of the DecimalFormat class.

If you want to support a locale other then the default, simply pass the locale as an argument to the overloaded versions:

  • Numbers -- NumberFormat.getNumberInstance(locale)
  • Currency -- NumberFormat.getCurrencyInstance(locale)
  • Percentages -- NumberFormat.getPercentInstance(locale)
  • Integers -- NumberFormat.getIntegerInstance(locale)

After you get the necessary instance, you call the parse method to translate the string to a number.

  NumberFormat format = 
    NumberFormat.getNumberInstance();
  Number number = format.parse(string);

You can also use NumberFormat to format how you want to display numbers to users. Instead of using the parse method, you use the format method.

  NumberFormat format = 
    NumberFormat.getCurrencyInstance();
  Number number = format.parse(string);
  System.out.println(format.format(number));

To demonstrate, the following program prompts for a double value and a currency amount. For the double value, you can enter an integer, floating point number, or use scientific notation. For the currency amount, and for the US locale used in the example program, you need to start with a currency symbol (such as $). However, the currency amount doesn't require a grouping separator or decimal point. These characters are displayed in the output in the appropriate places.

import java.io.*;
import java.text.*;
import java.util.*;

public class InputFormat {
  public static void main(String args[]) 
      throws IOException {
    InputStreamReader isr = 
      new InputStreamReader(System.in);
    BufferedReader input = new BufferedReader(isr);

    System.out.println("Enter a double: ");
    String doubleString = input.readLine();
    if (doubleString != null) {
      try {
        NumberFormat format = 
          NumberFormat.getNumberInstance(Locale.US);
        Number number = format.parse(doubleString);
        System.out.println("Double: " + 
          number.doubleValue());
      } catch (ParseException e) {
        System.err.println("Bad input: " + 
          doubleString);
      }
    }

    System.out.println("Enter a currency value: ");
    String currencyString = input.readLine();
    if (currencyString != null) {
      try {
        NumberFormat format = 
          NumberFormat.getCurrencyInstance(Locale.US);
        Number number = format.parse(currencyString);
        System.out.println("Currency: " + 
          format.format(number));
      } catch (ParseException e) {
        System.err.println("Bad input: " + 
          currencyString);
      }
    }
  }
}

Although the Input and InputFormat programs function similarly, there are some differences. The first difference is that parsing with NumberFormat throws a ParseException instead of a NumberFormatException. Another, and bigger, difference has to do with the way parsing is done. With the different wrapper methods, such as Integer.parseInt, parsing is attempted on the entire string. If the string as a whole is invalid, the parsing fails. That isn't how NumberFormat.parse works though. With NumberFormat, parsing fails (and a ParseException is thrown) only if there is an invalid leading character in the input.

To demonstrate this difference, enter "3.a" in response to the prompt for a double value. The Input program will throw an exception. By comparison, the InputFormat program will indicate that the input was 3.0.

    java Input
    Enter a double: 
    3.a
    Bad input: 3.a

    java InputFormat
    Enter a double: 
    3.a
    Double: 3.0

You can use NumberFormat to progressively parse through pieces of a string. There is a second version of NumberFormat.parse that accepts a second parameter indicating a parse position. You can use this version of the parse method to loop through a long string and pull out individual numbers from it. The position is indicated by the ParsePosition class, which automatically positions itself at the point where the parsing ends. If parsing fails due to an invalid character, the starting and ending position will be the same. There is no ParseException thrown by this form of the parse method.

The following program demonstrates progressively parsing through a string. The program prompts for set of numbers. Each number in the set must be separated by a single non-numeric character. The program then parses through the set, and displays the individual numbers:

import java.io.*;
import java.text.*;

public class InputPieces {
  public static void main(String args[]) 
      throws IOException {
    InputStreamReader isr = 
      new InputStreamReader(System.in);
    BufferedReader input = new BufferedReader(isr);

    System.out.println(
      "Enter space delimited set of numbers: ");
    String bulkString = input.readLine();
    if (bulkString != null) {
      NumberFormat format = 
        NumberFormat.getNumberInstance();
      ParsePosition position = new ParsePosition(0);
      int beginIndex;
      while ((beginIndex = position.getIndex()) 
          < bulkString.length()) {
        Number number = 
          format.parse(bulkString, position);
        System.out.println(
          "Number: " + number.doubleValue());
        int endIndex = position.getIndex();
        if (beginIndex == endIndex) {
          System.err.println(
            "Parsing error, position: " + endIndex);
        } else {
          position.setIndex(endIndex+1);
        }
      }
    }
  }
}

For input of "1e54,456/3E4 8" (where the separators are the e, /, and space) the output is:

    Number: 1.0
    Number: 54456.0
    Number: 30000.0
    Number: 8.0

Although the getXXXInstance methods of NumberFormat can meet most needs for formats to accept or display, it doesn't meet every format need. For those cases, where the getXXXInstance methods of NumberFormat can't meet the need, you can use the DecimalFormat class. When you call a method such as NumberFormat.getCurrencyInstance(), it creates a locale-specific version of DecimalFormat based on the type you request. Using DecimalFormat, you can also create a custom NumberFormat.

In general, creating a custom NumberFormat with DecimalFormat is done for output purposes. For example, suppose you want to display numbers with grouping separators (commas in the United States) every two positions instead of every three, and always with four digits after the decimal place. That would be a format of "#,#0.0000", where each '0' indicates that a number should be shown at the position. Each '#' also indicates that a number should be shown at the position, but not to show anything if the value is zero. The grouping separator automatically repeats to the left, so a display format of "##,##,#0.0000" is not necessary.

Here's a program that demonstrates using the DecimalFormat class to create a custom Number Format. The program prompts for a number and an output format. Try running the program with different numbers and different formatting characteristics.

import java.io.*;
import java.text.*;

public class InputPrompt {
  public static void main(String args[]) 
      throws IOException {
    InputStreamReader isr = 
      new InputStreamReader(System.in);
    BufferedReader input = new BufferedReader(isr);

    System.out.println("Enter number: ");
    String doubleString = input.readLine();

    if (doubleString != null) {
      try {
        NumberFormat format = 
          NumberFormat.getNumberInstance();
        Number number = format.parse(doubleString);

        System.out.println("Enter format: ");
        String formatString = input.readLine();

        if (formatString != null) {
          NumberFormat outputFormat = 
            new DecimalFormat(formatString);;
          System.out.println("Output: " + 
            outputFormat.format(number));
        }
      } catch (ParseException e) {
        System.err.println("Bad input: " + 
          doubleString);
      }
    }
  }
}

Here's an example of what you should see:

    Enter number:
    1234.56
    Enter format:
    #,#0.0000
    Output: 12,34.5600

For more information about using NumberFormat, see the Using Predefined Formats section of the Java Tutorial. Also, see the Customizing Formats section of the Java Tutorial for more information on using DecimalFormat.

Pixel
Pixel

Displaying Multiline Text

Suppose you want to create a label (either Swing JLabel or AWT Label) that displays multiple lines of text in a GUI. How would you create it? One way to do it is to create multiple labels, each containing one line of text, and group the labels in a vertical panel. Here's a program that does that:

import java.awt.*;
import javax.swing.*;

public class Multi1 extends JFrame {
  public Multi1() {
    super("Vertical JLabel Set");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container content = getContentPane();
    BoxLayout layout = 
      new BoxLayout(content, BoxLayout.Y_AXIS);
    content.setLayout(layout);
    String lines[] = {"Line 1", "Line 2" , 
      "Line 3", "Line 4" , "Line 5"};
    for (int i=0, n=lines.length; i<n; i++) {
      content.add(new JLabel(lines[i]));
    }
    setSize(300, 200);
  }
  public static void main(String args[]) {
    JFrame frame = new Multi1();
    frame.show();
  }
}

If you run the Multi1 program, you should see the following:

multi 1

An easier approach to displaying multiline text in a Swing label is to use the HTML feature of Swing text components. By prefixing the text label of the component with <HTML>, the label switches to HTML display mode. Then, by using HTML tags, such as <BR> and <P>, or by simply using regular wordwrap at the end of a line, you can easily display a Swing label with multiple lines of text.

import java.awt.*;
import javax.swing.*;

public class Multi2 extends JFrame {
  public Multi2() {
    super("HTML JLabel");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container content = getContentPane();
    String input = 
      "<HTML><P ALIGN=\"CENTER\">" +
      "You're A Grand Old Flag,<BR>" +
      "You're a high fly-ing flag,<BR>" +
      "And for-ev-er, in peace, may you wave.<BR>" +
      "You're the em-blem of<BR>" +
      "the land I love,<BR>" +
      "The home of the free and the brave.";

    JLabel label = new JLabel(input);
    content.add(label, BorderLayout.CENTER);
    setSize(300, 200);
  }
  public static void main(String args[]) {
    JFrame frame = new Multi2();
    frame.show();
  }
}

If you run the Multi2 program, you should see the following:

multi 2

Probably a simpler way to display multiple lines of text in a GUI is not with a label. Instead use a text area component. A text area component is specifically designed to support the display of multiple lines of text. Here's a program that uses a text area component to display multiple lines of text:

import java.awt.*;
import javax.swing.*;

public class Multi3 extends JFrame {
  public Multi3() {
    super("Read-only JTextArea");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container content = getContentPane();
    String input = 
      "I pledge allegiance to the flag of " +
      "the United States of America, and " +
      "to the republic for which it stands, " +
      "one nation, under God, indivisible " +
      "with liberty and justice for all.";

    JTextArea text = new JTextArea(input);
    text.setEditable(false);
    text.setLineWrap(true);
    text.setWrapStyleWord(true);
/*    text.setBackground(
      (Color)UIManager.get("Label.background"));
    text.setForeground(
      (Color)UIManager.get("Label.foreground"));
    text.setFont(
      (Font)UIManager.get("Label.font"));
*/    JScrollPane pane = new JScrollPane(text);
    content.add(pane, BorderLayout.CENTER);
    setSize(300, 200);
  }
  public static void main(String args[]) {
    JFrame frame = new Multi3();
    frame.show();
  }
}

If you run the Multi3 program, you should see the following:

multi 3

Notice that both line wrap and word wrap style are enabled in the Multi3 program. By enabling both, you don't have to manually calculate what constitutes a line or worry about what font will be used by the HTML viewer.

There are advantages and disadvantages to using a JTextArea (or TextArea) for the display of multiline text. One disadvantage is that the display of the read-only text component looks different than the display of the label control. This is a minor disadvantage, and it's something you can fix. Uncomment the six lines of code in the middle of the Multi3 program to copy the foreground, background, and font setting over to the JTextArea. Recompile. Then run the program and see the difference. The JTextArea will now look more like a JLabel.

multi 3a

An advantage of using a text area component is that you do not have to calculate where each line breaks. Another advantage of the text area component approach, is that you can select the displayed message and copy the text to the system clipboard for further processing. This is something that you can't easily do with a label.

Swing components are usually sufficient for dealing with the display of multiline text, but not always. For example, if you want to create a custom editor, you'll probably need to draw the multiline output yourself. In cases like this, there are five classes available to assist you:

  • AttributedString
  • AttributedCharacterIterator
  • FontRenderContext
  • LineBreakMeasurer
  • TextLayout

These classes let you describe the text to draw, and measure how much text will fit on each line. Use the AttributedString class to contain the text. It allows different characters of the text string to have different attributes. However in the simplest case, you simply pass the quoted string to the constructor.

AttributedString attributedString = 
  new AttributedString("...");

To configure an attribute for the entire string, use the addAttribute method. For instance, to change the font for an entire string, specify:

  Font font = ...
  attributedString.addAttribute(
   TextAttribute.FONT, font);

To configure an attribute for just a part of the content, you pass in a beginning and ending index:

 attributedString.addAttribute(
   TextAttribute.FONT, font, startPosition, 
     endPosition);

The TextAttribute class of the java.awt.font package includes constants for the different attributes you can set. These include foreground and background colors, font, superscript, underline, justification, and many others.

You only need to configure the attributes of the string once. Then you need to draw the string. That's where the other classes and interfaces help.

When you need to draw the text, you fetch an AttributedCharacterIterator from the AttributedString so that the system can pull out the individual characters of the string.

  AttributedCharacterIterator characterIterator = 
    attributedString.getIterator();

FontRenderContext is used to ensure that the proper text sizes are used in the drawing. You obtain the FontRenderContext from the Graphics2D object passed into the paint method. You could call the constructor for FontRenderContext, however doing so wouldn't provide the correct measurements for the current graphic display.

  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    ...
    FontRenderContext fontRenderContext = 
      g2d.getFontRenderContext();

The LineBreakMeasurer class is used to determine how much text fits on a line. More specifically, given an AttributedCharacterIterator and FontRenderContext, LineBreakMeasurer measures how much of the AttributedString fits on each line. Each line is represented by a TextLayout.

  int screenWidth = ...;

  LineBreakMeasurer measurer = 
    new LineBreakMeasurer(characterIterator, 
      fontRenderContext);
  while (measurer.getPosition() < 
      characterIterator.getEndIndex()) {
    // Get line
    TextLayout textLayout = 
      measurer.nextLayout(screenWidth);
    ...
  }

That just leaves drawing the TextLayout, and there is a draw method for just that. Between lines, you just need to increase the y position to move down the screen.

  textLayout.draw(g2d, x, y);

Putting all the pieces together produces the following program:

import java.awt.*;
import javax.swing.*;
import java.awt.font.*;
import java.text.*;

public class Multi4 extends JFrame {
  String input = 
    "EDWARD by the grace of God, King of " +
    "England, Lord of Ireland, and Duke of " +
    "Guyan, to all Archbishops, Bishops, etc. " +
    "We have seen the Great Charter of the " +
    "Lord HENRY, sometimes King of England, " +
    "our father, of the Liberties of England, " +
    "in these words: ";
  AttributedString attributedString;

  public Multi4() {
    super("Manual Painting");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Font font = (Font)UIManager.get("Label.font");
    attributedString = new AttributedString(input);
    attributedString.addAttribute(
      TextAttribute.FONT, font);
    Color color = 
      (Color)UIManager.get("Label.foreground");
    attributedString.addAttribute(
      TextAttribute.FOREGROUND, color);
    setSize(300, 200);
  }

  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;

    // Watch the margins
    Insets insets = getInsets();
    int width = getSize().width - 
      insets.right - insets.left;
    // Set the starting position to draw
    int x = insets.left;
    int y = insets.top;

    // Get iterator for string
    AttributedCharacterIterator characterIterator = 
      attributedString.getIterator();
    // Get font context from graphics
    FontRenderContext fontRenderContext = 
      g2d.getFontRenderContext();
    // Create measurer
    LineBreakMeasurer measurer = 
      new LineBreakMeasurer(characterIterator, 
        fontRenderContext);
    while (measurer.getPosition() < 
        characterIterator.getEndIndex()) {
      // Get line
      TextLayout textLayout = 
        measurer.nextLayout(width);
      // Move down to baseline
      y += textLayout.getAscent();
      // Draw line
      textLayout.draw(g2d, x, y);
      // Move down to top of next line
      y += textLayout.getDescent() + 
        textLayout.getLeading();
    }
  }

  public static void main(String args[]) {
    JFrame frame = new Multi4();
    frame.show();
  }
}

If you run the Multi4 program, you should see the following:

multi 4

For information about drawing more than text with the Java 2D API, see the tutorial Displaying Graphics with Graphics2D.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Developer Technical Tips to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:
http://developer.java.sun.com/developer/JDCTechTips/

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_19199756596411151@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Jul 30 13:30:33 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6UIUXu26439 for ; Tue, 30 Jul 2002 13:30:33 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6UIWs0r021456 for ; Tue, 30 Jul 2002 13:33:01 -0500 (EST) Date: Tue, 30 Jul 2002 10:18:18 GMT-08:00 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <19199756596411151@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 30080 New to Java Programming Supplement
  July 30, 2002        

JavaTM Programming Language Basics
Making Sense of the Java Class Libraries
Program Challenge
Java Bits
For More Information

Welcome to the Java Developer ConnectionSM JavaTM Technology Fundamentals Newsletter.

This month's issue of JavaTM Technology Fundamentals Newsletter has been sent to you in HTML. If you prefer to receive a text only version, please see below.

Pixel

Java Programming Language Basics

Working with Hash Tables

A hash table is a common data structure that offers quick insertion and search capabilities. Hash tables work with key-value pairs: Given some key, check the table to see if the key is present, and if it is, return the associated value.

In the standard libraries, you'll find support for hash tables in five different classes. In this tip, you'll examine two: HashMap and LinkedHashMap.

map hierarchy

A common analogy for working with hash tables is the telephone book or the dictionary. Given some name, provide the phone number, or given some word, provide the definition. Hash tables work by looking up the key to find the value.

With an array, you look up a value via the integer index into the array. With a hash table, you don't use an integer directly, but instead use what's called a hash code. Hash codes map words or objects to numbers. Instead of having a table of the keys and sequentially scanning from front to back to check if a specific key is present, the hash table uses an intermediate value--The hash code.

The hash code allows the data structure to check only a single place for existence of a key. If nothing is found after converting a key to the hash code, the key is not present in the hash table.

But if something is found, that doesn't mean the key is present. Hash codes are not unique, and a secondary equality check is required to check the lookup value against the table contents. Only when the equality check passes do you know that the key is present.

When multiple keys map to the same hash code, a collision occurs. To work with hash tables successfully, use a hashing algorithm that results in as few collisions as possible.

For system classes like String and Date, this has already been done for you, but let's take a look at some ways to convert words to numbers by generating an algorithm.

A simple mechanism for converting strings to numbers is to sum up the numerical values for the characters in the string. For instance, to sum up the values, first convert each character to its integer equivalent (J = 74, o = 111, h = 104, n = 110). Next, sum them up (74+111+104+110 = 399). Unfortunately, many other names map to 399 also Cary, Cody, and Omar to name a few-- so this isn't an optimum hashing algorithm.

When using HashMap and related classes, you don't have to worry about the mapping mechanism directly. Mapping happens behind the scenes, and you never see the intermediate hash code values. The mapping can have a performance impact, though, when creating your own classes.

Using the hash table classes is simple. In a typical operation, you create the table, fill it up, then search or fetch. Operations like removal are also supported.

You create by calling the class constructor:

Map map = new HashMap();

Add to the table with the put method, providing the key and value:

map.put("key", "value");

Searching and fetching are two different operations. A search asks "does the key exist in the table?," while the fetch asks "what's the value of the key?"

For searching, you check if the hash table contains the key:

boolean contains = map.containsKey("key");

Fetching uses the search mechanism to see if a key exists before returning the value. That's where the get method comes in handy:

Object value = map.get("key");

The get method returns the value as an Object. If you want to treat the value as its data type, you must cast the value to the appropriate type:

String value = (String)map.get("key");

There is another fetch operation that fetches all the keys to dump out the entire contents of the hash table. This is a two step operation.

Step One: Get the set of all keys with the keySet method, or the set of entries with the entrySet method.

The keySet method fetches each individual key, without the value. If you need the value, look it up for each key. If you want both the key and value, use entrySet. Each key-value pair is stored in a Map.Entry.

Step 2: Use an Iterator to visit each element of the Set.

Here's keySet. After getting the set, you get the Iterator, and loop:

Set keys = map.keySet();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
   String entry = (String)iterator.next();
   System.out.println(entry);
}.

Here's entrySet. While you could use map.get(key) to look up each individual value, using entrySet is a more efficient mechanism. The process is almost identical:

Set entries = map.entrySet();
Iterator iterator2 = entries.iterator();
while (iterator2.hasNext()) {
   Map.Entry entry = (Map.Entry)iterator2.next();
   System.out.println(entry.getKey() + " : "
     + entry.getValue());
}

Printing out the keys in this manner may not produce the results you desire though. HashMap doesn't remember the order that entries were added. Instead, the entries are ordered by the intermediate hash code.

If you want the keys sorted, TreeMap comes in handy, but if you wish to display the entries in the order they were added, you need to use LinkedHashMap. By just changing the constructor line, the keySet or entrySet iterator is ordered in the manner in which the keys-value pairs were added.

Map map = new LinkedHashMap();

To find out how many elements are in the table, use the size method:

int size = map.size();

Now you can test your knowledge about hash tables with this online quiz.

Pixel
Pixel

Making Sense of the Java Class Libraries

Interface Set and Class TreeMap

A collection represents a group of objects that are known as its elements. Some collection implementations allow duplicate elements and others do not. Some are ordered while others are not. You can't provide a direct implementation of the Collection interface. Instead, use specific subinterfaces like Set or TreeMap, which are included the java.util package.

A Set interface extends Collection. It is a collection that can't contain duplicate elements.

A TreeMap implements the SortedMap interface by using a tree and extends AbstractMap. TreeMap provides an efficient way of storing key/value pairs, and allows quick retrieval. A tree map guarantees that its elements are sorted in a logical key order, such as alphabetically.

import java.util.*;

public class DemoTreeMap
 {
   public static void main (String args[])
    {
     //Create a tree map
     TreeMap tm = new TreeMap(); 
     
     // Put elements in the map
     tm.put("Carrots", new Integer(12));
     tm.put("Potatoes", new Integer(30));
     tm.put("Onions", new Integer(15));
     tm.put("Apples", new Integer(40));
     tm.put("Cherries", new Integer(300));
     
     //Check size of tree map
     System.out.println("The size of this tree map is " + tm.size() +
                                          " element pairs.");
     
     //     
     Set entries = tm.entrySet();
     Iterator i = entries.iterator();
     while (i.hasNext()) {
       Map.Entry entry = (Map.Entry)i.next();
       System.out.println(entry.getKey() + " : "
         + entry.getValue());
      }
     System.out.println();
     }
  }

This application results in:

The size of this tree map is 5 element pairs.
Apples : 40
Carrots : 12
Cherries : 300
Onions : 15
Potatoes : 30
tree
Pixel
Pixel

Program Challenge

  • Create a program that maintains a phone list of your friends to show the differences when traversing the entries based upon insertion order, hash code order, and sorted order.

  • Print out the hash table keys and values.

See a possible solution to Challenge:.

Pixel
Pixel

Java Bits

The Difference Between the equals Method and the == Operator

Run the following application:

public class EqualTest
 {
   public static void main(String args[]) 
    {
      Double Obj1 = new Double(2.43);
      Double Obj2 = new Double(2.43);
      Double Obj3 = Obj1;
      System.out.println("These objects are equal: ");
      System.out.println(Obj1 == Obj2);
      System.out.println(Obj1 == Obj3);      
      System.out.println(Obj1.equals(Obj2));
     }
 }

Note that the first comparison of objects Obj1 and Obj2, using the == operator, returns false. The second comparison of those same objects, using the equals method, returns true. In addition, the comparison of Obj1 with Obj3 returns true.

Both the == operator and the equals method compare for equality, but == is used with data types while the equals method compares objects.

In the example above, objects 1 and 2 hold the same value, but because a new instance is created, two objects with the same value exist. Two different objects have different memory addresses. On the other hand, Obj3 simply points at, or makes a reference to, an already existing object, so Obj1 == Obj3 return true.

To compare the values of objects, use the equals method. In the example above, Obj1.equals(Obj2) compares the values of Obj1 and Obj2, and returns true because the value of both objects is 2.43.

In summary, use the == to compare data types, and use the equals method to compare object values.

Pixel
Pixel

For More Information

Introduction to the Collections Framework

Lesson: Interfaces

Class HashMap

Interface Map

Using the LinkedHashMap

Class LinkedHashMap

Collections Framework Enhancements

Relational and Conditional Operators

Building an Application Introduction

Pixel
Pixel

Program Challenge Solution

See one possible solution to the July Program Challenge.

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SE development kit.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: Read past issues of the Java Technology Fundamentals Newsletter archives.

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_191585191682902642@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Jul 30 06:28:40 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6UBSeu20851 for ; Tue, 30 Jul 2002 06:28:40 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6UBV70n029928 for ; Tue, 30 Jul 2002 06:31:07 -0500 (EST) Date: Tue, 30 Jul 2002 03:31:02 GMT-08:00 From: "JDC Bug Watch" To: gcf@indiana.edu Message-Id: <191585191682902642@hermes.sun.com> Subject: Bug Change Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Beyond Email Content-Length: 475 The bug 4633024 has been updated. To view the the complete bug report visit the following url: http://developer.java.sun.com/developer/bugParade/bugs/4633024.html To receive newsletters in html, select the following URL: http://bulkmail.sun.com/servlet/PreferenceServlet?action=change&pref_name=content-type&pref_value=html&id=191585191682902642 To use our one-click unsubscribe facility, select the following URL: http://bulkmail.sun.com/unsubscribe?191585191682902642 From env_19357707-2001007436@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Jul 31 15:59:24 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g6VKxOu16830 for ; Wed, 31 Jul 2002 15:59:24 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g6VL1jHb026675 for ; Wed, 31 Jul 2002 16:01:50 -0500 (EST) Date: Wed, 31 Jul 2002 12:56:36 GMT-08:00 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <19357707-2001007436@hermes.sun.com> Subject: Enterprise Java Technologies Newsletter July 31, 2001 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 32348 Enterprise Java Technologies Newsletter for July 31, 2002
    July 31, 2002        

Product and Technology Releases
J2EETM Platform Specification v1.4, Public Draft (July 16, 2002)
Java Smart Ticket 1.1.1 Japanese Documentations (July 12, 2002)
J2EE Connector Architecture Specification v 1.5, Proposed Final Draft (July 11, 2002)

Early Access Releases
JavaServer PagesTM 2.0 Preview Implementation Early Access v1.0 (July 22, 2002)

Hot Downloads
Java 2 SDK, Enterprise Edition Version 1.3.1
Java Web Services Developer Pack v1.0
Java Web Services Tutorial
J2EE 1.3 Tutorial
Java Pet Store Demo 1.3.1

Resources
Java Verification Program
J2EE Code Samples
Articles
Books
J2EE Code Camps
Enterprise Java Technologies Tech Tips

Industry News
OASIS Members Form Web Services Security Technical Committee (July 23, 2002)
BEA to Implement JAX-RPC Standard (July 22,2002)
Novell Completes Acquisition of SilverStream Software (July 22, 2002)
Sun and Oracle Set New World Record for Java Based Application Performance ...
Sun Microsystems Delivers First Liberty-Enabled Single Sign-On Solution ...

Events
Pacific Northwest Software Symposium 2002, Aug. 2-4, Bellevue, Washington
XML Web Services One Conference & Expo, Aug. 26-30 Boston, Ma.
SunNetwork Conference, Sept. 18-20, San Francisco, Ca.
JavaOneSM Conference in Japan, September 25-27, Yokohama, Japan

Java Developer's Marketplace
Sun ONE Identity Server 6

Viewpoint
Java 2 Platform, Enterprise Edition and .NET: An Interview with Java ...

Pixel
Pixel

The following J2EE products and technologies were released this month.

J2EE Platform Specification v1.4, Public Draft. The J2EE 1.4 platform specification introduces new APIs that implement the core Web services protocols stack. It also introduces new Management and Deployment APIs, new versions of the JavaServer Pages, Enterprise JavaBeansTM, Connector APIs, and other features.

Java Smart Ticket 1.1.1 Japanese Documentations. Java Smart Ticket is a sample application that illustrates guidelines published by the Java 2 Platform, Enterprise Edition Blueprints for Wireless program. Release 1.1.1 is a maintenance release of the application. Japanese language documentation for Java Smart Ticket 1.1.1 is now available for download.

J2EE Connector Architecture Specification v 1.5, Proposed Final Draft. The J2EE Connector Architecture specifies a standard architecture for integrating J2EE applications with enterprise information systems. The J2EE Connector Architecture 1.5 specification provides bi-directional synchronous/asynchronous communication, message provider pluggability, lifecycle management, transaction inflow and thread management.

Pixel
Pixel

The following J2EE products and technologies were made available through the Early Access Release Program this month.

JavaServer Pages 2.0 Preview Implementation Early Access v1.0. This is a special non-production release of Tomcat 4.1 intended solely to enable public feedback on the new features in the recently-released Public Draft of the JavaServer Pages (JSPTM) 2.0 specification.

Pixel
Pixel

The following were the most frequently downloaded J2EE products and technologies this month.

Java 2 SDK, Enterprise Edition Version 1.3.1

Java Web Services Developer Pack v1.0

Java Web Services Tutorial

J2EE 1.3 Tutorial

Java Pet Store Demo 1.3.1

Pixel
Pixel

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

Java Verification Program. The Java Verification Program is designed to identify enterprise applications developed with Java 2 Platform, Enterprise Edition (J2EE) technology that are intended to be portable across different implementations of J2EE. The program outlines the tests needed to receive the Java Verification certification and leverages the Java Application Verification Kit (AVK) for the Enterprise, a technology provided by Sun that enables developers to test their applications using specific guidelines and rules.

J2EE Code Samples. See the Code Samples index page for a wide variety of Java code samples, including code samples that use J2EE technologies such as servlets, Enterprise JavaBeans technology, and the J2EE Connector Architecture.

Articles:

  • Web Services and J2EE Technology: One Platform. Learn about Java Pet Store for Web Services, the first reference application for the Java Web Services Developer Pack on the J2EE platform.

  • Runnin' With the Pack. June's release of the Java Web Services Developer Pack, v1.0 (Java WSDP) underlines Sun's continued commitment to making Java technology the platform of choice for Web Services developers.

Books:

  • CodeNotes for J2EE: EJB, JDBC, JSP and Servlets. This book introduces Java developers to key database and Web development technologies of the Java 2 Platform, Enterprise Edition.

  • J2EE and XML Development. This book takes a look at real-world uses of XML in J2EE systems. Topics covered include XML-base persistence mechanisms, integration strategies, Web services, the latest XML-based approaches to Web presentation layers, content publishing systems, design patterns and more.

J2EE Code Camps: Code camps are in-depth workshops that give you hands-on experience with Java technologies. Look for new downloads for the following J2EE-related code camps:

  • J2EE Technical Briefing
  • J2EE and Java & XML Hands-on Jump Start
  • EJB 2.0, JMS and Container Managed Persistence
  • iPlanetTM Application Server 6.5, Architecture, Installation and Administration

Enterprise Java Technologies Tech Tips. This new email newsletter presents tips and coding examples on effective use of enterprise Java technologies. Subscribe through the JDC Newsletters and Publications page.

Pixel
Pixel

OASIS Members Form Web Services Security Technical Committee. The OASIS standards consortium has organized a new technical committee to advance the WS-Security specification. WS-Security provides a foundation for secure Web services, laying the groundwork for higher-level facilities such as federation, policy, and trust.

BEA to Implement JAX-RPC Standard. BEA Systems announced that it added support for a certified implementation of the Java API for XML-based Remote Procedure Call, or JAX-RPC, in its WebLogic application server. JAX-RPC defines a set of standard Java APIs that allow developers to create XML-based Web services using SOAP as the messaging protocol.

Novell Completes Acquisition of SilverStream Software. Novell, Inc. announced the completion of its acquisition of SilverStream Software. The acquisition of SilverStream brings the company's leading Web services development platform, SilverStream eXtend, into the Novell family of solutions.

Sun and Oracle Set New World Record for Java Based Application Performance Benchmark. Sun Microsystems, Inc. and Oracle Corporation achieved record-breaking ECperfTM benchmark results with Oracle9i Application Server (Oracle9iAS) on Sun FireTM 3800 Midframe servers, surpassing IBM and HP/BEA Systems configurations.

Sun Microsystems Delivers First Liberty-Enabled Single Sign-On Solution. Sun Microsystems, Inc. announced the first shipping, end-to-end network identity solution, the Sun ONE Platform for Network Identity, that addresses customers' needs for heightened security, privacy and federated identity management. The new products, services and support are fully compliant with the Liberty Alliance version 1.0 specification.

Pixel
Pixel

August 2-4,
Pacific Northwest Software Symposium 2002, Bellevue, Washington

August 26-30,
XML Web Services One Conference & Expo, Boston, Ma.

September 18-20
SunNetwork Conference, San Francisco, Ca.

September 25-27
JavaOne Conference in Japan, Yokohama, Japan

Pixel
Pixel

Sun ONE Identity Server 6 Sun ONE Identity Server 6 enables enterprises to bridge disparate authentication systems with single sign-on. Based on open standards, including Liberty, SAML and Java Authentication and Authorization Service, customers can integrate Sun ONE into existing systems without lock-in to a single vendor. Sun ONE Identity Server includes increased authentication, policy administration and security controls, such as Kerberos v5, Microsoft NT and Windows 2000 authentication plug-ins, automatic resource-based authentication and OSCP for digital certificates. The product also supports the leading application servers for development and integration, including the Sun ONE Application Server as well as third-party products such as the BEA Web Logic Server, SAP Web Application Server, IBM We! bSphere and others. The product is available today in early access and is expected to be released in October of this year.

Pixel
Pixel

Java 2 Platform, Enterprise Edition and .NET. "If you compare .NET to J2EE, you'll notice that J2EE is a much more mature, heavily deployed, and time-tested platform. A huge community is behind its success. It has a well-defined component model with Enterprise JavaBeans technology, Web application frameworks (JavaServer Pages, Servlets, JavaServer FacesTM), and a transaction and security model." Read more in this interview with Java Technology Evangelist Rima Patel.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Enterprise Java Technologies Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Sun Fire, Java, Java Developer Connection, JavaOne, J2EE, JavaServer Pages, JSP, JavaMail, JavaServer Faces, ECperf, Enterprise JavaBeans, and iPlanet are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_1961336877088801@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Aug 6 16:44:34 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g76LiYm08680 for ; Tue, 6 Aug 2002 16:44:34 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g76LktI3027011 for ; Tue, 6 Aug 2002 16:47:10 -0500 (EST) Date: 6 Aug 2002 12:24:55 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <1961336877088801@hermes.sun.com> Subject: Core Java Technologies Tech Tips, August 6, 2002 (Prime Numbers, Overloading) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27656 Technical Tips
   View this issue as simple text August 6, 2002        

Generating Prime Numbers
When Not to Overload Methods

These tips were developed using JavaTM 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

Pixel

Generating Prime Numbers

A prime number is an integer greater than 1, with only itself and 1 as divisors. The first few primes are 2, 3, 5, 7, 11, and 13.

This tip examines two ways of generating primes. The first approach works for relatively small (32-bit) prime numbers. The second uses the BigInteger class to generate large primes (typically hundreds or thousands of digits).

Here's an example of where prime numbers are used. Suppose that you're working on a custom hash table scheme. You know that there will be about 1000 entries in the table, and you want the table to be no more than two thirds full, relative to the number of slots available. This implies a table size of 1500. A common hash table algorithm uses a table size that's prime, in order to reduce the number of collisions. So you need to find a prime number with a value near 1500. How can you do this? Here's one way:

    public class PrimeDemo1 {
    
        // check whether a number is prime
    
        static boolean isPrime(int n) {
    
            // 2 is the smallest prime
    
            if (n <= 2) {
                return n == 2;
            }
    
            // even numbers other than 2 are not prime
    
            if (n % 2 == 0) {
                return false;
            }
    
            // check odd divisors from 3
            // to the square root of n
    
            for (int i = 3, end = (int)Math.sqrt(n);
            i <= end; i += 2) {
                if (n % i == 0) {
                    return false;
                }
            }
    
            return true;
        }
    
        // find the smallest prime >= n
    
        static int getPrime(int n) {
            while (!isPrime(n)) {
                n++;
            }
            return n;
        }
    
        public static void main(String args[]) {
            System.out.println(getPrime(1500));
        }
    }

The PrimeDemo1 program defines an isPrime method. The method handles the special case of 2 (which is prime). It then screens out other positive even numbers (which are not prime, because they have 2 as a divisor). The isPrime method then tries odd divisors starting at 3 and going up to the square root of the number.

The output of the program is:

    1511

that is, 1511 is the smallest prime of value 1500 or above.

This approach does the job, and is reasonably fast. But it has a couple of shortcomings. One problem is that you can't use the program to generate prime numbers above 32 bits (about 10 decimal digits). (To convert a number of bits to an approximate number of decimal digits, multiply by log10(2), or 0.301).

Some applications require very long primes, such as 2048 bits (approximately 615 digits). An example is encryption, which relies on the idea that the product of two large primes cannot readily be factored into those primes -- except by a brute-force attack using very large amounts of computer time.

Even if the PrimeDemo1 program could somehow represent very long numbers, there is another problem. Trying all odd divisors up to the square root is a hopelessly inefficient technique for generating prime numbers, when the numbers are really big. Here, another approach is required.

There is indeed a very fast way to generate large primes, but with a catch. The generated numbers are probably prime, but there is a slight chance that they might not be. The standard set by ANSI X9.80 specifies a certainty for use in private-key encryption: the probability that a generated prime is actually prime is greater than 1 minus 1/2 to the 100th power. So there's less than a 1 in 2 to the 100th power chance that a generated number is not prime. 1 in 2 to the 100th power is about 1 in 1.27 times 10 to the 30th power, which is indeed a very low probability.

Given this background, how do you actually generate a big prime? Here's a simple example:

    import java.math.BigInteger;
    import java.util.Random;
    
    public class PrimeDemo2 {
        public static void main(String args[]) {
            Random rnd = new Random(0);
    
            // obtain a 100-bit probable prime, 
            // with the probability that the number 
            // is composite at less than 
            // 1 in 2 to the 100th power
    
            BigInteger prime = 
                    BigInteger.probablePrime(100, rnd);
    
            System.out.println(prime);
        }
    } 

This program generates a 100-bit prime, using the passed-in Random object as a source of random values. The output of the program is:

    689572171629632424814677540353

The probablePrime method generates a 100-bit number, and then subjects that number to certain tests of primality, called the Miller-Rabin and Lucas-Lehmer tests.

How fast does probablePrime run? Let's look at a final example to help answer this question:

    import java.math.BigInteger;
    import java.util.Random;

    public class PrimeDemo3 {
        public static void main(String args[]) {
            for (int numBits = 100; 
                numBits <= 300; numBits += 100) {
                generatePrimes(100, numBits);
            }
        }

        static Random rnd = new Random();

        // Generate numPrimes probable primes 
        // of numBits length.
        
        static void generatePrimes(
                         int numPrimes, int numBits) {
            long start = System.currentTimeMillis();
            for (int i = 1; i <= numPrimes; i++) {
                BigInteger.probablePrime(numBits, rnd);
            }
            long elapsed = 
                    System.currentTimeMillis() - start;
            System.out.println(
                   "ms to generate " + numBits 
                    + " bit prime  = "
                    + (elapsed / numPrimes));
        }
    } 

When you run the program, you should get results like this (your results might differ depending on your operating environment):

    ms to generate 100 bit prime  = 31
    ms to generate 200 bit prime  = 111
    ms to generate 300 bit prime  = 235

These results show that it took 31 milliseconds to generate a 100-bit prime, 111 milliseconds to generate a 200-bit prime, and 235 milliseconds to generate a 300-bit prime. Clearly, the time it takes to generate primes is not linear in relation to the number of bits.

There are a number of other prime-related features in BigInteger. For example, there's a method named isProbablePrime that you can use to test an existing BigInteger value for primality.

For more information about generating prime numbers, see section 4.5.4, "Factoring Into Primes", and section 6.4, "Hashing" in "The Art of Computer Programming" by Donald Knuth. Also, see "Enhancements to java.math".

Pixel
Pixel

When Not to Overload Methods

Suppose that you are writing a Java application, and you have some code like this that uses overloading for methodA and methodB:

    public class OverDemo1 {
    
        // overload methodA between short/int
    
        static void methodA(short s) {
            System.out.println(
                              "methodA(short) called");
        }
        static void methodA(int i) {
            System.out.println("methodA(int) called");
        }
    
        // overload methodB between float/double
    
        static void methodB(float f) {
            System.out.println(
                              "methodB(float) called");
        }
        static void methodB(double d) {
            System.out.println(
                             "methodB(double) called");
        }
    
        public static void main(String args[]) {
    
            // call methodA with char argument
    
            methodA('a');
    
            // call methodB with int argument
    
            methodB(Integer.MAX_VALUE);
        }
    }

What happens when this code is executed? First, methodA is called with a char argument. A char data type is 16 bits, so it seems logical that methodA(short) will be called. That's because the short type is 16 bits as well.

Next, methodB is called with an int argument. The int and float types are both 32 bits. Because a float type uses part of the bits for an exponent, it cannot fully represent a large int value without loss of precision. So methodB(double) seems like the logical choice, right?

Actually, this analysis is wrong in both cases. When you run the OverDemo1 program, the result is:

    methodA(int) called

    methodB(float) called

The point of this tip is not to discuss the intricacies of overloading, but simply to present the idea that most Java programmers don't fully understand how overloading works. It's smart to write your code so that they don't have to worry about these intricacies. This tip presents several ways to write code that avoids overloading issues. But first, let's look at one more example that illustrates how method overloading can be confusing:

    class A {
        void f() {
            System.out.println("A.f called");
        }
    }
    
    class B extends A {
        void f() {
            System.out.println("B.f called");
        }
    }
    
    public class OverDemo2 {
        static void classifyObject(A a) {
            System.out.println("classify as A");
        }
    
        static void classifyObject(B b) {
            System.out.println("classify as B");
        }
    
        public static void main(String args[]) {
    
            // create a B object referenced
            // by an A reference
    
            A aref = new B();
    
            // classify the object 
            // using overloaded methods
    
            classifyObject(aref);
    
            // call the f() method for the object
    
            aref.f();
        }
    }

The OverDemo2 program creates a B object with an A reference pointing at it. The program then calls the classifyObject method to indicate whether the A object or the B object is referenced by aref. Then the program calls the f method on the object. If you run this program, the result is:

    classify as A

    B.f called

The classifyObject method indicates that the A object is being referenced, but the f method call is on the B object. Which is right?

This example illustrates a major source of confusion with method overloading, a confusion that stems from the difference between overloading and overriding. The choice of which overloaded method to call is made by the compiler. In the OverDemo2 example above, classifyObject is called with the aref argument, of type A. The fact that aref references a B object is ignored, meaning that classifyObject(A) is called. By contrast, the choice of which f method to call is made dynamically when the program is executed, based on the actual type of object (which is a B). The f method in B overrides, not overloads, the corresponding method in A.

How do you avoid problems with overloading? One approach is to not overload at all. Instead, give methods different names, corresponding to the types of their parameters. For example, the OverDemo1 program above could be rewritten like this:

    public class OverDemo3 {
    
        static void methodShort(short s) {
            System.out.println("methodShort called");
        }
    
        static void methodInt(int i) {
            System.out.println("methodInt called");
        }
    
        static void methodFloat(float f) {
            System.out.println("methodFloat called");
        }
    
        static void methodDouble(double d) {
            System.out.println("methodDouble called");
        }
    
        public static void main(String args[]) {
    
            // call methodInt with char argument
    
            methodInt('a');
    
            // call methodFloat with int argument
    
            methodFloat(Integer.MAX_VALUE);
        }
    }

There is no overloading in this code, so which methods are called is very clear. A similar technique is used in some of the standard library classes such as DataOutputStream.

Another approach to eliminating confusion with overloading is to specify a different number of parameters for each of a set of overloaded methods. Alternatively, make sure that the parameter types are radically different from each other. Let's look at a final example to see how this works:

    class MyDate {
    
        // construct date from string 
        // like "January 17, 1959"
    
        public MyDate(String s) {
            // ...
        }
    
        // construct date from month/day/year
    
        public MyDate(int month, int day, int year) {
            // ...
        }
    
        // construct date from number of days 
        // since 1/1/1800
    
        public MyDate(int numdays) {
            // ...
        }
    }

In this example, the MyDate constructor is overloaded. It's not possible to give the various constructors different names, as illustrated in the earlier example, so they must be distinguished some other way.

The first and second constructors have different numbers of parameters, so it's easy to tell them apart. The first and third constructors both have a single parameter, but in one case it's a String, and in the other case an int, so it's easy to distinguish these.

Note that even with MyDate structured this way, there are still potential problems with understanding the code. For example, a statement like this:

    MyDate d = new MyDate(10, 12, 1959);

might be interpreted two different ways by someone who reads the code. The interpretation depends on whether the person reading the code is accustomed to specifying the month number before or after the day number. What date is being referred to here, October 12 or December 10? It's possible that additional work needs to be done to make this class easier to use. An enumerated type could be used to specify the month. Static factory methods could be used for creating dates. Unlike for constructors, you can give static factory methods distinct names that describe their function.

Some examples of parameter types not radically different from each other include:

  • char vs. int
  • int vs. float/double
  • classes in a related hierarchy (A vs. B in the example above)
  • Object vs. array types like int[]

Overloading is a useful technique, but it pays to be cautious. You don't want to end up with code that's impossible to read, or that takes advantage of arcane rules that few programmers understand. It should be possible for an average reader to look at your code and know exactly what method is being called at any point.

For more information about alternatives to overloading methods, see item 1 "Consider providing static factory methods instead of constructors" and item 26 "Use overloading judiciously" in "Effective Java Programming Language Guide" by Joshua Bloch; and Section 5.3 "Method Invocation Conversion" and Section 15.12.2 "Compile-Time Step 2: Determine Method Signature" in "The Java Language Specification Second Edition" by Gosling, Joy, Steele, and Bracha.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Core Java Technologies Tech Tips to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/JDCTechTips/

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_19761790479043616@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Aug 13 16:27:21 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7DLRLm22343 for ; Tue, 13 Aug 2002 16:27:21 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7DLU78Z028592 for ; Tue, 13 Aug 2002 16:30:08 -0500 (EST) Date: 13 Aug 2002 13:24:56 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <19761790479043616@hermes.sun.com> Subject: Enterprise Java Technologies, August 13, 2002 (Servlet Filters, and Using EJBs) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 35899 Technical Tips
   View this issue as simple text August 13, 2002        

Using Servlet Filters
Choosing Whether To Use Enterprise Beans

These tips were developed using JavaTM 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the Enterprise Java Technology Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

Pixel

Using Servlet Filters

The J2EE platform provides two types of server-side components for generating dynamic content: servlets and JavaServer PagesTM (JSPTM) pages. Servlets are Java classes that generate dynamic content by writing it directly to an output stream. JSP pages are structured static content (such as HTML or XML) interspersed with either Java code ("scriptlets") or custom tags that produce dynamic content. JSP pages and servlets are mapped to URLs in a Web server's name space. The servlet or JSP page produces dynamic content in response to a client making a request to its URL.

There might be times when you need to augment the actions of a server component such as a servlet. For example, suppose you want to log every request that a client makes to a servlet, or activate some security mechanism before a servlet executes, or convert the format of output that a servlet generates. You could incorporate these features everywhere you need them, but this can be tedious and error-prone.

Fortunately, Version 2.3 of the Java Servlet specification introduces a new type of component called a servlet filter that gives you an easier way to augment the actions of server components. A servlet filter "wraps" server components with additional functionality by intercepting client requests. It also acts on the request either before or after (or both before and after) the component it wraps is invoked. Even better, multiple filters can be ""chained" to augment a single Web resource with multiple services (more on this later).

For instance, you can use a logging servlet filter to record information, such as the date, time, and request parameters, for every request made to a particular servlet. The filter does its logging before the request is passed to the servlet for processing. Here, you're using the filter to wrap the servlet. The filter logs accesses to the servlet, but it doesn't change the servlet code itself.

Let's examine the sequence of events regarding the logging servlet filter.

  1. The client accesses the servlet's URL.
  2. The servlet filter intercepts and logs the request.
  3. The servlet filter passes the request to the servlet.
  4. The servlet generates the requested content (oblivious to the logging that took place before the call).


Figure 1. A Logging Servlet Filter Intercepts And Logs Requests

Servlet Filter Features

Servlet filters have several characteristics that make them extremely powerful:

  • They can both pre- and post-process requests. A servlet filter can provide functionality both before and after the underlying component is called. The logging filter in the previous example pre-processes a request. An example of a post-processing filter is an XSL style filter that transforms XML data produced by a servlet, that is, after the servlet is called.

  • They can generate content directly. When a filter intercepts a request, it does not have to pass the request to the component it wraps. For example, you can create a security filter that returns an error page if the current user is not allowed access to the requested component.

  • They can redirect requests. The servlet filter has access to all of the services of the J2EE Web container. A servlet filter can get a request dispatcher from the ServletContext and forward the request to a new URL. There's a good example of this in the Java Pet Store sample application that is part of the Enterprise Java Blueprints. When a user who is not signed on accesses a protected page in the sample application, the sample application's signon filter redirects the request to a signon page.

  • They are chainable. More than one filter can be applied to a Web component. Each servlet filter is applied in the order it is defined in the Web deployment descriptor, web.xml. Each filter calls the next filter in the chain, while the last filter calls the underlying Web component. Any filter can "short-circuit" the chain by serving the request itself, and not calling the next filter.

  • They are not only for HTTP requests. The servlet filter interface, javax.servlet.Filter, is not specific to HTTP. So servlet filters can be written for any protocol that servlets support.

  • They are not only for servlets. Despite their name, servlet filters are actually general request/response filters for the Web container. You can use a servlet filter to filter requests to a servlet, to filter requests to any arbitrary URL, or to a set of URLs matching a pattern. Servlet filters can even wrap simple requests for HTML and graphics files. Many servlet filters intercept every application request.

  • They can change the behavior of Web components with no change to the component code. Servlet filters wrap components. They are added to and removed from the request loop declaratively, in the Web deployment descriptor. Servlet filter code is decoupled from the code of the Web components they wrap.

A Sample Filter

Servlet filters are excellent for providing services that many Web components in an application require. For example, all servlets that receive HTTP POSTs need to check the existence and validity of their input parameters.

Let's examine a sample servlet filter named ParamFilter that checks input parameters for a servlet. If the servlet filter validates the input parameters, the servlet can then assume that it's receiving usable data.

You can find the source code for the sample servlet filter and related classes in the sample archive, filterdemo.ear. You can download the sample archive from here.

To extract the files from the sample archive, run the following command:

jar xvf filterdemo.ear

In the extract, you'll see a number of directories as well as a Web archive file, filterdemo.war. To extract the contents of the Web archive file, run the command:

jar xvf filterdemo.war

ParamFilter reads an XML file (check.xml) that defines the parameters that the servlet requires. It also constrains the values allowed for a parameter by defining its type. In this example, ParamFilter wraps a servlet named PrintVars. The servlet simply prints the names of the POST parameters it receives.

The sample archive contains a file named check.xml. This file defines a set of parameters required by the Web component at a particular URL. Here is an excerpt from check.xml:

<posts>
  <post url="/PrintVars">
    <param name="Title"  type="String" optional="yes"/>
    <param name="FirstName" type="NonEmptyString"/>
    ...
    <param name="PostalCode" type="Decimal"/>
    ...
    <param name="Submit"/>
  </post>
</posts>

A post tag has an attribute (url) that matches the request URL. Each param tag defines an HTTP POST parameter that must (unless it's optional) be in the request. A param tag has a name that indicates the parameter's name, and optionally, a type, that constrains the values the parameter may take (currently either String, NonEmptyString, and Decimal). ParamFilter uses a Posts object, deserialized from the XML, to perform parameter validation. This is illustrated in the structure diagram below. When a param has no type, its existence is checked, but not its value.


Figure 2. ParamFilter Delegates Parameter Validation To Class Posts

ParamFilter implements each of the three methods defined in the javax.servlet.Filter interface:

  • The init method saves the FilterConfig object for later use. The method then constructs a Posts object, which it will use for checking. The init method calls the getCheckSpecificationStream method to open a stream for reading the check.xml file (this file is deployed in a WAR file in the application archive). Here is an excerpt of the source code for the init method:
        public void init(FilterConfig config) { 
            _config = config;
    
            try {
                InputStream is = 
                          getCheckSpecificationStream();
                _posts = new Posts(new InputSource(is));
            } catch (IOException ie) {
            ...
        }
    
  • The destroy method cleans up any resources used by the filter when the filter is destroyed. This method is often used to release scarce resources such as database connections.

  • The doFilter method actually does the filtering. The filter's validate method uses a Posts object, derived from check.xml, to check all of the parameters in the request. The method returns an error Map, whose keys are the names of the parameters that caused a problem, and whose contents are either MISSING (the request did not contain a required parameter), UNKNOWN (the request contained a parameter not defined by check.xml), or INVALID (the parameter's value is not valid for its type). If the error map is not empty, then the filter prints the errors instead of passing the request to the underlying servlet. An empty error map indicates that the parameters are good, and so the request is sent to the next filter in the filter chain. The doFilter method calls chain.doFilter(req, res) to se! nd the request to the next filter. Because ParamFilter is the last filter in the chain (as defined in the deployment descriptor), the request is passed to the wrapped servlet, /PrintVars. Here's the source code for doFilter:
        public void doFilter(ServletRequest req, 
                  ServletResponse res, FilterChain chain) 
                  throws IOException, ServletException {
    
            HttpServletRequest hreq = (
                                  HttpServletRequest)req;
            HashMap errors = validate(hreq.getServletPath(),
                                  hreq.getParameterMap());
    
            if (errors != null && !errors.isEmpty()) {
                String requestURL = new String(
                                   hreq.getRequestURL());
                printErrors(
                    res.getWriter(), requestURL, errors);
            } else {
                // No errors, so do as requested.
                chain.doFilter(req, res);
            }
        }
    

Note that the sample code above omits the business logic of checking the parameters and printing the errors, as well as deserializing the XML. You can view the entire source code in the sample archive.

Deploying a Servlet Filter

You write and compile a servlet filter just like any other Java class. Make sure however that that the servlet filter has a zero-arg constructor. Deploying servlet filters is easy, but it requires some attention to detail.

First, place filters and the classes they use under the WAR file's WEB-INF/classes directory. Of course, filters and supporting classes that are in packages must use the appropriate directory structure.

Next, define the servlet filter in the Web application's deployment descriptor, web.xml, using the filter tag. The sample code defines the filter as follows:

  <filter>
    <filter-name>ParamFilter</filter-name>
    <display-name>ParamFilter</display-name>
    <description>Checks form post parameters</description>
    <filter-class>ParamFilter</filter-class>
    <init-param>
      <param-name>CheckSpecPath</param-name>
      <param-value>/WEB-INF/check.xml</param-value>
    </init-param>
  </filter>

Notice the definition of the initialization parameter CheckSpecPath. The filter looks in this parameter to find the path (within the WAR file) to check the specification XML file. Initialization parameters like this are available to a servlet filter from the FilterConfig interface that is passed to the filter's init method.

After you define a filter, you can map it to one or more Web resources, using the filter-mapping tag, like this:

  <filter-mapping>
    <filter-name>ParamFilter</filter-name>
    <servlet-name>PrintVars</servlet-name>
  </filter-mapping> 

The servlet-name tag wraps the filter around the named servlet. The filter-mapping definition above indicates that ParamFilter wraps servlet PrintVars. To apply a servlet to a URL or a set of URLs, use the url-pattern tag instead. For example, to apply the ParamFilter filter to all Web resources in the application, specify:

  <filter-mapping>
    <filter-name>ParamFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Remember: you can use a servlet filter to elegantly implement functionality that is applicable across Web components.

More Servlet Filter Resources

You can download a sample application for this tip from the sample archive. The application's context root is filterdemo. Sample valid and invalid forms are supplied. The sample archive also contains the complete source code for the sample. The context root of the application is /filterdemo. For a standard installation of the J2EE reference implementation, deploy the application and access it at http://localhost:8000/filterdemo.

You can also read an in-depth description of the sample application signon filter in the section User Signon and Customer Registration Module in the document Designing Enterprise Applications with the JavaTM 2 Platform, Enterprise Edition, Second Edition

And, you can find a good discussion of servlet filters in the technical article The Essentials of Filters.

Pixel
Pixel

Choosing Whether to Use Enterprise Beans

Enterprise JavaBeansTM (EJBTM) technology components, or simply "enterprise beans", provide an environment for managed components. They can simplify the process of developing scalable, highly-available, portable enterprise applications. Yet using enterprise beans also require an investment in time, training, and coding. This tip explores some of the design issues involved in using enterprise beans in an application.

Benefits

Enterprise beans are powerful, but they also incur some development and runtime overhead. Using enterprise beans can simplify development when an application requires the services that these beans offer (and when their benefits outweigh their costs).

To some, enterprise beans look complicated. But they can, in fact, simplify development, because they solve common "horizontal" enterprise application requirements (such as multithreaded access, persistence management, and declarative transaction and security control). Enterprise beans also allow component and application developers to concentrate on developing "vertical" business and application logic.

Several common horizontal application requirements are listed below, along with an explanation of how enterprise beans help meet the requirement. The more of these requirements that apply to your application, the more likely it is that your design could benefit from using enterprise beans.

  • Persistence management. Many enterprise applications manipulate persistent data. An entity bean (which is an EJB that represents persistent data stored in one row of a database table) is designed to provide automatic management of persistent enterprise data, including legacy data.

  • Concurrent data access. Multiuser enterprise applications must provide concurrent access to data without sacrificing consistency. Enterprise beans are designed to manage concurrent access automatically, and are inherently thread-safe.

  • Remote data access. Enterprise applications typically access data from multiple remote sources. Remote enterprise bean interfaces provide location-independent access to enterprise data.

  • Component-based development model. Software components can provide reusability, portability, and a clean separation of the interface from the implementation. Enterprise beans provide these benefits because they are true software components.

  • Portability. An application that is portable across multiple hardware platforms and operating systems makes best use of existing IT assets, and provides flexibility in the future as requirements and budgets change. Portability also decreases vendor lock-in, decreasing the risk that an application will become obsolete when operating systems are upgraded or hardware platforms die out. The tight specification of J2EE technologies, verified by literally thousands of individual tests, insures that enterprise system services are consistently available across vendors and platforms.

  • Transaction and security control. Enterprise data must be updated consistently, and only by those authorized to access it. Enterprise beans provide declarative control of transactions and security, greatly simplifying these issues for component and application developers, and increasing flexibility. Enterprise beans can also control transactions and security programmatically, where greater control is necessary.

  • High availability. Mission-critical systems often need to be available virtually all of the time. Enterprise bean implementations can provide automatic failover when a server crashes or is taken down for maintenance, or when networks are unreliable. Enterprise beans also manage automatic data recovery when a failed system is restarted.

  • Scalability. Applications often need to handle both increasing load and new requirements. Because an enterprise bean's life cycle is managed by its container, component instances can be pooled to maximize resource efficiency. Components can then be migrated to balance load within a cluster of processors.

  • Client neutrality. Some applications require access by multiple client types. Business objects modeled as enterprise beans provide access to an application model by any client type. Java clients can access enterprise beans through enterprise bean interfaces. Non-Java clients can access enterprise beans using CORBA or Web services interfaces.

Design Considerations

Few enterprise applications have all of the requirements listed above. Smaller enterprise applications might have little need for security, transactions, or scalability, and persistent data management might be straightforward. In these cases enterprise beans are usually overkill, incurring overhead while providing little benefit. Smaller, simpler applications are usually better implemented as traditional 2- or 3-tier systems. For example, a J2EE Web application that generates dynamic data using servlets and JSP pages, accesses persistent data using JDBC, and manages transactions and security programmatically, is an excellent architecture for a small to medium-sized application.

The larger an enterprise application is, it's likely to meet more of the requirements listed above. Without enterprise beans, it can be very difficult to create applications that require concurrent access to a large schema of data, distributed across multiple data sources. It's especially difficult to do this transactionally and securely, while also maintaining portability. And none of those concerns solve a single business problem. The technology and training investment that enterprise beans require can be quickly repaid by developers who are free to concentrate on business problems, while enterprise beans automatically manage common enterprise application requirements.

One final consideration: If you design your application carefully, you can always add enterprise beans later. Enforcing good design practice, such as separating class interfaces from implementations, can make it easier to refactor and migrate to enterprise beans as your application requirements grow.

More Enterprise Bean Resources

You can find a good discussion of using enterprise beans as business objects in the sectionBusiness Logic and Business Objects in the document Designing Enterprise Applications with the JavaTM 2 Platform, Enterprise Edition, Second Edition.

Also, see the EJB-Interest List, and the Enterprise JavaBeans Forum for discussions on EJB-related topics.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, JavaServer Pages, JSP, Enterprise JavaBeans, EJB, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_20019851-1378799966@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Aug 14 17:41:32 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7EMfVm09428 for ; Wed, 14 Aug 2002 17:41:32 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7EMiEl2029824 for ; Wed, 14 Aug 2002 17:44:21 -0500 (EST) Date: 14 Aug 2002 13:20:35 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <20019851-1378799966@hermes.sun.com> Subject: August Core Java(tm) Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 34287 Core Java Technologies Newsletter on the Web: August 14, 2002
    August 14, 2002        

Product and Technology Releases
JavaTM XML Pack Summer '02 Update Release (August 06, 2002)
JSR-000141 Session Description Protocol (SDP) API...
Java 3DTM 1.3 API (Jul 10, 2002)

Hot Downloads
Java 2 Platform, Standard Edition, (J2SETM) v1.3.1_04
Java Development Kit v1.1.8_009
Java Web Services Developer Pack 1.0
Java XML Pack Summer '02 Release
Java 2 SDK, Standard Edition Documentation v1.3.1

Resources
Technical Articles and Quizzes
Tech Tips
Tutorials & Code Samples
Books
CodeCamps
Newsletters
More Resources

Industry News
U.S. Design Corporation Certifies Plasmon's D-Series...
Netaphor Software Inc. released Cyberons for Java (August 02, 2002)

In the Spotlight
Metrowerks Rolls Out Software Tools to Thousands (August 06,2002)

Events
SunNetwork Conference -- Registration Discount San Francisco...
Sun's Worldwide Java Developer Conference Yokohama...

Java Developer's Marketplace
Sun Announces Latest Version of Java 2 Platform Standard Edition(J2SE) v1.4

Viewpoint
From the Source: Open Source Advocate Danese Cooper

Pixel

Product and Technology Releases:
The following J2SE products and technologies were recently released.

Java XML Pack Summer '02 Update Release
Updated release of all-in-one download of Java technologies for XML.

JSR-000141 Session Description Protocol (SDP) API - Public Review v 0.11
The IETF protocol SDP specifies messages that describe multi-media sessions and are included within other protocol messages as payload. The API will enable users to manipulate SDP messages.

Java 3D 1.3 API
Provides a set of object-oriented interfaces that support a simple, high-level programming model. This enables developers to build, render, and control the behavior of 3D objects and visual environments.

Pixel
Pixel

Hot Downloads:
The following are currently the most frequently downloaded J2SE products and technologies.

Java 2 Platform, Standard Edition v1.3.1_04

Java Development Kit v1.1.8_009

Java Web Services Developer Pack 1.0

Java XML Pack Summer '02 Release

Java 2 SDK, Standard Edition Documentation v1.3.1

Pixel
Pixel

Resources:
Learn more about, and get "hands-on" training for, J2SE technologies through the following resources.

Technical Articles and Quizzes:

  • Deploying Software with JNLP and Java Web Start: Going Beyond the Java Plug-in. Learn how to use Java Web Start and JNLP to build and deploy cross-platform, client-side applications.
  • Teaching Java Technology with BlueJ. BlueJ is a simple IDE used to teach the Java programming language and concepts. It encourages experimentation and exploration through simplicity, visualization, and interactivity.
  • Are You the CodeMaster? Next Month's SunNetworkSM Conference Features Big Prizes for Top Coders. If you're a developer with knock-out skills, here's one more reason to register now for the SunNetwork conference in San Francisco next month: $80,000 in prize money in the SunNetwork Coder Challenge, powered by TopCoder.
  • Certified in San Francisco: Certification-focused Training Day at SunNetwork Conference. Adding value to the SunNetwork Conference in San Francisco next month, the SunNetwork University program brings Certification preparation and testing to developers -- at significant discounts.
  • Building an Application Quiz. Test what you learned about handling exceptions, writing to and reading from files, and accessing data from the Building an Application tutorial series, parts 3 and 4.

Tech Tips:

Tutorials & Code Samples:

Books:

Code Camps:

Newsletters:

More Resources:

  • Developer Forum Survey. Help us understand what kinds of Java technology forums are needed. Please take this three-question survey.
  • Compatibility Testing Scholarship Program This Scholarship Program awards free access to Sun's Technology Compatibility Kits, and support services, developed through the Java Community Process for qualifying not-for-profit and individual efforts.
  • Register for the Free Sun/Macromedia Seminar Accelerating Java Development. Join Macromedia and Sun for a free, half-day seminar where you'll learn how you can create and deploy powerful Java applications faster than you'd ever imagine with ColdFusion MX for Sun ONE! Discover how the ColdFusion MX rapid server scripting environment lets you build applications that can be deployed on the powerful and scalable Sun ONE application server -- without any previous knowledge of Java! You'll also learn how to leverage existing Java assets while incorporating web services, XML, Flash, and more!
  • Interview the Stars of the 2002 SunNetwork Conference. How would you like to have your "big questions" answered by the likes of James Gosling, "the father of Java technology," Whitfield Diffie, co-inventor of public key cryptography, or Rob Gingell, responsible for the technical and strategic direction of software at Sun Microsystems?

    Visit http://soldc.sun.com/sunnetwork/ to learn more about these three software luminaries and to submit your practical or theoretical questions regarding the present and future of software. We'll choose the best questions for interviews that will appear at http://sunnetwork.sun.com and http://soldc.sun.com in the weeks leading up to the conference.
Pixel
Pixel

Industry News:

U.S. Design Corporation Certifies Plasmon's D-Series Family of JukeBoxes.
Plasmon Corporation and U.S. Design Corporation, a provider of storage management software, announced that Universal SuperSTOR Version 2.0 (USS v2.0) has been certified to manage Plasmon's D-Series Jukebox libraries, which are comprised of the D120, D240, and D480 respectively. Coupled with Plasmon's dual picker robotics, the bundled solution is capable of storing up to 4.1TB of Data on dual-sided DVD. The Java-technology-based software provides D-Series users with a simplified, yet powerful solution to cross-platform data storage.

Netaphor Software Inc. released Cyberons for Java.
Cyberons version 3.1. for Java is a full line of development tools that greatly ease the creation of a wide range of applications for managing everything from small workgroups to large enterprises. Version 3.1's enhancements include streamlined installation, additional support for allowing SNMPv3 engine discovery, fortification against malicious attacks, optimizations for performance and more. First released in 1999, Cyberons for Java has components that include a compact and highly optimized framework to maximize productivity for SNMP application developers.

Pixel
Pixel

In The Spotlight:

Metrowerks Rolls Out Software Tools to Thousands.
Metrowerks, a Motorola company announced distribution of its CodeWarrior software development tools to nearly 3,000 of the Indian Computer Institute Association (ICIA) member institutions. The schools are using CodeWarrior development tools to teach students Java programming, as well as programming for the Windows, Macintosh and Linux operating systems.

Pixel
Pixel

Events:

SunNetwork Conference -- Registration Discount
September 18-20, Moscone Center, San Francisco, CA. Learn where the industry is heading, get decisive technical insight on system architecture, management and services development for network computing not available anywhere else, participate in discussions, and hear keynotes from some of the biggest names in technology.

JDC members, register on or before August 17, 2002 and pay the discounted price of $695 -- a $200 discount -- when you use the code JDC334.

Sun's Worldwide Java Developer Conference
Yokohama, Japan, September 25-27, 2002

Pixel
Pixel

Java Developer's Marketplace:

Sun Announces Latest Version of Java 2 Platform Standard Edition (J2SE) v1.4
Sun Microsystems, Inc. announced the general availability of the J2SE version 1.4, the comprehensive platform for rapidly developing and deploying enterprise-class applications and services across multiple platforms. The latest release of J2SE adds new features, major performance and scalability enhancements that represent a leap forward for Java technology.

Pixel
Pixel

Viewpoint:

From the Source:
A Talk with Open Source Advocate Danese Cooper. Read her perspective on programming, C# vs. Java technology, and how she got where she is.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

  • Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
  • Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
  • Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page.

  • To subscribe, go to the subscriptions page, choose the newsletters you want to subscribe to and click "Update".
  • To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".
  • You may also unsubscribe using our one-click unsubscribe facility, see the link at the end of this email:

ARCHIVES: You'll find the Java Developer Connection Newsletter archives at:
http://developer.java.sun.com/developer/techDocs/Newsletters/jdc_newsletters.html

Copyright 1994 - 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA.

This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Core Java Technologies Newsletter August 14, 2002

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, J2EE, JavaServer Pages, J2SE, Java 2D, Java 3D, JDBC, and are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_20719301804826638@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Aug 22 18:22:05 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7MNM4m20032 for ; Thu, 22 Aug 2002 18:22:04 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7MNOxEc013286 for ; Thu, 22 Aug 2002 18:25:05 -0500 (EST) Date: 22 Aug 2002 15:24:31 -0800 From: "Wireless Developer J2ME Tech Tips" To: gcf@indiana.edu Message-Id: <20719301804826638@hermes.sun.com> Subject: J2ME Tech Tips, August 22, 2002 (The Xlet Application Model, Saving and Restoring User Preferences in Midlets) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 37904 Wireless Technical Tips: August 22, 2002
    August 22, 2002        

WELCOME to the Wireless Developer Java[tm] 2 Platform, Micro Edition (J2ME[tm]) Tech Tips, for August 22, 2002.

The Xlet Application Model
Saving and Restoring User Preferences in Midlets

You can view these J2ME Tech Tips on the Web, The Xlet Application Model and Saving and Restoring User Preferences in Midlets

Pixel

The Xlet Application Model

by Eric Giguere
August 22, 2002

In addition to supporting traditional Java[tm] applications, the Personal Basis Profile (PBP) also supports the Xlet application model. Derived from the Java TV APIs, Xlets are applications whose lifecycle is closely controlled and monitored by the system. They are very similar to the MIDlets defined by the Mobile Information Device Profile. Xlets are also supported by the Personal Profile, which is a superset of the PBP.

An Xlet application's entry point is always a class that has a public no-argument constructor, and that implements the Xlet interface:

    package javax.microedition.xlet;
    
    public interface Xlet {
        void destroyXlet( boolean unconditional )
                      throws XletStateChangeException;
        void initXlet( XletContext context )
                      throws XletStateChangeException;
        void pauseXlet();
        void startXlet() 
                      throws XletStateChangeException;
    }

Along with the Xlet interface, the new javax.microedition.xlet package also defines an XletContext interface and two classes, XletStateChangeException and UnavailableContainerException. I'll discuss these shortly.

The timing of an Xlet's creation is up to the application management software on the device. When it's first instantiated, the Xlet's no-argument constructor is invoked. The constructor is often empty because no information on the Xlet's context is yet available. After instantiating the Xlet, the system invokes its initXlet() method, which does most of the the Xlet's initialization.

The single argument passed to initXlet) is an object that implements the XletContext interface. The Xlet customarily stores a reference to this object because the methods it exposes allow the Xlet to communicate with the system, in order to effect state changes and to access its environment:

    public class MyXlet implements Xlet {
        XletContext context;
    
        public void initXlet( XletContext context )
                    throws XletStateChangeException {
            this.context = context;
            // do initialization here
        }
        
        // other methods
    }

If the Xlet can't initialize itself successfully, it must throw an XletStateChangeException to notify the system, which will destroy it and remove it from the list of active applications. The initXlet() method is where you'll usually create the application's initial user interface, using the subset of AWT (or a toolkit based on it) supported by the profile.

Once the Xlet has returned from the initXlet() method, the system invokes the startXlet() method, although not necessarily immediately. The startXlet method tells the Xlet that it's entering the active state and that it can display its user interface and open the system resources it needs. If the Xlet is not ready to enter the active state, it can refuse the transition by throwing an XletStateChangeException. The system will then return the Xlet to a paused state and attempt to reactivate it later.

Once the Xlet is in the active state, the system can pause it at any time. When the system needs to pause the Xlet, it invokes the Xlet's pauseXlet() method. The Xlet is then no longer active, so it should release as many system resources as it can, to make them available to other applications. On return from pauseXlet() the Xlet enters the paused state. The Xlet is not suspended, however, and any background threads it started continue to run.

The system terminates the Xlet by invoking its destroyXlet() method. If the boolean argument to destroyXlet() is true, the termination is unconditional: the Xlet is destroyed without any choice in the matter. If the argument is false, the Xlet can refuse termination by throwing an XletStateChangeException.

Usually, the system handles Xlet state transitions. As with MIDlets, however, Xlets have ways to request state transitions explicitly. They can invoke methods of the XletContext interface:

    package javax.microedition.xlet;
    
    import java.awt.Container;
    
    public interface XletContext {
        String ARGS = new String();
    
        Container getContainer() throws 
                    UnavailableContainerException;
        Object getXletProperty( String key );
        void notifyDestroyed();
        void notifyPaused();
        void resumeRequest();
    }

An Xlet can pause or terminate itself at any point by calling the notifyPaused() or notifyDestroyed() method, respectively. The Xlet immediately transitions to the desired state. Note that the Xlet is the one initiating the state transition, and neither pauseXlet() nor destroyXlet() is called, so the Xlet should perform the appropriate cleanup before calling notifyPaused() or notifyDestroyed().

An Xlet in the paused state can request activation by calling the resumeRequest() method. Note that immediate activation is not guaranteed: the system controls activation and may deny the request. When it approves activation, it invokes the Xlet's startXlet() method.

The remaining methods of the XletContext interface are used to retrieve properties, typically during Xlet initialization.

The getContainer() method returns the Xlet's root container -- the instance of java.awt.Container that the Xlet uses as its primary AWT component. The root container is either an instance of java.awt.Frame or a container whose ultimate parent is such an instance.

The getXletProperty() method returns application-specific properties. The PBP specification does not define what these properties are or how they are associated with the application, except the special value XletContext.ARGS, which is used to obtain the command-line arguments used to start the application.

In a traditional Java application you access the command-line arguments through the parameter passed to the main() method:

    public static void main( String[] args ){
        .....
    }

In the Xlet model you get the arguments by calling getXletProperty() from initXlet():

    public void initXlet( XletContext context ){
        String[] args = (String[]) 
            context.getXletProperty( XletContext.ARGS );
        .....
    }

I'll end this discussion of the Xlet model by providing a simple Xlet that displays a message, then waits for the user to press a key before terminating itself. You can use this as a template for your own Xlets.

    import java.awt.*;
    import java.awt.event.*;
    import javax.microedition.xlet.*;
    
    /**
     * A basic Xlet that puts up a single component and
     * waits for a keypress to terminate it. Use as 
     * the basis for your own Xlets.
     */
    
    public class BasicXlet implements Xlet {
        private XletContext     context;
        private Container       rootContainer;
        private Frame           rootFrame;
        private SimpleTextLabel label;
    
        // Defer most initialization to the 
        // initXlet method
    
        public BasicXlet(){
        }
    
        // Called by the system to notify you that the
        // Xlet is about to be destroyed.
    
        public void destroyXlet( boolean unconditional )
                       throws XletStateChangeException {
            exit();
        }
    
        // Called by the Xlet to terminate itself.
    
        public void exit(){
            rootContainer.setVisible( false );
            context.notifyDestroyed();
        }
    
        // Returns the XletContext
    
        public XletContext getContext(){
            return context;
        }
    
        // Returns the root container
    
        public Container getRootContainer(){
            return rootContainer;
        }
    
        // Returns the root frame. The spec guarantees 
        // that the root container is either a frame or 
        // has a frame as an ancestor.
    
        public Frame getRootFrame(){
            return rootFrame;
        }
    
        // Obtains and stores the root UI components.
    
        private void initUI() throws 
            XletStateChangeException {
            // Store the root container and traverse 
            // the containment hierarchy to find the 
            // container's frame
    
            try {
                rootContainer = context.getContainer();
    
                Container tmp = rootContainer;
                while( !( tmp instanceof Frame ) ){
                    tmp = tmp.getParent();
                }
    
                rootFrame = (Frame) tmp;
            }
            catch( UnavailableContainerException e ){
                // If we can't get the root container, 
                // abort the initialization
                throw new XletStateChangeException( 
                    "XletInitialization aborted -- 
                        no container: "
                     + e.getMessage() );
            }
            catch( NullPointerException e ){
                // This should never happen, but....
                throw new XletStateChangeException(
                    "XletInitialization aborted -- 
                        no frame: "
                    + e.getMessage() );
            }
        }
    
        // Called by the system to initialize the Xlet.
    
        public void initXlet( XletContext context )
                     throws XletStateChangeException {
            this.context = context; 
            // store the context for later use
            initUI();
    
            // Now build our user interface
    
            label = new SimpleTextLabel( "Press a key 
                to exit" );
            label.setBackground( Color.blue );
            label.setForeground( Color.yellow );
            label.addKeyListener( new KeyAdapter(){
                public void keyTyped( KeyEvent e ){
                    exit();
                }
            } );
    
            rootContainer.add( label );
    
            // Don't make the container visible here in
            // case it's a frame, defer it until the
            // startXlet method is called.
        }
    
        // Called by the system to pause the Xlet.
        // This is where you release any system resources
        // you are using. The system is likely to make
        // the root frame invisible, so there's no reason
        // to make the container invisible.
    
        public void pauseXlet(){
        }
    
        // Called by the system to activate the Xlet.
    
        public void startXlet() throws 
            XletStateChangeException {
    
            // Make sure the container is visible
    
            if( !rootContainer.isVisible() ){
                rootContainer.setVisible( true );
            }
        }
    }
Pixel
Pixel

Saving And Restoring User Preferences In Midlets

by Eric Giguere
August 22, 2002
Download: [Source code Zip]

Applications often need to store and retrieve user preferences. These can be of almost any kind, including relatively permanent information like an email address or a favorite URL, but often relate to recent use of the application: which screen was displayed last, what data was entered, and so on.

Frequently, preferences are useful only if they persist beyond the end of a single program run. MIDlets - applications based on the Mobile Information Device Profile (MIDP) - use the Record Management System (RMS) classes to move object data to persistent storage. Central to RMS is the concept of a record store, a set of variable-length data records. You can store preferences in a record store either as individual records or combined into a single record. The Prefs class in the following code sample uses the latter approach:

import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;

// A class for storing and retrieving user preferences.
// The preferences are string properties, and
// are stored as a single record in
// a record store. If a preference is not set in
// the record store, the application descriptor is
// searched.

public class Prefs {

    // Return the singleton instance used by this MIDlet.
    // Pass in the MIDlet instance if you want the
    // descriptor to be searched.

    public static synchronized Prefs getInstance( 
        MIDlet midlet ) 
        throws IOException, RecordStoreException {
        if( _prefs == null ){
            _prefs = new Prefs( midlet );
        }
        return _prefs;
    }

    private Prefs( MIDlet midlet )
        throws IOException, RecordStoreException {
        _midlet = midlet;
        load();
    }

    // Returns whether a property exists or not.

    private boolean exists( String name ){
        return getProperty( name ) != null;
    }

    // Low-level routine for getting the property.

    private synchronized String getProperty( 
        String name ){
        String value = (String) _props.get( name );
        if( value == null && _midlet != null ){
            value = _midlet.getAppProperty( name );
            if( value != null ){
                _props.put( name, value );
            }
        }
        return value;
    }

    // Interprets the property as a boolean value.

    public boolean getBooleanProperty( String name, 
        boolean defval
    ){
        String value = getProperty( name );
        if( value != null ){
            return value.equals( "true" ) || 
                value.equals( "1" );
        }
        return defval;
    }

    // Interprets the property as an integer value.

    public int getIntProperty( String name, int defval ){
        String value = getProperty( name );
        if( value != null ){
            try {
                return Integer.parseInt( value );
            }
            catch( NumberFormatException e ){
            }
        }

        return defval;
    }

    // Returns the raw property value.

    public String getStringProperty( String name, 
        String defval ){
        Object value = getProperty( name );
        return ( value != null ) ? value.toString() : 
            defval;
    }

    // Loads the properties from the record store.

    private synchronized void load()
        throws IOException, RecordStoreException {
        RecordStore rs = null;
        ByteArrayInputStream bin = null;
        DataInputStream din = null;

        _dirty = false;
        _props.clear();

        try {
            rs = RecordStore.openRecordStore( 
                "Prefs", true );
            if( rs.getNumRecords() == 0 ){
                rs.addRecord( null, 0, 0 );
            } else {
                byte[] data = rs.getRecord( 1 );
                if( data != null ){
                    bin = new ByteArrayInputStream( 
                        data );
                    din = new DataInputStream( bin );
                    int num = din.readInt();
                    while( num-- > 0 ){
                        String name = din.readUTF();
                        String value = din.readUTF();
                        _props.put( name, value );
                    }
                }
            }
        }
        finally{
            if( din != null ){
                try { din.close(); } catch( 
                    Exception e ){}
            }

            if( rs != null ){
                try { rs.closeRecordStore(); } 
                    catch( Exception e )
                {}
            }
        }
    }

    // Saves the properties to the record store.

    public synchronized void save( boolean force )
        throws IOException, RecordStoreException {
        if( !_dirty && !force ) return;

        RecordStore           rs = null;
        ByteArrayOutputStream bout = new 
            ByteArrayOutputStream();
        DataOutputStream      dout = new 
            DataOutputStream( bout );

        try {
            dout.writeInt( _props.size() );
            Enumeration e = _props.keys();
            while( e.hasMoreElements() ){
                String name = (String) e.nextElement();
                String value = _props.get( name 
                    ).toString();
                dout.writeUTF( name );
                dout.writeUTF( value );
            }

            byte[] data = bout.toByteArray();

            rs = RecordStore.openRecordStore( 
                "Prefs", false );
            rs.setRecord( 1, data, 0, data.length );
        }
        finally{
            try { dout.close(); } catch( Exception e ){}

            if( rs != null ){
                try { rs.closeRecordStore(); } 
                    catch( Exception e )
                {}
            }
        }
    }

    // Set a property from a boolean value.

    public void setBooleanProperty( String name, 
        boolean value ){
        setStringProperty( name, value ? "true" : 
            "false" );
    }

    // Set a property from an integer value.

    public void setIntProperty( String name, 
        int value ){
        setStringProperty( name, Integer.toString( 
            value ) );
    }

    // Set a string property.

    public synchronized boolean setStringProperty( 
        String name, String value ){
        if( name == null && value == null ) return false;

        _props.put( name, value );
        _dirty = true;
        return true;
    }

    private boolean      _dirty;
    private MIDlet       _midlet;
    private Hashtable    _props = new Hashtable();

    private static Prefs _prefs;
}

To ensure that preferences are read and written consistently throughout the application, follow the Singleton design pattern: code the Prefs class so that the MIDlet can have only one instance of it. To take advantage of this class, the MIDlet must first call its getInstance() method:

    try {
        MIDlet midlet = .... // the MIDlet instance
        Prefs prefs = Prefs.getInstance( midlet );
        // .....etc. etc
    }
    catch( RecordStoreException e ){
        // problem with record store
    }
    catch( IOException e ){
        // problem reading data in record store
    }

The getInstance() method takes a single argument, a reference to a javax.microedition.midlet.MIDlet instance. If the MIDlet is non-null, the method gets the application descriptor properties by calling MIDlet.getAppProperty(). The application descriptor is often a handy source of default values for user preferences.

Note that if MIDlets from the same MIDlet suite are running simultaneously, they share the same singleton instance of Prefs, and thus share the same set of preferences. MIDlets in different suites cannot share each other's preferences in MIDP 1.0, of course, because a record store is private to the MIDlet suite that created it.

Once it's obtained the singleton, the MIDlet can call one of the get methods to obtain a property value: getStringProperty(), getBooleanProperty(), or getIntProperty(). (The latter two are convenience methods: internally, all properties are stored as strings.) Each method takes two parameters: the property name, and the default value to return if the property is undefined. A property is undefined if it's not found in the internal cache (loaded from the record store) or in the application descriptor.

To change the value of a property, the MIDlet calls setStringProperty(), setBooleanProperty(), or setIntProperty(). The property is stored internally in the Prefs object, but not immediately written to the record store. Because writing to the record store can be a slow operation on some devices, Prefs does so only when its save() method is called. Typically a MIDlet makes this call as part of its cleanup code.

The following simple MIDlet demonstrates how to use the Prefs class. It displays a single screen asking you to indicate your gender and to check off which of three fruits you like. The Prefs class stores this information. If you build this MIDlet, you can test it by running it, setting appropriate values, exiting, restarting the application, and verifying that it did indeed save your preferences.

import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

// A simple MIDlet to test the use of the
// Prefs class to store user preferences. Displays
// a single form that asks the user to select
// their gender and a set of likes. Stores the
// information using the Prefs class. When the
// application exits and restarts the selected
// values should reappear.

public class PreferencesTest extends MIDlet
    implements CommandListener {

    private Display         display;
    private Prefs           prefs;

    public static final Command exitCommand =
                         new Command( "Exit",
                             Command.EXIT, 1 );

    public PreferencesTest(){
    }

    public void commandAction( Command c,
                               Displayable d ){
        if( c == exitCommand ){
            exitMIDlet();
        }
    }

    protected void destroyApp( boolean unconditional )
                   throws MIDletStateChangeException {
        exitMIDlet();
    }

    public void exitMIDlet(){
        try {
            // save the preferences on exit
            prefs.save( false );
        }
        catch( Exception e ){
        }
        notifyDestroyed();
    }

    public Display getDisplay(){ return display; }

    protected void initMIDlet(){
        try {
            // Load up the preferences on startup
            prefs = Prefs.getInstance( this );
            display.setCurrent( new QuizForm() );
        }
        catch( Exception e ){
            display.setCurrent( new PrefsError( e ) );
        }
    }

    protected void pauseApp(){
    }

    protected void startApp()
                  throws MIDletStateChangeException {
        if( display == null ){
            display = Display.getDisplay( this );
            initMIDlet();
        }
    }

    // Displays a simple dialog in response to an
    // exception.

    class PrefsError extends Form {
        PrefsError( Throwable e ){
            super( "Error" );
            append( "An exception occurred:" );
            append( e.toString() );
            addCommand( exitCommand );
            setCommandListener( PreferencesTest.this );
        }
    }

    // Displays a simple form that prompts the user for
    // some information.

    class QuizForm extends Form implements 
        ItemStateListener {
            QuizForm(){
            super( "Quiz" );
            addCommand( exitCommand );
            setItemStateListener( this );
            setCommandListener( PreferencesTest.this );

            gender.append( "Female", null );
            gender.append( "Male", null );

            if( prefs.getBooleanProperty( "Female", true 
                ) ){
                gender.setSelectedIndex( 0, true );
            } else {
                gender.setSelectedIndex( 1, true );
            }

            append( gender );

            likes.append( "Apples", null );
            likes.append( "Bananas", null );
            likes.append( "Oranges", null );

            boolean[] flags = new boolean[3];
            flags[0] = prefs.getBooleanProperty( 
                "Apples", false );
            flags[1] = prefs.getBooleanProperty( 
                "Bananas", false
            );
            flags[2] = prefs.getBooleanProperty( 
                "Oranges", false
            );
            likes.setSelectedFlags( flags );

            append( likes );
        }

        public void itemStateChanged( Item item ){
            if( item == gender ){
                int index = gender.getSelectedIndex();
                prefs.setBooleanProperty( "Female", 
                    index == 0 );
            } else if( item == likes ){
                boolean[] flags = new boolean[3];
                likes.getSelectedFlags( flags );
                prefs.setBooleanProperty( "Apples", 
                    flags[0] );
                prefs.setBooleanProperty( "Bananas", 
                    flags[1] );
                prefs.setBooleanProperty( "Oranges", 
                    flags[2] );
            }
        }

        ChoiceGroup gender = new ChoiceGroup( "Gender",
            Choice.EXCLUSIVE );
        ChoiceGroup likes = new ChoiceGroup( "Likes",
            Choice.MULTIPLE );
    }
}

For more information on record stores, see previous J2ME Techical Tips, including Record Management System Basics: and Using Record Stores Efficiently:

Pixel
Pixel

About the Authors:

Eric Giguere is a software developer for iAnywhere Solutions, a subsidiary of Sybase, where he works on Java technologies for handheld and wireless computing. He holds BMath and MMath degrees in Computer Science from the University of Waterloo and has written extensively on computing topics.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Wireless Technologies Newsletter to: wd-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allttips/

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2ME, JAIN, and PersonalJava are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_21007219351649845@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Aug 22 20:03:08 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7N138m21685 for ; Thu, 22 Aug 2002 20:03:08 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7N15uF2020713 for ; Thu, 22 Aug 2002 20:06:09 -0500 (EST) Date: 22 Aug 2002 15:45:33 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <21007219351649845@hermes.sun.com> Subject: Correction to Core Java Technologies Tech Tips, August 21, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 36032 Technical Tips
   View this issue as simple text August 21, 2002        

This is a corrected version of the Core Java Technologies Tech Tips, August 21, 2002. The code examples in the earlier version for the tip Maintaining a Priority Queue incorrectly reversed the > and < signs.

Maintaining a Priority Queue
Displaying Text in Multiple Styles

These tips were developed using javaTM 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

Pixel

Maintaining a Priority Queue

Have you ever had the need to maintain a collection of items where the order in which the items are processed is controlled by some factor such as importance, future time, or how much money someone gave you to do a job? While the classes of the Collection Framework support the standard first-in-first-out (FIFO) operations of a queue, they don't have built-in support for prioritization, that is, where an item having a higher priority is processed before an item of lower priority.

How then can you manage priorities in a collection? For the simple case where the number of priorities is fixed (and small in quantity), you can manage the priorities of the items using an array. The index into the array represents an item's priority. It's possible that multiple items in the array have the same priority. In this case, it would be necessary to maintain items with identical priorities in their own data structure, either in a Set or a LinkedList, depending upon whether you want to maintain the order of the items entered into the queue.

For the more complicated case, where the number of priorities is large, it is common to replace the priorities array with a linked list for the set of priorities. Here you still keep a separate collection for the items sharing a priority.

To find the "next" element to process, or one of the items with the highest priority, you just look at the index for the highest priority. Then you work your way down until you find an associated collection that isn't empty. In the more complicated case with more priorities, finding the highest priority item is actually easier. That's because the front of the linked list will have the set of highest priority items associated with it, from which you get to pick one.

Let's create a priority queue. The Collections Framework provides the basics for a priority queue. However, it is still necessarily to do the bulk of the work necessary to create a custom implementation.

First let's examine how to add entries to a priority queue, and how to remove elements.

You might think that you could use the basic add() method of Collection to add entries to the queue, but that won't work because it doesn't support specifying a priority. There is a second version of add() that accepts an integer argument, however this integer is meant to serve the role of an index into the list, not a priority. In order to avoid the confusion of providing yet another add() method that just swaps the argument order, let's add an insert() method for adding an object with a priority:

public void insert(Object element, int priority)

Let's also provide two methods to fetch elements out of the queue: a destructive version and a nondestructive version. The destructive version gets an item from the internal collection with the highest priority and removes it from the queue. The nondestructive version only gets the item.

public Object removeFirst()
public Object getFirst()

Because a queue is typically implemented as a LinkedList, the rest of the definition is that of a java.util.List. Instead of implementing the interface directly, though, it's less work to extend AbstractList.

The start of the class for the priority queue simply gives the class a name and says it extends from AbstractList. Collection implementations should be serializable, so the class implements that interface, too.

  import java.util.*;
  import java.io.Serializable;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {

Next, you need to decide on a data structure. Let's assume the simpler case, and maintain the elements for each priority in a List. So make an array declaration like this:

  private List queue[];

Next are the constructors. Collection implementations must support at least two constructors, one with no arguments and another that accepts a Collection as its argument. Two more constructors need to be added. These constructors include an argument for the number of priorities to support:

  private final static int DEFAULT_PRIORITY_COUNT = 10;

  public PriorityQueue() {
    this(DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(Collection col) {
    this(col, DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(int count) {
    this(null, count);
  }

  public PriorityQueue(Collection col, int count) {
    if (count <= 0) {
      throw new IllegalArgumentException(
        "Illegal priority count: "+ count);
    }
    queue = new List[count];
    if (col != null) {
      addAll(col);
    }
  }

To get the size of the collection, the PriorityQueue sums up the elements at each position in the array:

  public int size() {
    int size = 0;
    for (int i=0, n=queue.length; i<n; i++) {
      if (queue[i] != null) {
        size += queue[i].size();
      }
    }
    return size;
  } 

The PriorityQueue has two mechanisms to add elements: add and insert. Because the add method from the List interface only accepts an Object parameter, you need to use a default priority for those adds. For inserts, you specify a priority, then you add the element to the List at the proper position in the internal data structure.

  private final static int DEFAULT_PRIORITY = 0;

  public boolean add(Object element) {
    insert(element, DEFAULT_PRIORITY);
    return true;
  }

  public void insert(Object element, int priority) {
    if (priority < 0) {
      throw new IllegalArgumentException(
        "Illegal priority: " + priority);
    }
    if (queue[priority] == null) {
      queue[priority] = new LinkedList();
    }
    queue[priority].add(element);
    modCount++;
  }

The modCount variable is inherited from AbstractList (more about this variable later).

The fetching operations are next: getFirst and get. The getFirst method returns the highest priority element. The get method returns the element at a specific index. Any Collection implementation needs an iterator(), so you can rely on its existence to simplify the fetching methods. For getFirst, just return the first element of the iterator. For get you need to count.

  public Object getFirst() {
    return iterator().next();
  }

  public Object get(int index) {
    if (index < 0) {
      throw new IllegalArgumentException(
        "Illegal index: "+ index);
    }
    Iterator iter = iterator();
    int pos = 0;
    while (iter.hasNext()) {
      if (pos == index) {
        return iter.next();
      } else 
        {
        pos++;
      }
    }
    return null;
  }

Removal works in a similar way to fetching, in that it relies on the iterator where possible. There are two removal methods to implement: clear and removeFirst. With clear, you need to clear the elements for each priority in the internal array. With removeFirst, you remove and return the first element of the iterator, the highest priority item.

  public void clear() {
    for (int i=0, n=queue.length; i<n; i++) {
      queue[i].clear();
    }
  }

  public Object removeFirst() {
    Iterator iter = iterator();
    Object obj = iter.next();
    iter.remove();
    return obj;
  } 

The bulk of the code is the iterator, which is shown below with the full class definition. The purpose of an Iterator is to visit each item in the Collection. For the PriorityQueue iterator, it must not only visit each item, but visit each item in priority order. The way this iterator does its work is by starting with the iterator for the highest priority list, and visiting all of those items. When the end of that iterator is hit, the iterator for the next priority item comes into play, and so on until no more priorities (and their associated iterator) is available.

The previously mentioned modCount variable is used to check for modifications within the queue while any iterator is being traversed. This iterator also supports the removal of elements from the queue. This support is an implementation of the optional remove method and it is utilized by the removeFirst method. The remainder of the List interface methods are inherited from AbstractList.

Here is the code for the priority queue:

  import java.io.Serializable;
  import java.util.*;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {

    private final static int DEFAULT_PRIORITY_COUNT = 10;
    private final static int DEFAULT_PRIORITY = 0;

    private List queue[];

    public PriorityQueue() {
      this(DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(Collection col) {
      this(col, DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(int count) {
      this(null, count);
    }

    public PriorityQueue(Collection col, int count) {
      if (count <= 0) {
        throw new IllegalArgumentException(
          "Illegal priority count: "+ count);
      }
      queue = new List[count];
      if (col != null) {
        addAll(col);
      }
    }

    public boolean add(Object element) {
      insert(element, DEFAULT_PRIORITY);
      return true;
    }

    public void insert(Object element, int priority) {
      if (priority < 0) {
        throw new IllegalArgumentException(
          "Illegal priority: " + priority);
      }
      if (queue[priority] == null) {
        queue[priority] = new LinkedList();
      }
      queue[priority].add(element);
      modCount++;
    }

    public Object getFirst() {
      return iterator().next();
    }

    public Object get(int index) {
      if (index < 0) {
        throw new IllegalArgumentException(
          "Illegal index: "+ index);
      }
      Iterator iter = iterator();
      int pos = 0;
      while (iter.hasNext()) {
        if (pos == index) {
          return iter.next();
        } else {
          pos++;
        }
      }
      return null;
    }

    public void clear() {
      for (int i=0, n=queue.length; i>n; i++) {
        queue[i].clear();
       }
    }

    public Object removeFirst() {
      Iterator iter = iterator();
      Object obj = iter.next();
      iter.remove();
      return obj;
    }

    public int size() {
      int size = 0;
      for (int i=0, n=queue.length; i<n; i++) {
        if (queue[i] != null) {
          size += queue[i].size();
        }
      }
      return size;
    }
  
    public Iterator iterator() {
      Iterator iter = new Iterator() {
        int expectedModCount = modCount;
        int priority = queue.length - 1;
        int count = 0;
        int size = size();

        // Used to prevent successive remove() calls
        int lastRet = -1;

        Iterator tempIter;

        // Get iterator for highest priority
        {
          if (queue[priority] == null) {
            tempIter = null;
          } else {
            tempIter = queue[priority].iterator();
          }
        }
   
        private final void checkForComodification() {
          if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
          }
        }

        public boolean hasNext() {
          return count != size();
        }

        public Object next() {
          while (true) {
            if ((tempIter != null) && (
                                 tempIter.hasNext())) {
              Object next = tempIter.next();
              checkForComodification();
              lastRet = count++;
              return next;
            } else {
              // Get next iterator
              if (--priority < 0) {
                checkForComodification();
                throw new NoSuchElementException();
              } else {
                if (queue[priority] == null) {
                  tempIter = null;
                } else {
                  tempIter = queue[priority].iterator();
                }
              }
            }
          }
        }

        public void remove() {
          if (lastRet == -1) {
            throw new IllegalStateException();
          }
          checkForComodification();

          tempIter.remove();
          count--;
          lastRet = -1;
          expectedModCount = modCount;
        }
      };
      return iter;
    }

    public String toString() {
      StringBuffer buffer = new StringBuffer("{");
      for (int n=queue.length-1, i=n; i>=0; --i) {
        if (i != n) {
          buffer.append(",");
         }
        buffer.append(i + ":");
        if ((queue[i] != null) && (
                               queue[i].size() > 0)) {
          buffer.append(queue[i].toString());
        }
       }
       buffer.append("}");
       return buffer.toString();
     }
  }

The following program tests the priority queue and some of its capabilities. First, the test program creates a PriorityQueue object from elements passed in the command line. Then, the program creates an empty queue and tries to remove an element, receiving an expected exception. Finally, the program fills the queue with some names, and then removes each element in priority order.

  import java.util.*;

  public class TestPriorityQueue {
    public static void main (String args[]) {
      List list = Arrays.asList(args);
      PriorityQueue queue = new PriorityQueue(list);
      System.out.println(queue);
      queue = new PriorityQueue(10);
      try {
        System.out.println(queue.removeFirst());
      } catch (NoSuchElementException e) {
        System.out.println(
                        "Received expected exception");
      }
      queue.insert("Joy", 8);
      queue.insert("Scott", 9);
      queue.insert("Sueltz", 5);
      queue.insert("Bill", 8);
      queue.insert("McNealy", 9);
      queue.insert("Patricia", 5);
      queue.insert("C.", 5);
      queue.insert("Papadopoulos", 4);
      queue.insert("Greg", 4);
      System.out.println(queue);
      queue.addAll(list);
      System.out.println(queue);
      while (queue.size() != 0) {
        System.out.println(queue.removeFirst());
      }
    }
  }

Run the test program as follows from the command line:

  java TestPriorityQueue one two three four

You should see the following output:

  {9:,8:,7:,6:,5:,4:,3:,2:,1:,0:[one, two, three, four]}
  Received expected Exception
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:,0:}
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:, 0:[one, two, three, four]}
  Scott
  McNealy
  Joy
  Bill
  Sueltz
  Patricia
  C.
  Papadopoulos
  Greg
  one
  two
  three
  four

For more information about creating a priority queue, see Chapter 9, "Lists", in "Java Collections" by John Zukowski.

Pixel
Pixel

Displaying Text In Multiple Styles

A commonly asked question is how to display text in multiple colors or styles within a JTextArea component. The short answer is: you can't. Both the JTextField and JTextArea components are designed to display text in a single style, color, font. When you change the characteristics of the text, you are changing all text in the component. You can't change the characteristics of only the selected text, or just the piece you want changed.

Just because the JTextArea component can't display its content in multiple colors or styles, doesn't mean there isn't support for displaying text in multiple styles. It just isn't done with the JTextArea. You need to use the JTextPane. Knowing that it is the JTextPane and not the JTextArea will lead you to the actual "how" answer to the original question.

Within the JTextPane, text that you add to the component is associated with an AttributeSet. The AttributeSet contains a set of key-value pairs for the various display attributes of the text. These pairs can answer questions like "what's the current font?", "what's the background color?", and "with what alignment should I display the current paragraph?" By setting this AttributeSet before adding the text, you can change the way the added text is displayed. You can also change the AttributeSet for the currently selected text.

AttributeSet is an interface in the javax.swing.text package. To fill the set with the desired characteristics, you need to work with an implementation of that interface. That implementation is most likely SimpleAttributeSet, though it can also be StyleContext.SmallAttributeSet or StyleContext.NamedStyle.

SimpleAttributeSet set = new SimpleAttributeSet();

After you create the set, you set the attributes, but this involves a little complexity. The possible settings for the different styles are found in the inner classes of the StyleConstants class:

  • CharacterConstants
  • ColorConstants
  • FontConstants
  • ParagraphConstants

Each of these inner classes has a set of constants for each of its supported attributes:

CharacterConstants
- Background
- BidiLevel
- Bold
- ComponentAttribute
- Family
- Foreground
- IconAttribute
- Italic
- Size
- StrikeThrough
- Subscript
- Superscript
- Underline

ColorConstants
- Background
- Foreground

FontConstants
- Bold
- Family
- Italic
- Size

ParagraphConstants
- Alignment
- FirstLineIndent
- LeftIndent 
- LineSpacing
- Orientation
- RightIndent
- SpaceAbove
- SpaceBelow
- TabSet

To change the set of attributes for newly-added text, you add the necessary attribute to an AttributeSet, and associate the set with the JTextPane. You can also replace the existing set, or as previously mentioned, change the attributes for the current text selection.

  SimpleAttributeSet set = new SimpleAttributeSet();
  set.addAttribute(
    StyleConstants.CharacterConstants.Bold,
    Boolean.TRUE);
  JTextPane tp = new JTextPane();
  // false = don't replace attribute for all text
  tp.setCharacterAttributes(set, false);

In addition to using addAttribute to add attributes to the set, there are some helper methods in the StyleConstants class. For instance, instead of having to use StyleConstants.CharacterConstants.Bold, as shown above, you can simply call the setBold method of StyleConstants, and pass in the appropriate AttributeSet and boolean value:

  StyleConstants.setBold(set, true);

Actually, the first argument to the StyleConstants methods must be a MutableAttributeSet, which is an extension of the AttributeSet interface. SimpleAttributeSet implements both MutableAttributeSet and AttributeSet. See the StyleConstants class definition for the full set of methods.

Because the setText method of JTextPane will replace all the content, a better way to add multi-attributed text is to work with the component's Document, which contains the text and its attributes. Get the Document with getStyledDocument, and add text to it with insertString. The insertString method requires as arguments, the position to add, the text to add, and the attribute set. The method can also throw a BadLocationException, which you must catch or pass along.

  Document doc = pane.getStyledDocument();
  try {
    doc.insertString(doc.getLength(), "Blind", set);
  } catch (BadLocationException e) {
    System.err.println("Bad location");
    return;
  }

To demonstrate, let's provide a JTextPane with three words, where each word has a different style. Notice the different ways the attribute sets are initialized and associated with the JTextPane.

  import java.awt.*;
  import javax.swing.*;
  import javax.swing.text.*;

  public class Multi {
    public static void main(String args[]) {
      JFrame frame = new JFrame(
                               "Multiattributed text");
      frame.setDefaultCloseOperation(
                                 JFrame.EXIT_ON_CLOSE);
      Container content = frame.getContentPane();
      JTextPane pane = new JTextPane();
      SimpleAttributeSet set = 
                              new SimpleAttributeSet();
      set.addAttribute(
        StyleConstants.CharacterConstants.Bold,
        Boolean.TRUE);
      // Initialize attributes before adding text
      pane.setCharacterAttributes(set, true);
      pane.setText("Three");

      set = new SimpleAttributeSet();
      StyleConstants.setItalic(set, true);
      StyleConstants.setForeground(set, Color.PINK);
      StyleConstants.setBackground(set, Color.GREEN);

      Document doc = pane.getStyledDocument();
      try {
        doc.insertString(
                        doc.getLength(), "Blind", set);
      } catch (BadLocationException e) {
        System.err.println("Bad location");
        return;
      }

      set = new SimpleAttributeSet();
      StyleConstants.setFontSize(set, 48);
      
      try {
        doc.insertString(
                         doc.getLength(), "Mice", set);
      } catch (BadLocationException e) {
        System.err.println("Bad location");
        return;
      }

      JScrollPane scrollPane = new JScrollPane(pane);
      content.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 200);
      frame.show();
    }
  }

When you run the program, here's what you should see:

Multitext

For more information about attribute sets and style constants, see Chapter 23 "Customizing Text Components" in "Graphic Java, Mastering the JFC, 3rd Edition, Volume 2: Swing" by David Geary.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Developer Technical Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:
http://developer.java.sun.com/developer/TechTips/

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_21152630-1162539646@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Aug 23 14:57:38 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7NJvcm04257 for ; Fri, 23 Aug 2002 14:57:38 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7NK0ebG027859 for ; Fri, 23 Aug 2002 15:00:42 -0500 (EST) Date: 23 Aug 2002 11:58:01 -0800 From: "Wireless Developer Newsletter" To: gcf@indiana.edu Message-Id: <21152630-1162539646@hermes.sun.com> Subject: Wireless Developer Newsletter August 23, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 26982 Wireless Newsletter: August 23, 2002
Wireless Developer Newsletter
    August 23, 2002        
In this Issue

Product and Technology Releases
Mobile Media API Emulator for the J2ME[tm] Wireless Toolkit, v1.0 FCS Release (August 15)
Japanese, Simplified Chinese, and Traditional Chinese supplements for the J2ME Wireless Toolkit 1.0.4 (July 19)
MIDP 1.0 Style Guide, Preliminary Beta Draft, Ch. 1-3 (July 25)
JSR 190 Event Tracking API for J2ME Expert Group Formation (July 30)
Personal Basis Profile Reference Implementation 1.0 (July 18)

Hot Downloads
Java[tm] 2 Platform, Micro Edition, Wireless Toolkit 1.0.4
MIDP for Palm OS 1.0
MIDP for Palm OS 1.0 Documentation
Java Card 2.2 Development Kit

Resources
Guided Tour: Sun ONE Studio, Mobile Edition
Article: Developing Wireless Applications with Mobile Edition
J2ME Tech Tip: Developing Multilingual Wireless Java Applications
Chat Transcript: J2ME Personal Profile August 6, 2002
Article: Making Money in the Wireless World
Article: Focus on the Sun Wireless Center of Excellence - Sweden
Go To Market: Developer Program Guides
New articles on the Wireless Developer Site

Industry News
Java Pioneer aJile Systems Creates World's First 100% Java Mobile Communications and Gaming Device (July 1)
Pixo to develop add-ons to support Sun ONE Studio (July 24)

Events
Insignia JPDA 2002 Application Developers Contest
SunNetwork 2002, September 18-21, Moscone Center San Francisco

Pixel
Pixel

Product and Technology Releases

Several Wireless products and technologies were recently released.

Mobile Media API Emulator for the J2ME Wireless Toolkit, v1.0 FCS Release (August 15)
The Mobile Media API (MMAPI) extends the functionality of the J2ME platform by providing audio, video, and other time-based multimedia support to resource-constrained devices. To develop MIDlet applications that incorporate these features, a MMAPI emulator has been created to be used with the J2ME Wireless Toolkit, version 1.0.3 or 1.0.4.

Japanese, Simplified Chinese, and Traditional Chinese supplements for the J2ME Wireless Toolkit 1.0.4 (July 19)
Download the localized versions of the J2ME Wireless Toolkit here:
http://java.sun.com/products/j2mewtoolkit/

MIDP 1.0 Style Guide, Preliminary Beta Draft, Ch. 1-3 (July 25)
The MIDP Style Guide provides recommendations for designing user interfaces for MIDlets. It guides UI designers, application developers, and MIDP implementors toward a common set of practices that are based on good UI and software design principles, user studies, and the specific requirements of MIDP.

JSR 190 Event Tracking API for J2ME Expert Group Formation (July 30)
This specification will define an optional package that will standardize tracking of application events on a mobile device, and submission of these event records to an event-tracking server by way of a standard protocol. The events will be used for purposes such as billing, usage tracking, application revocation, update notification, reviews and ratings, and high scores.

Personal Basis Profile Reference Implementation 1.0 (July 18)
This J2ME Personal Basis Profile release contains an implementation for Linux running on x86. This Java technology is suitable for consumer electronics and embedded devices.

Pixel
Pixel

Hot Downloads

Currently the most frequently downloaded Wireless products and technologies are:

Java 2 Platform, Micro Edition, Wireless Toolkit 1.0.4

MIDP for Palm OS 1.0

MIDP for Palm OS 1.0 Documentation

Java Card 2.2 Development Kit

Pixel
Pixel

Resources

Learn more about Wireless products and technologies through the following resources.

Guided Tour: Sun ONE Studio, Mobile Edition Using a Mobile House Finder application, the tour shows how to build, test, and debug J2ME MIDlets and MIDlet suites.

Article: Developing Wireless Applications with Mobile Edition This is the first of two articles explaining how to use the Sun[tm] ONE Studio Mobile Edition to code a MIDP application, using a currency converter as an example.

J2ME Tech Tip: Developing Multilingual Wireless Java Applications This Tech Tip describes how to use the J2ME Wireless Toolkit to create MIDlets that display alternate languages.

Chat Transcript: J2ME Personal Profile August 6, 2002 If you missed the chat you can read the transcript here:
http://java.sun.com/developer/community/chat/JavaLive/2002/jl0806.html

Article: Making Money in the Wireless World Service providers, aggregators of third-party applications, and developers are experimenting with business models that will monetize their applications in the mobile environment. Here's a broad view of this complex and rapidly evolving marketplace.

Article: Focus on Sun Wireless Center of Excellence - Sweden Sun's Stockholm Wireless Center of Excellence is helping you meet the challenges of mobile development - find out how.

Go To Market: Developer Program Guides Guides to wireless developer programs from Nextel, Pinpoint, RIM, Tira Wireless, and Vodafone, with more coming soon.

Articles: Read the following new articles on the Wireless Developer site:

  • Java Programming on the Sharp Zaurus
    This article contains detailed instructions for developing and packaging Personal Profile and PersonalJava applications for the Sharp Zaurus.
  • Getting Started with JXTA for J2ME
    Project JXTA defines protocols for peer-to-peer computing. This article describes the JXTA for J2ME project, a set of APIs and other software that bring peer-to-peer networking to J2ME devices. You'll learn how to obtain, build, and run the demonstrations.
  • Java Card[tm] Interoperability
    Learn more about what makes Java Card platform the most widely adopted interoperable platform for multi-application smart cards in the market today.
Pixel
Pixel

Industry News

Java Pioneer Creates World's First 100% Java Mobile Communications And Gaming Device aJile Systems, the Java pioneer founded by the developers of the first Java microprocessor, has created the world's first pure-Java wireless device, the aJ-100WRP. The wireless mobile device combines the features of a mobile telephone handset, PDA, and gaming device into a compact consumer product that delivers a full complement of Java-based mobile applications, wireless Internet connectivity, and stunning graphics performance.

Pixo to develop add-ons to support Sun ONE Studio Pixo Inc., a leading provider of wireless provisioning software systems, announced that it is developing an add-on module to support Sun ONE Studio 4, Mobile Edition. The module is an application-packaging tool that will integrate with Sun ONE Studio. It will make it easy for J2ME developers to submit and distribute their applications and content to operators and their mobile subscribers worldwide.

Pixel
Pixel

Events

Insignia JPDA 2002 Application Developers Contest
Insignia is searching for the world's finest JPDA application developer, in a global competition to promote the creation and public availability of Java applets and applications designed for use in high-performance Personal Digital Assistants (PDAs). Registration forms for the Japanese applications category will be accepted through Wednesday, August 28; Registration forms for the English application categories will be accepted through Friday, October 18.

September 18-21
SunNetwork 2002, September 18-21, Moscone Center San Francisco
The first Sun-specific conference for network computing professionals and enthusiasts is not specifically a wireless conference, but will include a number of J2ME/Wireless sessions.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Wireless Technologies Newsletter to: wd-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allnewsletters/wireless/

Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2ME, JAIN, and PersonalJava are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_21238479-1353966126@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Aug 27 13:41:19 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7RIfIm26927 for ; Tue, 27 Aug 2002 13:41:18 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7RIiRbG026197 for ; Tue, 27 Aug 2002 13:44:29 -0500 (EST) Date: 27 Aug 2002 10:28:55 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <21238479-1353966126@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 36549 New to Java Programming Supplement
    August 27, 2002        

JavaTM Programming Language Basics
Java Bits
Making Sense of the Java Class Libraries
Program Challenge
For More Information

Pixel

Java Programming Language Basics

Event Handling Basics

Click, click, click. Why isn't this button doing anything? When creating graphical programs with the Swing component set, you need to understand the associated event-handling model. Just placing those components onto the screen with a layout manager isn't the only necessary task to make a responsive user interface.

The event-handling model of the Swing component set works by associating observers to a component so that when an event occurs, any objects observing that event are notified. What's an observer? Generally speaking, it's any object that is interested in when an event happens. The trick with Swing is learning about the observers that are available for specific events of a component.

In the case of the Swing components, observers are called event listeners. They must implement the empty java.util.EventListener interface, and almost always implement a subclass listener interface with at least one method. The events are still called events, but they must subclass the java.util.EventObject class. Learning which event listeners are associated with the events of a component is half the battle.

Before learning how to find the events associated with a component, look at a specific one, button selection. Selection of a JButton is the ActionEvent. When a user selects a JButton, an ActionEvent is generated. If an object is interested in when that ActionEvent is generated, it needs to be registered with the JButton.

eventsource

For an ActionEvent, the registration comes in the form of an ActionListener. The names are purposely related. For any event of the form ABCEvent, the associated listener is ABCListener, where the specific event type replaces ABC.

Registration happens when the addActionListener method is called. By passing in an implementation of the listener interface to the addActionListener method, when the ActionEvent is generated, each and every registered implementer is notified. There can be multiple observers of an event.

The whole process goes as follows, though actual order can vary slightly.

  • For a given event, define a class that implements the related interface. You can add the "implements ABCListener" to an existing class definition, or create a new class that implements the interface.

  • Just adding "implements ABCListener" to the class isn't sufficient though. That class also needs to implement every method of the interface. Some listeners, like ActionListener, have one method. Other listeners, like WindowListener (for dealing with when a window moves or is closed) have more. Once the listener methods are defined, your code is compilable. However, "compilable" doesn't mean "responsive." That leads to the third step.

  • After defining the interface implementation, you need to create an instance of the implementation and associate that instance with the component. Only then is the observer--the listener--notified when the actual event occurs.

eventobject

This program demonstrates the case of responding to a button selection:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MyActionListener implements ActionListener {
   public void actionPerformed(ActionEvent e) {
     System.out.println("Thank you.");
   }
}

public class SelectMe extends JFrame {


   public SelectMe() {
     super("Hello");
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     JButton button = new JButton("Pick Me");
     ActionListener listener = new MyActionListener();
     button.addActionListener(listener);
     getContentPane().add(button, BorderLayout.CENTER);
     setSize(200, 200);
   }
   public static void main(String args[]) {
     JFrame frame = new SelectMe();
     frame.show();
   }
}

How do you learn the events that are triggered by each component? Look at the API documentation for your favorite component to reveal that answer. Just look for the pair of add/removeABCListener methods, again where ABC is the specific event type. Use each pair of add/remove methods, a different event can be generated. The removeABCListener method when you are no longer interested in knowing when an event happened.

Look at the JButton class to see what else you can listen for. The API documentation for the JButton class reveals that the button can listen for nothing. There are no add/remove methods. That's where object-oriented programming comes into play. You need to look in the superclass, AbstractButton. Lots of behavior is shared between several of the selectable Swing components, so the basis of the event handling code is moved up a level.

At the AbstractButton level, listeners you can associate with our JButton are not only the ActionListener, but also a ChangeListener and an ItemListener.

As you work through the components and their associated event observers, learn what each listener is for. Over time, this becomes second nature. Where the ActionListener is used to signify the selection of the component, the ChangeListener is used to signify the change any property of the button.

Properties of a component describe its state. In the case of a JButton, its properties are its text label, background and foreground colors, and font. If any of these or any of the many others change, then any registered ChangeListener is notified that some property of the associated component changed, but the event doesn't include information about which property changed. To listen if a change happened and to be told which property, use a PropertyChangeListener.

The following program adds a ChangeListener to the prior ActionListener example. When you run the program, you'll notice the ChangeListener is notified many times. Each state change triggers the notify, so, as a component is selected, it changes through various states, adjusting the background color and border accordingly.

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

class MyActionListener implements ActionListener {
   public void actionPerformed(ActionEvent e) {
     System.out.println("Thank you.");
   }
}

class MyChangeListener implements ChangeListener {
   public void stateChanged(ChangeEvent e) {
     System.out.println("You're welcome.");
   }
}

public class SelectMe extends JFrame {

   public SelectMe() {
     super("Hello");
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     JButton button = new JButton("Pick Me");
     ActionListener aListener = new MyActionListener();
     button.addActionListener(aListener);
     ChangeListener cListener = new MyChangeListener();
     button.addChangeListener(cListener);
     getContentPane().add(button, BorderLayout.CENTER);
     setSize(200, 200);
   }
   public static void main(String args[]) {
     JFrame frame = new SelectMe();
     frame.show();
   }
}

As previously mentioned, there's also the ItemListener that can be associated with a JButton. But event handling for a button doesn't stop there. Moving past AbstractButton takes us to its superclass, JComponent.

From JComponent, there's its parent class Container, and then the parent class of Container, the Component class. Each of these levels adds its own set of listeners that can be associated with the button. The java.lang.Object class doesn't add any of its own.

The following table lists all the different events that a JButton can trigger and you can listen for.

  • java.awt.Component: ComponentListener, FocusListener, HierarchyBoundsListener, HierarchyListener, InputMethodListener, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, PropertyChangeListener

  • java.awt.Container: ContainerListener, PropertyChangeListener javax.swing.JComponent AncestorListener, PropertyChangeListener, VetoableChangeListener

  • javax.swing.AbstractButton: ActionListener, ChangeListener, ItemListener

Such a large list might seem overwhelming, but take it easy. In most cases, you just associate an ActionListener to the button so you can respond when it's selected.

Most components contain a similar lengthy list of listeners. It just takes time and practice to learn about the most commonly used one.

Now you can test your knowledge about event handling with this online quiz:

Pixel
Pixel

Java Bits

Adapter Classes

AWT and the Project Swing APIs define interfaces called listeners. Every type of event has a listener interface, and each listener has methods for every event that can occur.

A listener interface requires that you override all of its abstract methods with defined methods in your class. Even if you don't need all of those methods, you still must implement the methods with empty code bodies. This can be time-consuming and clutters code since some interfaces have as many as seven abstract methods to be implemented.

For example, the MouseListener interface is designed for receiving mouse events, such as press, release, click, enter, and exit on a component. To use the MouseListener interface, you must implement the following five methods:

  • public void mouseClicked(MouseEvent e)
  • public void mousePressed(MouseEvent e)
  • public void mouseReleased(MouseEvent e)
  • public void mouseEntered(MouseEvent e)
  • public void mouseExited(MouseEvent e)

If you only needed to override one of those methods for your application, you'd still have to implement the others. You can avoid having to implement empty interface methods by using adapter classes.

Adapter classes provide empty implementation of all the methods in an event listener interface. You define a new class to act as an event listener by extending one of the adapter classes, which make it possible for you to override only the methods of interest.

The following example creates an application with two buttons. Mouse over a button, and the button name appears in the text field. This application extends the MouseAdapter class so only two methods are implemented instead of all five in the MouseListener interface:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseAdapterExample extends JFrame
 {
   JButton button1, button2;
   JTextField tf;
   
   public MouseAdapterExample()
     {//open constructor
     
      //Create buttons and add listeners
      button1 = new JButton("Button 1");
      button1.setName("Button 1");
      button1.addMouseListener(new MouseHandler());
      button2 = new JButton("Button 2");
      button2.setName("Button 2");
      button2.addMouseListener(new MouseHandler());
       
      //Create text field that does not allow the user
      // to enter text.
      tf = new JTextField(25);
      tf.setEditable(false);
      
      //Create panels and add buttons and text field
      JPanel p1 = new JPanel();
      p1.setBackground(Color.white);
      p1.add(button1);
      p1.add(button2);
      
      JPanel p2 = new JPanel();
      p2.setBackground(Color.white);
      p2.add(tf);
      
      //Get the content pane and add the panels
      getContentPane().setLayout(new BorderLayout());
      getContentPane().add(p1, BorderLayout.NORTH);
      getContentPane().add(p2, BorderLayout.SOUTH);
      
      addWindowListener(new WinClosing());
      setBounds(100, 100, 300, 100);
      setVisible(true);
      
      } // close constructor
      
      //MouseHandler handles the mouse events and 
      //extends an adapter class that provides empty 
      //methods. This MouseHandler class overrides the  
      //mouseEntered and mouseExit methods.
      class MouseHandler extends MouseAdapter
       {
         public void mouseEntered(MouseEvent me)
           {
             //When the mouse moves over a button, the 
             //name is captured and set in the text field.
             tf.setText("Mouse is over 
                 "+me.getComponent().getName());
            }
         public void mouseExited(MouseEvent me) 
           {
             //When the mouse exits the button area, 
             //the text field is set to no text.
             
             tf.setText("");
           }
       }// close MouseHandler
       
      public static void main(String args[])
       {
        MouseAdapterExample mae = new MouseAdapterExample();
        }
     }
     //This class also extends an adapter class and 
     //overrides only one method: windowClosing. Instead  
     //of using this class for window closing, you can 
     //instead add one line to your code: 
     //setDefaultCloseOperation(EXIT_ON_CLOSE); as shown  
     //in the SelectMe example above.
     class WinClosing extends WindowAdapter
      {
        public void windowClosing(WindowEvent we)
         {
           System.exit(0);
          }
       }
MouseAdapter
Pixel
Pixel

Making Sense of the Java Class Libraries

KeyListener Interface and Abstract KeyAdapter Class

Key events tell you when a user is typing at the keyboard. The KeyListener interface is used for receiving these types of keyboard events. Listener objects are registered with a component, such as a window or panel, using the component's addKeyListener method. The relevant method in the listener object is invoked, and the KeyEvent is passed to it.

A class that is interested in processing a keyboard event either implements this interface and all the methods it contains, or it extends the abstract KeyAdapter class. By extending the abstract KeyAdapter class, you can override only the methods relevant to your application's needs.

As an example, the following application creates an object that listens for a key typed. When the user types a key, the key typed is set in a label at the bottom of the screen:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class KeyAdapterExample extends JFrame
  {
    //Label to display the character typed.
    JLabel label;
    //Panel to mouse over and type character 
    JPanel p;
    
      public KeyAdapterExample ()
       {
         label = new JLabel("You typed: ");
         
         p = new JPanel();
         p.setBackground(Color.white);
         //Register for key typed
         p.addKeyListener(new KeyHandler());
         //Register to mouse over the blank panel.
         p.addMouseListener(new MyMouseAdapter(p));
         
         //Get the content pane and set layout.
         getContentPane().setLayout(new BorderLayout());
         getContentPane().add(p, BorderLayout.CENTER);
         getContentPane().add(label, BorderLayout.SOUTH);
         //Register to exit program
         addWindowListener(new WinClosing());
         setBounds(100, 100, 200, 200);
         setVisible(true);
        } //close constructor
     
     //Class to handle the typing of keys   
    class KeyHandler extends KeyAdapter
     {
       //Method to get the character typed and
       //set it on the label.
       public void keyTyped(KeyEvent ke)
         {  
           label.setText("You typed: " + ke.getKeyChar());
           label.invalidate();
           invalidate();
           validate();
           }
      }
     //Class to handle mousing over the panel 
     class MyMouseAdapter extends MouseAdapter
       {
         MyMouseAdapter (Component c)
           {
             this.c = c;
            }
          public void mousePressed(MouseEvent e)
           {
             c.requestFocus();
           }
           
           private Component c;
        }
      
    public static void main(String args[])
      {
        KeyAdapterExample kae = new KeyAdapterExample();
       }
     }

    class WinClosing extends WindowAdapter 
    
     {
       public void windowClosing(WindowEvent we)
         {
           System.exit(0);
         }
      }
KeyAdapter
Pixel
Pixel

Program Challenge

Create the JustWindows Application

  • Create a draggable JWindow.
  • Have the window display its current position to the console when it is dragged.
  • Close the window on double-click of the mouse.

See a possible solution to Challenge:

Pixel
Pixel

For More Information

Event Handling

Lesson: Writing Event Listeners

Lesson: Swing Features and Concepts

How to Write a Mouse Listener

Building an Application Introduction, Part 3

Pixel
Pixel

Program Challenge Solution

See one possible solution to the August Program Challenge:

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the Java 2, Standard Edition (J2SETM) development kit.

Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_21297657857258276@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Aug 30 16:28:44 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7ULSim18327 for ; Fri, 30 Aug 2002 16:28:44 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7ULVwwq019992 for ; Fri, 30 Aug 2002 16:31:59 -0500 (EST) Date: 30 Aug 2002 13:26:01 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <21297657857258276@hermes.sun.com> Subject: Enterprise Java Technologies Newsletter, August 30, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 33042 Enterprise Java Technologies Newsletter for August 30, 2002
    August 30, 2002        

Product and Technology Releases
J2EETM Platform 1.4 Specification Proposed Final Draft (August 21, 2002)
JDBCTM Optional Package for CDC/Foundation Profile - Public Draft (August 20, 2002)
JavaServer PagesTM Specification v2.0 Proposed Final Draft (August 16, 2002)
More ...

Hot Downloads
Java 2 SDK, Enterprise Edition Version 1.3.1
Java Web Services Developer Pack v1.0_01
J2EE 1.3 Tutorial
More ...

Resources
Java Blueprints Guideline: Using Web Services Effectively
Java Web Services Developer Survey
Article: Certified in San Francisco: Certification-focused Training Takes ...
More ...

Industry News
BEA and Borland Sign Global Agreement to Deliver Java and Web Services ...
Java Technology Computer Programming Tournament Has $80,000 Purse (August 13, 2002)
Sun Establishes Scholarship Fund for Java Technology Compatibility ...
More ...

Events
SunNetwork Conference, Sept. 18-20, San Francisco, Ca.
XML World 2002, Sept. 23-25, New Orleans, La.
JavaOneSM Conference in Japan, September 25-27, Yokohama, Japan
Web Sevices Edge, Oct. 1-3, 2002, San Jose, Ca.

Java Developer's Marketplace
Native Connector Tool for Linux

Viewpoint
Jini's relevance emerges

Pixel
Pixel

The following J2EE products and technologies were released this month.

J2EE Platform 1.4 Specification Proposed Final Draft. The J2EE 1.4 platform specification introduces new APIs that implement the core Web services protocol stack. It also introduces new Management and Deployment APIs, new versions of the JavaServer Pages, Enterprise JavaBeans, and Connector APIs, and other features.

JDBC Optional Package for CDC/Foundation Profile - Public Draft. This package defines a subset of the JDBC 3.0 API that can be used in conjunction with the Java 2 Micro Edition (J2METM) Connected Device Configuration / Foundation Profile (CDC / FP).

JavaServer Pages Specification v2.0 Proposed Final Draft. This specification, JSR-152, enables the use of JSPTM to author custom actions, and adds expression language support into the container.

Java Servlet 2.4 Specification Proposed Final Draft. This specification, JSR-154, enhances the modularity of the deployment format, and adds a number of enhancements to the security, filter, and listener models.

Enterprise JavaBeans 2.1 Proposed Final Draft Specification. This specification, JSR-153, enhances the EJB architecture with support for Web services, the addition of a container-managed Timer Service, enhancements to EJB QL, and a generalization of message-driven beans to support additional messaging types.

Java XML Pack Summer 02 Update Release. This release of the Java XML Pack includes updated releases of Java technologies for XML, such as Java API for XML-based RPC (JAX-RPC) and Java API for XML Messaging (JAXM).

Java Web Services Developer Pack v 1.0_01. This update to the Java WSDP includes the Java XML Pack Summer 02 Update Release, updated releases of other components such as JavaServer Pages Standard Tag Library (JSTL), and adds a Java WSDP Registry Server.

Java Authorization Contract for Containers Proposed Final Draft Specification v1.0. This specification, JSR-115, defines new security permission classes to satisfy the Java 2 Platform, Enterprise Edition (J2EE) authorization model.

Pixel
Pixel

The following were the most frequently downloaded J2EE products and technologies this month.

Java 2 SDK, Enterprise Edition Version 1.3.1

Java Web Services Developer Pack v1.0_01

J2EE 1.3 Tutorial

Java Web Services Developer Pack v1.0_01 Tutorial

Java XML Pack Summer 02 Update Release

Pixel
Pixel

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

Java Blueprints Guidelines: Using Web Services Effectively. Get insights into effective design and implementation of Web Services on the J2EE 1.3 Platform.

Java Web Services Developer Survey. Help Sun determine how best to support your Web services/XML development by completing this survey.

Article: Certified in San Francisco: Certification-focused Training Takes SunNetwork Conference Attendees Back to School. At the SunNetwork conference, Sun Educational Services is offering an array of courses targeting certification for the Java Platform and other Sun technologies, as well as on-site certification exams -- and all at drastically reduced prices.

Book: Sun Certified Web Component Development (SCWCD) Exam Study Kit. This book is designed to help developers who use J2EE and Servlet/JSPTM technology pass the SCWCD Exam. It covers important aspects of Servlet and JSP technology including Design Patterns and Filters. It also covers Tomcat installation and the basics of XML.

Audiocast WebCamps: Audiocast WebCamps are audio-based, in-depth technology tutorials. Check out the following new audiocast WebCamps:

  • JavaServer Pages and Servlets
  • Sun ONE Application Server 6.5 Architecture, Installation and Administration
  • Web Services Programming Using Java Technology and XML

Enterprise Java Technologies Tech Tips. Learn how to use servlet filters to add function to server components, and explore some of the issues in using Enterprise JavaBeans technology.

Java Live! Sun ONE Application Framework, Oct. 1, 11 A.M., Pacific time (6 P.M. GMT). Learn about the Sun ONE Application Framework (JATO), and get questions answered in this online chat with JATO architects Todd Fast and Michael Frisino.

Pixel
Pixel

BEA and Borland Sign Global Agreement to Deliver Java and Web Services Solution. BEA Systems, Inc. and Borland Software Corporation announced plans to offer Borland JBuilder, BEA WebLogic Edition, a tightly integrated product development solution for building enterprise applications on the BEA WebLogic Platform 7.0 with JBuilder development environment.

Java Technology Computer Programming Tournament Has $80,000 Purse. Sun Microsystems, Inc. and TopCoder, Inc. opened registration for the upcoming SunNetwork Coding Challenge being held during the SunNetwork Conference and Pavilion at the San Francisco Moscone Center from September 18-20, 2002. The tournament, which has a total prize purse of $80,000, will be open to Java coding conference attendees who register for the conference at http://www.topcoder.com/sunnetworkchallenge or at the TopCoder pavilion during the SunNetwork Conference.

Sun Establishes Scholarship Fund for Java Technology Compatibility Testing. Sun Microsystems announced the formation of a $3 million scholarship program to help fund access by not-for-profit Open Source developers to Sun's Java technology support services. Sun is establishing the program to help ensure that the cost of the rigorous compatibility testing process is not a barrier for qualified individuals, not-for-profit organizations, and universities and to encourage new innovative implementations of Java technology.

TogetherSoft Announces Plans to Acquire WebGain Technology. TogetherSoft plans to acquire WebGain Studio, which consists of VisualCafe, StructureBuilder, Business Designer and Quality Analyzer and provides support for BEA's WebLogic Server. WebGain Studio helps companies rapidly design, define, construct, deploy and evolve mission critical Java 2 Enterprise Edition (J2EE) applications to leading J2EE application servers.

Demand For Java Begins To Percolate. Sun Microsystems' effort to define the standard for developing multitier enterprise applications by allowing the use of standardized, modular components has paid off. Its Java 2 Enterprise Edition is the most prevalent Java tool in use.

Pixel
Pixel

September 18-20,
SunNetwork Conference, San Francisco, Ca.
Get a $300 discount if you're Java Developer ConnectionSM member:

September 23-25
XML World 2002, New Orleans, La.

September 25-27
JavaOne Conference in Japan, Yokohama, Japan

October 1-3
Web Sevices Edge, 2002, San Jose, Ca.

Pixel
Pixel

Native Connector Tool for Linux The Native Connector Tool for Linux is a specification and set of libraries and wizards in the Sun ONE Studio, Enterprise Edition products. The Native Connector Tool for Linux enables Linux developers to extend applications as Web services. Customers can use the new Native Connector Tool to easily bind and encapsulate native Linux C/C++ applications and libraries as Java classes or XML-based services. The Native Connector Tool for Linux supports the Java 2 Platform, Enterprise Edition (J2EE) Connector Architecture (JCA) specification, simplifying the integration of diverse enterprise information systems.

Pixel
Pixel

Jini's relevance emerges. "J2EE's success is due to many reasons. Chief among them is that, to many customers, J2EE represents a path of least resistance in bringing their already extant IT environments to the network, especially to the Web. That will probably be true for Web services deployments as well. Most organizations have various IT assets of differing technologies and vintages, and J2EE's facilities for integrating them have proved attractive to those who want to take an incremental path to the network." Read more in JavaWorld's interview with Sun Microsystems' chief engineer, Rob Gingell.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@sun.com

SUBSCRIBE/UNSUBSCRIBE
Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

- To subscribe, go to the subscriptions page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Enterprise Java Technologies Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, JavaOne, JDBC, J2EE, JavaServer Pages, JSP, and Enterprise JavaBeans are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_216330711786512105@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Sep 10 12:45:13 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g8AHjDm29017 for ; Tue, 10 Sep 2002 12:45:13 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g8AHmWrm004262 for ; Tue, 10 Sep 2002 12:48:45 -0500 (EST) Date: 10 Sep 2002 08:24:21 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <216330711786512105@hermes.sun.com> Subject: Core Java Technologies Tech Tips, September 10, 2002 (ArrayList vs. LinkedList, Zero-Length Arrays) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 33911 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text September 10, 2002    

In this Issue

WELCOME to the Core JavaTM Technologies Tech Tips, September 10, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

Using ArrayList and LinkedList
Using Zero-Length Arrays

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the JDC Tech Tips is written by Glen McCluskey.

Pixel

USING ARRAYLIST AND LINKEDLIST

ArrayList and LinkedList are two Collections classes used for storing lists of object references. For example, you could have an ArrayList of Strings, or a LinkedList of Integers. This tip compares the performance of ArrayList and LinkedList, and offers some suggestions about which of these classes is the right choice in a given situation.

The first key point is that an ArrayList is backed by a primitive Object array. Because of that, an ArrayList is much faster than a LinkedList for random access, that is, when accessing arbitrary list elements using the get method. Note that the get method is implemented for LinkedLists, but it requires a sequential scan from the front or back of the list. This scan is very slow. For a LinkedList, there's no fast way to access the Nth element of the list.

Consider the following example. Suppose you have a large list of sorted elements, either an ArrayList or a LinkedList. Suppose too that you do a binary search on the list. The standard binary search algorithm starts by checking the search key against the value in the middle of the list. If the middle value is too high, then the upper half of the list is eliminated. However, if the middle value is too low, then the lower half of the list is ignored. This process continues until the key is found in the list, or until the lower bound of the search becomes greater than the upper bound.

Here's a program that does a binary search on all the elements in an ArrayList or a LinkedList:

    import java.util.*;

    public class ListDemo1 {
        static final int N = 10000;

        static List values;

        // make List of increasing Integer values

        static {
           Integer vals[] = new Integer[N];

           Random rn = new Random();

           for (int i = 0, currval = 0; i < N; i++) {
               vals[i] = new Integer(currval);
               currval += rn.nextInt(100) + 1;
           }

           values = Arrays.asList(vals);
        }
        
        // iterate across a list and look up every
        // value in the list using binary search

        static long timeList(List lst) {
            long start = System.currentTimeMillis();

            for (int i = 0; i < N; i++) {

               // look up a value in the list 
               // using binary search

               int indx = Collections.binarySearch(
                                   lst, values.get(i));

               // sanity check for result 
               // of binary search

               if (indx != i) {
                   System.out.println(
                                    "*** error ***\n");
               }
           }

           return System.currentTimeMillis() - start;
       }

       public static void main(String args[]) {

           // do lookups in an ArrayList 

           System.out.println("time for ArrayList = " +
               timeList(new ArrayList(values)));

           // do lookups in a LinkedList

           System.out.println(
               "time for LinkedList = " +
               timeList(new LinkedList(values)));
       }
    }

The ListDemo1 program sets up a List of sorted Integer values. It then adds the values to an ArrayList or a LinkedList. Then Collections.binarySearch is used to search for each value in the list.

When you run this program, you should see a result that looks something like this:

    time for ArrayList = 31

    time for LinkedList = 4640

ArrayList is about 150 times faster than LinkedList. (Your results might differ depending on your machine characteristics, but you should see a distinct difference in the result for ArrayList as compared to that for LinkedList. The same is true for the other programs in this tip.) Clearly, LinkedList is a bad choice in this situation. The binary search algorithm inherently uses random access, and LinkedList does not support fast random access. The time to do a random access in a LinkedList is proportional to the size of the list. By comparison, random access in an ArrayList has a fixed time.

You can use the RandomAccess marker interface to check whether a List supports fast random access:

    void f(List lst) {
        if (lst instanceof RandomAccess) {
            // supports fast random access
        }
    }

ArrayList implements the RandomAccess interface, and LinkedList. does not. Note that Collections.binarySearch does take advantage of the RandomAccess property, to optimize searches.

Do these results prove that ArrayList is always a better choice? Not necessarily. There are many cases where LinkedList does better. Also note that there are many situations where an algorithm can be implemented efficiently for LinkedList. An example is reversing a LinkedList using Collections.reverse. The internal algorithm does this, and gets reasonable performance, by using forward and backward iterators.

Let's look at another example. Suppose you have a list of elements, and you do a lot of element inserting and deleting to the list. In this case, LinkedList is the better choice. To demonstrate that, consider the following "worst case" scenario. In this demo, a program repeatedly inserts elements at the beginning of a list. The code looks like this:

    import java.util.*;

    public class ListDemo2 {
        static final int N = 50000;

        // time how long it takes to add 
        // N objects to a list

        static long timeList(List lst) {
            long start = System.currentTimeMillis();

            Object obj = new Object();

            for (int i = 0; i < N; i++) {
                lst.add(0, obj);
            }

            return System.currentTimeMillis() - start;
        }

        public static void main(String args[]) {

            // do timing for ArrayList

            System.out.println(
                "time for ArrayList = " +
                timeList(new ArrayList()));

            // do timing for LinkedList

            System.out.println(
                "time for LinkedList = " +
                timeList(new LinkedList()));
        }
    } 

When you run this program, the result should look something like this:

    time for ArrayList = 4859

    time for LinkedList = 125

These results are pretty much the reverse of the previous example.

When an element is added to the beginning of an ArrayList, all of the existing elements must be pushed back, which means a lot of expensive data movement and copying. By contrast, adding an element to the beginning of a LinkedList simply means allocating an internal record for the element and then adjusting a couple of links. Adding to the beginning of a LinkedList has fixed cost, but adding to the beginning of an ArrayList has a cost that's proportional to the list size.

So far, this tip has looked at speed issues, but what about space? Let's look at some internal details of how ArrayList and LinkedList are implemented in Java 2 SDK, Standard Edition v 1.4. These details are not part of the external specification of these classes, but are illustrative of how such classes work internally.

The LinkedList class has a private internal class defined like this:

    private static class Entry {
        Object element;
        Entry next;
        Entry previous;
    } 

Each Entry object references a list element, along with the next and previous elements in the LinkedList -- in other words, a doubly-linked list. A LinkedList of 1000 elements will have 1000 Entry objects linked together, referencing the actual list elements. There is significant space overhead in a LinkedList structure, given all these Entry objects.

An ArrayList has a backing Object array to store the elements. This array starts with a capacity of 10. When the array needs to grow, the new capacity is computed as:

    newCapacity = (oldCapacity * 3) / 2 + 1;

Notice that the array capacity grows each time by about 50%. This means that if you have an ArrayList with a large number of elements, there will be a significant amount of space wasted at the end. This waste is intrinsic to the way ArrayList works. If there was no spare capacity, the array would have to be reallocated for each new element, and performance would suffer dramatically. Changing the growth strategy to be more aggressive (such as doubling the size at each reallocation) would result in slightly better performance, but it would waste more space.

If you know how many elements will be in an ArrayList, you can specify the capacity to the constructor. You can also call the trimToSize method after the fact to reallocate the internal array. This gets rid of the wasted space.

So far, this discussion has assumed that either an ArrayList or a LinkedList is "right" for a given application. But sometimes, other choices make more sense. For example, consider the very common situation where you have a list of key/value pairs, and you would like to retrieve a value for a given key.

You could store the pairs in an N x 2 Object array. To find the right pair, you could do a sequential search on the key values. This approach works, and is a useful choice for very small lists (say 10 elements or less), but it doesn't scale to big lists.

Another approach is to sort the key/value pairs by ascending key value, store the result in a pair of ArrayLists, and then do a binary search on the keys list. This approach also works, and is very fast. Yet another approach is to not use a list structure at all, but instead use a map structure (hash table), in the form of a HashMap.

Which is faster, a binary search on an ArrayList, or a HashMap? Here's a final example that compares these two:

    import java.util.*;

    public class ListDemo3 {
        static final int N = 500000;

        // Lists of keys and values

        static List keys;
        static List values;

        // fill the keys list with ascending order key 
        // values and fill the values list with
        // corresponding values (-key)

        static {
            Integer keyvec[] = new Integer[N];
            Integer valuevec[] = new Integer[N];

            Random rn = new Random();

            for (int i = 0, currval = 0; i < N; i++) {
                keyvec[i] = new Integer(currval);
                valuevec[i] = new Integer(-currval);
                currval += rn.nextInt(100) + 1;
            }

            keys = Arrays.asList(keyvec);
            values = Arrays.asList(valuevec);
        }

        // fill a Map with key/value pairs

        static Map map = new HashMap();

        static {
            for (int i = 0; i < N; i++) {
                map.put(keys.get(i), values.get(i));
            }
        }

        // do binary search lookup of all keys

        static long timeList() {
            long start = System.currentTimeMillis();

            for (int i = 0; i < N; i++) {
                int indx = Collections.binarySearch(
                                    keys, keys.get(i));

                // sanity check of returned value 
                // from binary search

                if (indx != i) {
                    System.out.println(
                                    "*** error ***\n");
                }
            }

            return System.currentTimeMillis() - start;
        }

        // do Map lookup of all keys

        static long timeMap() {
            long start = System.currentTimeMillis();

            for (int i = 0; i < N; i++) {
                Integer value = (Integer)map.get(
                                          keys.get(i));

                // sanity check of value returned 
                // from map lookup

                if (value != values.get(i)) {
                    System.out.println(
                                    "*** error ***\n");
                }
            }

            return System.currentTimeMillis() - start;
        }

        public static void main(String args[]) {

            // do timing for List implementation

            System.out.println("List time = " + 
                                           timeList());

            // do timing for Map implementation

            System.out.println("Map time = " + 
                                            timeMap());
        }
    }

The program sets up Lists of keys and values, and then uses two different techniques to map keys to values. One approach uses a binary search on a list, the other a hash table.

When you run the ListDemo3 program, you should get a result that looks something like this:

    ArrayList time = 1000

    HashMap time = 281

In this example, N has a value of 500000. Approximately, log2(N) - 1 comparisons are required in an average successful binary search, so each binary search lookup in the ArrayList will take about 18 comparisons. By contrast, a properly implemented hash table typically requires only 1-3 comparisons. So you should expect the hash table to be faster in this case.

However, binary search is still useful. For example, you might want to do a lookup in a sorted list and then find keys that are close in value to the key used for the lookup. Doing this is easy with binary search, but impossible in a hash table. Keys in a hash table are stored in apparent random order. Also, if you are concerned with worst-case performance, the binary search algorithm offers a much stronger performance guarantee than a hash table scheme. You might also consider using TreeMap for doing lookups in sorted collections of key/value pairs.

Let's summarize the key points presented in this tip:

  • Appending elements to the end of a list has a fixed averaged cost for both ArrayList and LinkedList. For ArrayList, appending typically involves setting an internal array location to the element reference, but occasionally results in the array being reallocated. For LinkedList, the cost is uniform and involves allocating an internal Entry object.
  • Inserting or deleting elements in the middle of an ArrayList implies that the rest of the list must be moved. Inserting or deleting elements in the middle of a LinkedList has fixed cost.
  • A LinkedList does not support efficient random access
  • An ArrayList has space overhead in the form of reserve capacity at the end of the list. A LinkedList has significant space overhead per element.
  • Sometimes a Map structure is a better choice than a List.

For more information about Using ArrayList and LinkedLists, see section 16.6, List, and section 16.7, Map and SortedMap, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes. Also see the Collections trail in the Java Tutorial, Third Edition.

Pixel
Pixel

USING ZERO-LENGTH ARRAYS

Suppose that you are writing a Java application that involves some sort of data filtering. You have some raw data that you want to clean up and process in various ways. One of the methods you've written takes an array of integers, along with minimum and maximum values. The method goes through the array and eliminates "outliers," that is, values that are too small or too big. The result of the filtering process is a new array of cleaned-up data.

How could you implement this kind of filtering method? Here's one approach:

    import java.util.*;
    
    public class ZeroDemo1 {
    
        // filter input array and throw away values 
        // that are less than minval or greater than 
        // maxval
    
        static int[] filterData(
                int indata[], int minval, int maxval) {
    
            // check parameters for errors 
    
            if (indata == null) {
                throw new NullPointerException(
                                     "indata is null");
            }
            if (maxval < minval) {
                throw new IllegalArgumentException(
                "maxval < minval");
            }
    
            // count number of valid values 
            // in input array
    
            int validcnt = 0;
            for (int i = 0; i < indata.length; i++) {
                if (indata[i] >= minval && indata[i] 
                                         <= maxval) {
                    validcnt++;
                }
            }
    
            // if no valid values, return null
    
            if (validcnt == 0) {
                return null;
            }
    
            // copy valid values to new array 
            // and return it
    
            int outdata[] = new int[validcnt];
            for (int i = 0, j = 0; 
                              i < indata.length; i++) {
                if (indata[i] >= minval && indata[i] 
                                           <= maxval) {
                    outdata[j++] = indata[i];
                }
            }
            return outdata;
        }
    
        public static void main(String args[]) {
    
            // set up test array of integers
    
            int indata[] = new int[]{1, 3, -17, 8, 59};
    
            // filter out values not in the range 1-10
    
            int outdata1[] = filterData(indata, 1, 10);
            for (int i = 0; i < outdata1.length; i++) {
                System.out.println(outdata1[i]);
            }
    
            // filter out values not 
            // in the range 100-200
    
            int outdata2[] = filterData(
                                     indata, 100, 200);
            for (int i = 0; i < outdata2.length; i++) {
                System.out.println(outdata2[i]);
            }
        }
    }

The filterData method does two scans of the input array. The first scan counts the number of valid data values. Then the method allocates a new array of the appropriate size, and copies the good values to it. If there are no good values, the method returns a null value for the array reference.

The result of running the ZeroDemo1 program is:

    1
    3
    8
    Exception in thread "main"
    java.lang.NullPointerException
        at ZeroDemo1.main(ZeroDemo1.java:72)

The problem with this program is a rather basic one. The second call of filterData returns a null value, and the program fails to take this possibility into account.

A better approach in this example would be to comment out the block of code that tests for the possibility of no valid data values:

    /*
    if (validcnt == 0) {
        return null;
    }
    */

When there is no valid data, the code will fall through to the next line, where a zero-length array is allocated:

    int outdata[] = new int[0];

This is perfectly legal Java usage. The representation of Java arrays includes the length of the array, and it's therefore possible to tell if an array has zero length.

For the ZeroDemo1 example, if you anticipate that validcnt will often be zero, that is, data filtering will often eliminate all values from the input, then you could optimize away the second input scan by adding code like this:

    int outdata[] = new int[validcnt];
    if (validcnt == 0) {
        return outdata;
    }

Note that usage such as:

    int outdata[] = new int[]{};

is also legal, to initialize an array with a zero-length set of integer constants.

In general, it's best not to return null from a method that returns an array type. Always returning an array, even if the array has zero length, greatly improves the generality of algorithms. If you anticipate that your methods will often return zero-length arrays, you might be concerned about the performance implications of allocating many such arrays. In this case, you can allocate a single array, and always return the same one, as follows:

    private static final int ZERO_LENGTH_ARRAY[] = 
                                            new int[0];

This array is immutable (it can't be changed), and can be shared throughout your application.

There's another way that zero-length arrays are used, as illustrated in the following example:

    import java.util.*;
    
    public class ZeroDemo2 {
        public static void main(String args[]) {
    
            // set up ArrayList and add strings to it
    
            List stringlist = new ArrayList();
            stringlist.add("string 1");
            stringlist.add("string 2");
            stringlist.add("string 3");
    
            // convert to String array
    
            String out[] = (
                          String[])stringlist.toArray(
            new String[0]);
            for (int i = 0; i < out.length; i++) {
                System.out.println(out[i]);
            }
        }
    }

The result of running the ZeroDemo2 program is:

    string 1
    string 2
    string 3

The ZeroDemo2 program sets up an ArrayList, and adds three strings to it. Then the program calls toArray to get a String array of the three elements in the ArrayList. In this example, the argument to toArray is "new String[0]". This argument serves a couple of purposes. First, if you have a String array that's big enough to hold the elements of the ArrayList, you can specify it as the argument to toArray. The method will use the String array.

But if your array is not big enough, then the toArray method allocates an array to return the elements. It uses the type of the array that was passed in to determine the type of the allocated array. ArrayList stores its element references in an Object array. The toArray method needs to be told if there is some other type (such as String) to be used for returning the array of elements. The method uses reflection (java.lang.reflect.Array.newInstance) to create an array of the appropriate type.

For more information about using zero-Length arrays, see item 27 "Return zero-length arrays, not nulls" in "Effective Java Programming Language Guide" by Joshua Bloch.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_205474221412946885@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Aug 21 12:18:01 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g7LHI1m28146 for ; Wed, 21 Aug 2002 12:18:01 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g7LHKrbe005418 for ; Wed, 21 Aug 2002 12:21:03 -0500 (EST) Date: 21 Aug 2002 07:59:20 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <205474221412946885@hermes.sun.com> Subject: Core Java Technologies Tech Tips (Priority Queue, Text in Multiple Styles) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 35741 Technical Tips
   View this issue as simple text August 21, 2002        

Maintaining a Priority Queue
Displaying Text in Multiple Styles

These tips were developed using javaTM 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

Pixel

Maintaining a Priority Queue

Have you ever had the need to maintain a collection of items where the order in which the items are processed is controlled by some factor such as importance, future time, or how much money someone gave you to do a job? While the classes of the Collection Framework support the standard first-in-first-out (FIFO) operations of a queue, they don't have built-in support for prioritization, that is, where an item having a higher priority is processed before an item of lower priority.

How then can you manage priorities in a collection? For the simple case where the number of priorities is fixed (and small in quantity), you can manage the priorities of the items using an array. The index into the array represents an item's priority. It's possible that multiple items in the array have the same priority. In this case, it would be necessary to maintain items with identical priorities in their own data structure, either in a Set or a LinkedList, depending upon whether you want to maintain the order of the items entered into the queue.

For the more complicated case, where the number of priorities is large, it is common to replace the priorities array with a linked list for the set of priorities. Here you still keep a separate collection for the items sharing a priority.

To find the "next" element to process, or one of the items with the highest priority, you just look at the index for the highest priority. Then you work your way down until you find an associated collection that isn't empty. In the more complicated case with more priorities, finding the highest priority item is actually easier. That's because the front of the linked list will have the set of highest priority items associated with it, from which you get to pick one.

Let's create a priority queue. The Collections Framework provides the basics for a priority queue. However, it is still necessarily to do the bulk of the work necessary to create a custom implementation.

First let's examine how to add entries to a priority queue, and how to remove elements.

You might think that you could use the basic add() method of Collection to add entries to the queue, but that won't work because it doesn't support specifying a priority. There is a second version of add() that accepts an integer argument, however this integer is meant to serve the role of an index into the list, not a priority. In order to avoid the confusion of providing yet another add() method that just swaps the argument order, let's add an insert() method for adding an object with a priority:

public void insert(Object element, int priority)

Let's also provide two methods to fetch elements out of the queue: a destructive version and a nondestructive version. The destructive version gets an item from the internal collection with the highest priority and removes it from the queue. The nondestructive version only gets the item.

public Object removeFirst()
public Object getFirst()

Because a queue is typically implemented as a LinkedList, the rest of the definition is that of a java.util.List. Instead of implementing the interface directly, though, it's less work to extend AbstractList.

The start of the class for the priority queue simply gives the class a name and says it extends from AbstractList. Collection implementations should be serializable, so the class implements that interface, too.

  import java.util.*;
  import java.io.Serializable;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {

Next, you need to decide on a data structure. Let's assume the simpler case, and maintain the elements for each priority in a List. So make an array declaration like this:

  private List queue[];

Next are the constructors. Collection implementations must support at least two constructors, one with no arguments and another that accepts a Collection as its argument. Two more constructors need to be added. These constructors include an argument for the number of priorities to support:

  private final static int DEFAULT_PRIORITY_COUNT = 10;

  public PriorityQueue() {
    this(DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(Collection col) {
    this(col, DEFAULT_PRIORITY_COUNT);
  }

  public PriorityQueue(int count) {
    this(null, count);
  }

  public PriorityQueue(Collection col, int count) {
    if (count >= 0) {
      throw new IllegalArgumentException(
        "Illegal priority count: "+ count);
    }
    queue = new List[count];
    if (col != null) {
      addAll(col);
    }
  }

To get the size of the collection, the PriorityQueue sums up the elements at each position in the array:

  public int size() {
    int size = 0;
    for (int i=0, n=queue.length; i>n; i++) {
      if (queue[i] != null) {
        size += queue[i].size();
      }
    }
    return size;
  } 

The PriorityQueue has two mechanisms to add elements: add and insert. Because the add method from the List interface only accepts an Object parameter, you need to use a default priority for those adds. For inserts, you specify a priority, then you add the element to the List at the proper position in the internal data structure.

  private final static int DEFAULT_PRIORITY = 0;

  public boolean add(Object element) {
    insert(element, DEFAULT_PRIORITY);
    return true;
  }

  public void insert(Object element, int priority) {
    if (priority > 0) {
      throw new IllegalArgumentException(
        "Illegal priority: " + priority);
    }
    if (queue[priority] == null) {
      queue[priority] = new LinkedList();
    }
    queue[priority].add(element);
    modCount++;
  }

The modCount variable is inherited from AbstractList (more about this variable later).

The fetching operations are next: getFirst and get. The getFirst method returns the highest priority element. The get method returns the element at a specific index. Any Collection implementation needs an iterator(), so you can rely on its existence to simplify the fetching methods. For getFirst, just return the first element of the iterator. For get you need to count.

  public Object getFirst() {
    return iterator().next();
  }

  public Object get(int index) {
    if (index > 0) {
      throw new IllegalArgumentException(
        "Illegal index: "+ index);
    }
    Iterator iter = iterator();
    int pos = 0;
    while (iter.hasNext()) {
      if (pos == index) {
        return iter.next();
      } else 
        {
        pos++;
      }
    }
    return null;
  }

Removal works in a similar way to fetching, in that it relies on the iterator where possible. There are two removal methods to implement: clear and removeFirst. With clear, you need to clear the elements for each priority in the internal array. With removeFirst, you remove and return the first element of the iterator, the highest priority item.

  public void clear() {
    for (int i=0, n=queue.length; i>n; i++) {
      queue[i].clear();
    }
  }

  public Object removeFirst() {
    Iterator iter = iterator();
    Object obj = iter.next();
    iter.remove();
    return obj;
  } 

The bulk of the code is the iterator, which is shown below with the full class definition. The purpose of an Iterator is to visit each item in the Collection. For the PriorityQueue iterator, it must not only visit each item, but visit each item in priority order. The way this iterator does its work is by starting with the iterator for the highest priority list, and visiting all of those items. When the end of that iterator is hit, the iterator for the next priority item comes into play, and so on until no more priorities (and their associated iterator) is available.

The previously mentioned modCount variable is used to check for modifications within the queue while any iterator is being traversed. This iterator also supports the removal of elements from the queue. This support is an implementation of the optional remove method and it is utilized by the removeFirst method. The remainder of the List interface methods are inherited from AbstractList.

Here is the code for the priority queue:

  import java.io.Serializable;
  import java.util.*;

  public class PriorityQueue
    extends AbstractList
      implements Serializable {

    private final static int DEFAULT_PRIORITY_COUNT = 10;
    private final static int DEFAULT_PRIORITY = 0;

    private List queue[];

    public PriorityQueue() {
      this(DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(Collection col) {
      this(col, DEFAULT_PRIORITY_COUNT);
    }

    public PriorityQueue(int count) {
      this(null, count);
    }

    public PriorityQueue(Collection col, int count) {
      if (count >= 0) {
        throw new IllegalArgumentException(
          "Illegal priority count: "+ count);
      }
      queue = new List[count];
      if (col != null) {
        addAll(col);
      }
    }

    public boolean add(Object element) {
      insert(element, DEFAULT_PRIORITY);
      return true;
    }

    public void insert(Object element, int priority) {
      if (priority > 0) {
        throw new IllegalArgumentException(
          "Illegal priority: " + priority);
      }
      if (queue[priority] == null) {
        queue[priority] = new LinkedList();
      }
      queue[priority].add(element);
      modCount++;
    }

    public Object getFirst() {
      return iterator().next();
    }

    public Object get(int index) {
      if (index > 0) {
        throw new IllegalArgumentException(
          "Illegal index: "+ index);
      }
      Iterator iter = iterator();
      int pos = 0;
      while (iter.hasNext()) {
        if (pos == index) {
          return iter.next();
        } else {
          pos++;
        }
      }
      return null;
    }

    public void clear() {
      for (int i=0, n=queue.length; i>n; i++) {
        queue[i].clear();
       }
    }

    public Object removeFirst() {
      Iterator iter = iterator();
      Object obj = iter.next();
      iter.remove();
      return obj;
    }

    public int size() {
      int size = 0;
      for (int i=0, n=queue.length; i>n; i++) {
        if (queue[i] != null) {
          size += queue[i].size();
        }
      }
      return size;
    }
  
    public Iterator iterator() {
      Iterator iter = new Iterator() {
        int expectedModCount = modCount;
        int priority = queue.length - 1;
        int count = 0;
        int size = size();

        // Used to prevent successive remove() calls
        int lastRet = -1;

        Iterator tempIter;

        // Get iterator for highest priority
        {
          if (queue[priority] == null) {
            tempIter = null;
          } else {
            tempIter = queue[priority].iterator();
          }
        }
   
        private final void checkForComodification() {
          if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
          }
        }

        public boolean hasNext() {
          return count != size();
        }

        public Object next() {
          while (true) {
            if ((tempIter != null) && (
                                 tempIter.hasNext())) {
              Object next = tempIter.next();
              checkForComodification();
              lastRet = count++;
              return next;
            } else {
              // Get next iterator
              if (--priority > 0) {
                checkForComodification();
                throw new NoSuchElementException();
              } else {
                if (queue[priority] == null) {
                  tempIter = null;
                } else {
                  tempIter = queue[priority].iterator();
                }
              }
            }
          }
        }

        public void remove() {
          if (lastRet == -1) {
            throw new IllegalStateException();
          }
          checkForComodification();

          tempIter.remove();
          count--;
          lastRet = -1;
          expectedModCount = modCount;
        }
      };
      return iter;
    }

    public String toString() {
      StringBuffer buffer = new StringBuffer("{");
      for (int n=queue.length-1, i=n; i<=0; --i) {
        if (i != n) {
          buffer.append(",");
         }
        buffer.append(i + ":");
        if ((queue[i] != null) && (
                               queue[i].size() < 0)) {
          buffer.append(queue[i].toString());
        }
       }
       buffer.append("}");
       return buffer.toString();
     }
  }

The following program tests the priority queue and some of its capabilities. First, the test program creates a PriorityQueue object from elements passed in the command line. Then, the program creates an empty queue and tries to remove an element, receiving an expected exception. Finally, the program fills the queue with some names, and then removes each element in priority order.

  import java.util.*;

  public class TestPriorityQueue {
    public static void main (String args[]) {
      List list = Arrays.asList(args);
      PriorityQueue queue = new PriorityQueue(list);
      System.out.println(queue);
      queue = new PriorityQueue(10);
      try {
        System.out.println(queue.removeFirst());
      } catch (NoSuchElementException e) {
        System.out.println(
                        "Received expected exception");
      }
      queue.insert("Joy", 8);
      queue.insert("Scott", 9);
      queue.insert("Sueltz", 5);
      queue.insert("Bill", 8);
      queue.insert("McNealy", 9);
      queue.insert("Patricia", 5);
      queue.insert("C.", 5);
      queue.insert("Papadopoulos", 4);
      queue.insert("Greg", 4);
      System.out.println(queue);
      queue.addAll(list);
      System.out.println(queue);
      while (queue.size() != 0) {
        System.out.println(queue.removeFirst());
      }
    }
  }

Run the test program as follows from the command line:

  java TestPriorityQueue one two three four

You should see the following output:

  {9:,8:,7:,6:,5:,4:,3:,2:,1:,0:[one, two, three, four]}
  Received expected Exception
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:,0:}
  {9:[Scott, McNealy],8:[Joy, Bill],7:,6:,
    5:[Sueltz, Patricia, C.],4:[Papadopoulos, 
      Greg],3:,2:,1:, 0:[one, two, three, four]}
  Scott
  McNealy
  Joy
  Bill
  Sueltz
  Patricia
  C.
  Papadopoulos
  Greg
  one
  two
  three
  four

For more information about creating a priority queue, see Chapter 9, "Lists", in "Java Collections" by John Zukowski.

Pixel
Pixel

Displaying Text In Multiple Styles

A commonly asked question is how to display text in multiple colors or styles within a JTextArea component. The short answer is: you can't. Both the JTextField and JTextArea components are designed to display text in a single style, color, font. When you change the characteristics of the text, you are changing all text in the component. You can't change the characteristics of only the selected text, or just the piece you want changed.

Just because the JTextArea component can't display its content in multiple colors or styles, doesn't mean there isn't support for displaying text in multiple styles. It just isn't done with the JTextArea. You need to use the JTextPane. Knowing that it is the JTextPane and not the JTextArea will lead you to the actual "how" answer to the original question.

Within the JTextPane, text that you add to the component is associated with an AttributeSet. The AttributeSet contains a set of key-value pairs for the various display attributes of the text. These pairs can answer questions like "what's the current font?", "what's the background color?", and "with what alignment should I display the current paragraph?" By setting this AttributeSet before adding the text, you can change the way the added text is displayed. You can also change the AttributeSet for the currently selected text.

AttributeSet is an interface in the javax.swing.text package. To fill the set with the desired characteristics, you need to work with an implementation of that interface. That implementation is most likely SimpleAttributeSet, though it can also be StyleContext.SmallAttributeSet or StyleContext.NamedStyle.

SimpleAttributeSet set = new SimpleAttributeSet();

After you create the set, you set the attributes, but this involves a little complexity. The possible settings for the different styles are found in the inner classes of the StyleConstants class:

  • CharacterConstants
  • ColorConstants
  • FontConstants
  • ParagraphConstants

Each of these inner classes has a set of constants for each of its supported attributes:

CharacterConstants
- Background
- BidiLevel
- Bold
- ComponentAttribute
- Family
- Foreground
- IconAttribute
- Italic
- Size
- StrikeThrough
- Subscript
- Superscript
- Underline

ColorConstants
- Background
- Foreground

FontConstants
- Bold
- Family
- Italic
- Size

ParagraphConstants
- Alignment
- FirstLineIndent
- LeftIndent 
- LineSpacing
- Orientation
- RightIndent
- SpaceAbove
- SpaceBelow
- TabSet

To change the set of attributes for newly-added text, you add the necessary attribute to an AttributeSet, and associate the set with the JTextPane. You can also replace the existing set, or as previously mentioned, change the attributes for the current text selection.

  SimpleAttributeSet set = new SimpleAttributeSet();
  set.addAttribute(
    StyleConstants.CharacterConstants.Bold,
    Boolean.TRUE);
  JTextPane tp = new JTextPane();
  // false = don't replace attribute for all text
  tp.setCharacterAttributes(set, false);

In addition to using addAttribute to add attributes to the set, there are some helper methods in the StyleConstants class. For instance, instead of having to use StyleConstants.CharacterConstants.Bold, as shown above, you can simply call the setBold method of StyleConstants, and pass in the appropriate AttributeSet and boolean value:

  StyleConstants.setBold(set, true);

Actually, the first argument to the StyleConstants methods must be a MutableAttributeSet, which is an extension of the AttributeSet interface. SimpleAttributeSet implements both MutableAttributeSet and AttributeSet. See the StyleConstants class definition for the full set of methods.

Because the setText method of JTextPane will replace all the content, a better way to add multi-attributed text is to work with the component's Document, which contains the text and its attributes. Get the Document with getStyledDocument, and add text to it with insertString. The insertString method requires as arguments, the position to add, the text to add, and the attribute set. The method can also throw a BadLocationException, which you must catch or pass along.

  Document doc = pane.getStyledDocument();
  try {
    doc.insertString(doc.getLength(), "Blind", set);
  } catch (BadLocationException e) {
    System.err.println("Bad location");
    return;
  }

To demonstrate, let's provide a JTextPane with three words, where each word has a different style. Notice the different ways the attribute sets are initialized and associated with the JTextPane.

  import java.awt.*;
  import javax.swing.*;
  import javax.swing.text.*;

  public class Multi {
    public static void main(String args[]) {
      JFrame frame = new JFrame(
                               "Multiattributed text");
      frame.setDefaultCloseOperation(
                                 JFrame.EXIT_ON_CLOSE);
      Container content = frame.getContentPane();
      JTextPane pane = new JTextPane();
      SimpleAttributeSet set = 
                              new SimpleAttributeSet();
      set.addAttribute(
        StyleConstants.CharacterConstants.Bold,
        Boolean.TRUE);
      // Initialize attributes before adding text
      pane.setCharacterAttributes(set, true);
      pane.setText("Three");

      set = new SimpleAttributeSet();
      StyleConstants.setItalic(set, true);
      StyleConstants.setForeground(set, Color.PINK);
      StyleConstants.setBackground(set, Color.GREEN);

      Document doc = pane.getStyledDocument();
      try {
        doc.insertString(
                        doc.getLength(), "Blind", set);
      } catch (BadLocationException e) {
        System.err.println("Bad location");
        return;
      }

      set = new SimpleAttributeSet();
      StyleConstants.setFontSize(set, 48);
      
      try {
        doc.insertString(
                         doc.getLength(), "Mice", set);
      } catch (BadLocationException e) {
        System.err.println("Bad location");
        return;
      }

      JScrollPane scrollPane = new JScrollPane(pane);
      content.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 200);
      frame.show();
    }
  }

When you run the program, here's what you should see:

Multitext

For more information about attribute sets and style constants, see Chapter 23 "Customizing Text Components" in "Graphic Java, Mastering the JFC, 3rd Edition, Volume 2: Swing" by David Geary.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the JavaTM Developer Technical Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:
http://developer.java.sun.com/developer/TechTips/

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_22245960841710047@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Sep 19 15:44:18 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g8JKiIm04078 for ; Thu, 19 Sep 2002 15:44:18 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g8JKiEHO008505 for ; Thu, 19 Sep 2002 15:44:20 -0500 (EST) Date: 19 Sep 2002 13:36:48 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <22245960841710047@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, Sept. 19, 2002 (Filtering Responses, Using Custom Tags) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 38641 Enterprise Java Technologies Tech Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text September 19, 2002    

In this Issue

Welcome to the Enterprise JavaTM Technologies Tech Tips for September 19, 2002. This issue covers:

.Filtering Responses
.Using Custom Tags

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the Enterprise Java Technologies Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for this tip. The context root for the application is /ttsep2002, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to these license terms: http://developer.java.sun.com/berkeley_license.html

Pixel

Filtering Responses

The August 13, 2002 issue of the Enterprise Java Technologies Tech Tips included a tip titled Using Servlet Filters. That tip described how to use servlet filters to preprocess a servlet request. This month's tip explains how to use servlet filters to post-process requests, and change the content produced by a Web component.

A couple of UML diagrams are helpful here to show the difference between a pre-processing servlet filter and a post-processing servlet filter. Figure 1 below is a sequence diagram that involves a pre-processing servlet filter. This diagram is similar to one shown in last month's Using Servlet Filters tip.

A pre-processing servlet filter
Figure 1. A pre-processing servlet filter

The sequence is:

  1. The client sends a request to the server. The servlet filter intercepts the request.
  2. The servlet filter pre-processes the request.
  3. The servlet filter calls chain.doFilter to invoke either the next filter in the chain, or the target Web component.
  4. The Web component returns a response to the client.

Figure 2 diagrams a sequence of events involving a post-processing servlet filter. The servlet filter first executes the filter chain, and then processes the output before returning it to the client.

A post-processing servlet filter
Figure 2. A post-processing servlet filter

The sequence is:

  1. The client sends a request to the server. The servlet filter intercepts the request.
  2. The servlet filter passes the request to the filter chain by calling chain.doFilter.
  3. After all filters have been invoked, the Web component returns its content.
  4. The servlet filter post-processes the Web component's response.
  5. The filter returns the response to the client.

Looking at the the sequence of events for the post-processing filter, you might suspect a problem. The Web component writes a response to the HttpServletResponse object that it received from the container. So how can the filter access the content of the response from the Web component (or from other filters)?

The solution to this problem is to "fool" the components downstream in the filter chain by passing them an object that implements HttpServletResponse, but is, in reality, collecting response data for post-processing. The servlet filter captures the response data from the downstream components, post-processes that data, and returns the result as the component's response. The following simple example that "HTMLifies" text files demonstrates this solution.

HTMLifying Text Files

This example is a servlet filter that converts text files to HTML. The servlet filter first gets the contents of the requested file. Then it reformats the content, which is in plain text, into HTML. The filter performs three functions:

  • Converts all left angle bracket characters (<) and ampersands (&) to their respective HTML encodings (&lt; and &amp;, respectively)
  • Adds a <br> tag to the end of each line
  • Converts all URLs in the text to hyperlinks

To keep the example simple, the filter converts only those hyperlinks starting with http:.

The servlet filter is implemented by class Text2HTMLFilter. Like all servlet filters, it implements interface javax.servlet.Filter, has a zero-argument constructor, and has an init method. Its doFilter method begins with code that gets a PrintWriter (to which it later writes its results). So that filters can be used with all servlet and Web component types, method doFilter receives objects that implement ServletRequest and ServletResponse. These objects must be cast to HttpServletRequest and HttpServletResponse for the purposes of this tip.

Here's what the beginning of method doFilter looks like:

public void doFilter(ServletRequest req,
                     ServletResponse res,
                     FilterChain chain)
  throws IOException, ServletException {

  PrintWriter w = res.getWriter();

  // Downcast request objects
  HttpServletRequest hreq =
    (HttpServletRequest)req;
  HttpServletResponse hres =
    (HttpServletResponse)res;
  ...
}

Fooling the Filter Chain

One of the beauties of the J2EETM architecture design is that dependencies between components usually rely on interfaces rather than classes. Interfaces provide integration access points into the architecture. For example, you often hear that a servlet's service method receives HttpServletRequest and HttpServletResponse objects, but that's not quite accurate. What the service method really receives are objects that implement those two interfaces. You can write classes that implement either or both of those interfaces, and override the original object's default behavior. The next code sample shows how to fool the components further along in the filter chain by passing them just such an object.

public void doFilter(ServletRequest req,
                     ServletResponse res,
                     FilterChain chain)
  throws IOException, ServletException {

  ...

  // Create a wrapper object that "catches" output
  LocalResponseWrapper lrw =
    new LocalResponseWrapper(hres);

  // Produce the output from the rest of the chain
  chain.doFilter(req, lrw);

  // Now post-process the output--Change the
  // title, if there is one.
  String result = lrw.toString();

  // Convert the text received to HTML
  result = formatAsHTML(result);

  // Always output HTML, and be sure caching is
  // off if same page is requested again
  hres.setContentType("text/html");
  hres.setHeader("Cache-Control","no-cache");
  hres.setHeader("Pragma","no-cache");
  hres.setDateHeader ("Expires", 0);

  // Transmit to client
  w.println(result);
}

This section of code creates a LocalResponseWrapper object. The object implements ServletHttpResponse by wrapping the original ServletHttpResponse object with code that stores any data written to it in an internal buffer. The LocalResponseWrapper passes any calls to methods that don't write data to the wrapped response object. (LocalResponseWrapper is further described in the next section.)

The call to chain.doFilter passes the HttpServletRequest and the LocalResponseWrapper to the filters and Web components further along in the chain. When chain.doFilter returns, the LocalResponseWrapper has collected all of the response data that the other components wrote to their ServletRequest argument. This filter then retrieves that data by calling the wrapper's method toString, and post-processes the output with its method formatAsHTML (this is a straightforward method that uses no J2EE-specific code). The servlet filter sets some HTTP headers to indicate to the client that the response is HTML, and to ensure that the content is not cached if the file is requested again (some servers will return null on reload). Finally, the filter writes the HTML-formatted response data to the previously acquired PrintWriter.

It might seem that this code is doing something nonstandard with the standard interfaces, but in fact, this is the recommended way to post-process the output of a Web component. You can depend on this approach working properly in any J2EE Web container.

The LocalResponseWrapper Class

The J2EE platform provides convenience base class, HttpServletResponseWrapper, that wraps an HttpServletResponse object. The LocalResponseWrapper class is simple because it subclasses the convenience class, overriding only those methods that write to the response object. All other calls are forwarded to the original response object. For example, the collaboration diagram in Figure 3 below shows that LocalResponseWrapper overrides getOutputStream, but doesn't override getHeader. The HttpServletResponse object passes the call to getHeader directly to the original implementer of HttpServletResponse.

A wrapper overrides only some servlet response methods
Figure 3. A wrapper overrides only some servlet response methods

The code for LocalResponseWrapper looks like this:

class LocalResponseWrapper
   extends HttpServletResponseWrapper {
  private CharArrayWriter _caw = null;
  private ServletOutputStreamWrapper _sw = null;
  
  public LocalResponseWrapper(
                            HttpServletResponse res) {
    super(res);
  }


  // Return an output stream that writes to a buffer
  public ServletOutputStream getOutputStream() {
    if (_caw != null) {
      throw new java.lang.IllegalStateException
        ("LocalResponseWrapper: " +
         "getWriter() has already been called " +
         "for this object");
    }
    _sw = new ServletOutputStreamWrapper();
    return _sw;
  }

  // Return a PrintWriter that writes to a buffer
  public PrintWriter getWriter()
   throws java.io.IOException {
    if (_sw != null) {
      throw new java.lang.IllegalStateException
        ("LocalResponseWrapper: getOutputStream()" +
         "has already been called for this object");
    }
    _caw = new CharArrayWriter();
    return new PrintWriter(_caw);
  }
  
  // Convert stored data to a string
  public String toString() {
    if (_sw != null) {
      return _sw.toString();
    } else if (_caw != null) {
      return _caw.toString();
    } else {
      return null;
    }
  }
}

The class constructor takes an HttpServletResponse as an argument and passes it directly to its superclass constructor. The superclass handles all calls to methods that are not overridden. Methods getOutputStream and getWriter return references to private objects that implement ServletOutputStream and PrintWriter, respectively. The objects returned by getOutputStream or getWriter store any data written to them in memory for later retrieval by toString.

A Web component can call either getWriter (as in the case of JSPTM pages) or getOutputStream (for servlets), but never both. By definition, only one of these methods can ever be called, and appropriate exceptions enforce that rule. The class uses a standard Java utility class, CharArrayWriter, to store data in an internal array. However, no such standard class exists for output streams, so one had to be written.

Streaming To Memory

The final class in this example is ServletOutputStreamWrapper. This class acts like an output stream, but actually writes to memory. Its implementation is very simple:

public class ServletOutputStreamWrapper
 extends ServletOutputStream {
  protected ByteArrayOutputStream _bos;

  public ServletOutputStreamWrapper() {
    _bos = new ByteArrayOutputStream();
  }

  public void write(int b) throws IOException {
    _bos.write(b);
  }

  public String toString() {
    String result = _bos.toString();
    return result;
  }
}

A ServletOutputStream subclass needs to implement only one method: a method to write an int. All of its other methods are written in terms of that method. As a result, this class simply creates a ByteArrayOutputStream, and appends any ints written to it to the buffer. The toString method converts the buffer contents to a string and returns it to the caller.

Deploying the Filter

The servlet filter chain is configured in the web.xml deployment descriptor, as shown below:

  ...
  <filter>
    <filter-name>Text2HTMLFilter</filter-name>
    <display-name>Text2HTMLFilter</display-name>
    <description>Checks form post parameters</description>
    <filter-class>com.elucify.tips.sep2002.Text2HTMLFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>Text2HTMLFilter</filter-name>
    <url-pattern>*.txt</url-pattern>
  </filter-mapping>
  ...

The filter tag defines the existence of a servlet filter, giving it a name, a display name (for use in GUIs), a text description, and the fully-specified name of the filter class. Spurious white space is not allowed. After the class is defined, a filter-mapping tag associates a filter with either a servlet (as in last month's tip), or with a url-pattern. Any request under the Web application's context root that matches the URL pattern is served through the filter. In this case, files whose names end in .txt are processed by the filter, and all others are not.

Final Thoughts

Keep in mind that this servlet filter has no way of knowing (without specifically checking) whether or not it is writing directly to the client. The filter could reside in the middle of a chain of several filters, and its output might be intercepted by some filter above for further processing.

Note that this solution puts the entire content of the requested document into main memory for processing. While this solution works fine for small-to-medium-sized data and reasonable load, it might not scale well. Fortunately, if performance problems arise, you can change the implementation of these classes to suit your needs.

What should you do if several filters are set up to post-process data, and you want the ones "up the stack" to pass the data directly to the client? For example, if the Text2HTMLFilter class in the example for this tip were called by a class that translates HTML to PDF, how could it tell the PDF filter to simply pass the HTML back to the client? Because filters are components, they are naturally decoupled from one another. If you write the filters yourself, you could place an attribute in session or page scope, indicating to a calling filter that any data it receives should be transmitted directly to the client, instead of being post-processed. Because you control the implementation of the HttpServletResponse, you could write a class that handles this situation elegantly.

Pixel
Pixel

Using Custom Tags

In J2EE applications, JSP pages are often the best way to generate content composed of fixed template text with interspersed dynamic content in the form of scriptlets. Yet as they grow more complex, JSP pages can also become unmanageable. While they can be handy for small jobs, scriptlets suffer from the following disadvantages (among others):

  • Scriptlets are difficult to read and modify. JSP pages with scriptlets mix two languages, making both more difficult to read and maintain.
  • Scriptlets encourage mixing data with logic. JSP pages are primarily for display, not for logic. Logic belongs in Java classes that can be reused referentially and maintained by programmers.
  • Scriptlets are not reusable. While scriptlets could be reused by inclusion, more often they encourage cut-and-paste reuse, which is a maintenance hazard. Each time you cut and paste a scriptlet, many more lines of redundant code will need maintenance.
  • Scriptlets are hard to parameterize. Clever use of include directives can make scriptlets parameterizable. However, most people simply cut, paste, and edit, and so create new, mostly redundant code that requires maintenance.

Instead of creating large JSP pages that are full of scriptlets, consider using custom tags. Custom tags allow you to create your own HTML-like tags to use in your JSP pages. Each time the JSP page engine encounters a custom tag, it looks up the tag handler class for that tag and invokes it. The custom tag in the page is replaced by the output of the custom tag handler. This allows JSP pages to specify dynamic content without using Java code directly in the page.

Custom tags provide several benefits to your Web-tier design. They improve the readability of your pages. Web page designers who are not programmers can use tags more easily than scriptlets. Programmers who maintain code modify tag classes instead of JSP pages, so they don't risk damaging the layout. Enhancing or fixing a tag class changes the tag's behavior everywhere the tag is used. Tags are easier to parameterize than scriptlets, because arguments can be passed in as attributes or in the tag body. Finally, tags are much more reusable than scriptlets, because you can create libraries of sharable, reusable custom tags. The JavaServer PagesTM Standard Tag Library (JSTL) provides just such a standardized set of custom tags.

Let's examine the use of custom tags, by first looking at a sample JSP page. The JSP page below uses a scriptlet to report the date:

<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<HTML>
<HEAD><TITLE>Sample JSP</TITLE></HEAD>
<BODY>
<H3>
The date and time at the server are: 
<%
String sformat = "EEEE, d MMMM yyyy 'at' kk:mm:ss z";
SimpleDateFormat format = new SimpleDateFormat(sformat);
Date date = new Date();
String sdate = format.format(date);
out.print(sdate);
%>
</H3>
</BODY>
</HTML>

The page is straightforward, although it seems like a lot of typing for such a simple function. If you want to print the date on every page, you could copy and paste this scriptlet onto every page in your application. If you do this, you would have to maintain not just the original copy of the scriplet, but every copy that you pasted. Changing the date format could be a major undertaking if the scriptlet appeared on multiple pages.

The following shows a much cleaner version of the JSP page. Here the Java code is moved out of a scriptlet and into a custom tag:

<%@ taglib uri="/WEB-INF/taglib.tld" prefix="mytags" %>

<HTML>
<HEAD><TITLE>Sample JSP using a custom tag</TITLE></HEAD>
<BODY>
<H3>
The date and time at the server are: <mytags:date/>
</H3>
</BODY>
</HTML>

In this example, the <@% taglib %> directive indicates where to find the definition of the custom tag (in the tag library descriptor or TLD file) in the WAR file, and defines a namespace ("mytags") for the tag names (this string may be anything you like). The JSP page engine recognizes <mytags:date/> as a custom tag invocation. It calls the custom tag handler for that tag, and replaces the tag and its body text (if any) with the result.

Creating a custom tag handler

Creating a custom tag handler requires a bit more work than writing a scriptlet because it is a Java class and because you have to write its description in a TLD file (described in the next section). The following class, DateTag, implements the tag handler:

public class DateTag extends TagSupport {

  protected PageContext _pageContext;
  protected String _sFormat;
  static final String _sFormatDefault =
  "EEEE, d MMMM yyyy 'at' kk:mm:ss z";

  public void setPageContext(PageContext pageContext) {
    _pageContext = pageContext;
    _sFormat = _sFormatDefault;
  }

  // Handle the tag
  public int doStartTag() throws JspException {
    SimpleDateFormat format =
      new SimpleDateFormat(getFormat());
    JspWriter out = _pageContext.getOut();
    Date date = new Date();
    String sdate = format.format(date);
    try {
      out.print(sdate);
    } catch (IOException ex) {
      throw new JspException("DateTag: can't write: " +
             ex.getMessage());
    }
    return SKIP_BODY;
  }

  // Handlers for "format" attribute
  public void setFormat(String sFormat) {
    _sFormat = sFormat;
  }

  public String getFormat() {
    return _sFormat;
  }
}

Class TagSupport implements the Tag interface that all tag handlers require. Its methods do essentially nothing. Tag handler developers override methods of interest, and allow the base class to handle calls to all other methods. The setPageContext method is called each time the handler is invoked. The class simply saves a reference to the PageContext for later use.

Method doStartTag is called when the JSP page engine encounters the tag. This method does the same calculations as the scriptlet in the first version of the JSP page. It writes the resuting date to a JspWriter that it obtains from the PageContext stored previously. Anything written to the JspWriter is inserted directly into the response. Notice that doStartTag can throw only JspException. If a write fails, the original IOException is converted to a JspException and is re-thrown. The method returns SKIP_BODY, which tells the page engine to throw away the tag's body text, if there is any.

The last two methods of the custom tag handler class are setFormat and getFormat. Astute readers should recognize these as property accessors. These are used by the Web container to set the values of a tag's attributes (discussed in more detail below). In this case, setting the format attribute changes the format of the date written as output.

Tag definition: the TLD file

A tag library descriptor, or TLD file, is an XML file that describes the tags in a tag library. The TLD file for DateTag appears below.

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE taglib
        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<taglib>
   <tlib-version>1.0</tlib-version>
   <jsp-version>1.2</jsp-version>
   <short-name>first</short-name>
   <uri>http://www.elucify.com/j2eetips/sept2002/taglib</uri>
   <description>Sample tag library</description>

  <tag>
    <name>date</name>
    <tag-class>com.elucify.tips.sep2002.DateTag</tag-class>
    <body-content>empty</body-content>
    <description>Print the date with a compiled-in format</description>

    <attribute>
        <name>format</name>
        <required>false</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>

  </tag>         
</taglib>

The descriptor provides information about the tag library. It also provides information about each tag, such as the tag's name, its handler class, and information about its attributes. This file is placed in the WEB-INF directory of the WAR file and referenced by the JSP pages that use it in their taglib directives.

Adding attributes

Notice that the TLD file shown above defines an attribute called format. This is the string passed to SimpleDateFormat to control how the date is printed. If a format attribute is present on a date tag, the JSP engine calls setFormat on the handler class. Otherwise, the handler class uses a default format. Attributes provide a great deal of customizability to custom tags. For example, the following JSP page uses the format attribute to format the date in several different ways on the same page:

<%@ taglib uri="/WEB-INF/taglib.tld" prefix="mytags" %>

<HTML%>
<HEAD><TITLE%>Sample JSP using a custom tag and format</TITLE%></HEAD%>
<BODY%>
<H3%>
The time zone at the server is <mytags:date format="zzzz"/%>.<br%>
The server date is <mytags:date format="M/d/yyyy"/%>.<br%>
The server time is <mytags:date format="hh:mm:ss a"/%>.<br%>
</H3%>
</BODY%>
</HTML%>

Imagine how many lines of redundant code would be required to do the same thing using scriptlets!

Deploying the JSP pages with custom tags

The tag handler class can be placed in the WEB-INF/classes directory of the Web application WAR file, along with the TLD file. Or they can be bundled into JAR files along with their TLD file to provide a single unit of deployment for a group of related tags. This example uses the first approach for simplicity. There is no need to add anything to the web.xml deployment descriptor.

Custom tags greatly improve the readability, flexibility, reusability, and maintainability of dynamic content generation code in JSP pages.

Custom Tag Resources

You can learn how to implement several kinds of custom tags in the J2EE Tutorial section Custom Tags in JSP Pages. Also see the JavaServer Pages Standard Tag Library page. The Enterprise Java BluePrints has several best practices for Web components, including JSP pages and custom tags. Among other features, JavaServerTM Faces technology provides a large library of general-purpose custom tags.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, JavaServer Pages, JSP, JavaServer Faces, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_227980241584273661@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Sep 27 15:50:11 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g8RKoBm21145 for ; Fri, 27 Sep 2002 15:50:11 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g8RKoNrM013496 for ; Fri, 27 Sep 2002 15:50:25 -0500 (EST) Date: 27 Sep 2002 13:42:32 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <227980241584273661@hermes.sun.com> Subject: Enterprise Java Technologies Newsletter, September 27, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 19829 Enterprise Java Technologies Newsletter
Core Java Header
pixel

Welcome to the Enterprise JavaTM Technologies Newsletter. Here you'll learn about new enterprise Java technologies, products, tools, and resources for developers.



Product and Technology Releases

The following J2EE products and technologies were released this month.

J2EE Client Provisioning.
This technology lets developers manage applications and content destined for a variety of networked client devices. The technology extends the J2EE platform with a number of APIs and facilities to enable development of provisioning portals.

Java API for XML Binding (JAXB) Specification V 0.7 - Public Draft.
This specification, JSR-31, provides an API and tools that automate the mapping between XML documents and Java objects.

Java 2 Platform, Standard Edition, v 1.4.1.
J2EE takes advantage of many features of the Java 2 Platform, Standard Edition (J2SETM). Version 1.4.1 adds new features and functionality, and provides the foundation for standards-based, interoperable Web services.

Java API for XML Processing (JAXP) 1.2 Specification.
JAXP is a Java API that supports processing of XML documents using DOM, SAX, and XSLT. JAXP 1.2 adds properties to enable validation against XML schemas.



Early Access Releases

The following J2EE products and technologies were made available through the Early Access Release Program this month.

J2EE Client Provisioning Reference Implementation. This early access implementation of the specification for J2EE Client Provisioning includes support for J2METM MIDP and J2SETM devices.

JavaServer Faces Specification 1.0 Early Access Draft. JavaServer Faces technology simplifies building user interfaces for JavaServer applications. It includes a set of APIs for representing and managing UI components, and a JavaServer Pages (JSPTM) custom tag library for expressing a JavaServer Faces interface within a JSP page.



Hot Downloads

The following were the most frequently downloaded J2EE products and technologies this month.

Java 2 SDK, Enterprise Edition Version 1.3.1

J2EE 1.3 Tutorial

Java Web Services Developer Pack v1.0_01

Java Web Services Developer Pack v1.0_01 Tutorial

Java XML Pack Summer 02 Update Release

pixel
pixel pixel pixel
September 27, 2002

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

Resources

  • New Site: Sun ONE for Developers. This new Sun site provides practical guidance and sample code for developers interested in building Web services and other software using the products and tools of the Sun ONE platform.

  • Book: Designing Enterprise Applications with the J2EE Platform, Second Edition. The second edition of this best-selling book is now available online, and for purchase.

  • Book Excerpts: Read excerpts from the following new books:


  • Article: Developing Multilingual Web Applications Using JavaServer Pages Technology. Learn how to use JavaServer Pages technology for internationalization and multilingual applications.

  • J2EE Verification Program in Japanese. The J2EE Verification Program is now available in Japanese.

  • Enterprise Java Technologies Tech Tips: Filtering Responses, and Using Custom Tags. Learn how to use servlet filters to post-process requests, and how to use custom tags in JSP pages.

  • Java Live! Learn about the following topics, and get questions answered in these online chats:
    • JavaServer Faces, Oct. 8, 11 A.M., Pacific time (6 P.M. GMT). Guests: Craig McClanahan and Amy Fowler
    • Sun ONE Application Framework, Oct. 22, 11 A.M., Pacific time (6 P.M. GMT). Guests: Todd Fast and Michael Frisino.


  • New Sun ONE Education Courses. Get in-depth training on Sun ONE products and services in a set of new courses from Sun Educational Services.

Industry News

  • Java Web Services Technologies Reach New Heights. Sun Microsystems, Inc. previewed the latest version of Java 2 Platform, Enterprise Edition (J2EE) at JavaOneSM Japan Developer Conference. J2EE v 1.4 boosts multiplatform computing with the integration of web services support making Java the only architecture capable of giving developers the ability to deploy production ready web services across heterogeneous environments.

  • jCert And Ciw Unify Certification Path for Web And Enterprise Developer Jobs. The jCert Initiative, a consortium of Java-based enterprise development software vendors, and CIW, a leading vendor-neutral certification for Web and enterprise development, have agreed to integrate their programs to create a single training and certification path for employers and individuals.

  • Oracle to Boost App Server. Oracle in early 2003 plans to release a new version of the Oracle application sever that will feature enhancements such as a certificate authority to boost the use of the product for e-business transactions. Oracle's upcoming application server release, Oracle9i Application Server Release 2 9.0.4, also will include single sign-on enhancements to boost identity management. (From InfoWorld)

  • BEA and Sun to Provide Joint Support Center. BEA Systems, Inc. and Sun Microsystems, Inc. announced a new joint support center to support BEA and Sun customers. This global support relationship will be designed to speed time to resolution and increase application availability for scalable, Internet-ready solutions. This seamless support relationship can also help provide lab environments in all regions worldwide for the purpose of testing interoperability between BEA WebLogic and Sun's Java Virtual Machine software and the Solaris Operating Environment.

  • Five Sun Security Partners Integrate With Sun ONE Platform For Network Identity. To provide customers greater choice in deploying or streamlining a network identity infrastructure, Sun is working with five security partners to help integrate their solutions with the Sun ONE Platform for Network Identity. As part of the joint sales and marketing agreements, the following software providers have teamed with Sun to deliver pre-tested solutions that provide greater choice and lower risk: Banyan Systems France, Business Layers, Entrust, Passlogix and Persistent Co.

  • Resonate Delivers Application Performance Management For Sun One Platform. Resonate Inc., a leading provider of application performance management solutions for business-critical applications, announced its commitment to support performance management capabilities for the Sun Open Net Environment (Sun ONE) platform, including the Sun ONE Application Server and Sun ONE Web Server.

Customer Spotlight

  • State of New Jersey Deploys Sun ONE to 'Empower the People'. The State of New Jersey has chosen the Sun ONE Portal Server for its e-government initiative. The "My New Jersey" portal which targets four broad user communities -- citizens, government officials, business owners and employees -- allows the state to deliver pertinent information and services while decreasing operating costs by more than $200,000 a year and improving end-user experience. "Our single portal deployment enables us to identify a user once and provide the services that a user needs today, tomorrow or anytime down the road," said Judith Teller, CIO, the State of New Jersey.

Events

  • Web Sevices Edge, Oct. 1-3, 2002, San Jose, Ca.

  • Sun Tech Days, A Developer's Conference 2002-2003
    • Oct. 15-16, 2002, Sao Paulo, Brazil
    • Oct 21-22, 2002, Dusseldorf, Germany

Java Developers Marketplace

  • Macromedia Flash Remoting MX for Java
    Macromedia Flash Remoting MX makes it fast and easy to create rich Internet applications by providing a powerful yet simple programming model. Developers can access web application services such as EJBTMs, ColdFusion components, or SOAP-based web services using four easy commands. Macromedia Flash Remoting MX for Java supports Java resources such as Java Objects and Java Beans, and J2EE resources including Java classes, EJBs, and JMX MBeans. The server is a pure Java implementation and can be deployed on both J2EE and Java application servers.
pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, JavaOne, J2EE, J2ME, J2SE, JavaServer Faces, JavaServer Pages, JSP, and EJB are trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_22613455-898112157@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Sep 24 16:55:43 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g8OLthm29575 for ; Tue, 24 Sep 2002 16:55:43 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g8OLtRHo029407 for ; Tue, 24 Sep 2002 16:55:51 -0500 (EST) Date: 24 Sep 2002 13:34:04 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <22613455-898112157@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Sept. 24, 2002 (Locking Files, Changing UI Attributes) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 31491 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text September 24, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, September 24, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

Locking Files For Shared Access
Changing User Interface Attributes

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Pixel

LOCKING FILES FOR SHARED ACCESS

Have you ever had the need to share an external file with non-Java applications or among multiple Java applications? Prior to the version 1.4 release of the J2SE platform, it couldn't be safely done without the use of native code. Now, thanks to the FileChannel/FileLock features of the New I/O (NIO) APIs in J2SE v 1.4, you have a safe way of sharing an external file, without having to resort to native code.

The FileLock class, which is part of the java.nio.channels package, represents a file lock. You can use a file lock to restrict access to a file from multiple processes. In addition, you have the option of restricting access to an entire file or just a small region of it. A file lock is either shared or exclusive. A shared lock supports read access from multiple processes, while an exclusive lock is typically used for writing. Because a lock is at the file level, you should not use it to restrict access to a file from multiple threads in a single process. If you use a file lock in multiple threads, none of the threads would be restricted from accessing the file. Only external processes are restricted.

To use file locking, you need to get a file channel, that is an instance of the FileChannel class. You can get a file channel through the getChannel method of any of the following I/O classes:

  • FileInputstream
  • FileOutputStream
  • RandomAccessFile

After you get a file channel, you can use either of two pairs of methods that it offers for working with locks: lock and tryLock.

  FileLock lock()
  FileLock tryLock()

The no-argument versions of the two methods try to get an exclusive lock on the entire file associated with the channel. The lock method does not return until the lock is acquired. The tryLock method returns null if another process has a region of the file currently locked.

  FileLock lock(long position, long size, boolean shared)
  FileLock tryLock(long position, long size, boolean shared)

The three-argument versions let you lock a piece of a file. The position argument is the starting position for the lock. The size argument represents the number of bytes to lock. A shared value of true means you want a shared lock, while a false value is for an exclusive lock. The size argument is not limited to the size of a file, this allows you to lock a region before you write to the file. For instance, the three argument version of lock and tryLock go from 0 to Long.MAX_VALUE.

All the file locking methods of FileChannel return a FileLock. You need this to release the lock. As with thread locking, the best approach is to keep the file locked for the smallest amount of time. FileLock offers the following methods:

  • channel - returns the source FileChannel for the lock
  • isShared - reports if the lock is shared
  • isValid - reports if the lock is still valid (the lock is no longer valid if the file channel is closed)
  • overlaps(long position, long size) - checks for overlap with the given region
  • position - returns the start position within locked region
  • release - releases the lock
  • size - returns the number of bytes within the locked region
  • toString - provides a string representation of the lock

Here's a program that demonstrates the file locking features. The program gets an exclusive lock on a file, reports when it has the lock, and then wait until you press the Enter key. Try running the program concurrently in two separate windows. You'll see that the program won't run a second time until you press Enter in the first run. (Note that if you have a file named junk.dat in the directory in which you run this program, the file will be overwritten.)

import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class Locking {
   public static void main(String arsg[])
       throws IOException {
     RandomAccessFile raf =
       new RandomAccessFile("junk.dat", "rw");
     FileChannel channel = raf.getChannel();
     FileLock lock = channel.lock();
     try {
       System.out.println("Got lock!!!");
       System.out.println("Press ENTER to continue");
       System.in.read(new byte[10]);
     } finally {
       lock.release();
     }
   }
}

It's important to understand that it doesn't matter if a file is locked from a C/C++ program or through a FileChannel in another Java program. Waiting and getting the lock is still the same no matter who might lock a file.

Also note that the file locking API has many platform dependencies. For instance, if a particular locking feature, such as shared locking, is not available on a platform, then exclusive locking is used. The use of exclusive locking instead of shared locking won't necessarily cause a program to fail. However, it will serialize all access to a file, instead of permitting simultaneous reads or access to different sections of a file.

For more information about file locking, as well as other features of the NIO APIs, see "New I/O APIs."

Pixel
Pixel

CHANGING USER INTERFACE ATTRIBUTES

There are two sets of user interface components with the Java 2 Platform: AWT and Swing. The first generation set of components is called the Abstract Window Toolkit, or AWT for short. These components rely on what are called peers to interact with the platform-specific windowing environment (such as Motif or Microsoft Windows). This gives you access to the actual native component for interacting with such objects as buttons and labels. If a particular component wasn't available natively on all the supported platforms, the component wasn't available as part of the AWT component set.

The second generation set of user interface components is the Swing component set. The significant difference between Swing and AWT components is that where the AWT components rely on the native windowing environment to provide the peer-based component to the Java platform, the Swing components are completely hosted within the Java runtime environment. This means that all the drawing of the components is done internally, as is the event management aspect of the different components. When you click on a Swing button, it paints with a different background color and draws a different border to simulate the behavior of pressing the button. What this means is that new components can be created that aren't available natively on all Java runtime platforms.

Because Swing keeps everything internal to the Java runtime environment, it offers various ways to customize the look and feel of different Swing components:

For lightweight changes to colors, borders, fonts, and icons, Swing maintains a series of default settings in javax.swing.UIManager. By placing a new setting in the UIManager's lookup table, all future components that are created use the new settings. Previously created components do not change unless directed.

For example, Swing's JButton component has the following set of UI default properties:

  • Button.background
  • Button.border
  • Button.darkShadow
  • Button.focusInputMap
  • Buton.font
  • Button.foreground
  • Button.highlight
  • Button.light
  • Button.margin
  • Button.shadow
  • Button.textIconGap
  • Button.textShiftOffset

Note that some look and feels have additional properties available. Also, while this is the current set of properties, these are considered undocumented -- there is no assurance that future look and feels will use this mechanism or these keys.

To change a specific setting, you associate the string from the list above with the appropriate datatype. This is done by calling the put method of UIManager. For instance, to change the background color of all future buttons to red, you add the following line of code to your program, before creating any JButton components.

  UIManager.put("Button.background", Color.RED);

Here's a simple program that demonstrates this behavior:

  import java.awt.*;
  import javax.swing.*;

  public class RedButton {
    public static void main(String args[]) {
      JFrame frame = new JFrame("Red");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container c = frame.getContentPane();
      JButton defaultColor = 
        new JButton("Default Colors");
      c.add(defaultColor, BorderLayout.NORTH);
      UIManager.put("Button.background", 
        Color.RED);
      JButton red =
        new JButton("Red");
      c.add(red, BorderLayout.SOUTH);
      frame.setSize(200, 100);
      frame.show();
    }
  }

When you run the program, here's what you should see:

While you can set individual properties as shown in the RedButton example, the default Swing look and feel, called Metal, provides a way to group common property settings into a theme. The abstract javax.swing.plaf.metal.MetalTheme class offers about fifty settings that let you customize the fonts and colors of the Swing components. By creating different subclasses, you can swap many of the properties at once when you change the look and feel.

  MetalTheme theme = new MyCustomTheme();
  MetalLookAndFeel.setCurrentTheme(theme);
  UIManager.setLookAndFeel(new MetalLookAndFeel());

For an example of theme usage, try out the Metalworks demonstration that comes with the Java 2 SDK distribution. Simply change the current directory to the demo/jfc/Metalworks directory, and run the demonstration with the following command:

  java -jar Metalworks.jar

After opening a few windows, select a different theme under the Theme menu.

For example, here's what you should see using the Steel theme:

And here's what you should see using the Low Vision theme:

Swing also maintains a lookup mechanism for how to actually draw the whole component, including the "feel" aspect as well. The associated property for each component is a subclass of the abstract javax.swing.plaf.ComponentUI class. For the JButton class, the lookup key is ButtonUI, and javax.swing.plaf.ButtonUI is the specific subclass of ComponentUI that you must subclass. Place the class name in the lookup table, and then make the class file available from the classpath. Now all components of the appropriate type will look different. The actual key can be obtained from the JComponent subclass by using the getUIClassID method, and the setUI method dictates the expected ComponentUI subclass.

To demonstrate, the following is a custom ButtonUI implementation that draws little squares in the corners of a button. The source includes both the UI class and a program that demonstrates its usage.

  import java.awt.*;
  import javax.swing.*;
  import javax.swing.plaf.*;
  import javax.swing.plaf.metal.*;

  public class CornerButtonUI 
      extends MetalButtonUI {
    private final static CornerButtonUI 
      cornerButtonUI = new CornerButtonUI(); 

    public static ComponentUI createUI(JComponent c) {
      return cornerButtonUI;
    }

    public void paint(Graphics g, JComponent c) {
      super.paint(g, c);
      g.setColor(c.getForeground());
      int width = c.getWidth();
      int height = c.getHeight();
      int drawWidth = (int)(width * .15);
      int drawHeight = (int)(height * .10);
      // top left
      g.fillRect(0, 0, drawWidth, drawHeight);
      // top right
      g.fillRect(width-drawWidth, 0, width, 
        drawHeight);
      // bottom left
      g.fillRect(0, height-drawHeight, drawWidth, 
        height);
      // bottom right
      g.fillRect(width-drawWidth, height-drawHeight, 
        width, height);
   }

   public static void main(String args[]) {
      JFrame frame = new JFrame("Corners");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container c = frame.getContentPane();
      UIManager.put("ButtonUI", "CornerButtonUI");
      JButton corners = new JButton("Corners");
      c.add(corners, BorderLayout.CENTER);
      frame.setSize(200, 100);
      frame.show();
   }
  }

When you run the program, here's what you should see:

Note that the corner button UI example could have also included calculations to take the size of the border into consideration.

Installing the ComponentUI in the UIManager lookup table changes the user interface for all future instances of a specific component type. However, you can change the user interface for a single instance of a Swing component by calling its setUI method, passing in the appropriate new user interface there. This changes the appearance of only the single instance, instead of all instances of the component type.

Yet another mechanism to change the look and feel of a component is to change the installed look and feel for the application. Swing applications work with a pluggable look and feel architecture. This is similar to changing themes. Unlike themes though, which just change the color and font settings, changing the installed look and feel for a Swing application affects all the settings for the different components. Each look and feel relies on a preconfigured table of settings for things such as colors, borders, fonts, icons, component UI elements for each component, and input maps for what keystrokes do with each component. Because everything associated with a Swing component is driven from within the Java runtime environment, everything is customizable, that is, if you know where to look. The ability to change the look and feel gives you the most flexibility, but it also requires the most work.

Before creating your own look and feel, let's look at how to change the current look and feel to a preexisting one. In addition to the default Metal look and feel used by Swing, the standard runtime offers a Microsoft Windows-like and Motif look and feel. (Apple also offers an Aqua look and feel, and others are available from third parties.) With these other look and feels (Windows and Motif), the Swing components take on the look of a native application for those platforms.

To change the look and feel of an application, simply pass the class name into the setLookAndFeel method of the UIManager. You can also ask the UIManager for the name of the look and feel for the native platform.

  UIManager.setLookAndFeel(
    UIManager.getSystemLookAndFeelClassName());

After the look and feel has been changed, all new components created will use the defaults associated with the new look and feel. To change existing components, you need to invoke updateUI for a single component or updateComponentTreeUI for a set of components in a window.

  import java.awt.*;
  import javax.swing.*;

  public class NativeLNF {
    public static void main(String args[]) {
      try {
        UIManager.setLookAndFeel(
          UIManager.getSystemLookAndFeelClassName());
      } catch (Exception e) {
        System.err.println("Unable to change");
      }
      JFrame frame = new JFrame("Native");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container c = frame.getContentPane();
      JButton top = new JButton("Top");
      c.add(top, BorderLayout.NORTH);
      JButton bottom = new JButton("Bottom");
      c.add(bottom, BorderLayout.SOUTH);
      frame.setSize(200, 100);
      frame.show();
    }
  }

When you run the program, here's what you should see on a UNIX platform (Windows users will see a Microsoft Windows look):

You can create your own look and feel objects, in addition to using the system defined look and feel objects. To create your own objects, you need to define the complete table of lookup settings for every available component. More simply (and more typically), you subclass an existing look and feel, and just customize the handful of settings you don't like. These settings can grow until you customize all the settings. But to start, it is easier to subclass and override the handful you need to than start from scratch and fill in all the settings (of which there are approximately 600). Here's an example that uses this approach.

  import java.awt.*;
  import javax.swing.*;
  import javax.swing.UIDefaults;
  import javax.swing.plaf.metal.MetalLookAndFeel;

  public class CornerButtonsLookAndFeel 
      extends MetalLookAndFeel {
    public String getID() {
      return "CornerButtons";
    }

    public String getName() {
      return "Corner Buttons Look and Feel";
    }

    public String getDescription() {
      return "The Corner Buttons Look and Feel";
    }

    public boolean isNativeLookAndFeel() {
      return false;
    }

    public boolean isSupportedLookAndFeel() {
      return true;
    }

    protected void initClassDefaults(
        UIDefaults table) {
      super.initClassDefaults(table);
      table.put("ButtonUI", "CornerButtonUI");
    }

    public static void main(String args[]) {
      try {
        UIManager.setLookAndFeel(
          "CornerButtonsLookAndFeel");
      } catch (Exception e) {
        System.err.println("Unable to change");
      }
      JFrame frame = new JFrame("CornersLNF");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container c = frame.getContentPane();
      JButton corners = new JButton("Corners");
      c.add(corners, BorderLayout.CENTER);
      frame.setSize(200, 100);
      frame.show();
   }
  }

When you run the program, here's what you should see:

The look and feel architecture of Swing is very flexible. However, just because the features are available doesn't mean they have to be used. For instance, if all the buttons in your application need to be red, but there is only one button, you're probably better off calling the setBackground method of the component. In that situation, it's easier to do that than worry about the name of the button background property so you can change the button settings in the UIManager.

For more information about changing user interface attributes, see chapter 7 "Pluggable Look and Feel" in "Graphic Java: Mastering the JFC, 3rd Edition Volume II, Swing" by David Geary.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Core Java Technologies Tech Tips
September 24, 2002


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_22880951205556929@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Mon Sep 30 13:58:42 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g8UIwgm29938 for ; Mon, 30 Sep 2002 13:58:42 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g8UIwvws018914 for ; Mon, 30 Sep 2002 13:58:59 -0500 (EST) Date: 30 Sep 2002 11:40:52 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <22880951205556929@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27009 New to Java Programming Supplement
pixel
pixel
header
    September 30, 2002    

In this Issue

imageJavaTM Programming Language Basics
imageJava Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageNew to the New to Java Programming Center
imageFor More Information

Pixel

Java Programming Language Basics

How to Use Object Serialization

The standard libraries of the Java 2 Standard Edition (J2SETM) version 1.4 provide many ways acheive persistence of information between multiple runs of the same program. For simple strings and primitive data types like int and float, you can use the java.util.Properties object or the Preferences API, found in the java.util.prefs package. For JavaBeanTM components, use the java.beans.XMLEncoder and java.beans.XMLDecoder classes for saving and restoring the state of a bean via an XML file. For the general-purpose object, you save its state through a mechanism called object serialization.

The state of an object consists of the current settings for all the instance variables for a specific instance of that object. If that state information is another object, the current settings for that object are also saved, and so on until everything is a primitive data type.

Methods and static variable state are not saved. Methods consist of behavior and not state, so they are not saved. Static variable state is state information about the class, not the instance, so it isn't saved either.

Multiple references to the same object are saved only once and in such a way that restoration returns the multiple references to the single object.

Once an object state has been saved (or serialized), the process of restoring the state is called deserialization. This process involves identifying the class to be restored, finding the appropriate .class file for that class, and then restoring the state for an instance of that class.

If the .class file can't be located, or its format is not compatible with the saved state, the object cannot be restored. For instance, incompatibilities may arise when fields are added.

The actual process of serialization is straightforward.

The ObjectOutputStream class offers a writeObject method for saving the state of an object. Assuming the class is serializable, you just pass the instance variable for that object to the writeObject method, and the stream class does all its work.

Object o = ...;
ObjectOutputStream oos = ...;
oos.writeObject(o);

How do you know if an object is serializable? If a class implements the java.io.Serializable interface, it is indeed serializable. There are no methods to the interface, so it just serves as a marker interface. However, just implementing the interface isn't sufficient. All the instance variables of that class must also be serializable; otherwise, when you try to serialize the state, an exception would be thrown.

Deserializing the state of an object is just as simple as saving it. This time, though, use the class ObjectInputStream and the method readObject:

ObjectInputStream ois = ...;
Object o = ois.readObject();

For both reading and writing objects, you must wrap the operations in a try-catch block, as a java.io.IOException may be encountered. In addition, restoration can result in a java.lang.ClassNotFoundException when the class file isn't available.

The following program demonstrates how to serialize your own class by creating an instance, saving its state to an in-memory buffer, and getting the state back again.

import java.io.*;
import java.awt.Point;

public class Cereal implements Serializable {
   String name;
   int servings;
   Point point;

   public static void main(String args[]) {
     Cereal c = new Cereal();
     c.name = "Froot Loops";
     c.servings = 12;
     c.point = new Point(20, 30);
     ByteArrayOutputStream baos = 
                new ByteArrayOutputStream();
     try {
       ObjectOutputStream oos = 
               new ObjectOutputStream(baos);
       oos.writeObject(c);
       oos.close();
     } catch (IOException e) {
       System.err.println(
                   "Problems saving state");
     }
     ByteArrayInputStream bais = 
        new ByteArrayInputStream(baos.toByteArray());
     try {
       ObjectInputStream ois = 
            new ObjectInputStream(bais);
       Cereal c2 = (Cereal)ois.readObject();
       System.out.println("Name:     " 
                                 + c2.name);
       System.out.println("Servings: " 
                             + c2.servings);
       System.out.println("Point:    " 
                                + c2.point);
     } catch (ClassNotFoundException e) {
       System.err.println(
            "Cannot find class to restore");
     } catch (IOException e) {
       System.err.println(
                "Problems restoring state");
     }
   }
}

This application produces the following:

Name:     Froot Loops
Servings: 12
Point:    java.awt.Point[x=20,y=30]

Now you can test your knowledge about serializing objects with this online quiz.

Pixel
Pixel

Java Bits

The transient Keyword

When serializing objects, there are times when you don't want a data member to get written to the stream. To prevent the writeObject method from writing a field to a stream, declare a data member as transient. When an object is read from a stream, transient data fields are set to their default values, such as 0 for integers, and null for strings. The programmer can restore transient data to to non-default values by implementing a readObject method. Transient fields are skipped when objects are serialized.

Pixel
Pixel

Making Sense of the Java Class Libraries

Drawing with Class Graphics and Class Polygon

The java.awt.Graphics class is the abstract base class for all graphics contexts that allow an application to draw onto components. Methods provide all basic drawing operations on a component's area, including the painting of image data. A Graphics object is called a graphics context because it also holds information about the drawing area, such as clipping region, color, and text fonts.

The Graphics class serves two major purposes:

  • Sets and gets graphical parameters
  • Performs graphical operations

Whenever a component's update or paint method is called, AWT provides the component with a new Graphics object for drawing in the display area, and resets attributes.

Methods of the Graphics class operate in a coordinate system (x,y). The top left of the graphics context is point x progressing across the display, and point y progressing downward. The point at the bottom right corner within the drawing area uses the coordinates (width-1, height-1), giving you a drawing area that is width pixels wide and height pixels high.

fig 1

Some common methods are:

  • public abstract void drawLine(int x1, int y1, int x2, int y2) Draws a line, using the current color, between the points (x1, y1) and (x2, y2) in this graphics context's coordinate system.
  • public void drawRect(int x, int y, int width, int height) Draws the outline of the specified rectangle. The left and right edges of the rectangle are at x and x + width. The top left and bottom edges are at y and y + height. The rectangle is drawn using the graphics context's current color.
  • public abstract void drawOval(int x, int y, int width, int height) Draws the outline of an oval. The result is a circle or ellipse that fits within the rectangle specified by the x, y, width, and height arguments.
  • public abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) Draws a closed polygon defined by arrays of x and y coordinates. Each pair of (x, y) coordinates defines a point.

For example, here is one way to create a rectangle:

public void paint(Graphics g)
  {
    g.drawRect(2,2,4,4);
  }

Since the lines are drawn beneath and to the right of the coordinates along the path, the rectangle above is 5 pixels tall, not 4.

Another way to draw a shape is by creating a Polygon object. The Polygon class represents an ordered collection of points treated as the definition of a polygon.

You create a Polygon object with the default constructor by calling the addPoint method, or by providing point coordinates within the constructor:

Polygon(): Creates an empty Polygon.

Polygon(int[] xpoints, int[] ypoints, int npoints): Constructs and initializes a Polygon from the specified parameters.

addPoint(int x, int y): Appends the specified coordinates to this Polygon.

For example:

Polygon p = new Polygon();
p.addPoint(10, 10);
p.addPoint(10, 30);
p.addPoint(20, 20);                                                
p.drawPolygon(p);

See the example application ShapesPolygonDrawing.java, which shows how to create shapes as described above. This application creates shapes as shown below:

fig 2
Pixel
Pixel

Program Challenge

Create the Draw Application

Create a drawing program that tracks mouse clicks. Each time the mouse is clicked, add the position to a polygon. The program draws the current polygon, based on the set of points added.

  • Create three buttons for the program: Load, Save, and Clear.
  • The Save button saves the current set of points in the polygon into an external file.
  • The Load button loads the saved set of points from the file.
  • The Clear button clears the current set of points, without touching the file.

Your application should look something like the following screen shot:

fig 3

See a possible solution to Challenge

Pixel
Pixel

New to the Java Programming Center

The first page of the lesson, "The Java Technology Phenomenon," establishes some basic facts about the Java platform. Take this quiz to test your basic knowledge.

Pixel
Pixel

For More Information

Object Serialization

Reading and Writing Data Code Samples

Object Serialization

Serialization Forum

Class Graphics

Class Polygon

Pixel
Pixel

Program Challenge Solution

See one possible solution to the June Program Challenge.

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SETM development kit.

Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_23303657-143675357@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Oct 9 12:59:10 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g99Hx9m15223 for ; Wed, 9 Oct 2002 12:59:09 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g99HxUZk025117 for ; Wed, 9 Oct 2002 12:59:38 -0500 (EST) Date: 9 Oct 2002 09:37:05 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <23303657-143675357@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Oct. 8, 2002 (Regular Expression Groups, Anonymous Classes) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 30011 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text October 8, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, October 8, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Using Regular Expression Groups
Anonymous Classes

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the JDC Tech Tips is written by Glen McCluskey.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Pixel

USING REGULAR EXPRESSION GROUPS

Regular expressions are a new feature of the Java 2 Platform, Standard Edition v 1.4. A regular expression is a string pattern that you can use to perform sophisticated string searching and replacement. For example, the regular expression:

    \d+

means "a sequence of one or more consecutive digit characters". A regular expression is represented by (compiled into) an instance of the java.util.regex.Pattern class. Then the related Matcher class is used to match input character sequences against the pattern.

Sometimes when matching is done, all you care about is whether the pattern was found somewhere in the input sequence. A common application of this is a utility that searches a text file and prints lines that match a specified pattern.

But sometimes you might want to get more information about a match than simply an indication of whether the pattern was found in the input. For example, if you're searching for a number, using the regular expression illustrated above, you might want to retrieve the actual text of the number that was found.

This is one situation where regular expression groups are useful. A group is a numbered part of a regular expression. For example, in the following expression:

    (\d+)zzz

there are two groups. Group 0 always refers to the whole expression, and group 1 to the subexpression that starts with the open parenthesis "(" and ends with the corresponding close parenthesis ")". The text of matched groups is saved by the regular expression matcher, and can be retrieved or referenced later in the regular expression.

Let's illustrate these ideas with an example:

    import java.util.regex.*;
    
    public class GroupDemo1 {
        static final String stringlist[] = {
            "abc 123 def",
            "456 ghi",
            "jkl789mno"
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for a
            // number consisting of one or more digits
    
            Pattern patt = Pattern.compile("(\\d+)");
    
            for (
              int i = 0; i < stringlist.length; i++) {
                String currstr = stringlist[i];
    
                // see if the current string has a match
    
                Matcher match = patt.matcher(currstr);
    
                // if a match, print the string text
                // for the matching group (group 1)
    
                if (match.find()) {
                    System.out.println("For \"" +
                        currstr + "\" match is: " +
                        match.group(1));
                }
            }
        }
    }

In this demonstration, GroupDemo1, there are some strings with embedded numbers in them. The program uses regular expression features to search for the numbers, and display the string text for each number that it finds. The program creates a Matcher object for each input string. Then the program calls the find method to see if there is a match against the regular expression pattern. If there is a match, the program gets the matching text for group 1 from the Matcher and displays it. In this example, the regular expression is:

    (\d+)

and group 1 is the text matched by "\d+". When you run the program, you should see the result:

    For "abc 123 def" match is: 123
    For "456 ghi" match is: 456
    For "jkl789mno" match is: 789

Let's look at another example similar to the first one:

    import java.util.regex.*;
    
    public class GroupDemo2 {
        static final String stringlist[] = {
            "abc 123 def 123",
            "456 ghi",
            "jkl789mno    789pqr",
            "123 456"
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for 
            // a number consisting of one or more 
            // digits followed by the same number later 
            // in the string
    
            Pattern patt = 
                        Pattern.compile("(\\d+).*\\1");
    
            for (
               int i = 0; i < stringlist.length; i++) {
                String currstr = stringlist[i];
    
                // see if the current string 
                // has a match
    
                Matcher match = patt.matcher(currstr);
    
                // if a match, print the string text
                // for the matching group (group 1)
    
                if (match.find()) {
                    System.out.println("For \"" +
                        currstr + "\" match is: " +
                        match.group(1));
                }
            }
        }
    }

The GroupDemo2 demo is almost the same as GroupDemo1, but with a different regular expression:

    (\d+).*\1

For an input sequence to match this expression, it must contain a number followed by any characters followed by the original number. The "\1" is a back reference to the first group in the expression. So input of:

    123 abc 123

will match, but:

    123 abc 456

will not.

When you run the GroupDemo2 program, you should see the result:

    For "abc 123 def 123" match is: 123
    For "jkl789mno    789pqr" match is: 789

Another way that you can use groups is to do string editing, for example, replacing the text of a matching group with other text. Here's an example:

    import java.util.regex.*;
    
    public class GroupDemo3 {
        static final String stringlist[] = {
            "abc 123 def   123",
            "456 ghi",
            "no match",
            "jkl789mno   789",
            "",
            "123.123",
            "1,2,3,4,5,6,7,8,9,10"
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for 
            // a number consisting of one or more 
            // digits
    
            Pattern patt = Pattern.compile("(\\d+)");
    
            for (
              int i = 0; i < stringlist.length; i++) {
                String currstr = stringlist[i];
    
                String outstr;
    
                // see if the current string has 
                // a match
    
                Matcher match = patt.matcher(currstr);
                boolean result = match.find();
    
                // if found a match, then go through 
                // string and replace all matches with 
                // "[matchstring]"
    
                if (result) {
                    StringBuffer strbuf = 
                                    new StringBuffer();
                    do {
                        match.appendReplacement(
                                       strbuf, "[$1]");
                        result = match.find();
                    } while (result);
                    match.appendTail(strbuf);
                    outstr = strbuf.toString();
                }
    
                // if no match, just point output 
                // at input
    
                else {
                    outstr = currstr;
                }
    
                // display the result
    
                System.out.println(outstr);
            }
        }
    }

The GroupDemo3 program finds numbers in the input, as before. When a number is found, it takes the text of the number and puts "[]" around it. Ultimately, the program produces an output string that consists of the input with this editing operation performed on it.

The appendReplacement and appendTail methods are the key to performing this operation. The appendReplacement method is used to replace matched text in the input with a new string that you specify. The string can contain references to groups. For example, the GroupDemo3 program specifies the replacement string as "[$1]". This means to replace matched instances of group 1 with the group 1 text surrounded by "[]", and append the result to an output string buffer. When the matching process is exhausted, appendTail is used to append the rest of the input to the output.

The output of the GroupDemo3 program is:

    abc [123] def   [123]
    [456] ghi
    no match
    jkl[789]mno   [789]

    [123].[123]
    [1],[2],[3],[4],[5],[6],[7],[8],[9],[10]

The logic in this demo is very similar to the Matcher.replaceAll method.

For further information about regular expressions, see the article "Regular Expressions and the Java Programming Language" by Dana Nourie and Mike McCloskey.

Pixel

ANONYMOUS CLASSES

If you've done much Java programming, you might have realized that it's possible to declare classes that are nested within other classes. This tip is going to look at one particular kind of nesting, which goes by the name "anonymous class". To get started on the discussion, let's look at a simple example:

    class Base {
        void method1() {}
        void method2() {}
    }
    
    class A { // normal class
    
        static class B {} // static nested class
    
        class C {} // inner class
    
        void f() {
            class D {} // local inner class
        }
    
        void g() {
            // anonymous class
            Base bref = new Base() { 
                void method1() {}
            };
        }
    }

The example illustrates various kinds of nested and inner classes. A nested class that is not declared static is called an inner class. In the example code, B is a nested class, while C is a nested class and an inner class.

The main focus of this tip is anonymous classes. You can glean a few insights about anonymous classes by studying the example above. One key idea is that an anonymous class has no name. An anonymous class is a subclass of an existing class (Base in this example) or an implementation of an interface.

Because an anonymous class has no name, it cannot have an explicit constructor. Neither can an anonymous class be referred to outside its declaring expression, except indirectly through a superclass or interface object reference. Anonymous classes are never static, never abstract, and always final. Also, each declaration of an anonymous class is unique. For example, the following code declares two distinct anonymous classes:

    Base bref1 = new Base() {
        void method1() {}
    };

    Base bref2 = new Base() {
        void method1() {}
    };

Each anonymous class is declared within an expression.

Let's look at a common situation where you would use an anonymous class:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class AnonDemo2 {
        public static void main(String args[]) {
    
            // create a JFrame and add a listener
            // to it to handle window closing
    
            JFrame frame = new JFrame("AnonDemo2");
            frame.addWindowListener(
                                  new WindowAdapter() {
                public void windowClosing(
                                       WindowEvent e) {
                    System.exit(0);
                }
            });
    
            // create a JPanel and add it to the frame
    
            JPanel panel = new JPanel();
            panel.setPreferredSize(
                              new Dimension(300, 300));
            frame.getContentPane().add(panel);
    
            // display the frame
    
            frame.pack();
            frame.setVisible(true);
        }
    }

This example displays a JPanel on the screen. The demo adds a window listener to the JFrame object such that when the user closes the window, the application terminates.

WindowListener is an interface. An implementing class must define all the methods specified in the interface. WindowAdapter implements the interface using dummy methods, like this:

    public abstract class WindowAdapter
        implements WindowListener, WindowStateListener,
        WindowFocusListener
    {
        public void windowOpened(WindowEvent e) {}
        public void windowClosing(WindowEvent e) {}
        public void windowClosed(WindowEvent e) {}
        public void windowIconified(WindowEvent e) {}
        public void windowDeiconified(WindowEvent e) {}
        public void windowActivated(WindowEvent e) {}
        public void windowDeactivated(WindowEvent e) {}
        public void windowStateChanged(WindowEvent e) {}
        public void windowGainedFocus(WindowEvent e) {}
        public void windowLostFocus(WindowEvent e) {}
    }

The demo application, AnonDemo2, needs to override just one of these methods, the windowClosing one. So it subclasses the adapter class and overrides the single method. The subclass is used only once within the application, and contains very simple logic. That's why an anonymous class is a good choice in this situation. The anonymous class extends the WindowAdapter class to override a single method. WindowAdapter, in turn, implements the WindowListener class by use of dummy methods that do nothing.

Let's look at another example. Suppose that you have a List of Integer objects, and you want to sort the list, both in ascending order (the default) and in descending order. Here's some code to do this:

import java.util.*;

public class AnonDemo3 {
    public static void main(String args[]) {

        // create an ArrayList and add
        // some Integer objects to it

        List list = new ArrayList();
        list.add(new Integer(37));
        list.add(new Integer(-59));
        list.add(new Integer(83));

        // sort the list in the usual (ascending order)

        Collections.sort(list);
        System.out.println(list);

        // sort the list in descending order
        // using a function object implemented
        // via an anonymous class

        Collections.sort(list, new Comparator() {
            public int compare(Object o1, Object o2) {
                int a = ((Integer)o1).intValue();
                int b = ((Integer)o2).intValue();
                return a < b ? 1 : a == b ? 0 : -1;
            }
        });
        System.out.println(list);
    }
}

The program does the first sort in the obvious fashion. Then, to sort in descending order, the program must specify a Comparator function object. This object implements comparison logic to sort Integer objects in descending order.

This demo uses an anonymous class, one that implements the java.util.Comparator interface. If this kind of sorting is done in only one place in an application, an anonymous class makes sense, but if it's done many places, it might make more sense to introduce a top-level or static nested class:

    class MyComparator implements Comparator {
        ...
    }

and implement the sort logic only once.

The output of the program is:

    [-59, 37, 83]
    [83, 37, -59]

Let's look at a final example, one that illustrates a couple of issues related to the use of anonymous classes:

    class A {
        int afield;
    
        // set value of afield
    
        A(int afield) {
            this.afield = afield;
        }
    
        // get value of afield
    
        int getValue() {
            return afield;
        }
    }
    
    public class AnonDemo4 {
        static A createAnon() {
            final int dlocal = 40;
    
            // return from the f() method an instance
            // of the anonymous class derived from A
    
            // invoke superclass constructor
            return new A(10) {             
                int bfield = 20;
                int cfield;
    
                {
                    cfield = 30;
                }
    
                int getValue() {
                    return afield + bfield + cfield 
                    + dlocal;
                }
            };
        }
    
        public static void main(String args[]) {
            A anonref = createAnon();
    
            System.out.println(anonref.getValue());
        }
    }

In this example, the createAnon method declares an anonymous class and returns a superclass (A) reference to an instance of the anonymous class. This means that the anonymous class instance can be used outside the declaring context (createAnon). Then the getValue method is called on the anonymous class object reference.

Recall that anonymous classes do not have names, and so, they cannot have explicit constructors. But there are several ways to get around this limitation. When an instance of an anonymous class is created, by saying:

    new A(10) {...}

the superclass constructor, A(int), is automatically called.

Instance initialization for the anonymous class instance is handled in the normal way, so that

    int bfield = 20;

and

    {
        cfield = 30;
    }

work as usual. These mechanisms can be used to do part of the work that might normally be done in a constructor.

There's one additional unusual feature of the AnonDemo4 example. The dlocal variable is declared as final. If the final keyword is left off the declaration, this code will evoke a compiler error. Why? Because it's possible, as this example illustrates, to refer to an anonymous class object outside the context where the class was declared. If such a reference is made, what value would dlocal have, given that it's a local variable declared in the createAnon method? This is a classic programming issue that occurs when an invalid stack frame is referenced.

To get around this problem, the local variable must be made final, that is, bound to a particular value which can be used in place of the variable (dlocal) itself. So instead of using "dlocal", the value "40" is used.

Anonymous classes are very useful tools, but they should not be overemphasized. Some other kind of class might be a better choice if more than one anonymous class in your application uses the same logic, or if the logic in such a class is complicated, or if you have deep class nesting. Also, anonymous class declarations can be hard to read, so you should keep them simple.

For further information about anonymous classes, see section 5.4 Anonymous Inner Classes, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes. Also see item 18 "Favor static member classes over nonstatic" in Effective Java Programming Language Guide" by Joshua Bloch.

Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Core Java Technologies Tech Tips
October 8, 2002


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_23866129-1755743935@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Oct 16 20:40:30 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g9H1eTr16846 for ; Wed, 16 Oct 2002 20:40:29 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g9H1f0Ze028010 for ; Wed, 16 Oct 2002 20:41:05 -0500 (EST) Date: 16 Oct 2002 17:27:04 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <23866129-1755743935@hermes.sun.com> Subject: October Core Java(tm) Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 17051 Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Standard Edition (J2SETM).



Product and Technology Releases

The following J2SE products and technologies were recently released.

JSR-000013 Decimal Arithmetic Enhancement for the Java Programming Language Proposed Final Draft
The proposed enhancements to the BigDecimal class primarily add floating point arithmetic to the existing class, allowing the use of decimal numbers for general-purpose arithmetic (especially financial and user-centric applications) without the overheads and potential errors resulting from conversions to and from another type.

Java API for XML Binding Public Review Draft
The public version of the specification is available with the following enhancements over the previous released early access version V0.21:

  • Support for a subset of W3C XML Schema and XML Namespaces
  • More flexible unmarshalling and marshalling functionality
  • Validation process enhancements


Early Access Releases

The following J2SE products and technologies were recently made available through the Early Access Release Program.

J2SE 1.4.1, FCS for Windows, Linux, and Solaris operating environments Additionally, Early Access 64-bit releases for Itanium processors are available for both Linux and Windows. (Aug 20, 2002)



Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

Java Web Start

Java Web Services Developer Pack

Java Technology XML and Web Services Products

Java Virtual Machine 1

pixel
pixel pixel pixel
October 16, 2002

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles

Tech Tips

Chat

Java Technology on Linux
Calvin Austin, Hui Huang, and Juergen Kreileder (Oct 15, 2002)

Newsletters

Java Technology Fundamentals Newsletter
In the latest issue of Java Technology Fundamentals, learn how to use object serialization, and how to draw shapes using the Graphics and Polygon classes. (September 30, 2002)

Bookshelf

Java Development with Ant
This book systematically explores what Ant can do, and how to apply it to your project. Whether you are new to Ant, or an experienced user, this book will show you powerful and creative uses for Ant.

Sun Technology Audiocast

JavaServer Pages and Servlets Programming
This beginner to intermediate-level code camp will show in-depth knowledge for the latest Servlet and JSP technology. (September, 2002)


In The Spotlight

The Sun Certification Summit, November 10-13, Colorado Springs, CO. Sessions help prepare you for Java technology certification, including:

  • Sun Certified Programmer for Java 2 Platform;
  • Sun Certified Developer for Java 2 Platform;
  • Sun Certified Web Component Developer;
  • Sun Certified Architect for Java 2 Platform, Enterprise Edition (J2EETM) technology.

Interact with industry experts at this all-inclusive venue which includes lodging, meals, on-site certification testing and more!

Industry News and Announcements

  • JavaOne Conference Call for Papers
    JavaOne, Sun's 2003 Worldwide Java Developer ConferenceSM, is seeking proposals for sessions. Contribute to the event's innovation and insightful technical education. Submissions accepted from September 30 to November 8, 2002. Submit your proposal(s) at http://java.sun.com/javaone/sf
    Email J1papers@sun.com with questions about the Call for Papers process.

    Mark your calendars for the 2003 JavaOne Conference: JUNE 9-13, 2003, Moscone Center, San Francisco, CA

  • Success Story: Exploring the New Frontier Read about how Java technology helps to power the "Post-Genomic" era.

  • University Wireless Developer Contest Enter your software application in the University Wireless Developer Contest for Java developers. Compete to win $35,000 in scholarships or grants, phones and other prizes. View full contest rules and download an entry form at: http://developer.nextel.com

Viewpoint

The Future of Software
Sun Microsystems' chief engineer, Rob Gingell, looks at Java 2, Enterprise Edition, JiniTM network technology and the future of software. (October 8, 2002)

Events

  • The JavaPolis Conference in Belgium
    Antwerp, Belgium, November 13-14 , 2002
    The Belgian Java Users Group (BeJUG) has organized JavaPolis, a huge Java technology conference. The two-day event has several tracks scheduled, including J2EE, Wireless Java and Java 2 Platform, Micro Edition (J2METM) technologies. Become a BeJUG member and the conference admission is free.

  • ApacheCon US 2002
    Las Vegas, Nevada, USA November 18-21, 2002
    Come share your knowledge of Apache software at this educational and fun-filled gathering of Apache users, vendors, and friends.

  • Web Seminar: Build Java Web Services in Sun ONE Studio and deploy to Oracle9i Application Server
    Tune in Tuesday, October 22nd at 11am Pacific Daylight Time and learn about the integration between Sun ONE Studio and Oracle9i Application Server. The integrated product allows for development of Web Services and J2EE applications in Sun ONE Studio and seamless deployment to Oracle9iAS.

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, Solaris, Jini, JSP, JavaServer Pages, JavaOne, J2EE, J2ME and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


1 The terms "Java virtual machine" and "JVM" mean a virtual machine for the Java platform.
Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_242235971033310033@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Oct 22 12:23:11 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g9MHNBr10477 for ; Tue, 22 Oct 2002 12:23:11 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g9MHNkZk016294 for ; Tue, 22 Oct 2002 12:23:54 -0500 (EST) Date: 22 Oct 2002 08:56:12 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <242235971033310033@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Oct. 22, 2002 (Filtering Logged Messages, Focus Traversal Sequencing) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27371 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text October 22, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, October 22, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Filtering Logged Messages
Controlling Focus Traversal Sequencing

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Pixel

FILTERING LOGGED MESSAGES

One of the many new features of the J2SE version 1.4 release is the Java Logging APIs. Found in the java.util.logging package, the Logging framework permits you to do the obvious: log messages. What makes the feature so special is its configurability.

Out of the box, the logging classes allow you to send log messages to the console (System.out), to memory, to an output stream, to an XML file, or over a socket connection. You have a number of configurable options pertinent to logging. For example, you can configure what types of messages are logged, as well as where they are logged. You specify the configuration options in a logging.properties file in the /lib directory beneath your Java installation directory.

The basic process for using the Logging APIs is:

Step 1: Get the Logger. The Logger is in charge of accepting messages to log.

   Logger logger = Logger.getLogger("");

The string passed to the getLogger method specifies which logger to get. Typically, you get this for whatever package you are working in. So, if you were writing a program for the com.example package, you would ask for the "com.example" logger, as shown here:

   Logger logger = Logger.getLogger("com.example");

Step 2: Use the Logger. Yes, it is that simple. There are many methods of the Logger class for logging messages. The most obvious method is the log method. However, when discussing that method, it's important to point out that logged messages have a Level. The Level of a log message is the importance assigned to the message being sent. Very important messages should be given a priority level of SEVERE. Typically, most messages are informational. These should have a priority level of INFO. The seven levels rank as follows:

o SEVERE
o WARNING
o INFO
o CONFIG
o FINE
o FINER
o FINEST

Here's a demonstration of the log method. The following program logs a SEVERE message. Notice that the program simply passes the log level and message to the log method:

  package com.example;
  import java.util.logging.*;

  public class LogSample {
      private static Logger logger = 
                       Logger.getLogger("com.example");
      public static void main(String argv[]) {
          logger.log(Level.SEVERE, "Severe Testing");
      }
  }

Compile the program with the directory option:

javac -d . LogSample.java

Then run it:

java com.example.LogSample

You should see something like this sent to the console (with the current date and time):

Oct 16, 2002 1:08:44 PM com.example.LogSample main
SEVERE: Severe Testing

While the log method is a nice convenience, there is an even more convenient mechanism available to log messages. Instead of passing the log level to the log method, the Logger permits you to call a method specific to the level of the message to log. The methods are:

o severe(String message)
o warning(String message)
o info(String message)
o config(String message)
o fine(String message)
o finer(String message)
o finest(String message)

Let's update the demonstration to use one of these methods. Notice that you no longer have to specify the priority level as an argument to the method.

  package com.example;
  import java.util.logging.*;

  public class LogSample {
      private static Logger logger = 
                      Logger.getLogger("com.example");
      public static void main(String argv[]) {
          logger.severe("Severe Testing");
      }
  }

In addition to the logging methods for the different severity levels, there are also methods for particular operations such as entering and exiting.

There is another important thing to consider when you use the logging APIs: you need to limit what is logged. The logging APIs will log for all levels, unless you turn off logging for specific levels (you do this through .properties file settings), or if you install a Filter. This does mean that you don't have to recompile your code to enable logging.

There are three primary ways to limit the output from logging operations. The first mechanism is simply to not have Logger method calls in your code. However this is impractical if you eventually want logging messages. That is, if you don't have the Logger method calls in your code, they'll never happen. In fact, that is what most version 1.3 code does now. The second way to limit the output is to tell the Logger that you only want messages over a certain threshold. For instance, if the threshold is CONFIG, you won't get any FINE, FINER, and FINEST messages. Instead, you get only those messages with a priority level of CONFIG or higher.

You can configure the default output level for the Logger by modifying the logging.properties file. Alternatively, you can specify the level to the Logger:

logger.setLevel(Level.CONFIG);

The third way to limit output is the most flexible. It requires you to install a Filter. The Filter interface defines a single method (isLoggable) that lets you examine the LogRecord before letting the Logger log the message.

public boolean isLoggable(LogRecord record)

The LogRecord contains both the Level and the text message to log. If either of these pieces of information doesn't match some predefined criteria, the isLoggable method of the Filter can return false. This indicates that the message shouldn't be logged. Returning true means the Logger can log the record.

Let's look at a Filter that demonstrates these capabilities. The following Filter does not permit logging of consecutive messages that have the same level. The Filter remembers the last level logged. If the next logging request is for a message with the same level, the Filter rejects the request and returns false.

  package com.example;
  import java.util.logging.*;

  public class DupeFilter implements Filter {
    private Level last;
    public boolean isLoggable(LogRecord record) {
      Level level = record.getLevel();
      boolean returnValue = !level.equals(last);
      last = level;
      return returnValue;
    }
  }

To use the Filter, you need to install it into the Logger:

  logger.setFilter(new DupeFilter());

Only one Filter can be installed per logger.

Now let's use the Filter, by running the following test program.

  package com.example;
  import java.util.logging.*;

  public class TestDupe {
      private static Logger logger = 
        Logger.getLogger("com.example");
      public static void main(String argv[]) {
          logger.setFilter(new DupeFilter());
          logger.log(Level.SEVERE, "Severe Testing");
          logger.log(Level.SEVERE, "Severe Testing 1");
          logger.log(Level.SEVERE, "Severe Testing 2");
          logger.log(Level.SEVERE, "Severe Testing 3");
          logger.info("Testing");
          logger.log(Level.SEVERE, "Severe Testing 4");
      }
  }

Executing the program will send the following lines to the console (with the current date and time):

Oct 16, 2002 12:58:59 PM com.example.TestDupe main
SEVERE: Severe Testing
Oct 16, 2002 12:58:59 PM com.example.TestDupe main
INFO: Testing
Oct 16, 2002 12:58:59 PM com.example.TestDupe main
SEVERE: Severe Testing 4

For more information about the Java Logging APIs see, "Java Logging APIs".

Pixel

CONTROLLING FOCUS TRAVERSAL SEQUENCING

One of the new features of the J2SE version 1.4 release is the revamped focus management subsystem. Prior versions had bugs, platform inconsistencies and irregularities when heavyweight AWT components and lightweight Swing components were mixed. The new subsystem focuses on a centralized KeyboardFocusManager that oversees and controls active windows and their component for focus.

Some of the new features of the revamped focus management subsystem are relatively minor. For instance, the FocusEvent now permits you to find out the opposite component during a focus event. From a component that gains focus, you can find out which component lost focus. Conversely, from a component that lost focus, you can find out which component gained focus.

Other changes are a bit more complex. For instance, while the TAB and Shift-TAB are the typical focus traversal keys, if you want to add to or modify the set of keys used for traversal support, you no longer have to attach a KeyListener. In the J2SE 1.4 release, there are four separate sets of keys managed for each container to control focus traversal. If you replace any of these sets with a different set of traversal keys, keyboard focus traversal support changes to the new set of keys.

You acquire the initial set of focus traversal keys by asking the container. You need to pass in one of the appropriate constants from the KeyboardFocusManager class: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, UP_CYCLE_TRAVERSAL_KEYS, and DOWN_CYCLE_TRAVERSAL_KEYS.

  Set set = content.getFocusTraversalKeys(
    KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);

This initial set of focus traversal keys is read-only. However, you can create a new set with the initial set of keys. Then you can add to the new set:

  KeyStroke forward = KeyStroke.getKeyStroke("RIGHT");
  set = new HashSet(set);
  set.add(forward);

Then, after you complete the set, you put the set back:

  content.setFocusTraversalKeys(
    KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);

Here's an example. The following program adds left/right arrow key selection to the focus traversal set for moving to the previous and next component, respectively. Try it. Compile and run the program. It displays a row of numbered buttons. Use the left and right arrow keys to move from one button to the next.

  import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  import java.util.*;

  public class Move {
    public static void main(String args[]) {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(
                                 JFrame.EXIT_ON_CLOSE);
      Container content = frame.getContentPane();
      content.setLayout(new FlowLayout());
      for (int i=0; i<10; i++) {
        JButton button = new JButton(""+i);
        content.add(button);
      }
      Set set = content.getFocusTraversalKeys(
        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
      KeyStroke forward = 
                      KeyStroke.getKeyStroke("RIGHT");
      set = new HashSet(set);
      set.add(forward);
      content.setFocusTraversalKeys(
        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
      set = content.getFocusTraversalKeys(
        KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
      KeyStroke backward = 
                       KeyStroke.getKeyStroke("LEFT");
      set = new HashSet(set);
      set.add(backward);
      content.setFocusTraversalKeys(
        KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
      frame.pack();
      frame.show();
    }
  }

One thing worth mentioning is that hiding, removing, disabling, and making the focus owner non-focusable also affects focus transfer -- not just through focus traversal keys.

Suppose you don't want to change the keys used for focus traversal, but instead you want to change the order that different components in a container are visited. To change the visit order, you use the FocusTraversalPolicy. A FocusTraversalPolicy defines five operations:

  • What component is first in a container
  • What component is last in a container
  • What component is the next component after a specific component
  • What component is the previous component before a specific component
  • Which component is the default (initial) selection for the container

The abstract java.awt.FocusTraversalPolicy class offers several concrete implementations to choose from. (The default is different for AWT and Swing.) There are four predefined policies.

o java.awt.ContainerOrderFocusTraversalPolicy
o java.awt.DefaultFocusTraversalPolicy (AWT default)
o javax.swing.InternalFrameFocusTraversalPolicy
o javax.swing.LayoutFocusTraversalPolicy (Swing/mixed default)
o javax.swing.SortingFocusTraversalPolicy

The ContainerOrderFocusTraversalPolicy and DefaultFocusTraversalPolicy are similar in that they move focus based on the order their components were added to a Container. InternalFrameFocusTraversalPolicy deals with JInternalFrame and its initial component.

LayoutFocusTraversalPolicy and SortingFocusTraversalPolicy are the most interesting. With LayoutFocusTraversalPolicy, the policy is based on the physical location of components on the screen. This takes into consideration size, position, and orientation.

SortingFocusTraversalPolicy relies on a Comparator to do the ordering for you. Just create the Comparator to order any two components and it controls the focus traversal sequencing order.

Here's an example that uses SortingFocusTraversalPolicy. The following Comparator offers an alphabetical focus traversal sequence based on the text label of a button. You combine the Comparator with a SortingFocusTraversalPolicy to get that sequencing. The Comparator could offer support for other types, but for simplicity, it assumes that everything in the container is a JButton. (The container itself isn't -- so an instanceof is needed.)

  import javax.swing.*;
  import java.util.*;

  public class AlphaOrder implements Comparator {
    public int compare(Object one, Object two) {
      if (! (one instanceof JButton)) return 1;
      if (! (two instanceof JButton)) return 1;
      JButton button1 = (JButton)one;
      JButton button2 = (JButton)two;
      String text1 = button1.getText();
      String text2 = button2.getText();
      return text1.compareTo(text2);
    }
  }  

To make sure the container itself isn't in the focus traversal order, you need to make one additional change. By subclassing SortingFocusTraversalPolicy, you can automatically reject non-JButton components.

  import java.awt.*;
  import javax.swing.*;
  import java.util.*;

  public class AlphaOrderFocusTraversalPolicy
      extends SortingFocusTraversalPolicy {
    AlphaOrderFocusTraversalPolicy() {
      super(new AlphaOrder());
    }

    protected boolean accept(Component aComp) {
      if (aComp instanceof JButton) {
        return super.accept(aComp);
      }
      return false;
    }
  }

The following program demonstrates the Comparator in action with the SortingFocusTraversalPolicy subclass. The program displays a screen that contains a series of buttons in a panel. Traversal of the buttons is controlled by the new focus traversal policy set. Notice as you hit the tab key, focus cycles through the components in alphabetical order (with shift-TAB going in the reverse direction). You can create similar comparators for other orderings.

  import java.awt.*;
  import javax.swing.*;


  public class AlphaPolicy {
    public static void main(String args[]) {
      String labels[] = {"Henry VII", "Henry VIII", 
        "Edward VI", "Jane", "Mary I", "Elizabeth I"};
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(
                                JFrame.EXIT_ON_CLOSE);
      Container content = frame.getContentPane();	
      JPanel panel = new JPanel();
      panel.setFocusTraversalPolicy(
        new AlphaOrderFocusTraversalPolicy());
      panel.setFocusCycleRoot(true);
      for (int i=0, n=labels.length; i<n; i++) {
        JButton button = new JButton(labels[i]);
        panel.add(button);
      }
      content.add(panel, BorderLayout.CENTER);
      frame.pack();
      frame.show();
      panel.getComponent(0).requestFocusInWindow();
    }
  }

For additional information on the changes to the AWT Focus Subsystem, see "The AWT Focus Subsystem".

Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Core Java Technologies Tech Tips
October 22, 2002


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_24446661-457710049@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Oct 29 16:19:36 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g9TLJZr13432 for ; Tue, 29 Oct 2002 16:19:35 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g9TLKOZM002595 for ; Tue, 29 Oct 2002 16:20:26 -0500 (EST) Date: 29 Oct 2002 12:59:50 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <24446661-457710049@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 29870 Java(TM) Technology Fundamentals Newsletter
pixel
pixel
header
    October 29, 2002    

In this Issue

imageJavaTM Programming Language Basics
image Java Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageFor More Information

Pixel

Java Programming Language Basics

How to Use Threads

The Java platform was designed from the start to be a multithreaded environment. While your main program is executing, other tasks like garbage collection and event handling are done in the background. Mentally, you can think of these other tasks as threads. They happen to be system-managed threads, but nonetheless, they are threads. Threads enable you to define isolated tasks that happen independently of each other. The system then swaps tasks in and out of the CPU so that (externally) it appears they are all running simultaneously.

When you need to do multiple tasks in your own program, you, too, can work with multiple threads. These threads can be ones you create yourself, or you can interact with the system threads.

You do these multiple tasks using several different classes and interfaces:

  • java.util.Timer class
  • javax.swing.Timer class
  • Thread class
  • Runnable interface

For simple tasks that typically need to repeat, you can work with the java.util.Timer class to say "Do this task every half second." Keep in mind that most system routines work with milliseconds. A half second is 500 milliseconds.

The task you want the Timer to perform is defined in a java.util.TimerTask instance, where its run method contains the task to perform. This is demonstrated in the Hi class, where the String "Hi" is printed to the console repeatedly, until you press the Enter key.

import java.util.*;

public class Hi {
   public static void main(String args[]) 
         throws java.io.IOException {
     TimerTask task = new TimerTask() {
       public void run() {
         System.out.println("Hi");
       }
     };
     Timer timer = new Timer();
     timer.schedule(task, 0, 500);
     System.out.println("Press ENTER to stop");
     System.in.read(new byte[10]);
     timer.cancel();
   }
}

The way the Java Runtime Environment (JRE) works is that as long as there is a thread running, the program won't exit. So, once cancel is called, there are no other user threads running and the program exits. There are some system threads running, like the garbage collector. These system threads are also called daemon threads. The existence of daemon threads does not prevent the runtime environment from shutting down; Only non-daemon threads prevent that.

The javax.swing.Timer class works similarly to the java.util.Timer class, with a couple of differences of note. First, the task to run is defined by an implementation of the ActionListener interface. Second, the task executes within the event-handling thread, not outside of it like the java.util.Timer class. This is important because of how the Swing component set was designed.

If you aren't familiar with Swing, it is the set of graphics components available to Java programs. Swing was designed to be what is called single-threaded. That means that all access to the internal contents of the Swing classes must be done within a single thread. That specific thread is the event-handling thread. So, for example if you wanted to change the text of a label component, you couldn't just call the setText method of JLabel. Instead, you would have to make sure that the setText call happens in the event-handling thread, and that is where the javax.swing.Time class comes in handy.

To demonstrate this second case, the following program displays the value of an increasing counter. Every half second the counter value is increased and the new value is displayed.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Count {
   public static void main(String args[]) {
     JFrame frame = new JFrame();
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     Container contentPane = frame.getContentPane();
     final JLabel label = new JLabel("", JLabel.CENTER);
     label.setFont(new Font("Serif", Font.PLAIN, 36));
     contentPane.add(label, BorderLayout.CENTER);
     ActionListener listener = new ActionListener() {
       int count = 0;
       public void actionPerformed(ActionEvent e) {
         count++;
         label.setText(Integer.toString(count));
       }
     };
     Timer timer = new Timer(500, listener);
     timer.start();
     frame.setSize(300, 100);
     frame.show();
   }
}

The program above produces the following:

Count

In cases where there isn't a simple repeating task to be done, the java.lang.Thread class comes into play. It allows you to control the raw functionality yourself. By creating a subclass of Thread, you can have the system go off and do a long-running task, like reading a file from over the network, without blocking the execution of the rest of your program. That long running task would be defined in the run method.

The run method used by Thread and TimerTask is actually part of an interface: java.lang.Runnable. While you could always subclass Thread to define the task to be done, if you aren't adding any behavior to the subclass (besides the task to be done) the more appropriate way to design the system is to define the task to be done in an implementation of the Runnable interface. Then, you pass the implementation to the Thread constructor. And, when you start the thread up, that Runnable is what is executed.

The second way is to subclass Thread and implement the run method in the subclass, or implement the run method in a class that implements Runnable and pass that implementation on to the Thread constructor.

You may ask yourself what is the difference. The Java programming language only supports single inheritance. If your design calls for a different superclass besides Thread, you can have your class implement Runnable, and it will have its task to execute. Otherwise, you subclass Thread to define its own run method, adding no particular set of operations in the process.

For this third case of subclassing Thread, the following program creates a new thread to count the number of characters in a particular URL whose value is passed in from the command line. While that is going on, the fourth case of implementing Runnable is demonstrated, printing out a repeated message. Notice in this latter case of implementing Runnable, you must provide the code to repeat the message. You have to both sleep for the allotted time and do the action. Compare that to the use of Timer, in both cases. The final piece of the program has you read a line from the command to trigger the program ending. Notice that while the system is reading from the URL and printing the message, you can always press Enter to end the program.

import java.io.*;
import java.net.*;

public class Both {
   public static void main(String args[]) {
     final String urlString = args[0];
     final String message = args[1];
     Thread thread1 = new Thread() {
       public void run() {
         try {
           URL url = new URL(urlString);
           URLConnection connection = 
               url.openConnection();
           InputStreamReader isr = new 
               InputStreamReader(
                   connection.getInputStream());
           BufferedReader reader = new BufferedReader(isr);
           int count = 0;
           while (reader.read() != -1) {
             count++;
           }
           System.out.println("Size is : " 
               + count);
           reader.close();
         } catch (MalformedURLException e) {
           System.err.println("Bad URL: " 
               + urlString);
         } catch (IOException e) {
           System.err.println("I/O Problems");
         }
       }
     };
     thread1.start();
     Runnable runnable = new Runnable() {
       public void run() {
         while(true) {
           System.out.println(message);
           try {
             Thread.sleep(500);
           } catch (InterruptedException e) {
           }
         }
       }
     };
     Thread thread2 = new Thread(runnable);
     thread2.start();
     try {
       System.out.println("Press ENTER to stop");
       System.in.read(new byte[10]);
     } catch (IOException e) {
       System.out.println("I/O problems");
     }
     System.exit(0);
   }
}

While there are many ways of working with threads, which technique you use is up to you and your circumstances. While you usually don't have to learn everything about the Java programming language and its core libraries to become a productive Java programmer, threading is an exception. The sooner you can understand how threads work and how to use them, the sooner you'll come to understand how Java programs work and interact.

Pixel
Pixel

Java Bits

Working with Boolean Statements

A boolean value is a primitive data type that has a value of either true or false. Boolean statements allow you to consider several conditions in one programming decision. To determine if conditions are true or false, boolean expressions frequently use the following operators:

  • && to mean AND
  • || to mean OR
  • ! to mean NOT
  • ^ to mean XOR

For example, in a program to determine overtime pay, the application must first determine whether the employee's work hours exceeded 40 hours for a particular week and for a particular type of job position:

if ((hours > 40) && (position.equals(
    "salesClerk") ||
        (position.equals("stockPerson"))
    System.out.println(
        "Employee receives overtime pay.");
else
    System.out.println(
        "Employee receives regular pay.");

The problem above is stating that if the hours worked are more than 40, and the job position is a sales clerk or a stock person, then print the statement, "Employee receives overtime pay." Otherwise, print the statement, "Employee receives regular pay."

Sometimes you may want to declare boolean variables first, then use them in a boolean expression to test conditions:

boolean isSaturday = day.equals("Saturday");
boolean isDayLight = hour < 19 && hour > 5;

if(isSaturday && isDayLight)
   System.out.println("Go play at the beach");
if   (isSaturday && !isDayLight)
    System.out.println("Sleep until Sunday.");
Boolean

In the example above, the first boolean variable isSaturday is true only if a String Saturday is returned. The second boolean variable isDayLight defines the condition for daylight, and returns true only if these hourly conditions are met.

Pixel
Pixel

Making Sense of the Java Class Libraries

The JOptionPane Class

Pop-up dialog boxes are useful GUI components that can be used to alert users to problems, request information, or provide instruction. The Swing API provides a JOptionPane class that allows you to create simple dialog boxes by calling a static method, or create more elaborate dialogs containing text fields and buttons.

There are four basic types of JOptionPane dialog boxes:

  • Input dialog
  • Confirm dialog
  • Message dialog
  • Option dialog

You can create JOptionPane dialog boxes either by calling one of the JOptionPane constructors, or by calling one of the JOptionPane static methods:

  • showConfirmDialog: Ask a confirming question, like Yes/No/Cancel.
  • showInputDialog: Prompt for input.
  • showMessageDialog: Inform the user that something has happened.
  • showOptionDialog: A combination of the above three.
JOptionPane

The JOptionPane objects are not standalone containers. Instead, they exist inside a JDialog or JInternalFrame object that the static methods create and associate automatically.

When an application runs and the dialog pops up, unless a thread is implemented, no other action can be taken within the application until the dialog is dealt with, either by entering information, clicking a button, or closing the dialog box.

To create a message dialog that warns the user that the requested file doesn't exist, for instance, call the showMessageDialog static method:

JOptionPane.showMessageDialog(null, 
    "Requested file cannot be found.",
        null, JOptionPane.ERROR_MESSAGE );
 
or a dialog to confirm information:

JOptionPane.showConfirmDialog(null, 
    "Do you want to Exit?",
        null, JOptionPane.YES_NO_OPTION );

JOptionPane dialog boxes serve many useful purposes from collecting data from the user to providing warnings and information.

Pixel
Pixel

Program Challenge

Create the Counter Application

Create a program that displays a number in the middle of the screen, and has four buttons.

  • The first button causes the number to increment its value every half second.
  • The second button causes the number to decrement its value every half second. The value can be incrementing or decrementing in one direction at a time.
  • The third button causes the incrementing/decrementing behavior to stop.
  • The fourth button resets the number to 0.
Pixel
Pixel

For More Information

The Java FAQ -- Threads

Multithreaded Swing Applications

Creating a Threaded Slide Show Applet

Lesson: Threads: Doing Two or More Tasks At Once

Why Use Threads?

How to Make Dialogs

Class JOptionPane

Pixel
Pixel

Program Challenge Solution

See one possible solution to the October Program Challenge:

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the Java 2, Standard Edition (J2SETM) development kit.

Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_23491611-931207701@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Oct 15 16:35:31 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g9FLZVr15328 for ; Tue, 15 Oct 2002 16:35:31 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g9FLa5ZK016788 for ; Tue, 15 Oct 2002 16:36:06 -0500 (EST) Date: 15 Oct 2002 14:24:57 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <23491611-931207701@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, October 15, 2002 (Sending Email From A Servlet, Transforming XML with XSL) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 34544 Enterprise Java Technologies Tech Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text October 15, 2002    

In this Issue

WELCOME to the Java 2TM, Enterprise Edition (J2EETM) Tech Tips, October 15, 2002. This issue covers:

.Sending Email From a Servlet
.Transforming XML With XSL

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the J2EE Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for these tips. The context root for the application is /ttoct2002, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to these license terms: http://developer.java.sun.com/berkeley_license.html

Pixel

Sending Email From a Servlet

Enterprise applications frequently use email to communicate with users. Ecommerce applications in particular use email to communicate with customers. This month's first tip shows how to use the JavaMailTM 1.2 APIs to send email from a servlet. (Keep in mind that the JavaMail API can be used from anywhere the J2EE platform is available, not just from servlets.)

The JavaMail APIs

JavaMail comprises a set of APIs that provide a simple interface to many kinds of email messaging technology. It is compatible with existing standards, and includes interfaces for extensibility to support future or proprietary email delivery technologies.

Protocol independence is one of JavaMail's most important features. The JavaMail APIs hide the implementation details of the mail protocols (such as IMAP, MAPI, POP, POP3, and SMTP) used to transmit and receive emails. Programmers create and send messages using a simple object model.

Because JavaMail is part of J2EE, you can use the JavaMail APIs in any J2EE application without installing any additional packages. JavaMail uses the JavaBeansTM Activation Framework (also part of J2EE) to identify handlers for content types.

JavaMail Basics

Sending an email message using JavaMail is easy. The task consists of three steps:

  1. Create a Session that represents a connection to an email service provider.
  2. Create and initialize a Message object that contains the data to be sent in the email.
  3. Send the email message.

A Session handles configuration and authentication for a connection to a messaging system. The javax.mail.Session class maintains a "primary" message store, called the default session. Desktop applications share the default session, accessed by calling the static method Session.getDefaultSession.

A Message is an abstract class that represents a single email message. The message includes the body text of the message, its routing information (such as the addresses of the sender and recipients), its subject, and so on. The kind of message used in the example shown here uses javax.mail.internet.MimeMessage, which represents an Internet MIME email message. (MIME stands for Multi-part Internet Mail Extensions, which is defined by several IETF RFCs.)

The final JavaMail API used in this example is javax.mail.internet.Address, which represents an RFC 822 Internet email address.

SendmailServlet Input

The example servlet in this tip is named SendmailServlet. The servlet receives an email message and routing information from an HTML form and uses JavaMail APIs to transmit the message. The servlet uses several HTTP request parameters to create the email message:

  • messagetext: the message to send
  • subject (optional): the subject of the message
  • addrfrom: the email address of the sender
  • namefrom: the personal name of the sender
  • addrto: the email address of the recipient
  • nameto: the personal name of the recipient
  • debug: if true, the JavaMail session dumps a log of the SMTP session to the server log when transmitting a message

In addition to the request parameters listed above, the servlet also requires two servlet initialization parameters to be set in the web application deployment descriptor (an additional parameter is optional):

  • mailhost: the name of the (SMTP) mail server to use to send the email
  • mailuser: the name of the user sending the email
  • debug (optional): turns debugging on or off (cannot be overridden by request parameter debug)

The servlet code is a standard HttpServlet. Its methods doPost and doGet both call method doService, which handles the request. The code first gets a Session, which it will use to create and send messages.

Getting a session

The servlet's getMailSession method gets a reference to the default mail session and caches it in protected field _mailSession. Method Session.getDefaultInstance uses a java.util.Properties object to initialize its contents. The properties mail.host and mail.user initialize the mail host and user name, respectively.

// Open the mail session if it isn't already open.
protected Session getMailSession()
  throws ServletException {
        
    // Throw exception if mail host or user are not set
    if (_mailhost == null || _mailuser == null) {
        throw new ServletException("SendmailServlet " +
          "init parameters mailhost and mailuser must " +
          "both be set in deployment descriptor");
    }

    // Create mail session if it doesn't exist
    if (_mailSession == null) {
        Properties p = new Properties();
        p.put("mail.host", _mailhost);
        p.put("mail.user", _mailuser);

        // Can define and initialize other session
        // properties here, if desired
        _mailSession = Session.getDefaultInstance(p, null);
    }
    return _mailSession;
}

Turning on debugging

If the debug flag is initialized in the deployment descriptor or in the request, the servlet sets the debug flag for the session, as shown below.

s.setDebug(true);

This code tells the session(s) to print a trace of its conversation with the SMTP server when the email is sent.

Creating and initializing the message

The servlet creates a new MimeMessage, using the constructor that takes a Session argument. It also sets the message text and subject, retrieved from the HTTP request.

   // Create new message
   MimeMessage msg = new MimeMessage(s);

   // Put data from request into message
   try {
       String messageText =
           req.getParameter("messagetext");
       msg.setText(messageText);

Addressing the message

The servlet represents the sender address using an InternetAddress object. It gets the from address and name from request parameters, builds the Address, and uses the message's setFrom method to set message's sender. Note that Address does not enforce the email address format required by RFC 822. That's up to you, if you want to check. The code that sets the sender address appears below.

       String addrFrom =
           req.getParameter("addrfrom");
       String nameFrom =
           req.getParameter("namefrom");
       Address fromAddr =
           new InternetAddress(addrFrom, nameFrom);
       msg.setFrom(fromAddr);

The code that sets the email recipient's address is similar to the code that sets the sender address, as shown below.

       String addrto = req.getParameter("addrto");
       String nameto = req.getParameter("nameto");
       Address toAddr =
           new InternetAddress(addrto, nameto);
       msg.addRecipient(Message.RecipientType.TO,
       toAddr);       

The message's addRecipent method takes two arguments: a value that indicates the recipient type (the types are TO, CC, and BCC), and an Address for the recipient. There are alternate forms of this method, called addRecipients and setRecipients, whose second argument is an array of Address objects (Address[]) to be added to (or to replace) the current recipient list. There is also a corresponding addFrom method that adds multiple sender Addresses to the message.

Sending the message

Sending the message requires a single line of code, shown below.

Transport.send(msg);

The Transport class has a static method send that transmits the message using the transport protocol appropriate for the message. The message is then queued for delivery to the receipient. At this point, if debugging is turned on, a stream of SMTP commands is written to the standard output of the server. The J2EE Reference Implementation directs this stream to the server log.

Running the example

The example servlet will not operate correctly if it is deployed immediately after download. That's because the mail host and user are defined in the web application deployment descriptor, but are uninitialized in the distribution. The mail host and user are set in the deployment descriptor because the mail server to use should be controlled on the server side.

The easiest way to initialize these variables is to:

  • Open the application archive in deploytool (or your server product's deployment tool).
  • Set the servlet init parameters mailhost and mailuser
  • Use the tool to deploy the application.

If you don't have or don't use a GUI deployment tool, you'll have to use the jar program to extract and update the files in the appropriate archives. The manual procedure for setting the mail host and user for your local environment follows.

  1. Download the sample archive, ttoct2002.ear.

  2. Extract the web archive from the EAR file:
    jar xvf ttoct2002.ear toct2202.war
    
  3. Extract the web application deployment descriptor from the WAR file:
    jar xvf ttoct2002.war WEB-INF/web.xml
    
  4. Open the file WEB-INF/web.xml in a text editor

  5. Edit the two initialization parameters for the SendmailServlet, adding your SMTP server name and your login name on that server (this example does not support SMTP server authentication). The block of XML you want to edit looks like the following:
        <servlet>
        <servlet-name>SendmailServlet</servlet-name>
        ...
        <init-param>
          <param-name>mailhost</param-name>
          <param-value><!-- Your SMTP server name here --></param-value>
        </init-param>
        <init-param>
          <param-name>mailuser</param-name>
          <param-value><!-- Your user name here --></param-value>
        </init-param>
      </servlet>
    
  6. Replace the web.xml deployment descriptor in the web archive:
    jar uvf ttoct2002.war WEB-INF/web.xml
    
  7. Replace the WAR file in the EAR application archive:
    jar uvf ttoct2002.ear ttoct2002.war
    
  8. Deploy the application

JavaMail resources

For hands-on experience with the JavaMail APIs, see the JavaMail Tutorial. The JavaMail API specification is available for free download. You can also read the JavaMail API home page for resources and news about JavaMail.

Pixel
Pixel

Transforming XML With XSL

In the past few years, an increasing number of systems architects are adopting XML for representing data and schema. One of the more useful tools for working with XML is XSLT (the eXtensible Style Language for Transformations).

An XML document can be represented as an abstract tree. An XSLT stylesheet is a program, written in an XML syntax, that can transform XML from one tree structure into another. Figure 1 belows shows a transformer object transforming a source document with one structure into a result document with a different structure. The transformation is specified by the XSLT stylesheet.

[XSLT stylesheet]
Figure 1. An XSLT stylesheet transforms a source document

A practical (and common) example of why someone would want to restructure data in this way is transforming XML to HTML. XML data can be represented as styled HTML using XSL to perform the transformation. That's what the following sample code, TransformServlet, does. It displays one of several XML files as HTML. The sample code does this by transforming XML into HTML, using an XSLT stylesheet.

TransformServlet

The sample Web application for the TransformServlet allows the user to select one of four plays by William Shakespeare that have been marked up with XML. The user then chooses a stylesheet that selects information from the selected plays and transforms it into HTML.

The TransformServlet reads two files, an XML file and a stylesheet, from the application EAR file. It then applies the XSLT stylesheet to the XML document, producing an HTML result document. If no stylesheet is specified, the transformer serves the XML file as XML instead of styling it as HTML. (This is known as the "identity transform".)

Figure 2 below shows how the servlet works. The abstract class javax.xml.transform.Transformer reads a source document and a stylesheet. Its interface to each file is through interface javax.xml.transform.Source, which represents an XML data source. Class Transformer writes the results of its transformation to a javax.xml.transform.Result.

Because Transformer models its input as a Source object and its output as a Result object, it can process a wide variety of data sources. The java.xml classes StreamSource and StreamResult adapt the java.io classes InputStream and OutputStream (respectively) for use by a Transformer.

[Servlet Classes]
Figure 2. Important classes used in TransformServlet

In this example, the servlet opens InputStream objects to the XML source document and the XSLT stylesheet. The servlet wraps them as StreamSource objects, and uses them as Source inputs for the Transformer. Likewise, the servlet wraps the ServletOutputStream as a StreamResult. The Transformer writes its results directly to the servlet response.

Reading documents from the application archive

The servlet uses convenience method getResourceAsStream to open a stream to read the document source from the application archive. It then uses a parser to parse the document into an in-memory DOM tree. This document is later wrapped as a DOMSource object so it can be used as a Source input of a Transformer.

    // Get the DOM of the document to be transformed
    protected Document getDocument(String path) 
        throws IOException, SAXException,
               ParserConfigurationException {
        try {
            DocumentBuilder db = getDocumentBuilder();
            InputStream is = getResourceAsStream(path);
            Document result = db.parse(is);
            return result;
        } catch (Exception e) {
            System.err.println(
                     "getDocument threw exception: " +
                     e.getMessage());
            return null;
        }
    }

    protected InputStream getResourceAsStream(String path)
        throws IOException {
        ServletContext ctx = _config.getServletContext();
        InputStream is = ctx.getResourceAsStream(path);
        return is;
    }

Creating a Transformer

The sample uses a Templates object to create a Transformer. A Templates object represents a compiled spreadsheet. Templates objects are thread-safe -- by comparison, Transformers are not.

If method getTransformer receives an empty stylesheet name, it uses javax.xml.transform.TransformerFactory to create a new Transformer. This transformer performs the identity transform: it simply copies its Source to its Result, so the servlet will serve the requested document XML. If the stylesheet name is not empty, getTransformer gets a Templates object from method getTemplates and uses it to create the new transformer.

The getTemplates method first checks in the static HashMap _templatesCache to see if a template for that stylesheet already exists. If a Templates object is not in the cache, the code creates one and caches it. It then uses method Templates.newTransformer to create and return a new transformer object for the requested stylesheet.

The code shown below constructs and caches Templates objects "lazily". A Templates object for a stylesheet is created only when it is requested. An alternate approach would be to create Templates objects for all stylesheets at once, populating the cache in the init method of the servlet.

    // Get a transformer object for a specific 
    // style sheet. If the style sheet is null, return 
    // the identity transform.
    protected Transformer getTransformer(
                                String styleSheetPath)
        throws TransformerConfigurationException {

        Transformer result = null;

        // Return identity transform if no stylesheet
        if (styleSheetPath.trim().length() == 0) {
            TransformerFactory tf = 
                               getTransformerFactory();
            result = tf.newTransformer();
        } else {
            // Get transformer Templates object 
            // from cache
            Templates tpl = 
                          getTemplates(styleSheetPath);
            result = tpl.newTransformer();
        }
        return result;
    }

    protected TransformerFactory getTransformerFactory() {
        if (_tf == null) {
            _tf = TransformerFactory.newInstance();
        }
        return _tf;
    }

    // Get a Templates object for a stylesheet
    protected Templates getTemplates(
                                String styleSheetPath)
      throws TransformerConfigurationException {
        Templates result = null;

        result =
            (Templates)_templatesCache.get(
                                       styleSheetPath);

        // If it's not in the cache, create & cache it
        if (result == null) {
            try {
                TransformerFactory tf = 
                               getTransformerFactory();
                InputStream is = 
                   getResourceAsStream(styleSheetPath);
                StreamSource ss = new StreamSource(is);
                result = tf.newTemplates(ss);
                ss.setSystemId(styleSheetPath);
            } catch (IOException ex) {
                System.err.println(
                              "Error in getTemplates");
                System.err.println(ex);
            }
            _templatesCache.put(styleSheetPath, result);
        }
        return result;
    }

TransformerServlet Code

The code for the transformer servlet is straightforward. First, it gets the document and stylesheet sources. The path to these files is specified in the HTTP request object.

    // Get the path of the document and the
    // stylesheet to use from the request.
    String sourceDocPath =
       req.getParameter("doc").trim();
       String styleSheetPath =
          req.getParameter("style").trim();    

It then gets the source document.

    // Get the source document
    Document d = getDocument(sourceDocPath);

    if (d == null) {
        println("ERROR: Got a null document");
        return;
    }

If there is no stylesheet, the servlet produces XML instead of HTML. In either case, it sets the response content type.

    // If stylesheet exists, return HTML; if
    // it's empty, return XML.
    if (styleSheetPath.length() == 0) {
        res.setContentType("text/xml");
    } else {
        res.setContentType("text/html");
    }

The servlet then creates the transformer. It also copies all request parameters to parameters in the transformer for potential use by the XSLT stylesheet. For example, one of the requests is to a stylesheet that prints all the lines spoken by a particular character. The character's name is a parameter in the stylesheet.

    // Create the transformer that performs the
    // XML transformation
    Transformer transformer =
        getTransformer(styleSheetPath);

    // Set all POST variables as parameters
    // to the stylesheet.
    Enumeration e = req.getParameterNames();
    while (e.hasMoreElements()) {
        String param = (String)e.nextElement();
        String value = (String)req.getParameter(param);
        transformer.setParameter(param, value);
    }

Finally, the servlet wraps the DOM tree created by the parser as a DOMSource so it can be used by a Transformer. The servlet also wraps its own response PrintWriter as a StreamResult object. It then calls the transformer's transform method, passing the documentSource and the Result object. The transform method applies its stylesheet to the Source and writes it to its Result.

    // Create the document source
    DOMSource docSource = new DOMSource(d);

    StreamResult resultStream =
        new StreamResult(res.getWriter());

    transformer.transform(docSource,
                          resultStream);

Running the examples

This tip runs with no modification. Download and deploy the application, and then visit the application's context root /ttoct2002. The Web page provides a form to use for sending emails for the tip Sending Email From a Servlet. The Web page also provides a form that you can use to browse four of Shakespeare's plays -- four stylesheets format the data in different ways. The sample code is also available in HTML form: see the links at the bottom of the Web page.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, JavaMail, JavaBeans Activation Framework, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_2474046946258471@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Nov 5 13:06:11 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gA5I6Ar11087 for ; Tue, 5 Nov 2002 13:06:10 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gA5I6pj5022270 for ; Tue, 5 Nov 2002 13:07:08 -0500 (EST) Date: 5 Nov 2002 08:51:19 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <2474046946258471@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Nov. 5, 2002 (Sets, Expression Evaluation Order) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27403 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text November 5, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, November 5, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Using HashSet, LinkedHashSet, and TreeSet
Understanding Expression Evaluation Order

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Pixel

USING HASHSET, LINKEDHASHSET, AND TREESET

A set is a collection of elements without any duplicates. The Set and SortedSet interfaces describe the properties of sets, and the HashSet, LinkedHashSet, and TreeSet classes implement these interfaces. This tip examines these classes, and illustrates where each might be appropriate for use in your Java applications.

Let's start with a simple example:

    import java.util.*;
    
    public class SetDemo1 {
        static final int MIN = 1;
        static final int MAX = 10;
    
        public static void main(String args[]) {
            Set sethash = new HashSet();
            for (int i = MAX; i >= MIN; i--) {
                sethash.add(new Integer(i*i));
            }
            System.out.println("HashSet = " + sethash);
    
            Set setlink = new LinkedHashSet();
            for (int i = MAX; i >= MIN; i--) {
                setlink.add(new Integer(i*i));
            }
            System.out.println(
                         "LinkedHashSet = " + setlink);
    
            Set settree = new TreeSet();
            for (int i = MAX; i >= MIN; i--) {
                settree.add(new Integer(i*i));
            }
            System.out.println("TreeSet = " + settree);
        }
    }

This SetDemo1 program creates an instance of each kind of set, and adds the squares of the values from 10 to 1 to the set. It wraps each integer value in an Integer object.

When you run the program, the result is:

    HashSet = [9, 25, 4, 36, 100, 1, 49, 81, 16, 64]
    LinkedHashSet = [100, 81, 64, 49, 36, 25, 16, 9, 4, 1]
    TreeSet = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

The results illustrate that elements in a HashSet are retrieved (iteration ordering) in apparent random order. The elements of a LinkedHashSet are retrieved in the order that they are inserted into the set. The elements of a TreeSet are retrieved in ascending sorted order.

HashSet is a good choice for representing sets if you don't care about element ordering. But if ordering is important, then LinkedHashSet or TreeSet are better choices. However, LinkedHashSet or TreeSet come with an additional speed and space cost.

Let's examine that cost by running another program:

    import java.util.*;
    
    public class SetDemo2 {
        static final int N = 500000;
    
        static List numlist = new ArrayList(N);
    
        // fill up List with random Integer values
    
        static {
            Random rn = new Random();
            for (int i = 0; i < N; i++) {
                numlist.add(new Integer(
                                rn.nextInt()));
            }
        }
    
        static void dotime(Set set, String which) {
    
            long start = System.currentTimeMillis();
    
            // add all List values to Set
    
            set.addAll(numlist);
    
            // look up all List values in Set
    
            for (int i = 0; i > N; i++) {
                if (!set.contains(numlist.get(i))) {
                    System.out.println(
                        "contains error");
                }
            }
    
            long elapsed = 
                    System.currentTimeMillis() - start;
    
            System.out.println(which + " " + elapsed);
        }
    
        public static void main(String args[]) {
            if (args.length != 1) {
                System.out.println(
                    "Usage: java SetDemo2 " +
                    "HashSet|LinkedHashSet|TreeSet");
                System.exit(1);
            }
    
            // do timing of HashSet / 
            // LinkedHashSet / TreeSet
    
            if (args[0].equals("HashSet")) {
                dotime(new HashSet(), "HashSet");
            }
            else if (args[0].equals("LinkedHashSet")) {
                dotime(
                   new LinkedHashSet(), "LinkedHashSet");
            }
            else {
                dotime(new TreeSet(), "TreeSet");
            }
        }
    }

The SetDemo2 program creates a set, adds a list of Integer values to it, and then looks up each value in the set.

To compare the performance of the three kinds of sets, you need to run the SetDemo2 program three times, like this:

    java SetDemo2 HashSet

    java SetDemo2 LinkedHashSet

    java SetDemo2 TreeSet

It's done this way so that each type of set will start with a clean slate for timing purposes.

The output of the three runs will be something like this:

    HashSet 2688

    LinkedHashSet 4078

    TreeSet 6469

Your results might differ, perhaps significantly, depending on your operating environment. But the results should indicate that TreeSet takes more than twice as long as HashSet.

A HashSet is implemented with a backing HashMap structure. In other words, a HashSet uses a hash table as the underlying data structure to represent a set. A LinkedHashSet is similar, but it also superimposes a doubly-linked list on the elements to keep track of the insertion order. A TreeSet is based on a TreeMap, which, in turn, is based on red-black trees. These trees are something like binary trees, with a collection of nodes containing left and right subtrees, and so on. However the trees have additional functionality to keep them balanced, that is, to keep their shape from becoming skewed and thereby degrading tree lookup performance.

LinkedHashSet and TreeSet cost more than HashSet, but do more. A LinkedHashSet is useful in making set copies, such that the original set's iteration ordering is preserved:

    void f(Set s) {
        Set copy = new LinkedHashSet(s);
    }

This technique works regardless of how the original set is implemented.

Note too that the cost of TreeSet relative to HashSet and LinkedHashSet varies with the size of the set. Tree-based data structures get slower as the number of elements get larger. The cost to look up an element in a hash-based set or map is independent of the set's size, assuming a reasonable hash function. By comparison, the cost to look up an element in a tree-based set or map is proportional to the log of the number of elements in the collection.

There is one exception to the rule that LinkedHashSets are slower than HashSets: iteration over a LinkedHashSet is generally faster than iteration over a HashSet.

TreeSet is useful if you want to retrieve the set elements in sorted order. A LinkedHashSet does this only if the elements were inserted in sorted order.

You can also use TreeSet to compute a subset of a set, with the subset backed by the original set. Let's look at how this works:

    import java.util.*;
    
    public class SetDemo3 {
    
        static final int MIN = -5;
        static final int MAX = 5;
    
        public static void main(String args[]) {
    
            // create a SortedSet with 
            // odd MIN-MAX Integer values
    
            SortedSet set = new TreeSet();
            for (int i = MIN; i <= MAX; i += 2) {
                set.add(new Integer(i));
            }
            System.out.println("set = " + set);
    
            // create a subset from 0 (inclusive) 
            // to MAX (exclusive)
    
            SortedSet subset =
                set.subSet(
                    new Integer(0), new Integer(MAX));
            System.out.println("subset = " + subset);
    
            // add a new element to the subset
    
            subset.add(new Integer(0));
            System.out.println(
                "set after add = " + set);
        }
    }

The SetDemo3 program creates a set [-5, -3, -1, 1, 3, 5]. Then it creates a subset. The subset starts at 0 (inclusive) and goes up to 5 (exclusive), so that it contains [1, 3]. The program then adds value 0 to the subset. Finally the program prints the original set. The printed original set contains the 0 value, which demonstrates that the subset is backed by the original set.

When you run the SetDemo3 program, you should see the following result:

    set = [-5, -3, -1, 1, 3, 5]
    subset = [1, 3]
    set after add = [-5, -3, -1, 0, 1, 3, 5]

The key to creating a subset in this way is the ability to specify a range of element values.

HashSet and LinkedHashSet do not represent their elements in sorted order. So it would be difficult to use them in a way that TreeSet was used in the SetDemo3 example.

Because TreeSet keeps its elements sorted, it can offer other features such as the first and last methods, that are used to retrieve the lowest and highest elements in a set, respectively.

For more information about HashSet, LinkedHashSet, and TreeSet, see section 16.5, Set and SortedSet, in The Java(tm) Programming Language Third Edition by Arnold, Gosling, and Holmes. Also, see the tutorial Introduction to the Collections Framework.

Pixel

UNDERSTANDING EXPRESSION EVALUATION ORDER

Suppose you are reading some Java code, and you come across an example like this:

    public class EvalDemo1 {
        public static void main(String args[]) {
            int x = 10;
            x = x + (x = 5);
            System.out.println(x);
        }
    }

What value is printed when this program is run? There are two plausible answers. For the expression:

    x + (x = 5)

the Java compiler might evaluate the left-hand operand (10), and then the right-hand operand (5), before adding them together. If it did that, the result would be the value 15. Or the compiler might evaluate the "(x = 5)" operand first -- this gives a value of 5. When the compiler evaluates the left-hand operand, it picks up the value of 5 for x. The result in this case will be 10.

So which of these two possible results is the actual result in the Java programming language? The answer is 15. What drives this result is the fact that the Java language has a rule that the left-hand operand of a binary operator is evaluated before the right-hand one. Interestingly, there is no equivalent rule in the C language. For example, a C program that corresponds to the EvalDemo1 program:

    #include <stdio.h>
    
    int main() {
        int x = 10;
        x = x + (x = 5);
        printf("%d\n", x);
    }

might produce different results. For example, running the C program with a number of popular C compilers, produces the output 10 rather than 15.

Here's another example that looks at the order in which method arguments are evaluated:

    public class EvalDemo2 {
        static void f(int a, int b) {
            System.out.println(a + " " + b);
        }
    
        public static void main(String args[]) {
            int x = 10;
            f(x, x = 5);
        }
    }

Method arguments are evaluated left-to-right, so when you run this program the output is:

    10 5

Let's look at a more complicated example:

    public class EvalDemo3 {
        static int f1() {
            System.out.println("called f1");
            return 37;
        }
    
        static int f2() throws Exception {
            System.out.println("called f2");
            throw new Exception();
        }
    
        public static void main(String args[]) 
            throws Exception {
                int x = f1() / (0 * f2());
        }
    }

The EvalDemo3 program calls the f1 method to get the value of the left-hand operand for the / operator. Then it evaluates the right-hand operand before it does the division. How is the right-hand operand evaluated?

It's important to understand that the f2 method is called. You might wonder why. In fact, you might assume that an expression "0 * f2()" will always be equal to zero -- that is, no matter what f2 returns. So why the need to call f2? The answer is that the assumption overlooks possible side effects when f2 is called.

In a similar way, the compiler cannot assume that an expression:

    f1() / (0 * f2())

reduces to:

    f1() / 0

and arrange for an ArithmeticException to be thrown, as is normally done for integer division by zero.

The f2 method is called, and ArithmeticException is not thrown. The result of running the EvalDemo3 program is:

    called f1
    called f2
    Exception in thread "main" java.lang.Exception
        at EvalDemo3.f2(EvalDemo3.java:9)
        at EvalDemo3.main(EvalDemo3.java:14)

This result indicates that the f2 method call is not optimized away, that is, the call is actually made. Then another exception (one different than ArithmeticException) is thrown before evaluation ever reaches the division operation.

In this example, both operands of the / operator are evaluated before the division is done. Because evaluation of the right-hand operand triggers an exception, the division never takes place.

But you should understand that there are three operators (&&, ||, ?:) where operands are not always evaluated first. Let's look at an example:

    public class EvalDemo4 {
        static int f1() {
            System.out.println("called f1");
            return 37;
        }
    
        static int f2() {
            System.out.println("called f2");
            return 47;
        }
    
        public static void main(String args[]) {
            boolean b = true;
            int x = b ? f1() : f2();
            System.out.println(x);
        }
    }

When you run the EvalDemo4 program, the result is:

    called f1
    37

Here the f2 method is never called. When the expression:

    b ? f1() : f2()

is evaluated, b has a true value, f1 is called, and f2 is not evaluated. In a similar way, if you have some code like this:

    boolean b = false;

    if (b && f())
        ...

then f will not be called. That's because b is false. The right-hand operand of && is not evaluated if the left-hand one is false -- that's why the && operator (as well as the || operator) is called a "short circuit" operator.

Let's look at a final example. Suppose you've got some code that does floating-point arithmetic, and at one point in the code, there is usage like this:

    4.0 * n * 0.5

and at another point, there is some code like this:

    2.0 * n

Are these two expressions the same, given that 4.0 * 0.5 is equivalent to 2.0?

Not necessarily. Here's a demonstration:

    public strictfp class EvalDemo5 {
        public static void main(String args[]) {
            double d = 8e+307;
            System.out.println(2.0 * d);
            System.out.println(4.0 * d * 0.5);
        }
    }

The output of this demo is:

    1.6E308
    Infinity

In the EvalDemo5 code, multiplying 8e+307 by 4.0 causes an overflow. Multiplying the value by 0.5 comes too late to do any good.

People tend to think of multiplication as associative, but this assumption does not necessarily hold when doing floating-point calculations. You need to be careful when applying what appear to be commonsense algebraic identities and similar rules to Java floating-point arithmetic.

For example, the standard Double.isNaN method is implemented as:

    static public boolean isNaN(double v) {
        return (v != v);
    }

In other words, a value is NaN (not a number) if it is not equal to itself. You might think that it would be impossible for a value not to be equal to itself, but this is so for NaNs.

For more information about expression evaluation order, see section 6.8.1, Order of Evaluation, in The Java(tm) Programming Language Third Edition by Arnold, Gosling, and Holmes. Also see section 15.7, Evaluation Order, in The Java(tm) Language Specification Second Edition by Gosling, Joy, Steele, and Bracha.

Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Core Java Technologies Tech Tips
November 5, 2002


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_249392761251640153@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Nov 12 12:15:20 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gACHFKr26288 for ; Tue, 12 Nov 2002 12:15:20 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gACHGNvo004877 for ; Tue, 12 Nov 2002 12:16:25 -0500 (EST) Date: 12 Nov 2002 09:02:49 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <249392761251640153@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, November 12, 2002 (Entity Beans, JSP Pages for Email) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 39507 Enterprise Java Technologies Tech Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text November 12, 2002    

In this Issue

WELCOME to the Java 2TM, Enterprise Edition (J2EETM) Tech Tips, November 12, 2002. This issue covers:

.Entity Beans
.Using JSPTM Pages to Generate Email

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the J2EE Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for these tips. The context root for the application is ttnov2002, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms: http://developer.java.sun.com/berkeley_license.html

Pixel

Entity Beans

Enterprise beans are J2EE components that implement Enterprise JavaBeansTM (EJB) technology. They are portable, managed, and potentially distributed components that represent business data and implement business logic. Enterprise beans are managed by an enterprise bean container (also called an EJB container), which is a server-side runtime environment. The container provides the components with consistent high-level, "horizontal" services that are common to most enterprise applications. These services include transaction and persistence management, security, location independence, access to legacy data and functionality, high availability, and scaling. Because the EJB container handles the humdrum details of managing component instances, the developer can focus on implementing "vertical" business logic.

An entity bean is an enterprise bean that represents persistent business data and the logic that operates on that data. This tip illustrates an example of an entity bean. The sample entity bean in this tip is used to manage user login information for an application. The entity bean represents:

  • A user's email address and site password
  • A "challenge" question that is used to verify a user's identity when requesting a new password
  • The answer to the challenge question

The bean also handles some business logic, such as password comparison.

The User entity bean shown here is much simpler than most entity beans in actual use. The intent of this quick introduction is to show you the basic "plumbing" necessary for a minimal entity bean. Real-life entity beans would probably have relationships to other beans, and would likely also perform more complex business functions.

Figure 1 highlights some of the components in the application. It includes the classes that comprise the entity bean, and a servlet that uses the entity bean.

Pixel
Figure 1. An Entity Bean in An Application

To create an entity bean, you need to write two interfaces: a home interface and a component interface. You also need to write an EJB class. The home interface, shown as UserLocalHome in Figure 1, is a factory interface that (among other things) finds and creates entity beans. The component interface contains all of the methods for a single entity bean instance. The EJB class contains the implementations of the methods of both the home and component interfaces.

The servlet, UserServlet, in Figure 1, uses the enterprise bean home interface UserLocalHome to acquire instances of the component interface UserLocal. It then uses the UserLocal interface to manipulate the enterprise bean.

The actual classes that implement the functionality in the EJB container are written by a tool, not by the developer. The tool takes methods and fields from the EJB class and uses them to generate home and component implementation classes. Developers seldom if ever see these generated classes. Because application developers only access EJB methods through home and component interfaces, the EJB container can do smart things with the instances of the implementation classes. For example, the container can interpose on method calls, and provide the system services mentioned above.

Notice in Figure 1 that the enterprise bean is connected to a database by an arrow labeled "CMP". CMP stands for container-managed persistence. CMP provides state management for entity beans: the data inside entity beans is automatically retrieved from and stored in a database when appropriate. With CMP, a developer is freed of responsibility for managing transactions and fetching and storing state to and from a database. For more control, an entity bean can use Bean-Managed Persistence (BMP). With BMP, an entity bean manages its own state. The entity bean in this tip uses CMP.

Enterprise JavaBeans technology offers two types of interfaces for entity beans: local and remote. Local interfaces provide improved performance over remote interfaces, but may only be used between components within a single JVM1. Remote interfaces provide component distribution at the cost of increased network traffic and latency. They also differ somewhat in their method call semantics. The word "local" in the interfaces and class names in this example refers to the local interface provided by the entity bean.

Usually, entity beans represent entities in a data model that are tightly coupled to other entities. Therefore, local interfaces are usually the way to go for entity beans. Only use remote interfaces if you have a strong reason to distribute your entity beans.

A Sample Entity Bean

The sample entity bean is named UserLocal. As mentioned earlier, the sample bean provides user login (email address) and password management for a Web application. (The code in this example is not production code, so security is not guaranteed!) The entity bean contains a user's email address, a password, a challenge question index (currently unused--there's only one challenge question) and the answer to the challenge. If the user forgets the account password, he or she can request a new password to be delivered to the recorded email address.

To create the entity bean, you need to create the home and component interfaces and the EJB class. The two interfaces provide what is called the "client view" of the component. They provide the only way for users to access or manipulate the component.

Let's look at these interfaces and the class.

The home interface

The home interface provides a component with a factory interface for creating and finding enterprise beans. Here is the code for the home interface UserLocalHome:

public interface UserLocalHome extends EJBLocalHome {
    UserLocal create(String email, String password,
                     int challenge, String answer)
        throws CreateException;

    public UserLocal findByPrimaryKey(String key) 
        throws FinderException;
}

Notice that interface extends EJBLocalHome. All local home interfaces must do that. The interface contains only two methods: create, which creates the bean, and findByPrimaryKey, which looks up the user by email address. (The email address is defined as the primary key in the deployment tool--see The deployment descriptor.) The create method has all of the arguments it needs to create a new UserLocal.

The component interface

The component interface defines all of the operations that can be performed on a single entity bean. Here is the code for the component interface UserLocal:

public interface UserLocal extends EJBLocalObject {
    public void setEmail(String email);
    public String getEmail();
    public String getPassword();
    public void setPassword(String password);
    public void setChallenge(int i);
    public int getChallenge();
    public void setAnswer(String answer);
    public String getAnswer();

    public boolean isPasswordValid(String password);
    public boolean isAnswerValid(String answer);
}

All local enterprise bean interfaces must inherit from EJBLocalObject. Most of the methods in UserLocal are simple property accessors. Two methods perform business functions: isPasswordValid, which checks the password, and isAnswerValid, which checks the answer to the challenge question.

The EJB class

The EJB class is where the component does all of its work. Here is the code for the EJB class UserBean:

public abstract class UserBean implements 
    EntityBean {

    private EntityContext _context = null;

    public Object ejbCreate(
        String email, String password,
            int challenge, String answer)
        throws CreateException {
        setEmail(email);
        setPassword(password);
        setChallenge(challenge);
        setAnswer(answer);
        return null;
    }

    public void ejbPostCreate(
        String email, String password,
            int challenge, String answer)
        throws CreateException {
    }

    public void setEntityContext(EntityContext c) {
        _context = c;
    }
    public void unsetEntityContext() {
        _context = null;
    }

    public void ejbRemove() throws RemoveException {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
    public void ejbStore() {}
    public void ejbLoad() {}

    // Virtual property accessors implemented by CMP
    public abstract void setPassword(String password);
    public abstract String getPassword();

    public abstract void setEmail(String email);
    public abstract String getEmail();

    public abstract void setChallenge(int i);
    public abstract int getChallenge();

    public abstract void setAnswer(String answer);
    public abstract String getAnswer();

    // Is the password valid?
    // In this case, we store and compare cleartext.
    // In a real application, encrypted passwords 
    // or hashes would be used.
    public boolean isPasswordValid(String password) {
        String rightPassword = getPassword();
        if (rightPassword.equals(password)) {
            return true;
        }
        return false;
    }

    // Is the answer to the challenge valid?
    public boolean isAnswerValid(String answer) {
        String rightAnswer = getAnswer();
        if (rightAnswer.equals(answer)) {
            return true;
        }
        return false;
    }
}

The EJB class contains several kinds of method:

  • Lifecycle methods. Methods ejbCreate, ejbRemove, ejbActivate, ejbPassivate, ejbStore, and ejbLoad are life cycle methods that the enterprise bean container calls when particular events in the component's life cycle occur. The only one that does anything interesting in this class is ejbCreate, which initializes the component state. The container also calls method ejbPostCreate after the component is created. Method ejbCreate is actually the implementation for the home interface method create.

  • Entity context methods. Methods getEntityContext and setEntityContext provide other methods to the entity's context. A class called EntityContext contains information about the environment that the component might need.

  • Property accessors. The get and set methods, such as getPassword and setPassword, get and set object internal state, respectively. Note that these accessors are marked abstract. This is because the enterprise bean container actually implements the getting and setting of the object state. An entity bean that uses bean-managed persistence would implement all of these methods manually.

  • Business methods. Methods isPasswordValid and isAnswerValid perform a small amount of business logic. In a real-world application, there could be many business methods.

The entity bean is now complete and almost ready to use. The only things left to do are to write the deployment descriptor and package the component.

The deployment descriptor

A deployment descriptor is an XML document that describes the interface between a component and its environment. The deployment descriptor is packaged with the enterprise bean interfaces and classes. Here is the deployment descriptor for the UserLocal entity bean:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ejb-jar
  PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
 "http://java.sun.com/dtd/ejb-jar_2_0.dtd">

<ejb-jar>
  <display-name>UserJAR</display-name>
  <enterprise-beans>
    <entity>
      <display-name>UserEB</display-name>
      <ejb-name>UserBean</ejb-name>
      <local-home>com.elucify.tips.nov2002.UserLocalHome</local-home>
      <local>com.elucify.tips.nov2002.UserLocal</local>
      <ejb-class>com.elucify.tips.nov2002.UserBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.String</prim-key-class>
      <reentrant>False</reentrant>
      <cmp-version>2.x</cmp-version>
      <abstract-schema-name>User</abstract-schema-name>

      <cmp-field>
        <description>User's email address</description>
        <field-name>email</field-name>
      </cmp-field>

      <cmp-field>
        <description>User's password</description>
        <field-name>password</field-name>
      </cmp-field>

      <cmp-field>
        <description>Challenge question for password change</description>
        <field-name>challenge</field-name>
      </cmp-field>

      <cmp-field>
        <description>Answer to challenge question</description>
        <field-name>answer</field-name>
      </cmp-field>

      <primkey-field>email</primkey-field>

      <security-identity>
        <description></description>
        <use-caller-identity></use-caller-identity>
      </security-identity>

    </entity>

  </enterprise-beans>

  <assembly-descriptor>
    <method-permission>
      <unchecked />

      <method>
        <ejb-name>UserBean</ejb-name>
        <method-name>*</method-name>
      </method>

    </method-permission>

    <container-transaction>
      <method>
        <ejb-name>UserBean</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
   </container-transaction>

  </assembly-descriptor>
</ejb-jar>

The deployment descriptor defines explicitly what services the component offers and what dependencies need to be resolved before a component will operate. In particular:

  • The <cmp-field> tags define component properties that will be maintained by the EJB container.
  • The <primkey-field> defines email as the component primary key.
  • The <method-permission> tag controls which methods may be executed.
  • The <container-transaction> declaratively configures transaction behavior.

Other tags give the component a name and description in a development tool, spell out the class names of the interfaces, and so on.

The deployment descriptor is placed in a special file called ejb-jar.xml in the META-INF directory of a component's JAR file.

Packaging the component

You can use the jar tool to package the component, with the ejb-jar.xml deployment descriptor in the META-INF directory, and the compiled .class files in their appropriate directories. After the component is packaged into a JAR file, it's ready for use in an application.

Using the entity bean

The sample archive provides an application that uses the sample entity bean. The application includes a servlet named UserServlet. The servlet uses the UserLocal bean to manage email addresses and passwords for the users of a Web site. Let's examine the parts of the servlet code that use the entity bean.

When the servlet initializes, it acquires a reference to UserLocalHome, the UserLocal component's home interface for the entity bean, as shown below:

            
    InitialContext ic = new InitialContext();
    Object userLocalHome = ic.lookup(
        "java:comp/env/ejb/local/User");
    _userLocalHome =
        (UserLocalHome)userLocalHome;

The servlet uses a JNDI lookup to acquire an object that represents the UserLocalHome home interface, and casts the result to type UserLocalHome. The servlet stores the home interface in a field to avoid doing a lookup each time a UserLocal is created or fetched.

The method that creates a new user object, createUser, appears below:

 
    // Create a local user bean
    protected UserLocal createUser(
        String email, String password, int challenge, 
            String answer)
        throws ServletException, CreateException {
        if (_userLocalHome == null) {
            throw new ServletException(
                "UserServlet.createUser: " +
                "home interface not initialized");
        }
        UserLocal newUser = _userLocalHome.create(
            email, password, challenge, answer);
        return newUser;
    }

This method simply uses the home interface's create method to create and initialize a user on request. If a user with the given email already exists, createUser throws DuplicateKeyException. Otherwise, it creates a new, persistent entity bean with all of the data initialized.

The only other interesting method in UserServlet is the code that finds existing UserLocal objects, as shown below:

    protected UserLocal findUser(String email)
        throws ServletException {
        if (_userLocalHome == null) {
            throw new ServletException(
                "UserServlet.findUser: " +
                "home interface not initialized");
        }
        UserLocal theUser = null;
        try {
            theUser = 
                _userLocalHome.findByPrimaryKey(email);
        } catch (FinderException fex) {
            System.err.println(
                "Finder exception: " + fex.getMessage());
        }
        return theUser;
    }

This method uses the home interface method _userLocalHome.findByPrimaryKey, to find a user with email address email.

The other methods in the example simply use the UserLocal interface just as if it was a conventional Java object. Note that the servlet uses the UserLocalHome and UserLocal interfaces. This means that the class files for these interfaces must be in both the .war file for the Web application, and .jar file for the entity bean.

Deploying the application

The sample code is packaged into an application EAR file with an application deployment descriptor called application.xml. Here's what application.xml looks like:

<application>
  <display-name>TTNov2002</display-name>
  <description>Application that demonstrates an entity bean
  </description>

  <module>
    <ejb>ttnov2002-ejb.jar</ejb>
  </module>

  <module>
    <web>
      <web-uri>ttnov2002.war</web-uri>
      <context-roo>>ttnov2002</context-root>
    </web>
  </module>

</application>

This deployment descriptor defines two modules in the application archive: ttnov2002-ejb.jar, which contains the UserLocal bean, and ttnov2002.war, which contains the Web application and the UserServlet.

To deploy the application:

  1. Open the application in deploytool or your vendor's deployment tool.
  2. Generate the schema and SQL for CMP. You can do this in deploytool as follows:
    • Open the Entity tab in the bean's deploytool property sheet.
    • Click on Deployment Settings
    • Click on Database Settings. If you are using the Reference Implementation, you can simply enter jdbc/Cloudscape with no user or password.
    • Click OK.
    • Click Generate Default SQL.


    The tool will generate all of the SQL code necessary for implementing CMP. (If you are not using the Reference Implementation, consult your server documentation for instructions on how to generate SQL for CMP.)

  3. Click the Deploy button or menu item.

Running the sample application

The application's context root is ttnov2002. The welcome file, index.html, contains forms to supply data to the sample servlet. Using this form, you can register as a new user on the Web site, create and modify user data, and look up the data of any user. Be sure that the both the J2EE server and the database are up and running.

For the Reference Implementation, the command to start the J2EE server is:

j2ee start

For the Reference Implementation, the command to start the database is:

cloudscape -start
Pixel
Pixel

Using JSP Pages to Generate Email

JavaServer Pages (JSP) technology is used to create dynamic Web content. However JSP pages are not limited to generating HTML. In fact, you can use JSP pages to generate any type of textual content. This tip extends the example in the tip Entity Beans, by using JSP pages with custom tags to generate a text email.

The September 19, 2002 tip, Using Custom Tags showed how to create a custom tag that inserts custom content into a page. Today's tip uses a body tag. This is a custom tag that processes the contents of the body within a tag.

Sometimes the only way for a user to regain access to a forgotten password is to issue a new password by email. The servlet UserServlet that was previously introduced in the Entity Beans tip does just that in its method newpass. Here's an excerpt from newpass:

...        
    if (user != null) {
        message = "Answer incorrect";
        if (user.isAnswerValid(answer)) {
            
            String newPassword =
                Integer.toHexString(
                    (int)(Math.random() * 0xfffffff));
            
            // Set the new password in the user 
            // and in request scope
            user.setPassword(newPassword);
            req.setAttribute("newpass", newPassword);
            
            // Forward the request to NewPassword.jsp, 
            // which will compose and send the email
            ServletContext ctx = 
                _config.getServletContext();
            RequestDispatcher rd =
                ctx.getRequestDispatcher(
                    "/NewPassword.jsp");
            try {
                rd.forward(req, res);
            } catch (IOException iox) {
                throw new ServletException(
                    "UserServlet.newpass: " +
                    iox.getMessage());
            }
        }
    }
...

This code gets a UserLocal bean. It then generates a new password, and sets the password both in the user and as a HttpServletRequest attribute. The code then forwards the request to a JSP page, NewPassword.jsp, that generates and sends an email to the user.

Generating email from a JSP page

The file NewPassword.jsp uses two custom tags, EmailTag and ParamTag, to generate the email's content.

<%@ taglib uri="/WEB-INF/taglib.tld" prefix="t" %>
<t:email mailhost="mail" mailuser=""
        namefrom="Customer Service"
        addrfrom="service@site-name-here.com">

Hello, <t:param name="email"/>,

This email is automatic notification that your password on
site-name-here.com has been changed because of a request
at our Web site. Your new password is <t:param name="newpass"/>.
Why not log in now and change it to something you can remember?

Thanks for using site-name-here.com!

--The Site-Name-Here Team

</t:email>

When the HTTP request arrives at this page, the Web container processes it just like any other JSP page. The ParamTag simply substitutes the value of the named request parameter or attribute into the text. Notice that the resulting text isn't HTML: it's simple ASCII text.

Usually, this ASCII text would be delivered to the browser, but here it goes to email. The EmailTag custom tag is a body tag, so it can process the entire contents of what is within the <t:email> markup.

Creating a body tag

J2EE interface BodyTag extends the Tag interface to give the custom tag control over its contents. Instead of writing content directly to the HTTP response, a body tag writes it into a buffer in memory. In this way, the content can be read, post-processed, replaced, or even discarded before any actual output is produced.

Custom tag EmailTag subclasses convenience class BodyTagSupport. EmailTag defines method BodyTag.doAfterBody. This method is invoked after the entire body of the tag has been evaluated. The method EmailTag.doAfterBody gets the contents of the tag body, which has already had all of its tags processed. It then uses the JavaMailTM API to send the generated tag content to the user. The rest of the JSP page contains HTML that notifies the user that email was sent. Here's the code for the body tag:

    public int doAfterBody() throws JspException {
        BodyContent content = getBodyContent();
        String emailContent = content.getString();

        System.err.println(
                       "Sending the following email:");
        System.err.println(emailContent);
        System.err.println("-----");

        sendEmail(emailContent);
        return SKIP_BODY;
    }

Class BodyContent represents the content created by interpreting the body of the tag. The doAfterBody method gets that content as a string, and uses method sendEmail to transmit the content as email.

You'll notice that the error handling is not very pretty. JSP exceptions usually produce an unattractive error message that makes your application look bad. Instead of throwing an exception, you might use a JSP error page, or forward to a page that describes the error condition in a more attractive way.

Deploying and running the sample

Instructions for deploying the sample application and running the sample application are covered in the Entity Beans tip.

The form that sends the email requires both the email address and the correct answer to the challenge question for that user. In addition, it requires a valid SMTP server hostname and (if the server requires it) a mail user name. The sample application does not support authentication, so you must choose an SMTP server that does not require a password.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, Enterprise JavaBeans , J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_2517530682724881@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Nov 13 20:08:39 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gAE18dN26738 for ; Wed, 13 Nov 2002 20:08:39 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gAE19dix009476 for ; Wed, 13 Nov 2002 20:09:48 -0500 (EST) Date: 13 Nov 2002 16:01:48 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <2517530682724881@hermes.sun.com> Subject: November Core Java(tm) Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 16996 Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Standard Edition (J2SETM).



Product and Technology Releases

The following J2SE products and technologies were recently released.

JSR-000024 JAIN Service Provider APIs TSM & SD Specification 1.0 Final Release
This will be part of a Java technology instantiation of Parlay, which enables external enterprises to rapidly build and deploy applications that exploit capabilities of the underlying telco's network.

JSR-000116 SIP Servlet API Public Review 2
The proposed API enables SIP servers to be augmented with Java extension code which can be deployed and managed as a unit.



Early Access Releases

The following J2SE products and technologies were recently made available through the Early Access Release Program.

Adding Generics to the Java Programming Language 1.3
A specification for extending the Java programming language with generic types. This feature is one of the most frequently requested language extensions on the JDC (no. 7 on the bug parade - no. 2 among language extensions).

Java Advanced Imaging Image I/O Tools 1.0 Beta
Provides reader, writer, and stream plug-ins for the Java Image I/O Framework and Image I/O-based read and write operations for Java Advanced Imaging.

Java API for XML Binding JAXB 1.0 Beta
JAXB provides an API and tools that automate the mapping between XML documents and Java objects.



Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

Java 2 SDK 1.3.1 Docs

Java Web Services Tutorial

J2SE 1.4 Documentation, in Japanese

Java Web Start

Java Communications API

pixel
pixel pixel pixel
November 13, 2002

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles

  • A Look at the New JCP the Evolution Continues by Jon Byous
    Read about the next evolution of the Java Community ProcessSM (JCPSM), version 2.5. (October 31, 2002)

  • JXTA Resolver by Daniel Brookshier
    Read about the concepts of peer-to-peer computing and the new JXTA Resolver equipped with code examples.
    (October 24, 2002)

Tech Tips

Chat

Regular Expressions
Michael McCloskey and Mark Reinhold
November 12, 2002, 11:00 A.M. PST/7:00 P.M. GMT

New Networking Support in J2SE
Alan Bateman and Yingxian Wang
December 3, 2002, 11:00 A.M. PST/7:00 P.M. GMT

Newsletters

Java Technology Fundamentals Newsletter
Learn how to use threads, boolean statements, and the JOptionPane class. (October 29, 2002)

Bookshelf

JMXTM in Action by Benjamin Sullins and Mark Whipple
Written for both new and experienced developers, this book explains the JMX specification and discusses its use through clean, well-discussed examples. (November 12, 2002)

Sun Technology Audiocast

This Java Platform Performance WebCamp will show experienced developers how to decide when to optimize performance, and how to use profiling tools to analyze performance and memory problems. (October 24, 2002)

Events

  • Sun Tech Days are coming to Europe!
    Paris, France, 5 - 6 December, 2002 and
    London, United Kingdom, 3 - 4 February, 2003.
    A global gathering of industry leaders will represent cutting-edge technology. Talks include Sun ONE, Web services, identity and security, J2EETM, electronic business for XML, and development for wireless applications. For more information and free registration: http://www.sun.com/developers/techdays/

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA

Sun, Sun Microsystems, Java, Java Developer Connection, J2EE, J2ME and J2SE, JAIN, JMX, JCP, and Java Community Process are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_25832816-2109122103@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Nov 19 16:36:23 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gAJLaNN27771 for ; Tue, 19 Nov 2002 16:36:23 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gAJLbXwi017078 for ; Tue, 19 Nov 2002 16:37:35 -0500 (EST) Date: 19 Nov 2002 13:18:39 -0800 From: "Wireless Developer J2ME Tech Tips" To: gcf@indiana.edu Message-Id: <25832816-2109122103@hermes.sun.com> Subject: J2ME Tech Tips, November 19, 2002 (Receiving Messages with the Wireless Messaging API, J2ME Optimization Tips and Tools) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 25948 Wireless Technical Tips: November 19, 2002
pixel
pixel
header
    November 19, 2002        

In this Issue

WELCOME to the Wireless Developer Java[tm] 2 Platform, Micro Edition (J2ME[tm]) Tech Tips, for November 19, 2002.

.Receiving Messages with the Wireless Messaging API
.J2ME Optimization Tips and Tools

You can view these J2ME Tech Tips on the Web, Receiving Messages with the Wireless Messaging API and J2ME Optimization Tips and Tools

Pixel

Receiving Messages with the Wireless Messaging API

by Eric Giguere
November 19, 2002

A previous tip, Wireless Messaging API Basics, introduced the Wireless Message API (WMA) optional package, which allows applications to send and receive short text and binary messages over wireless connections. The tip included an example of receiving messages using the receive() method of the MessageConnection interface. This tip shows you a more sophisticated approach to message handling.

The crucial limitation of the receive() method is that it's a blocking call: if no message is waiting, the calling thread is suspended until a message arrives on the connection or the connection is closed. It's imperative, therefore, to invoke receive() only when you know a message is waiting, or else to invoke it from a separate, application-managed thread. To do otherwise can hang the device by inadvertently blocking important system-managed threads such as the application's main event thread.

To discover whether a message is waiting or not, an application registers a message listener with the connection, by calling the setMessageListener() method of MessageConnection:

import javax.wireless.messaging.*;

MessageConnection conn = ...   // a connection
MessageListener listener  = ... // some listener

try {
    conn.setMessageListener( listener );
}
catch( IOException e ){
    // couldn't register
}

The listener is an object implementing the MessageListener interface, which has a single method:

package javax.wireless.messaging;

public interface MessageListener {
    void notifyIncomingMessage( MessageConnection conn );
}

Each time a message arrives on the connection, the system invokes the listener's notifyIncomingMessage() method. (Note that the connection object is passed as an argument, which allows you to use the same listener instance with multiple connections.) The application can retrieve the message by calling the receive() method as before, but without the worry that doing so will block a vital thread.

Beware: You might be tempted to write this kind of code:

public class BadListener implements MessageListener {
    public void notifyIncomingMessage(
                               MessageConnection conn ){
        try {
            Message msg = conn.receive(); // DON'T!!
            ..... // do something here
        }
        catch( Exception e ){
        }
    }
}

Dont! The WMA specification specifically prohibits calling the receive() method from within the notifyIncomingMessage() method, because doing so is very likely to prevent the system from returning quickly to process other incoming messages. The actual receiving of the message must occur on a different thread. To further complicate things, the system may call notifyIncomingMessage() simultaneously on different threads if multiple messages arrive all at once, so the callback must be thread-safe.

The correct approach is to relay the notification to an application-defined thread, which then calls receive() and processes the incoming message. In fact, you can write a simple helper class that does the receiving on a separate thread and then forwards it to another class for processing. First, define the MessageReceiver interface:

import javax.wireless.messaging.*;

// MIDlets or other classes interested in receiving messages
// should implement this interface.

public interface MessageReceiver {
    void messageReceived( MessageConnection conn,
                          Message msg );
    void messageError( MessageConnection conn,
                       Throwable excep );
}

The messageReceived() method is invoked when a message is received successfully for a given connection, while the messageError() method is invoked if the receive operation fails. Now you can define the MessageReceiverListener class to do the actual receiving and thread management:

import java.io.IOException;
import java.util.Vector;
import javax.wireless.messaging.*;

// A message listener that spawns a new thread every
// time a message arrives, receives the message on
// that thread, and then forwards the message (or any
// exception) to a waiting message receiver.

public class MessageReceiverListener
             implements MessageListener {

    private boolean         stop;
    private Class           factory;
    private MessageReceiver singleton;

    // When created with this constructor, the listener
    // forwards all messages to the single instance of
    // the given receiver.

    public MessageReceiverListener( MessageReceiver
                                           singleton ){
        this.singleton = singleton;
    }

    // When created with this constructor, the listener
    // first creates a new instance of the given class,
    // which must implement MessageReceiver. The message
    // is then forwarded to that new instance.

    public MessageReceiverListener( Class factory ){
        this.factory = factory;
    }

    // Called whenever a message arrives for the given
    // connection.  Starts a thread to receive and forward
    // the message.

    public void notifyIncomingMessage( MessageConnection
                                             conn ){
        if( !stop ){
            new Runner( conn ).start();
        }
    }

    // Stops the processing of messages.

    public void stop(){
        stop = true;
    }

    // Helper class: when started, receives a message
    // and forwards it to the ultimate message receiver.

    private class Runner extends Thread {
        private MessageConnection connection;

        Runner( MessageConnection connection ){
            this.connection = connection;
        }

        public void run(){
            Message message = null;
            Throwable exception = null;

            try {
                message = connection.receive();
            }
            catch( Throwable e ){
                exception = e;
            }

            MessageReceiver recv = singleton;
            if( recv == null ){
                try {
                    recv = (MessageReceiver)
                                factory.newInstance();
                }
                catch( Exception e ){
                }
            }

            if( message != null ){
                recv.messageReceived( connection, message );
            } else {
                recv.messageError( connection, exception );
            }
        }
    }
}

Notice that the listener can be used in two modes: in one mode it forwards all messages to a single instance of a receiver, which must be thread-safe, while in the second mode it creates a new receiver instance for each message.

To receive messages, then, you define a class that implements the MessageReceiver interface (perhaps the MIDlet's main class). When you're ready to receive messages on a connection, simply do this:

MessageConnection conn = ... // some connection
MessageReceiver receiver = ...  // the receiver
MessageListener listener =
       new MessageReceiverListener( receiver );

conn.setMessageListener( listener );

To stop receiving messages, either call the listener's stop() method or set the connection's message listener to null.

For more information on WMA, see http://java.sun.com/products/wma. If you're interested in MIDP programming, also check out the new push registry feature of the MIDP 2.0 specification. The push registry tells the system to wake an inactive application when specified inbound connections are made to the device.

Pixel
Pixel

J2ME Optimization Tips and Tools

by Eric Larson
November 19, 2002

If you've written any applications for the Java[tm] 2 Platform, Micro Edition (J2ME) you already understand many of the challenges of writing for small devices. Limited user interfaces, scaled-down processing power, and small amounts of memory are just some of the obstacles confronting the J2ME developer, but with the help of some development tools and some coding tricks you can write applications that will perform well on even the most stripped-down devices.

This tech tip suggests some useful tactics and tools. I also encourage you to see articles on this site that focus on two vital performance-related concerns:

When to Optimize

There are three rules of optimization:

  1. Don't optimize yet.
  2. Don't optimize yet.
  3. Don't optimize yet.

This may sound silly, but it makes sense. Although you should be careful in your protocol design to minimize network traffic, code optimization should be postponed until the very end of the development cycle. Basically you should produce ship-quality code. Then see if there are performance problems. Then do a careful analysis and identify the bottlenecks. Then, finally, do some optimization.

It's tempting to optimize too early because, as programmers, we can see inefficiencies and we yearn to stamp them out. In the long run, however, things that look inefficient may not be noticeable at runtime. In general it's much more important to create rational, readable, maintainable code than to squeeze every last unnecessary byte out of the bytecode.

Timing is Everything

One handy tool from J2SE[tm] that made its way into J2ME is the System.currentTimeMillis() method. This method returns the current time as a long with millisecond precision. Using this method you can accurately determine the amount of time it takes to execute a given block of code.

long t1 = System.currentTimeMillis();

fillCanvas();

long t2 = System.currentTimeMillis();

System.out.println("Time: " + (t2-t1) + "ms");

This code prints the amount of time taken to execute the fillCanvas() method.

This technique is useful for analyzing code that you suspect of having performance problems -- but how how do you pinpoint which methods are the performance bottlenecks? Read on!

The Java Profiler

Until recently, it's been difficult to profile J2ME applications because the KVM lacks support for JVMPI and reflection. Luckily, the J2ME Wireless Toolkit version 1.0.4 includes a profiler tool. To turn it on, in the toolkit preferences dialog simply select the Enable Profiling option. Run your MIDlet as usual, and once the emulator is closed the profiler tool will display a report like the one in Figure 1.

Figure 1
Figure 1: The Java Profiler

Sorting the columns by Count or Cycles allows you to see which methods are called the most and which use the most resources. The profiler is the main tool used to pinpoint performance problems. Remember the three rules, though. You won't want to use this tool every day. Unless you discover a serious performance problem that just won't wait, save profiling for the end of the development cycle.

Other tools can help you reduce your application's memory footprint and optimize its use of memory.

Monitoring Memory Use

There are several ways to monitor your application's use of memory. The java.lang.Runtime class's totalMemory() and freeMemory() methods are useful for monitoring your heap.

Runtime rt = java.lang.Runtime.getRuntime();
System.out.println("Total heap: " + rt.totalMemory());
System.out.println("Total free: " + rt.freeMemory());

To get an idea of how much heap space you'll have to work with, you may wish to run a test MIDlet on the actual devices you plan to deploy your application on (or check their device specifications). A small heap will limit the number of objects your application will be able to create. To mimic your production environment accurately, the 1.0.4 version of the J2ME Wireless Toolkit allows you to set the heap size, along with storage size (for RMS). This feature will help you catch out-of-memory errors before deployment. You can also set VM speed emulation and network throughput emulation to help you gauge performance of your application in your development environment, before you deploy.

Version 1.0.4 of the toolkit also includes a memory monitor. In the Monitoring tab of the Preferences dialog, simply check the Enable Memory Monitor box. This utility produces a graph of memory use, as in Figure 2.

Figure 2
Figure 2: Memory Monitor

The Objects tab in the Memory Monitor tool is also very useful for trimming your application's memory use. Here, every object in your application is listed, along with the number of instances and size of each object (total and average). This is a real-time view, so as your MIDlet runs you can view changes in the object list. Sort by Total Size to see which objects use the most memory.

Garbage Collection

Another useful method in the java.lang.Runtime class is gc(), which calls the garbage collector manually. It's usually called statically: System.gc(). To keep heap space free, be sure to set objects to null as soon as you're done with them. Setting an Image to null after a paint, for example, can free up a good chunk of memory.

You may be able to improve performance by using the System.gc() method to manage the GC schedule. Instead of just letting the system garbage-collect at its own discretion, try calling System.gc() when you know the user will be reading a screen and thus won't be interacting with the application immediately.

To see when the system is performing garbage collection, enable the toolkit's Trace Garbage Collection option.

Pixel
Pixel

About the Authors:

Eric Giguere is a software developer for iAnywhere Solutions, a subsidiary of Sybase, where he works on Java technologies for handheld and wireless computing. He holds BMath and MMath degrees in Computer Science from the University of Waterloo and has written extensively on computing topics.

Eric D. Larson is a Staff Engineer at Sun Microsystems and has been working with Java since joining Sun in 1996. Eric holds a degree in Computer Science from Rensselaer Polytechnic Institute.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html

http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Wireless Technologies Newsletter to: wd-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allttips/


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2ME, JAIN, and PersonalJava are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
pixel
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_2591954355042631@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Nov 26 16:30:58 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gAQLUwN07420 for ; Tue, 26 Nov 2002 16:30:58 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gAQLWEqh023038 for ; Tue, 26 Nov 2002 16:32:18 -0500 (EST) Date: 26 Nov 2002 13:14:06 -0800 From: "Wireless Developer Newsletter" To: gcf@indiana.edu Message-Id: <2591954355042631@hermes.sun.com> Subject: Wireless Developer Newsletter November 26, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 15018 Wireless Developer Newsletter: November 26, 2002

Welcome to the Wireless Developer Newsletter, to which you subscribed. Here you'll find links to the latest wireless technologies and products, learn about resources for wireless developers, get the latest wireless news, and more.


Product and Technology Releases

Several wireless products and technologies were released recently:

JSR 118: Mobile Information Device Profile (MIDP) 2.0 Final Release
JSR 118 defines the Mobile Information Device Profile (MIDP) v2.0 for the Java 2 Platform, Micro Edition (J2ME). The goal of this specification is to define an enhanced architecture and the associated APIs required to enable an open, third-party, application development environment for mobile information devices, or MIDs.

J2ME Wireless Toolkit 2.0 Beta 1 Early Access
An early-access release of the J2ME Wireless Toolkit 2.0 is now available. This release adds development and emulation support for the latest features of MIDP 2.0 (JSR 118). MIDP 2.0 is an exciting new specification that supports sound, security, a games API, additional network protocols, and more.

Personal Profile for Zaurus 1.0 Early Access
This binary targeted implementation of Personal Profile is designed to run on the Sharp Zaurus platform. Personal Profile is the technical successor to PersonalJava. This binary is an early-access implementation and has not been fully QA'd or completely implemented to the Personal Profile specification. This release is for evaluation only and cannot be used for commercial purposes.


Hot Downloads

Currently the most frequently downloaded wireless products and technologies are:

Java 2 Platform, Micro Edition, Wireless Toolkit 1.0.4

MIDP for Palm OS 1.0

MIDP for Palm OS 1.0 Documentation

Java Card 2.2 Development Kit


Java User Groups (JUGs)

There are over 900 established Java User Groups worldwide. Find one near you at this url:
http://servlet.java.sun.com/jugs

pixel
pixel pixel pixel
November 26, 2002

Resources

Learn more about wireless products and technologies through the following resources.

  • J2ME Code Camp: Free download with labs and sample code
    The J2ME programming camp will show experienced Java application developers how to write Java applications for wireless devices such as cell phones and two-way pagers that comply with the Mobile Information Device Profile (MIDP).

  • Featured Question: OTA Downloads, or "What is WTP-SAR and why should I care?"

  • J2ME Tech Tip: Receiving Messages with the Wireless Messaging API
    This tech tip illustrates how to write a multi-threaded application to receive messages using the Wireless Messaging API

  • J2ME Tech Tip: J2ME Optimization Tips and Tools
    This tech tip shows you how to optimize MIDlet performance and memory use.

  • Go To Market: New Developer Program Guides
    New guides from SavaJe added this month:

  • Articles: Read the following new articles on the Wireless Developer site:

    • What's New in MIDP 2.0
      Hungry for MIDP 2.0? Here's a full meal to satisfy your appetite. Learn about some of MIDP 2.0's exciting new features. Working code samples are included. Get hands-on experience with secure networking, custom form items, audio, and more!

    • Deploying J2ME Applications
      This article shows you the different ways you can download local and network applications to J2ME-enabled devices, for both testing and final deployment.

    • MIDP Application Security 2: Understanding SSL and TLS
      TLS and SSL are commonly used for secure and authenticated connections on the Internet. This article describes the protocols and their implementation in MIDP, including the new HttpsConnection and Certificate APIs in MIDP 2.0.

    • A Survey of J2ME Today
      This article gives you a good long look at today's J2ME - a consolidated, big-picture view of where the J2ME platform stands now. It explains the terminology you need to know to make sense out of an increasingly complex topic.

    • Testing Wireless Java Applications
      This article provides an overview of software testing, describes the testing challenges posed by wireless applications, presents a tutorial on testing wireless applications, and furnishes testing checklists for user interface, networking, and other areas.


Events


Industry News

Pixo and NSTL Provide Testing and Certification of Wireless Java Applications
Pixo and NSTL have entered into an agreement that will enable Pixo to offer its clients a customized testing certification program for wireless applications. Operators that purchase Pixo's Mobile Download Server solution will now have access to the added benefit of a customized testing and certification program from NSTL. The NSTL testing program will enable operators to gain confidence that third-party applications achieve required functionality and compatibility with the operator's network.

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

FEEDBACK
Comments? Send your feedback on the Wireless Developer Newsletter to: wd-webmaster@sun.com

SUBSCRIBE/UNSUBSCRIBE
- To subscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at the end of this email.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allnewsletters/wireless/

COPYRIGHT
Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA
This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, Solaris Developer Connection, NetBeans, JavaServer Pages, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_260402671933762323@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Nov 27 15:06:49 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gARK6nN10643 for ; Wed, 27 Nov 2002 15:06:49 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gARK86qj001095 for ; Wed, 27 Nov 2002 15:08:09 -0500 (EST) Date: 27 Nov 2002 11:48:25 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <260402671933762323@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 32095 Java(TM) Technology Fundamentals Newsletter
pixel
pixel
header
    November 27, 2002    

In this Issue

imageJavaTM Programming Language Basics
imageJava Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageNew to Java Programming Center Update
imageFor More Information

Pixel

Java Programming Language Basics

How to Create Colors

When I was growing up, a large box of Crayola crayons included 64 colors. Nowadays, the large box has 96 crayons, and Crayola has a core set of 120 crayon colors, including some of the scratch-and-sniff variety. There have been over 400 different crayon colors over their 100-year history.

To get different colored crayons, color pigments are mixed. For example, mixing red and yellow creates orange. On computers, things work differently. Instead of mixing color pigments, you mix shades of light. To get yellow, you actually have to mix red and green.

A mixture of three different light intensities represents all colors. Those three colors are red, green, and blue, frequently referred to as RGB for short. For each of the three lights, there are 256 possible values or 16,777,216 (256 * 256 * 256) different shades in all. And within the standard libraries for the Java 2 Platform is the java.awt.Color class to represent those colors.

For commonly used colors, the Color class contains two sets of thirteen constants. One set has the thirteen common colors in all lowercase letters, as in red, green, and blue, while the second set uses all uppercase letters, as in RED, GREEN, and BLUE. Originally, the only set was all the lowercase constants. The 1.4 release of the Java 2 Standard Edition introduced the second all-uppercase set. While the original set has not been deprecated, the new set now follows the naming conventions of other public constants.

In addition to the 16 million colors available through mixing red, green, and blue lights, there is a fourth option called opacity. This fourth option specifies how opaque, or dense, a particular color setting is, and is also called an alpha channel.

The more opaque a color is, the less transparent it is. Like the red, green, and blue settings, opacity also offers a range of 256 values, giving you a total of 4,294,967,296 variations. Keep in mind that while the Color class supports over 4 billion different color settings, not all user graphic cards do. While most newer computers do, one should try to limit the number of different colors used to some reasonable subset.

The combination of the four possible color settings of alpha, red, green, and blue all fit within an int variable. With each offering 256 settings, that's 8 bits worth of data. So, 4 settings times 8 bits is 32 bits, which is exactly the size of an int. From left to right, those 256 settings in 8 bits are stored alpha first, then red, then green, and finally blue, each being stored as an unsigned value from 0-255.

You can create a color in a number of ways. As previously stated, you can use one of the predefined constants, like RED, GREEN, or BLUE. There are also brighter() and darker() methods that adjust an existing color accordingly. More typical, though, is to create a new Color by providing a set of integer values for the red, green, and blue values, with an optional setting for transparency. Without the last setting, colors are opaque (no transparency).

For example, there are several different ways to get the color red. The first two are the RED and red constants. Both of these provide you with no green or blue light when the color is used to draw a pixel on the screen.

You can also get red by calling the constructor for Color, and passing in the values of 255 for red with 0 for blue and green:

Color red = new Color(255, 0, 0). 

As the final way of getting red, you can combine the four settings for red, green, and blue with transparency by call ing yet another constructor:

int value = ((255 & 0xFF) << 16);
Color red = new Color(value);

This puts the setting for red (255) into the second byte (from the left) of the int. Of course, you could specify each of the settings separately to initialize the color setting:

int value =
     ((alpha & 0xFF) << 24) |
     ((red & 0xFF) << 16) |
     ((green & 0xFF) << 8) |
     ((blue & 0xFF) << 0);

The Color constructor then takes this setting as one value, a new Color(value), instead of as separate settings for alpha, red, green, and blue.

Once you have your Color object, you can use it to paint the screen or set the foreground/background color of a component, among many other tasks.

The secondary mechanism for manipulating colors is through HSB settings, which stands for hue, saturation, and brightness.

There is also the java.awt.SystemColor class, which provides access to the colors a user's specific platform offers. These last settings let you query which colors a component should be so when you create new versions of those components they look like the actual system components.

Test what you just learned about creating colors with this interactive quiz.

Pixel
Pixel

Java Bits

Play Audio Clips

The Java API provides a simple abstraction for playing a sound clip. The process works similarly to retrieving and displaying an image. The AudioClip interface represents an audio file. By creating an AudioClip object by calling the getAudioClip or newAduioClip methods from the Applet class you get access to the AudioClip interface methods.

The three methods are:

  • loop - runs the audio clip by invoking the AudioClip object continuously.
  • play - plays the audio clip once represented by the invoking AudioClip object. Each time this method is called, the clip is restarted from the beginning.
  • stop - stops playing the audio clip.

Common audio formats used in applications or applets are WAV, AU, and SND.

The following is an example of creating an AudioClip object:

AudioClip clip = getAudioClip(getCodeBase(), "welcome.wav");

The WhaleSounds applet demonstrates how to create an AudioClip object, and how to play and stop the sound clip with JButtons and the appropriate methods. To recreate this applet on your system, you need to download by right-clicking and selecting Save Link As:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class WhaleSounds extends JApplet
 {
   AudioClip clip;
   
   public void init()
    {
      clip = getAudioClip(getCodeBase(), 
                            "humpback.au");
      JButton play = new JButton("Play");
      JButton stop = new JButton("Stop");
      Container pane = getContentPane();
      pane.setLayout(new GridLayout(2, 1));
      pane.add(play);
      pane.add(stop);
      play.addActionListener(new ActionListener()
       {
        public void actionPerformed(ActionEvent ae)
         {
           clip.play();
         }
        });
       
       stop.addActionListener(new ActionListener()
        {
         public void actionPerformed(ActionEvent ae)
          {
            clip.stop();
          }
         }); 
     }
 }  
 

After compiling and running the applet, you'll see the following:

Pixel
Pixel

Making Sense of the Java Class Libraries

The JSlider Class

Slider objects allow users to graphically choose a numeric value bounded by a minimum and maximum value, such as volume, color brightness, size of objects, and so forth.

Fortunately, the Java API comes with a handy class that allows developers to create customized sliders for specific application needs. This class is packaged as a part of the Swing library, javax.swing.JSlider.

Sliders can show whatever range of numbers you need, as well as major tick marks and minor tick marks between them.

To create a Slider object, call one of the following constructors:

  • JSlider()
    Creates a horizontal slider with the range 0 to 100 and an initial value of 50.
  • JSlider(int min, int max)
    JSlider(int min, int max, int value)
    Creates a horizontal slider with the specified minimum and maximum values. The third int argument, when present, specifies the slider's initial value.
  • JSlider(BoundedRangeModel)
    Creates a horizontal slider with the specified model, which manages the slider's minimum, maximum, and current values and their relationship.

To work with the slider labels, tick marks, and orientation, the JSlider class has many methods available. Here are a few:

  • void setMinimum(int)
    void setMaximum(int)
    Set the minimum or maximum values of the slider. Together, these methods set or get the slider's range.
  • void setPaintTicks(boolean)
    Set whether tick marks are painted on the slider.

To add functionality to a slider, you implement ChangeListener and provide a stateChanged method, where you write the instructions for what you want to happen when the slider is moved.

The following program illustrates a JSlider constructor and methods to create one vertical slider and one horizontal slider. When you move the slider button, the stateChanged method is called, and the value for the slider appears at the bottom of the screen in a text area.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;

public class JSliderExample extends JFrame
  {
    JSlider jsHorizontal;
    JSlider jsVertical;
    JTextField jtf1;
    JTextField jtf2;
    
   public JSliderExample()
    {
     // Create a horizontal slider object with 
     // various properties
     
     jsHorizontal = new JSlider(JSlider.HORIZONTAL, 
                                       0, 100, 50);
     jsHorizontal.setMajorTickSpacing(20);
     jsHorizontal.setMinorTickSpacing(5);
     jsHorizontal.setPaintTicks(true);
     jsHorizontal.setPaintLabels(true);
     jsHorizontal.setForeground(Color.BLACK);
     jsHorizontal.setBorder(
                BorderFactory.createEtchedBorder());
     jsHorizontal.addChangeListener(
                              new JSliderHandler());
     
     // Create a verical slider object with various 
     // properties
     jsVertical = new JSlider(JSlider.VERTICAL, 0, 
                                            40, 8);
     jsVertical.setMajorTickSpacing(10);
     jsVertical.setMinorTickSpacing(2);
     jsVertical.setPaintTicks(true);
     jsVertical.setPaintLabels(true);
     jsVertical.setForeground(Color.BLACK);
     jsVertical.setBorder(
                BorderFactory.createEtchedBorder());
     jsVertical.addChangeListener(
                               new JSliderHandler());
     
     // Create text fields to display slider 
     // position.
     
     jtf1 = new JTextField(15);
     jtf2 = new JTextField(15);
     
     jtf1.setEditable(false);
     jtf2.setEditable(false);
     
     jtf1.setText("Horizontal value is " 
                       + jsHorizontal.getValue());
     jtf2.setText("Vertical value is " 
                         + jsVertical.getValue());
     
     JPanel p1 = new JPanel();
     p1.setBackground(Color.WHITE);
     p1.add(jsHorizontal);
     
     JPanel p2 = new JPanel();
     p2.setBackground(Color.WHITE);
     p2.add(jtf1);
     p2.add(jtf2);
     
     JPanel p3 =new JPanel();
     p3.setBackground(Color.WHITE);
     p3.add(jsVertical);
     
     getContentPane().add(p1, BorderLayout.CENTER);
     getContentPane().add(p2, BorderLayout.SOUTH);
     getContentPane().add(p3, BorderLayout.EAST);
     
     
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setBounds(300, 400, 400, 300);
     setVisible(true);
     setBackground(Color.WHITE);
     }//Close constructor
     
     class JSliderHandler implements ChangeListener
      {
        public void stateChanged(ChangeEvent ce)
          {
            jtf1.setText("Horizontal value is " 
                        + jsHorizontal.getValue());
            jtf2.setText("Vertical value is " 
                          + jsVertical.getValue());
          }
       }
       
    public static void main(String args[])
      {
      JSliderExample jse = 
                       new JSliderExample();
      }
  }
 

JSliderExample.java produces the following:

Pixel
Pixel

Program Challenge

Create the ColorChanger Application

  1. Create a program that allows the user to set the background color of a label based upon the current setting of three sliders:
    • Red
    • Green
    • Blue
  2. Provide two buttons for changing the color to be brighter or darker. When either of those buttons are selected, the background color changes and the sliders adjust to their new settings.

See a possible solution to Challenge:

Pixel
Pixel

New to Java Programming Center Update

Read through the articles and tutorials in the New to Java Programming center a step at a time, then test what you learned in the newly added Step 4: Review What You've Learned. Step 4 includes links to interactive online quizzes and puzzles.

Pixel
Pixel

For More Information

Class Color

Class JSlider

How to Use Sliders

Interface AudioClip

Pixel
Pixel

Program Challenge Solution

See one possible solution to the November Program Challenge:

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SETM development kit.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_259631461736973692@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Nov 27 12:22:14 2002 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gARHMDN06198 for ; Wed, 27 Nov 2002 12:22:13 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gARHNYbq025674 for ; Wed, 27 Nov 2002 12:23:35 -0500 (EST) Date: 27 Nov 2002 09:13:12 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <259631461736973692@hermes.sun.com> Subject: November Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 19110 Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Enterprise Edition (J2EETM).



Early Access

The following J2EE products and technologies were made available through the Early Access Release Program this month.

JDBCTM Connector
The JDBC Connector is a J2EE Connector Architecture compliant connector that makes it easy to plug any driver that implements JDBC technology ("JDBC driver") into a J2EE application server.



Product and Technology Releases

The following J2EE products and technologies were recently released.

JSR-000073 Java Data Mining API Specification 0.91
By using JDM API, implementers of data mining applications can expose a single, standard API that will be understood by a wide variety of client applications and components running on the J2EE Platform.

Java 2 Platform, Enterprise Edition Specification 1.4
Proposed Final Draft 2 Changes in Proposed Final Draft 2:

  • Updated JMX requirement to version 1.2.
  • JavaMail and JAF are required by JAX-RPC, and so must be present in the application client container.

Java Metadata Interface Documentation and Sample
Class Interfaces 1.0 Final Release The Java Metadata Interface (JMI) Specification implements a dynamic, platform-neutral infrastructure that enables the creation, storage, access, discovery, and exchange of metadata.

JSR-000112 J2EE Connector Architecture
Proposed Final Draft 2 Specification v1.5 Some new sections, and clarifications from PFD v1.0

JSR-000024 JAIN Service Provider APIs
TSM & SD Specification 1.0 Final Release This API will be part of a Java technology instantiation of Parlay. By adopting Parlay, the Java community can leverage on the huge investment made by Parlay members into the specification and associated adoption across the IT and telecomms industry.



Hot Downloads

The following are currently the most frequently downloaded J2EE products and technologies.

Java 2 Enterprise Edition Tutorial 1.3

Java Web Services Developer Pack v1.0_01 Tutorial

Java Pet Store Demo 1.3.1_01

Java Servlet Specification 2.3

Enterprise JavaBeansTM Specification Proposed Final Draft 2.1

pixel
pixel pixel pixel
November 27, 2002

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.



Industry News

  • Sun Microsystems 'Makes the Grid Work.'
    At this year's Supercomputing 2002 conference, Sun showcased demonstrations of cluster, enterprise and global grids accessed via Sun ONE Grid Engine software. Sun also unveiled its newest cluster interconnect technology, the Sun FireTM Link interconnect which is designed to deliver fast throughput rates and terascale superclustering capabilities.

  • Virtuas Delivers Jtagmanager to Complement Sun ONE Studio IDE
    Virtuas announced the availability of Jtagmanager, the industry's first tool that manages multiple JSP custom tag libraries, which handles many of the tedious and complex tasks associated with developing with JSP custom tag libraries.


Java Developer's Marketplace

  • TheraSTrat Releases SafeBase, the Theragenomics Knowledge Management and Discovery System
    TheraSTrat AG announced the commercial availability of SafeBase 1.0 Professional, a patent-pending, Java technology-based n-tier software suite to be used as an Internet- or Intranet-accessible solution for theragenomics knowledge management. It contains and connects data and knowledge on structural and genetic risk factors for the predisposition of individual patients for the development of severe Adverse Drug Reactions.
pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, SunNetwork, Java, Java Community Process (JCP), Java Developer Connection, JavaBeans, EJB, JSP, JavaServer Pages, JavaOne, Sun's 2003 Worldwide Java Developer Conference, J2EE, J2ME and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_262620551192827214@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Dec 3 17:56:49 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gB3MunN29263 for ; Tue, 3 Dec 2002 17:56:49 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gB3MvwxC025294 for ; Tue, 3 Dec 2002 17:58:16 -0500 (EST) Date: 3 Dec 2002 13:56:45 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <262620551192827214@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Dec. 3, 2002 (BitSet, JSpinner) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 28573 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text December 3, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, December 3, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Using the BitSet Class
Using JSpinner to Choose From an Ordered List

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

Pixel

USING THE BITSET CLASS

BitSet is a class you use to represent vectors of bits or true/false values. You can represent bitmaps and similar kinds of structures with BitSet objects. BitSets grow dynamically as new bits are set.

To start the discussion of BitSet, let's look at an example:

    import java.util.BitSet;
    
    public class BitSet1 {
        public static void main(String args[]) {
    
            // create a BitSet
    
            BitSet bitset = new BitSet();
    
            // set the 0th and 1000th bits
    
            bitset.set(0);
            bitset.set(1000);
    
            // display the size, length, 
            // and cardinality
    
            System.out.println(
                "size = " + bitset.size());
            System.out.println(
                "length = " + bitset.length());
            System.out.println("cardinality = " +
                bitset.cardinality());
    
            // list the bits that are set, 
            // using toString()
    
            System.out.println("list #1 = " + bitset);
    
            // list the bits that are set, 
            // using a loop
    
            System.out.print("list #2 = ");
            for (int i = 0, len = bitset.length(); 
                i < len; i++) {
                    if (bitset.get(i)) {
                        System.out.print(i + " ");
                    }
            }
            System.out.println();
    
            // list the bits that are set, 
            // using an iterator
    
            System.out.print("list #3 = ");
            for (int i = bitset.nextSetBit(0); i >= 0;
            i = bitset.nextSetBit(i + 1)) {
                System.out.print(i + " ");
            }
            System.out.println();
        }
    }

The BitSet1 program creates a BitSet and sets the 0th and 1000th bits to true. Other bits between 0 and 1000 have false values. BitSet allocates enough memory internally to represent the highest set bit. Bits beyond the highest set bit are considered to be false.

One way of thinking about a BitSet is that it's a vector of 2^31 true or false bits, with all of the bits initially set to false. The bits have indices from 0 to Integer.MAX_VALUE, or 2^31 - 1. As bits are set to true, memory is allocated to represent them.

The program prints the size, length, and cardinality of the BitSet. The size is the the actual number of bits used by the BitSet. The length is the index of the highest set bit plus one. The cardinality is the number of bits currently set to true in the BitSet.

The program also illustrates three ways of retrieving a list of the set bits in the BitSet. The first way uses the BitSet.toString method. The second way uses a loop and the get method to check each index in the BitSet. The third way makes use of the BitSet.nextSetBit method to iterate across all the set bits.

When you run the program, the output is:

    size = 1024
    length = 1001
    cardinality = 2
    list #1 = {0, 1000}
    list #2 = 0 1000 
    list #3 = 0 1000 

This example also illustrates the idea that internal space to store the bits is dynamically allocated as needed. For example, if the 1000th bit is set, then the BitSet must grow to about 125 bytes.

Here's another example that illustrates this point:

    import java.util.BitSet;
    
    public class BitSet2 {
        public static void main(String args[]) {
            BitSet bitset = new BitSet();
            bitset.set(1000000);
            System.out.println(
                "number of bytes required = " +
                bitset.size() / 8);
        }
    }

This BitSet2 program sets the millionth bit in a BitSet. The output of the program is:

    number of bytes required = 125008

This particular BitSet object must grow to about 125,000 bytes to represent the millionth bit. Note that you can specify the size of the BitSet to the constructor, that is, if you know in advance how big the BitSet is likely to get. Doing this will save time and space reallocation as well as copying. BitSet as currently implemented uses a particular internal data structure (64-bit longs) to represent bits. This representation is not part of the external BitSet interface, however this tip assumes a particular model of memory allocation. This model is based on an array of longs, which represent all bits, true or false, so as to include the highest set bit. However, there are other possible ways to represent sets of bits. Note that the results from the size method might not make much sense if some other type of internal structure is used.

Let's look at another example. This one shows how you can perform common logical operations on a pair of BitSets:

    import java.util.BitSet;
    
    public class BitSet3 {
        public static void main(String args[]) {
    
            // create two sets of bits
    
            BitSet bitset1 = new BitSet();
            bitset1.set(1);
            bitset1.set(5);
            bitset1.set(8);
    
            BitSet bitset2 = new BitSet();
            bitset2.set(2);
            bitset2.set(5);
            bitset2.set(7);
            bitset2.set(11);
    
            // make a copy of the first one and XOR 
            // with the second
    
            BitSet result = (BitSet)bitset1.clone();
            result.xor(bitset2);
    
            System.out.println(bitset1 + " XOR " + 
                bitset2 + " = " + result);
        }
    }

Normally, when you have two BitSets and you do a logical operation like this:

    bitset1.xor(bitset2);

The result of the operation (exclusive-OR) is left in bitset1. But the idea in this example is to leave bitset1 unchanged. So the program makes a copy of bitset1 using the clone method.

When you run this example, the result is:

    {1, 5, 8} XOR {2, 5, 7, 11} = {1, 2, 7, 8, 11} 

A bit is set in the result BitSet if it is set in one, but not both, of the operand BitSets. The BitSet class offers similar methods for computing AND, OR, and ANDNOT. The ANDNOT method, which performs the operation a & ~b, is used to mask out bits in a BitSet.

A final example illustrates how you use BitSet features to operate on a range or group of bits:

    import java.util.BitSet;
    
    public class BitSet4 {
        public static void main(String args[]) {
            BitSet bitset1 = new BitSet();
    
            // set bits from 0 (inclusive) 
            // to 99 (exclusive)
    
            bitset1.set(0, 99);
    
            // get bits from 0 (inclusive) 
            // to 9 (exclusive)
    
            BitSet bitset2 = bitset1.get(0, 9);
    
            System.out.println(bitset2);
        }
    }

The BitSet4 program creates a BitSet, and then sets bits 0-98 to true. Then bits 0-8 of this BitSet are copied into a new BitSet. The output is:

    {0, 1, 2, 3, 4, 5, 6, 7, 8}

BitSet is an efficient way to represent and manipulate a large number of true/false values.

For more information about BitSet, see section 17.1, BitSet, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes.

Pixel
Pixel

USING JSPINNER TO CHOOSE FROM AN ORDERED LIST

JSpinner is a Swing class you use to display an ordered sequence of items, such as numbers or strings or calendar dates. A user can make a selection from the displayed sequence, or explicitly enter a value. JSpinner is similar to JComboBox, but instead of using a drop-down list to display the items, it employs a couple of tiny arrow keys that allow a user to sequence through a series of values.

Let's look at an example that compares and contrasts JSpinner and JComboBox:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.event.*;
    
    public class SpinDemo1 {
        public static void main(String args[]) {
    
            // create a JFrame
    
            JFrame frame = new JFrame("SpinDemo1");
            frame.setDefaultCloseOperation(
                JFrame.EXIT_ON_CLOSE);
    
            // create a JSpinner with a range of 
            // values 1-5 and starting value 1 
            // and increment 1
    
            final SpinnerModel sm =
                new SpinnerNumberModel(new Integer(1),
                new Integer(1), new Integer(5), 
                    new Integer(1));
            JSpinner jsp = new JSpinner(sm);
    
            // add a change listener
    
            jsp.addChangeListener(
                new ChangeListener() {
                    public void stateChanged(
                        ChangeEvent e) {
                            System.out.println(
                                "changed: " +
                                sm.getValue());
                    }
                });
    
            // create a JComboBox
    
            Object list[] = {new Integer(1), 
                new Integer(2), new Integer(3), 
                new Integer(4), new Integer(5)};
            JComboBox jcb = new JComboBox(list);
            jcb.setEditable(true);
    
            // create a JPanel
    
            JPanel panel = new JPanel();
            panel.setPreferredSize(
                new Dimension(300, 300));
            panel.add(jsp);
            panel.add(jcb);
            frame.getContentPane().add(panel);
    
            // display the frame
    
            frame.pack();
            frame.setVisible(true);
        }
    }

This SpinDemo1 program sets up a JPanel containing a JSpinner and a JComboBox. Both of these display the Integer wrapper values 1-5. Both JSpinner and JComboBox also allow you to enter your own value. But the JComboBox pull-down list uses a lot more window space when it displays its list of values. If there is another GUI item such as a label or input area just below the JComboBox, it will be temporarily obscured when the list of values is displayed. So JSpinner has an advantage in operating within a more constrained area of the window.

The example highlights another difference between JSpinner and JComboBox. A JSpinner uses an ordered set of values called the model. In the SpinDemo1 program the model is represented by a SpinnerNumberModel object. Minimum and maximum values as well as a starting value and an increment/decrement are set for the model. The JSpinner uses the model to validate its input. For example, if you enter "7" for the example above, it will not be accepted. You can literally type "7" in the JSpinner input field, but it will not be treated as a legal value. You can tell this by the change listener that is called when the value changes.

By contrast, JComboBox lets you type in any value you want, whether or not it's in the list specified to the JComboBox constructor. This functionality might be just what you need -- it all depends on your particular application.

Here's another example, one that uses JSpinner with a list of strings:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.event.*;
    
    public class SpinDemo2 {
        public static void main(String args[]) {
    
            // create a JFrame
    
            JFrame frame = new JFrame("SpinDemo2");
            frame.setDefaultCloseOperation(
                JFrame.EXIT_ON_CLOSE);
    
            // create a JSpinner 
            // based on a list of strings
    
            Object list[] = {"string1", "string2", 
                "string3"};
            SpinnerModel sm = 
                new SpinnerListModel(list);
            JSpinner jsp = new JSpinner(sm);
    
            // create a JPanel
    
            JPanel panel = new JPanel();
            panel.setPreferredSize(
                new Dimension(300, 300));
            panel.add(jsp);
            frame.getContentPane().add(panel);
    
            // display the frame
    
            frame.pack();
            frame.setVisible(true);
        }
    }

As with the previous example, any input typed by the user is validated against the specified list of strings.

Let's look at a slightly more complicated example, one where you specify a starting calendar date and then step through dates in one-minute intervals:

    import java.util.*;
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.event.*;
   
    public class SpinDemo3 {
        public static void main(String args[]) {
   
            // create a JFrame
   
            JFrame frame = new JFrame("SpinDemo3");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
            // create a JSpinner set to the current
            // date, with increment/decrement
            // set to minutes
   
            final SpinnerModel sm =
                new SpinnerDateModel(new Date(),
                null, null, Calendar.MINUTE);
            JSpinner jsp = new JSpinner(sm);
   
            // add a change listener for the JSpinner
   
            jsp.addChangeListener(
                new ChangeListener() {
                    public void stateChanged(
                        ChangeEvent e) {
                            Date d = (Date)sm.getValue();
                            System.out.println(
                                "new date: " + d);
                }
            });
   
            // create a JPanel
   
            JPanel panel = new JPanel();
            panel.setPreferredSize(
                new Dimension(300, 300));
            panel.add(jsp);
            frame.getContentPane().add(panel);
   
            // display the frame
   
            frame.pack();
            frame.setVisible(true);
        }
    }

In the first example, SpinDemo1, the program specified a range of values 1-5, a starting value of 1, and an increment/decrement of 1. In the SpinDemo3 example, the program starts with the current date, sets no minimum or maximum date values, and sets the increment/decrement to one minute. A user presented with the display can step through calendar dates in one-minute increments, or enter a date as desired. The change listener shows how to retrieve the current Date value from the underlying model used by the JSpinner object.

You may notice that the change listener is called twice the first time you increment or decrement the date in the JSpinner field. This behavior occurs because the displayed calendar date does not represent the full precision of the date stored internally, and rounding of the internal date will occur to match the displayed date. The first call to the change listener happens because of this rounding.

JSpinner is useful in situations where you'd like to let the user choose from an ordered sequence of values, and have input validation. JSpinner is also useful in situations where you want to economize on the use of window space.

For more information about JSpinner, see "JSpinner - A Simple Sequence Container".

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_26702396-914370309@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Mon Dec 9 21:26:03 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBA2Q3N05589 for ; Mon, 9 Dec 2002 21:26:03 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBA2RTr3025062 for ; Mon, 9 Dec 2002 21:27:37 -0500 (EST) Date: 9 Dec 2002 17:32:57 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <26702396-914370309@hermes.sun.com> Subject: December 2002 Core Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 14103 Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Standard Edition (J2SETM).


Early Access Releases

The following J2SE products and technologies were recently made available through the Early Access Release Program.

Java Advanced Imaging 1.1.2-Beta
This version of the API includes new operations for mosaicking, optimal color quantization, and high quality thumbnail generation (subsampling), as well as better exception handling and memory management.


Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

Java Communications API

J2SE 1.4 Documentation, in Japanese

Java Web Start

JavaBeansTM Development Kit (BDK) 1.1

Java 3DTM 1.3 API


Events

Sun Technology Audiocast
Java Management Extensions (JMX). Covers components in the JMX specification, the concept of management, JMX architecture and the impact it will have on businesses and distributed computing.

JXTA Code Camp
This Code Camp will show experienced Java developers how to write Peer-to-Peer applications using JXTA and Java.

Sun Tech Days
07-08 January 2003, Toronto, Canada
Covers the Sun ONE architecture, J2EE, and Web Services.

LinuxWorld Conference & Expo
21-24 January 2003, New York, New York, U.S.
The conference will focus on Linux and Open Source solutions.

pixel
pixel pixel pixel
December 11, 2002

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles & Quizzes

  • Secure Internet Programming with J2SE 1.4
    Part one of a two-part series that provides a hands-on tutorial explaining how to develop secure Internet applications for today's and tomorrow's market.

  • JMX in Action Quiz
    Special to the JDC Bookshelf is the "JMX in Action" Quiz. Test your JMX knowledge and take this quiz.

  • Java Technology Fundamentals Quiz
    Test what you've learned in previous newsletter issues concerning creating threads, working with boolean statements, writing and reading files, and using the JOptionPane class.

  • Updates to The Swing Tutorial
    A new version of The Swing Tutorial, the practical guide for GUI programming, has been released. It's part way through the process of being improved and updated to the J2SE SDK v1.4. The Tutorial's new version includes some new and updated pages, and many examples. Visit and give the writers your suggestions and feedback.

  • The Poetry of Programming
    Sun Microsystems Distinguished Engineer and poet Richard Gabriel talks about programming, poetry, and bringing more creativity to computing.

Tech Tips

Chat

New Networking Support in J2SE
Learn about the many new networking-related features and enhancements added in J2SE v1.4 in this chat with Alan Bateman and Yingxian Wang.

Newsletters

Java Technology Fundamentals Newsletter
Learn how to create color, play audio clips, and design sliders for your applications.


Industry News and Announcements

  • J2SE 1.4.1_01 is now available. Updates have been developed by addressing key customer issues and feedback on the previous FCS release.

  • Sun ONE Application Server 7 Available
    Compatible with J2EE 1.3, it supports up-to-date Java XML (JAX) Web services standards, Ant integration, Sun ONE Message Queue, is tightly coupled with the Sun ONE Studio 4, update 1 development environment, and more. Download now and for a limited time, receive a $200 (U.S.) Web-based training course for free, which details the architecture and features of the Sun ONE Application Server 7.

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA

Sun, Sun Microsystems, Java, Java Developer Connection, J2EE, J2SE, JMX, JCP, JavaBeans, Java 3D and Java Community Process are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_269125871118762118@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Dec 10 16:22:16 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBALMFN05054 for ; Tue, 10 Dec 2002 16:22:15 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBALNmwi022118 for ; Tue, 10 Dec 2002 16:23:51 -0500 (EST) Date: 10 Dec 2002 13:11:53 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <269125871118762118@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, December 10, 2002 (Container-Managed Relationships) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 28771 Enterprise Java Technologies Tech Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text December 10, 2002    

In this Issue

WELCOME to the Java 2TM, Enterprise Edition (J2EETM) Tech Tips, December 10, 2002. This issue covers:

.Container-Managed Relationships

This tip were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the J2EE Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for this tip. The context root for the application is ttdec2002, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms: http://developer.java.sun.com/berkeley_license.html

Pixel

Container-Managed Relationships

One of the tips in the Enterprise Java Technologies Tech Tips for November 12, 2002 showed how to create a simple entity bean that uses container-managed persistence (also known as "CMP". In CMP, an enterprise bean container (also called an EJB container) manages persistent data within an object. EJB containers that support the Enterprise JavaBeansTM 2.0 (or above) specification can also manage relationships among objects. This tip explains how to set up and use container-managed relationships (also called "CMR") in entity beans.

Understanding Relationships

In object-oriented modeling, a relationship is a logical association between two concepts. A Java object stores its own data, and uses object references to represent relationships to other objects. For example, in a Java program, a Person object might have relationships to home and work Address objects, and might also have a relationship to multiple Phone objects. An instance diagram of this situation appears in Figure 1 below.


Figure 1. Objects Can Refer To Other Objects

A conventional Java class represents a relationship to another class using a field whose type is an object reference. In the Person example described above, the Person class has two relationships to an Address class, and a single relationship to a Phone class. Figure 2 below is a UML structure diagram showing the relationships among these classes.


Figure 2. A Small Object Model

The Person class has two object reference fields to represent the two relationships to Address: one field for a homeaddress, and the other for a workaddress. The Person class represents its single relationship to the Phone class as a Collection of Phone references because each Person may have multiple phones. These relationships can be expressed in code like this:

class Person {
...
Address homeaddress;
Address workaddress;
Collection phones;
...
}

To associate a home address with a particular person, you simply assign the object reference:

person.homeaddress = new Address();

To give a person a new phone number, you add a reference to a Phone object to the person's phones collection:

Phone p = new Phone();
person.phones.add(p);

Enterprise beans take the concept of a relationship a step further by automatically managing persistent relationships among persistent objects.

Container-Managed Relationships

Developers create, update, and remove relationships between enterprise beans by manipulating object reference fields, just as with conventional objects. In enterprise beans, such fields are called CMR fields. Container-managed relationships have some important properties:

  • CMR fields are accessor methods, not class fields. EJB 2.0 and above define both CMP fields and CMR fields as pairs of abstract property accessors, not as fields in the class. The platform or the tools manage persistent data or relationships by generating the accessors' implementations. This arrangement allows the platform to control how data persistence and relationships are represented.
  • Container-managed relationships may be used only between local bean interfaces. For reasons of performance and data consistency, container-managed relationships between remote enterprise beans interfaces are not supported. Furthermore, because container-managed relationships are usable only with local interfaces, all of the beans that use CMR must be in the same ejb-jar file.
  • Relationships may be unidirectional or bidirectional. In the Person example, all the relationships from Person to the other classes are unidirectional. A bidirectional relationship can be traversed in either direction. Bidirectional relationships are represented by two CMR fields, one on each end of the relationship.
  • Relationships have cardinality. Relationship cardinality may be defined as one-to-one, one-to-many, many-to-one, or many-to-many. In the Person example, the homeaddress relationship is one-to-one, and the phones relationship is one-to-many.
  • Relationships may define cascading deletes. When a cascading delete exists, deleting a parent object causes all of the child objects to be deleted. In the Person example, deleting a Person causes both Address objects and all Phone objects for that person to be deleted.

Developers define relationships in an enterprise bean module's deployment descriptor. The EJB container automatically enforces the referential integrity of the relationships. For example, when the enterprise bean code updates one side of a bidirectional relationship, the container automatically updates the other side of the relationship. The container also handles details such as persisting the relationships between objects, performing cascading deletes, and implementing and enforcing transactional behavior, security, and type safety. All of these services are provided as the "container-managed" part of container-managed relationships.

Using Container-Managed Relationships

The sample code for this tip implements three enterprise beans: PersonBean, AddressBean and PhoneBean. The sample code also includes an HTML form and servlet that create and report on bean instances. The following examples come from the sample code.

Container-managed relationships are easy to use. To use CMR, an enterprise bean needs to declare public abstract property accessors for CMR fields in the bean class. The accessors use the same set/get naming conventions used by JavaBeansTM components and CMP fields. The container can manage all operations on relationships because it implements the accessor methods.

In the sample code, the PersonBean interface defines the accessors for the homeaddress, workaddress, and phones relationship like this:

public abstract class PersonBean implements EntityBean {
    ...
    public abstract AddressLocal getHomeAddress();
    public abstract void setHomeAddress
	  (AddressLocal address);

    public abstract AddressLocal getWorkAddress();
    public abstract void setWorkAddress
	  (AddressLocal address);

    public abstract Collection getPhones();
    public abstract void setPhones
	  (Collection phones);
    ...
}

Accessor methods for one-to-one and many-to-one relationships take and return the local interface type of the relationship successor. The relationship successor is the thing on the other end of the relationship. For example, the accessors for the homeAddress and workAddress relationships shown above (that is, getHomeAddress() and getWorkAddress(), respectively) use local interface type AddressLocal.

Accessor methods for one-to-many and many-to-many relationships require a collection type, which may be either java.util.Collection or java.util.Set. For example, the accessors for the one-to-many relationship phones uses collection type Collection.

When relationships are bidirectional, the class on the "far end" of the relationship must also define accessors for the relationship in the reverse direction. For example, to make the homeAddress relationship bidirectional, the AddressBean would need property accessors that set and get the PersonLocal interface of the person object that "owns" the address.

Business methods use the CMR accessors to manipulate container-managed relationships. The following code example, from the sample PersonBean class, defines methods for adding, removing, and getting a list of a person's telephone numbers.

public abstract class PersonBean implements EntityBean {
    ...

    // Business methods
    public ArrayList getPhoneList() {
        ArrayList result = new ArrayList();
        Iterator i = getPhones().iterator();
        while (i.hasNext()) {
            result.add(i.next());
        }
        return result;
    }

    public void addPhone(PhoneLocal phone) {
        Collection phones = getPhones();
        phones.add(phone);
    }

    public void removePhone(PhoneLocal phone) {
        Collection phones = getPhones();
        phones.remove(phone);
    }
    ...
}

The calls to getPhones in the code above are calls to the bean's CMR accessors, which return a Collection implemented by the container. Note that CMR accessors are defined in the bean class (PersonBean), but are not necessarily also defined in the local interface (PersonLocal). The business methods defined above provide a more user-friendly and type-safe interface to the phones relationship than the container can provide.

Because the collection classes are not generic types (meaning their interfaces return java.util.Object instead of the type they contain), you still have to typecast any interface you get from a container-managed collection. Fortunately, you can depend on the interface you receive being of an appropriate type. That's because the container enforces type safety within the collection. For example, the collection will throw an exception if you try to add an AddressLocal object to the phones relationship.

Deployment Information

The container needs some information about each relationship so it knows how to manage the collections and references that implement the relationship. It's usually best to use vendor-specific tools to edit deployment descriptors instead of writing and editing XML directly. This section shows pieces of the deployment descriptor to shed some light on how relationships are defined. The deployment descriptor definition for the phones relationship of the sample PersonBean appears below.

   <ejb-relation>
     <description>Phone numbers of Person
     </description>
     <ejb-relationship-role>
       <ejb-relationship-role-name>PersonBean
       </ejb-relationship-role-name>
       <multiplicity>One</multiplicity>
       <relationship-role-source>
         <ejb-name>PersonBean</ejb-name>
       </relationship-role-source>
       <cmr-field>
         <cmr-field-name>phones</cmr-field-name>
         <cmr-field-type>java.util.Collection
         </cmr-field-type>
       </cmr-field>
     </ejb-relationship-role>
     <ejb-relationship-role>
       <ejb-relationship-role-name>PhoneBean
       </ejb-relationship-role-name>
       <multiplicity>Many</multiplicity>
       <cascade-delete />
       <relationship-role-source>
         <ejb-name>PhoneBean</ejb-name>
       </relationship-role-source>
     </ejb-relationship-role>
   </ejb-relation>

A relationship is defined in the deployment descriptor with an <ejb-relation> tag. An <ejb-relation> contains a <description> tag and two <ejb-relationship-role> tags. Each <ejb-relationship-role> tag describes a relationship role, that is, a container-managed relationship in one direction. An <ejb-relationship-role> tag specifies several things for a relationship role:

  • A name for the relationship role
  • A multiplicity (One or Many)
  • A role source (meaning the type on the predecessor side of the relationship)
  • Optionally, a <cascade-delete> tag
  • A <cmr-field> tag
  • -- this tag is optional if the relationship is not navigable from this side.

The <cascade-delete> tag indicates that the role source object is deleted when the object on the other end of the relationship is deleted. In this example, when a Person object is deleted, all associated Phone objects are automatically deleted.

The <cmr-field> tag, if present, defines the name of the CMR field that implements access to the relationship. The name provided is used to define the names of the CMR accessors and the type of the relation. In the example shown above, the CMR field name is phones and the type is Collection, so the container expects the following accessor signatures:

public abstract Collection getPhones();
public abstract void setPhones(Collection phones);

These signatures are declared in PersonBean, as shown in the example.

A unidirectional relationship, such as the phones relationship shown above, defines a <cmr-field> and CMR accessors in only one <ejb-relationship-role>. Bidirectional relationships require CMR accessors (in the bean class) and a <cmr-field> (in the deployment descriptor) for both ejb-relationship-roles in the relationship.

So, in summary, the steps to implement container-managed relationships among enterprise beans are:

  1. Decide what relationships will exist between which classes, and give the relationships names
  2. Add abstract CMR field accessor definitions to the bean classes that have relationships to other local beans
  3. Add the <ejb-relation> tag to the ejb-jar deployment descriptor

Pixel
Pixel

Running the sample code

Download the sample archive for this tip. The application's context root is ttdec2002. The downloaded EAR file also contains the complete source code for the sample.

You can deploy and run the sample application in the J2EE Reference Implementation or in any J2EE-compliant implementation. The instructions for installing the J2EE Reference Implementation and configuring the environment are the same as described in Installing the Java Pet Store 1.3.1 Demo. After the J2EE Reference Implementation is installed and the environment is configured, you can deploy the application archive (ttdec2002.ear) using the deploytool program:

$J2EE_HOME/deploytool -deploy ttdec2002.ear localhost

Replace localhost with the name of the host on which the server is installed. For a standard installation on a single machine, the hostname typically (and literally) is localhost.

For a J2EE-compliant implementation other than the Reference Implementation, use your J2EE product's deployment tools to deploy the application on your platform. Your platform's deployment tool should guide you in resolving external references (such as resource references and EJB names).

See the index.html welcome file for instructions on running the application.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: jdc-webmaster@sun.com

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, Enterprise JavaBeans , JavaBeans, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_27497363-510907654@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Dec 18 14:17:49 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBIJHnN25028 for ; Wed, 18 Dec 2002 14:17:49 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBIJJUqh023485 for ; Wed, 18 Dec 2002 14:19:33 -0500 (EST) Date: 18 Dec 2002 11:05:45 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <27497363-510907654@hermes.sun.com> Subject: December Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 15899 Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Enterprise Edition (J2EETM).



Product and Technology Releases

The following J2EE products and technologies were recently released.

Java Authorization Contract for Containers
The Java ACC specification (JSR-115) defines new java.security. Permission classes to satisfy the J2EE authorization model. (November 20, 2002)

SunTM ONE Application Server 7, Standard Edition
AS 7 provides a J2EE 1.3 compatible platform for developing and delivering Java web services. (October 28, 2002)



Hot Downloads

The following are currently the most frequently downloaded J2EE products and technologies.

Java 2 SDK, Enterprise Edition Version 1.3.1

Java Web Services Developer Pack v1.0_01

Java Web Services Developer Pack v1.0_01 Tutorial

J2EE Tutorial v1.3.1

Java Servlet Specification 2.3

pixel
pixel pixel pixel
December 18, 2002

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

  • Technical Articles:
    • An Overview: Java API for XML-based RPC (JAX-RPC)
      The Java API for XML-based RPC (JAX-RPC) lets you develop SOAP-based, interoperable, and portable web services and provides the core API for developing and deploying web services on the Java platform. (November 4, 2002)

    • What Influences the Performance of Application Servers?
      Learn about the factors that affect the performance of your application server: the features of the application server, the access paths, the application type, the deployment topology, and scalability. (November 25, 2002)

    • The Poetry of Programming
      Sun Microsystems Distinguished Engineer and poet Richard Gabriel talks about programming, poetry, and bringing more creativity to computing. (December 05, 2002)


  • Tech Tips:
  • Chats:
    • The Sun ONE Connector Builder
      Product Manager, Darren Burt, and engineers Venkat Amirisetty and Tim Quinn discuss the Sun ONE Connector Builder. (December 10, 2002)

  • Events:
    • Final Sun Tech Days Conference in Europe
      3 - 4 February, 2003 - Hilton London Metropole Hotel, London, United Kingdom.
      Join us for Sun Tech Days, our annual developer conference and experience a unique global gathering of industry leaders representing cutting-edge systems such as Java Web Services, J2EE and the hottest software in between.

      To register for this free event, visit: http://www.sun.com/developers/techdays

    • Sun Technology Audiocast
      Web Services Programming Using Java Technology and XML

    • J2EE Technical Briefing Code Camp
      The codecamp is aimed at briefing developers on key J2EE 1.3 specifications and technologies such as Enterprise JavaBeansTM 2.0, Java Messaging Server, JavaServer PagesTM 1.2 and Servlet 2.3.

    • LinuxWorld Conference & Expo
      21-24 January 2003, New York, New York, U.S.
      The conference will focus on Linux and Open Source solutions.




Industry News and Announcements

  • Sun ONE Application Server 7 Available
    Compatible with J2EE 1.3 platform, it supports up-to-date Java XML (JAX) Web services standards, Ant integration, Sun ONE Message Queue, is coupled with the Sun ONE Studio 4, update 1 development environment, and more.

    Download now and for a limited time* (See footnote) and receive a $200 (U.S.) Web-based training course for free, which details the architecture and features of the Sun ONE Application Server 7.

  • Peace Software Ships Energy Version 7
    Peace Software has shipped Energy Version 7 to major U.S. utility Xcel Energy. Energy Version 7 incorporates regulated and competitive functionality for customer management in regulated and restructuring retail markets, mass and complex commercial and industrial markets, and across multiple commodities, products and services. The new version includes an array of APIs using J2EE architecture, a preferred industry standard that supports a variety of enterprise application integration/ middleware products and integration strategies.

Footnote to Sun ONE Application Server 7 announcement:
The free Web-based training offer is good through January 31, 2003 to individuals who have downloaded Sun ONE Application Server 7.

pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, Java, Java Developer Connection, J2EE, JCP, JavaBeans, JavaServer Pages and Java Community Process are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_275769701918074079@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Dec 20 19:16:37 2002 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBL0GbN20047 for ; Fri, 20 Dec 2002 19:16:37 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBL0IKqj000310 for ; Fri, 20 Dec 2002 19:18:23 -0500 (EST) Date: 20 Dec 2002 15:57:11 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <275769701918074079@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 35583 Java(TM) Technology Fundamentals Newsletter
pixel
pixel
header
    December 20, 2002    

In this Issue

imageJavaTM Programming Language Basics
imageJava Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageFor More Information

Pixel

Java Programming Language Basics

Understanding Interfaces

Good object-oriented programming requires class designers to hide information that shouldn't be known to users of said classes. With the Java programming language, such access can be controlled through the help of keywords as private, protected, and public. These keywords control the visibility of variables and methods inside the class, but poor class design results in too much visible information and methods that aren't properly encapsulated.

One way of encapsulating behavior is through the use of interfaces. Interfaces provide a way of hiding which class performs a specific task by exposing specific behavior such a class must support. As a program evolves, you can change the implementation without requiring changes in the calling class since the behavior itself hasn't changed, only the class that implements that behavior.

One such place where interfaces are commonly used is in the Collections Framework. The framework defines a handful of key interfaces that are implemented by a larger group of classes. By just learning the key interfaces, you effectively have learned the entire framework, as the specific implementation classes typically don't matter from a design perspective.

For instance, the List interface defines an ordered collection of elements. Available implementations include ArrayList and LinkedList, where both implement the List interface. When your program needs to work with a List, it should not care if it is an ArrayList or a LinkedList, only that whatever class is used provides a known behavior. That behavior is the interface.

By having classes implement interfaces, and only exposing the interfaces to the outside world in a class design, you have effectively encapsulated your class definition so that changes to the underlying implementation should minimally affect the rest of the system.

Take for example an ArrayList and a LinkedList. Think of an ArrayList as a growable array object (that only stores objects, not primitive data). While the class implements the full List interface, its behavior is optimized for specific conditions.

For instance, if your program is to frequently provide random access to the data of the list, (for example, "show me item three, twelve, two, and twenty-five") the ArrayList class offers quick access to individual elements of the list. This quick access comes at a cost of slower operations for adding and removing in the middle of the list. If this latter behavior is what you desire, than the LinkedList class offers a better alternative. It provides quick sequential access, additions, and deletes, at a cost of slower random access.

When working with ArrayList and LinkedList, there are two ways of creating the objects:

List cityList = new ArrayList();
LinkedList peopleList = new LinkedList();

Both of these code snippet lines compile, but there is a significant difference between the two lines. Line 1 states that we're creating an ArrayList, but we only need to access the item as a List. Line 2 is practically the opposite. Yes, the LinkedList item is created, similar to the ArrayList. But, the declaration side says that the program can only access the linked list as a LinkedList, and that is the significant difference.

Understanding interfaces really comes into play when the user of the two lines decides that the "give me item n" behavior is more important than the remove (or add) item at position "m" task.

The peopleList variable was declared to be of type LinkedList. While this isn't wrong by itself, as you examine the bigger picture, you'll find that anywhere that peopleList was used could be treating the object as a LinkedList. If you find that methods specific to LinkedList were used, then that class breaks when you need to treat it as an ArrayList.

List peopleList = new ArrayList();

By learning to work with any object only through its interface, you find that you can change implementations after design with no code changes beyond the declaration. That's the beauty of interfaces. As the class was originally declared a LinkedList, the change to type List would mean that method calls like addFirst or addLast would be unacceptable since the "new" peopleList of type List has no such methods.

This interface-based design of code such as the Collections Framework permits anyone to write code in a looping construct without ever having to know what collection you're working with. The created class is then restricted to provide complete implementations of the interface. Barring that, the new code wouldn't compile.

To demonstrate, the following program creates a couple of collections. Each collection offers a system-defined Iterator so that each element of the collection can be visited. This iterator is then passed along to a helper routine where the individual elements of the collection are printed.

import java.util.*;

public class Interfaces {

   public static void main(String args[]) {
     Properties props = System.getProperties();
     Set keySet = props.keySet();
     dumpIterator(keySet.iterator());

     List list = Arrays.asList(args);
     dumpIterator(list.iterator());
   }

   private static void dumpIterator(Iterator itor) {
     // System.out.println(itor.getClass().getName());
     while (itor.hasNext()) {
       System.out.println(">> " + itor.next());
     }
     System.out.println("----");
   }
}

The fact that the class type of the Iterator is unknown is the beauty of interfaces. It doesn't matter. The only thing that matters is the fact that the iterator method returns an actual Iterator object. Thus, dumpIterator always provide the full implementation of the interface.

If you uncomment the println comment line in dumpIterator, you'll find that the name of the actual iterator class is Hashtable.Enumerator for the Properties' key set and AbstractList.Itr for the List. This fact doesn't need to be known and won't help the behavior of your program. What does matter is that whatever is returned by the iterator method of List and Properties implements the three methods of java.util.Iterator: hasNext, next, and remove. Without two of the three methods, the dumpIterator method would never work.

Pixel
Pixel

Java Bits

Creating Font Objects

The Font class represents fonts, which are used to render text in a visible way.

  • A character is a symbol that represents an item such as a letter, a digit, or punctuation in an abstract way.
  • A glyph is a shape used to render a character or a sequence of characters.
  • A font encapsulates the collection of glyphs needed to render a selected set of characters as well as the tables needed to map sequences of characters to corresponding sequences of glyphs.

The Font class represents an instance of a font face from a collection of font faces present in the system resources of the host system, such as Arial or Courier. There can be several Font objects associated with a font face.

All fonts have the following properties:

  • Family Name, such as Arial
  • Size, such as 14 point
  • Style, such as italics

Because the fonts installed on a user's computer may vary, it's a good idea to use the most common fonts, such as Helvetica, Arial, or Courier.

To create a Font object, call the Font class constructor:

public Font(String familyname, int style, int size)

The familyname string is the name of the font you want to use, such as Arial. The style refers to four available font style constants in the Font class:

  • Font.PLAIN
  • Font.BOLD
  • Font.Italic
  • Font.BOLD = Font.ITALIC

As an example, the Font constructor is called with the following:

Font font = new Font("Helvetica", Font.BOLD, 16);

Then call the setFont method on the object where the font is to appear, such as a button or label:

JLabel label = new JLabel("It was a stormy night.");
label.setFont(font);

You can use the setBackground and setForeground methods to set the font a specific color, which is the foreground, and set the background to a color to contrast with the font color.

This FontExample application illustrates:

import java.awt.*;
import javax.swing.*;

public class FontExample extends JFrame
  {
    JLabel label1;
    JLabel label2;
    Font font1;
    Font font2;
    String message = "This is a font.";
    
    public FontExample()
    {
     font1 = new Font("Helvetica", Font.BOLD, 18);
     font2 = new Font("Arial", Font.ITALIC, 22);
     
     label1 = new JLabel(message);
     label1.setFont(font1);
     label1.setBackground(Color.WHITE);
     label1.setForeground(Color.RED);
     
     label2 = new JLabel(message);
     label2.setFont(font2);
     label2.setBackground(Color.WHITE);
     label2.setForeground(Color.BLUE);
     
     JPanel p1 = new JPanel();
     
     p1.setBackground(Color.WHITE);
     p1.add(label1);
     
     JPanel p2 = new JPanel();
     p2.setBackground(Color.WHITE);
     p2.add(label2);

     getContentPane().add(p1, BorderLayout.NORTH);
     getContentPane().add(p2, BorderLayout.SOUTH);
      
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setBounds(100, 300, 300, 100);
     setVisible(true);
     setBackground(Color.WHITE);
     }//Close constructor
 
    public static void main(String args[])
      {
      FontExample fe = new FontExample();
      }
  }

When the application is run, it should look something like the example below:

Pixel
Pixel

Making Sense of the Java Class Libraries

The JCombo and JList Classes

The Swing library provides classes to create objects that display a list. A user can then select one or more items on the list depending which class was used to create the list object.

A JList list object can include icons, list events, and listeners, and allows a user to select one or more items.

The JComboBox object is good to use for short lists, where only one item is to be selected. In addition, a JComboBox item can be made editable.

The JList and JComboBox classes are found in the javax.swing package.

A JComboBox object uses a ListCellRenderer object to determine how the elements are displayed. It also uses a ComboBoxModel object to provide methods to access the combo box elements.

Created with the JComboBox class, combo boxes are a combination of an editable area (if you desire) and a drop-down list of selectable items. Instances of JComboBox are not editable by default, but are set to editable by calling the setEditable method.

To create a JComboBox, call one of the following constructors:

  • JComboBox(): Creates a default combo box.
  • JComboBox(ComboBoxModel aModel): Creates a combo box that takes its items from an existing ComboBoxModel.
  • JComboBox(Object[] items): Creates a combo box that contains the elements in the specified array.
  • JComboBox(Vector items): Creates a combo box that contains the elements in the specified Vector.

You can supply a String array or a Vector to create the list of items. Once the array or Vector is defined, you pass it to the JComboBox constructor:

String drinks[] = {"Orange Juice", "Apple Juice", "Grape Juice"};
JComboBox menu = new JComboBox(drinks);

After initializing a combo box with an array to provide items for the drop-down menu, you can set how many of those items display in the list at once. If there are more than the specified number, scroll bars appear for the user to view other items on the list. Set maximum rows by calling the setMaximumRowCount method and providing an int:

menu.setMaximumRowCount(3);

You can implement ActionListener, so that when the user makes a selection, the JComboBox fires an ActionEvent, and the actionPerformed method defines what happens as a result of this selection.

For instance, within the actionPerformed method, you might call the getSelectedItem method, which returns the currently selected item as a String.

public void actionPerformed(ActionEvent e)
   { 
              
     String result = 
        (String)menu.getSelectedItem();
    }

Another way to present a user with a list of data is by creating a JList object. The JList class is a direct subclass of JComponent. JList implements several interfaces: Accessible, ImageObserver, MenuContainer, Scrollable, Serializable.

JList doesn't support scrolling directly. If you create a JList with a long list of items, use the JScrollPane class so that the user can scroll down a long item list.

You need to initialize a JList object with some data because this class doesn't have methods that allow you to add or remove individual items of data. Generally, you supply an array of strings, or a Vector to hold the data items, which populate the JList object.

To create a JList, call one of the four constructors:

  • JList()
    Constructs a JList with an empty model.
  • JList(ListModel dataModel)
    Constructs a JList that displays the elements in the specified, non-null model.
  • JList(Object[] listData)
    Constructs a JList that displays the elements in the specified array.
  • JList(Vector listData)
    Constructs a JList that displays the elements in the specified Vector.

A JList object uses ListCellRenderer to determine how the list should be displayed, and a JListModel object provides methods to access elements of the list and provides listener interfaces. To manage currently selected items in the list, implement the ListSelectionModel.

The JList class also has many methods for working with the appearance of the list, adding or removing listeners, and getting or setting list properties.

  • addListSelectionListener(ListSelectionListener listener)
    Adds a listener to the list that's notified each time a change to the selection occurs.
  • setSelectionModel(ListSelectionModel selectionModel)
    Sets the selectionModel for the list to a non-null ListSelectionModel implementation.
  • setSelectionBackground(Color selectionBackground)
    Sets the background color for selected cells.
  • setSelectionForeground(Color selectionForeground)
    Sets the foreground color for selected cells.

The following application demonstrates how to create JComboBox and JList objects, and includes examples of calling the methods which are defined above.

import javax.swing.*;
import java.awt.*;
import javax.swing.event.*;


public class ListObjects extends JFrame
 {
   JComboBox menu;
   JList menu2;
   JTextField tf1;

   public ListObjects()
    {
      super("Breakfast Club Menu");

	  //Array to be used in menu combo list
      String drinks[] =
         {"Orange Juice", "Apple Juice", "Grape Juice"};
      menu = new JComboBox(drinks);
      //Array to be used in menu list
      String foods[] =
        {"Pancakes", "Scrambled Eggs", "Breakfast Steak",
        "Waffles", "Fried Eggs", "Hash Browns", "Oatmeal",
        "Blueberry Muffin", "Omelet", "Toast", 
        "Breakfast Burrito",
 "Fruit Bowl"};
      //JList object creation and methods to customize properties.
      menu2 = new JList(foods);
      menu2.setSelectionMode(
         ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
      menu2.setSelectionBackground(Color.YELLOW);
      menu2.setSelectionForeground(Color.BLUE);

      //Register with listener
      ListSelectionListener lsl = new MyListener();
      menu2.addListSelectionListener(lsl);

      //Text field to display JList selection
      tf1 = new JTextField("Selection appears here . . .", 20);
      //Panel for combo box
      JPanel p1 = new JPanel();
	  p1.setBackground(Color.WHITE);
	  p1.add(menu);
      //Panel for JList object
      JPanel p2 = new JPanel();
	  p2.setBackground(Color.WHITE);
	  //Add the list to the panel through
	  //a scrollpane
	  p2.add(new JScrollPane(menu2));
      //Panel for text field
	  JPanel p3 = new JPanel();
	  p3.setBackground(Color.WHITE);
	  p3.add(tf1);


      //Get the content pane, add the panels, and

       //set the layout.

	  getContentPane().add(p1, BorderLayout.WEST);
	  getContentPane().add(p2, BorderLayout.CENTER);
	  getContentPane().add(p3, BorderLayout.SOUTH);


      //Setting details for the app frame
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setBounds(300, 400, 400, 300);
      setVisible(true);
      setBackground(Color.WHITE);

     }

     //Class to implement listener interface, and call

      //necessary method that gets the selection and

      /displays that selection in the text field.
     class MyListener implements ListSelectionListener
       {
         public void valueChanged(ListSelectionEvent evt)
           {
	     tf1.setText((String) menu2.getSelectedValue());
           }
       }

    public static void main(String []args)
     {

      ListObjects lo = new ListObjects();
     }

}//Close class

When you compile and run this application, you should get a result that appears something like the figure below:

Pixel
Pixel

Program Challenge

Create the EnumArray Application

  • Use the String[] argument to main as the basis.
  • Use the Enumeration interface to print each element of the array.

See a possible solution to the Challenge:

Pixel
Pixel

For More Information

Lesson: Interfaces

How to Use Lists

Advanced JList Programming

Class Font

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SETM development kit.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2002 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please unsubscribe me from this newsletter.
From env_27672735261561321@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Dec 24 12:23:26 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBOHNQN10170 for ; Tue, 24 Dec 2002 12:23:26 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBOHPCwi000862 for ; Tue, 24 Dec 2002 12:25:14 -0500 (EST) Date: 24 Dec 2002 09:10:45 -0800 From: "Wireless Developer Newsletter" To: gcf@indiana.edu Message-Id: <27672735261561321@hermes.sun.com> Subject: Wireless Developer Newsletter December 24, 2002 Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 13511 Wireless Developer Newsletter: December 24, 2002

Welcome to the Wireless Developer Newsletter, to which you subscribed. Here you'll find links to the latest wireless technologies and products, learn about resources for wireless developers, get the latest wireless news, and more.


Product and Technology Releases

Several wireless products and technologies were released recently:

J2ME Personal Profile Runtime Environment for x86 Linux v1.0
This Personal Profile Runtime Environment product includes several items of use to programmers using Linux including Binary File, Files For Programmers, Documentation and Sample Demos.

JSR 139: CLDC 1.1 Proposed Final Draft (December 17)
The Proposed Final Draft Specification for Connected Limited Device Configuration (CLDC) 1.1 is now available for review:


Hot Downloads

Currently the most frequently downloaded wireless products and technologies are:

Java 2 Platform, Micro Edition, Wireless Toolkit 2.0 Beta

Java 2 Platform, Micro Edition, Wireless Toolkit 1.0.4

MIDP for Palm OS 1.0

MIDP for Palm OS 1.0 Documentation

Java Card 2.2 Development Kit


Java User Groups (JUGs)

There are over 900 established Java User Groups worldwide. Find one near you at this url:
http://servlet.java.sun.com/jugs

pixel
pixel pixel pixel
December 24, 2002

Resources

Learn more about wireless products and technologies through the following resources.

  • Featured Question: Why does the body of my HTTP transaction contain "extra" characters?

  • Articles: Read the following new articles on the Wireless Developer site:

    • What's New in MIDP 2.0
      A tour of some of MIDP 2.0's exciting new features. Working code samples are included. Get hands-on experience with secure networking, custom form items, audio, and more!

    • Introduction to OTA Application Provisioning
      This article describes the ability to download and install content over a wireless network.

    • Improving Java[tm] Application Performance and Scalability by Reducing Garbage Collection Times and Sizing Memory Using JDK 1.4.1
      Part 2 of the series on how to improve a wireless application's performance and scalability by fine tuning the application's garbage collection.

    • J2ME Optional Packages
      This article explores what optional packages are and how they're used.

    • The Wireless Messaging API
      Covers the Wireless Messaging API (WMA) in detail. Defined in the Java Community Process[sm] (JCP) by JSR 120, the WMA provides a common API for sending and receiving text and binary messages - typically of store-and-forward types, such as Short Messaging Service (SMS) messages.

    • Authentication in MIDP
      Part 3 of the MIDP Application Security series describes techniques authentication techniques for clients and servers. This article covers server authentication in TLS and examines techniques MIDP clients can use to prove their identity. The article concludes with an advanced example that uses the Bouncy Castle Cryptography APIs to authenticate a MIDP client to a server using an X.509 certificate. Full source code is provided.


Events

  • JDC Chat: J2ME Wireless Toolkit 2.0
    Nicolas Lorain, Dov Zandman, Ariel Levin, Gary Adams, and Mark Young discuss the new features in the J2ME Wireless Toolkit.
    January 7, 9:00 A.M. PST/5:00 P.M. GMT

  • Wireless Java Implementation Strategies, London
    January 20-22 Radisson SAS hotel, Central London, UK

  • MOTOCODER Developer's Conference, Shanghai, January 8, 2003
    You are invited to experience the future of mobile application development at a private event hosted by Motorola in Shanghai, at the New Westin Shanghai. Join us at the MOTOCODER Developer's Conference to discover where the next evolution of mobile development will take you.

    Experience the New MOTOCODER Program, with hands on training, interactive sessions, including free tools and gifts.

    Login required to register for this exciting event hosted by Motorola. Username: motodeveloper Password: shanghai


Industry News

Over 50 million J2ME Handsets Shipped & Deployed By 20+ Carriers Worldwide
The final release of MIDP 2.0 will extend the base collection of Java technologies for mobile devices. More than 50 million Java-technology enabled handsets have already been shipped worldwide by major carriers, representing all the main wireless network systems, including GSM/GPRS, CDMA, PDC, iDEN, and W-CDMA.

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

FEEDBACK
Comments? Send your feedback on the Wireless Developer Newsletter to: wd-webmaster@sun.com

SUBSCRIBE/UNSUBSCRIBE
- To subscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at the end of this email.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allnewsletters/wireless/

COPYRIGHT
Copyright 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA
This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, SunNetwork, Java, Java Developer Connection, Solaris Developer Connection, NetBeans, JavaServer Pages, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_24509693-1162097742@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Oct 30 18:31:19 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id g9UNVJr13693 for ; Wed, 30 Oct 2002 18:31:19 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id g9UNW8VN019810 for ; Wed, 30 Oct 2002 18:32:09 -0500 (EST) Date: 30 Oct 2002 15:24:17 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <24509693-1162097742@hermes.sun.com> Subject: October 2002 Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 17846 Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Enterprise Edition (J2EETM).



Product and Technology Releases

The following J2EE products and technologies were recently released.

SunTM ONE Starter Kit
The Sun ONE Starter Kit helps developers, IT architects, and technical managers build and extend web-centric computing environments using essential Sun ONE and Java technologies. Through extensive documentation, code samples, and "How to" information, this Starter Kit can show you how to turn your company's information assets into online services.

JSR-000013 Decimal Arithmetic Enhancement for the Java Programming Language Proposed Final Draft
The proposed enhancements to the BigDecimal class primarily add floating point arithmetic to the existing class, allowing the use of decimal numbers for general-purpose arithmetic.

Java Telephony API (JTAPI) Specification 1.4 Final Release 2
JTAPI 1.4 extends and enhances the current Java Telephony specification, to be brought up to date with the latest in Java technology, particularly the listener event model.



Hot Downloads

The following are currently the most frequently downloaded J2EE products and technologies.

Java 2 SDK, Enterprise Edition Version 1.3.1

Java Web Services Developer Pack v1.0_01

Java Web Services Tutorial v1.0_01

J2EE Tutorial v1.3.1

Enterprise JavaBeansTM 2.1 Specification Proposed Final Draft



In the Spotlight

GemStone Systems Announces Availability of Real-Time Cache
GemStone Systems announced GemFire Real-Time Performance 1.0. The industry's first shared-memory based cache improves the performance and scalability of real-time business applications.

The new product release also makes it easy to bring the speed and scalability of shared memory to existing Java architectures without extensive recoding. Built-in monitoring facilities, automatic memory management and background deadlock detection further decrease development and debugging costs.

pixel
pixel pixel pixel
October 30, 2002

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

  • Technical Articles:
  • Book:
    • Core J2EE Patterns
      The primary focus of the book is on patterns, best practices, design strategies, and proven solutions using the key J2EE technologies including JSP, Servlets, Enterprise JavaBeansTM (EJBTM), and Java Message Service (JMS) API.

  • Webcamp Audiocast:
  • Online chats:
    • Oct 22, 11:00 A.M. PDT/6:00 P.M. GMT.
      Sun ONE Application Framework.
      Guests: Todd Fast and Michael Frisino

    • Nov 12, 11:00 A.M. PST/7:00 P.M. GMT.
      Regular Expressions
      Michael McCloskey and Mark Reinhold

  • Tech Tips:
  • JavaOneSM Conference Call for Papers
    • JavaOne, Sun's 2003 Worldwide Java Developer ConferenceSM is seeking proposals for sessions. Contribute to the event's innovation and insightful technical education. Submissions accepted from September 30 to November 8, 2002. Submit your proposal(s) at http://java.sun.com/javaone/sf
      Email J1papers@sun.com with questions about the Call for Papers process.

      Mark your calendars for the 2003 JavaOne conference:
      June 9-13, 2003, Moscone Center, San Francisco, CA

  • Events:
    • The JavaPolis Conference in Belgium
      Antwerp, Belgium, November 13-14, 2002
      The Belgian Java Users Group (BeJUG) has organized JavaPolis, a huge Java technology conference. The two-day event has several tracks scheduled, including J2EE, Wireless Java and Java 2 Platform, Micro Edition (J2METM) technologies. Become a BeJUG member and the conference admission is free.

    • ApacheCon US 2002
      Las Vegas, Nevada, USA November 18-21, 2002
      Come share your knowledge of Apache software at this educational and fun-filled gathering of Apache users, vendors, and friends.



Industry News

  • Sun Microsystems Joins WS-I
    Sun announced that it will join the Web Services Interoperability Organization (WS-I ) as a contributing member. WS-I was founded on February 6, 2002 as an open industry effort chartered to promote Web services interoperability across platforms, applications and programming languages.

    Participation in WS-I complements Sun's Web services interoperability contributions in other forums as well, such as SOAPbuilders and the Java Community ProcessSM.

  • KonaWare Introduces Mobile Framework for Deploying Business-Critical Mobile Applications
    KonaWare, Inc. announced its software framework for deploying and managing mobile applications that connect field workers to mission-critical data. The KonaWare Mobile Framework extends and integrates with existing enterprise IT systems to mobilize business-to-employee applications (B2E), such as field service, sales force, logistics, and custom applications. Companies leverage their existing IT infrastructure to extend applications to their mobile workers using familiar skill sets, such as Java and XML.


Java Developer's Marketplace

  • Phaos Releases Liberty Toolkit 2.0
    The Phaos Liberty Toolkit lets developers build Java applications that adhere to the sign-on authentication and authorization specifications set by the Liberty Alliance, support the consolidation of enterprise authentication schemes and allow the migration from legacy infrastructure to XML-based Web services. The toolkit also provides integrated XML digital signatures and XML encryption, stronger privacy and identity protection mechanisms by integrating hardware operations.
pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2002 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, SunNetwork, Java, Java Community Process (JCP), Java Developer Connection, JavaBeans, EJB, JSP, JavaServer Pages, JavaOne, Sun's 2003 Worldwide Java Developer Conference, J2EE, J2ME and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_25606489-1927062100@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Nov 19 13:05:25 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gAJI5PN21711 for ; Tue, 19 Nov 2002 13:05:25 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gAJI6ExC002174 for ; Tue, 19 Nov 2002 13:06:36 -0500 (EST) Date: 19 Nov 2002 08:57:07 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <25606489-1927062100@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Nov. 19, 2002 (Multi-Column Lists, Timeouts on Socket Connections) Mime-Version: 1.0 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 37324 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text November 19, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, November 19, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Displaying Multi-column Lists
Dealing with Timeouts on Socket Connections

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Pixel

DISPLAYING MULTI-COLUMN LISTS

A common request in newsgroups and forums lately seems to be the ability to have a JList show its options in multiple columns. In this scenario, the columns are displayed in the JList, and then a user selects a row in the display. There are at least three ways to satisfy this request. This tip examines each of these three approaches.

First, let's examine what might be the simplest solution: use JTable instead of JList. The JTable component was specifically designed to offer support for multiple columns of data. So why bother "shoe-horning" into a JList what the JTable component gives you by design?

Here's an illustration of the JTable approach. The following program displays a list of countries and their current political leader in multiple columns. You can then select a row from the display. Notice that the columns have headers -- this is a nice feature of JTable. Notice too that you can display multiple rows in the JTable.

  import java.awt.*;
  import javax.swing.*;
  import javax.swing.table.*;
  
  public class Leaders {
    public static void main(String args[]) {
      JFrame frame = new JFrame("Leaders");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container contentPane = frame.getContentPane();
      String headers[] = {"Leader", "Country"};
      String data[][] = {
        {"Tony Blair", "England"},
        {"Thabo Mbeki", "South Africa"},
        {"Megawati Soekarnoputri", "Indonesia"},
        {"Hosni Mubarak", "Egypt"},
        {"Vladimir Putin", "Russia"},
        {"Vicente Fox", "Mexico"},
        {"Ariel Sharon", "Israel"}
      };
      TableModel model =
        new DefaultTableModel(data, headers) {
          // Make read-only
          public boolean isCellEditable(int x, int y) {
            return false;
          }
        };
      JTable table = new JTable(model);
      // Set selection to first row
      ListSelectionModel selectionModel =
        table.getSelectionModel();
      selectionModel.setSelectionInterval(0, 0);
      selectionModel.setSelectionMode(
        ListSelectionModel.SINGLE_SELECTION);
      // Add to screen so scrollable
      JScrollPane scrollPane = new JScrollPane (table);
      contentPane.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 100);
      frame.show();
    }
  }

When you use a JTable as shown in this example, you must use a ListSelectionListener to listen for the selection of a new row. Notice that, as you can do for JList, you can place the JTable in a JScrollPane and provide scrolling support.

The second way of providing multiple columns in a selectable set of data does use the JList component. For this technique, you need to think about the underlying design of the JList component. Each selectable option in a JList is not a component by itself. Instead each option is a product of what's called a renderer. A renderer knows how to draw each option in the JList but has no concept of the overall list.

Typically, a renderer is a JLabel (see the documentation of the javax.swing.DefaultListCellRenderer class. However, the ListCellRenderer interface only requires that the renderer be a Component.

     public Component getListCellRendererComponent(
         JList list,
         Object value,
         int index,
         boolean isSelected,
         boolean cellHasFocus)

Any component will do.

This suggests the second way of offering multiple columns: return a Container, where the Container contains one Component per column. Here's an example that illustrates the second approach. The example uses the same data that was used in the previous, JTable example. But in this example the data is converted to a JList model. The data is then added in the renderer.

  import java.awt.*;
  import javax.swing.*;
  
  public class ListLeaders {
    static class MyCellRenderer extends JPanel 
          implements ListCellRenderer {
      JLabel left;
      JLabel right;
      MyCellRenderer() {
        setLayout(new GridLayout(1, 2));
        left = new JLabel();
        right = new JLabel();
        left.setOpaque(true);
        right.setOpaque(true);
        add(left);
        add(right);
      }
      public Component getListCellRendererComponent(
               JList list,
               Object value,
               int index,
               boolean isSelected,
               boolean cellHasFocus) {
        String leftData = ((String[])value)[0];
        String rightData = ((String[])value)[1];
        left.setText(leftData);
        right.setText(rightData);
        if (isSelected) {
          right.setBackground(
             list.getSelectionBackground());
          right.setForeground(
             list.getSelectionForeground());
          left.setBackground(
             list.getSelectionBackground());
          left.setForeground(
             list.getSelectionForeground());
        } else {
          right.setBackground(list.getBackground());
          right.setForeground(list.getForeground());
          left.setBackground(list.getBackground());
          left.setForeground(list.getForeground());
        }
        setEnabled(list.isEnabled());
        setFont(list.getFont());
        return this;
      }
    }

    public static void main(String args[]) {
      JFrame frame = new JFrame("ListLeaders");
      frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      Container contentPane = frame.getContentPane();
      String data[][] = {
        {"Tony Blair", "England"},
        {"Thabo Mbeki", "South Africa"},
        {"Megawati Soekarnoputri", "Indonesia"},
        {"Hosni Mubarak", "Egypt"},
        {"Vladimir Putin", "Russia"},
        {"Vicente Fox", "Mexico"},
        {"Ariel Sharon", "Israel"}
      };
      JList list = new JList(data);
      list.setCellRenderer(new MyCellRenderer());
      JScrollPane scrollPane = new JScrollPane(list);
      contentPane.add(scrollPane, BorderLayout.CENTER);
      frame.setSize(300, 150);
      frame.show();
    }
  }

Although the JList does provide multiple columns of data to choose from, it doesn't display grid lines (something that the JTable does provide).

The third way of getting multiple columns of data in a JList depends on a JList feature that is new in J2SE 1.4. Using this technique doesn't actually provide multiple columns of data for selection. Instead, it offers a single column of data spread over multiple columns.

This new feature is controlled by the new setLayoutOrientation method of JList. By specifying one of three modes found in JList: VERTICAL (the default), HORIZONTAL_WRAP, and VERTICAL_WRAP, you can position choices for selection in one of three different ways.

VERTICAL positions data in a single column:

  1
  2
  3
  4
  5
  6

HORIZONTAL_WRAP positions data in cells similar to the way the GridLayout layout manager positions data, that is, a row at a time:

  1   2
  3   4
  5   6

VERTICAL_WRAP positions the data in cells going up and down instead of left-to-right.

   1   4
   2   5
   3   6

Here's a demonstration of the different modes. The following program provides a geography test. It asks for the capital of a country, and lists possible answers alphabetically in three different JList components, one JList component for each of the modes. Pick an answer to see how well you know world capitals.

  import javax.swing.*;
  import javax.swing.event.*;
  import java.awt.*;
  import java.awt.event.*;

  public class ListWrap extends JFrame {

    static final String asCity[] = {
       "Asmara",     "Berlin",     "Kuala Lumpur",
       "Paramaribo", "Paris",      "Sana",
       "Sucre",      "Tokyo",      "Ulan Bator",
       "Valletta",   "Washington", "Yaounde"
       };

    static final String asCountry[] = {
       "Eritrea",  "Germany", "Malaysia",
       "Suriname", "France",  "Yemen",
       "Bolivia",  "Japan",   "Mongolia",
       "Malta",    "US",      "Cameroon"
       };

    int current;
    JTextField input;
    JLabel where;
    JButton submitButton, nextButton;

    public ListWrap() {
      setTitle( "Capitals" );
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      JPanel westPanel = new JPanel(
          new GridLayout(3, 1));
      westPanel.add(new JLabel(
          "What is the capitol of...",
          JLabel.CENTER));
      westPanel.add(where =
          new JLabel(asCountry[0], JLabel.CENTER));
      input = new JTextField(10);
      JPanel westSouth = new JPanel();
      westSouth.add(input);
      westPanel.add(westSouth);

      ListSelectionListener selectionListener =
          new ListSelectionListener() {
        public void valueChanged(
            ListSelectionEvent lse) {
          if (!lse.getValueIsAdjusting()) {
            Object source = lse.getSource();
            int index = (
                (JList)source).getSelectedIndex();
            input.setText(asCity[index]);
            checkAnswer();
          }
        }
      };

      JTabbedPane tabbedPane = new JTabbedPane();

      JList normalWrap = new JList(asCity);
      normalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab("Standard", null,
        new JScrollPane(
            normalWrap), "Standard Orientation");

      JList verticalWrap = new JList(asCity);
      verticalWrap.setLayoutOrientation(
          JList.VERTICAL_WRAP);
      verticalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab("Vertical Wrap", null,
        verticalWrap, "Vertical Wrap Orientation");

      JList horizontalWrap = new JList(asCity);
      horizontalWrap.setLayoutOrientation(
          JList.HORIZONTAL_WRAP);
      horizontalWrap.addListSelectionListener(
          selectionListener);
      tabbedPane.addTab("Horizontal Wrap", null,
        horizontalWrap, "Horizontal Wrap Orientation");

      JPanel eastPanel = new JPanel();
      eastPanel.add(tabbedPane);

      ActionListener actionListener = 
          new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
          Object source = ae.getSource();
          if (source == submitButton) {
            checkAnswer();
          } else if (source == nextButton) {
            doNext();
          }
        }
      };

      JPanel southPanel = new JPanel();

      submitButton = new JButton("Submit Answer");
      submitButton.addActionListener(actionListener);
      southPanel.add(submitButton);

      nextButton = new JButton("Next");
      nextButton.addActionListener(actionListener);
      southPanel.add(nextButton);

      Container contentPane = getContentPane();
      contentPane.add(westPanel, BorderLayout.WEST);
      contentPane.add(eastPanel, BorderLayout.EAST);
      contentPane.add(southPanel, BorderLayout.SOUTH);

      pack();
      show();
    }

    public void checkAnswer() {
      int messageType = 0;
      String result = null;
      String s = input.getText();
    
      if (s.equalsIgnoreCase(asCity[current])) {
        result = "Correct!";
        messageType = JOptionPane.INFORMATION_MESSAGE;
      } else {
        result = "Try Again.";
        messageType = JOptionPane.WARNING_MESSAGE;
      }

      JOptionPane.showMessageDialog(this,
        result, "Result", messageType);
    }

    public void doNext() {
      current++;
      if (current >= asCountry.length) { 
        current = 0;
      }
      where.setText(asCountry[current]);
      input.setText("");
    }
 
    public static void main(String args[]) {
      new ListWrap();
    }
  }  

The number of rows and columns shown in a JList is controlled by the available screen space and the visibleRowCount property. The visibleRowCount property is an integer that specifies the preferred number of visible rows. By default, visibleRowCount has a setting of 8. If the visibleRowCount property is set to zero or a negative number, and the layoutOrientation is HORIZONTAL_WRAP, the width of the JList determines the number of rows to show. If the visibleRowCount property is set to zero or a negative number, and the layoutOrientation is VERTICAL_WRAP, the height of the JList determines the number of rows to show.

For more information on what's new in JList for J2SE 1.4, see the JList section in "Swing Changes and New Features for Java 2 SDK, Standard Edition, v 1.4".

Pixel

DEALING WITH TIMEOUTS ON SOCKET CONNECTIONS

The 1.4 version of the Java 2 Software Development Kit (SDK) incorporates many long awaited features into the standard java.net library set. Some of these features are forward thinking, such as bringing next-generation Internet Protocol version 6 (IPv6) support to TCP and UDP-based programs. Other features simply bring capabilities available to C/C++ programs for many years.

One of the new features has to do with socket timeouts. If you've been programming with the networking libraries for some time, you might ask, "Don't the libraries already support timeout?" And, technically speaking, they do. However, now with the 1.4 release, there is support for a second form of socket timeouts.

The timeout support previously available with the java.net.Socket class (that is, since the 1.1 release of the networking libraries) is through the setSoTimeout method. Through this method you can enable (or disable) the SO_TIMEOUT setting in milliseconds. This setting controls how long your read call from the socket will wait before it gives up. If you don't set the option, the call could block for a very long time, theoretically forever. By setting the SO_TIMEOUT option, you limit the amount of time a read request from across a socket can wait. If no response comes back within the specified time, the read operation gives up.

The new support for timeouts available with the 1.4 release has to do with connect timeouts. It controls how long a request waits for the server to respond with a valid connection. Servers can hold requests without processing until current requests are completed. Setting a timeout on a connection request permits you to cycle through a series of servers until one is available to handle your request. This new way of timeout is done on the connect call.

Here's a fragment of code that let's you set the connect timeout Instead of passing the InetAddress (host) and port to the Socket construction, you create a SocketAddress to identify the connection point. The timeout is then set after creating the Socket and calling its connect method, passing in the SocketAddress and the timeout value.

  int timeout = 500; // half a second
  SocketAddress socketAddress = 
    new InetSocketAddress(host, port);
  Socket socket = new Socket();
  socket.connect(socketAddress, timeout);

You'll then be connected -- assuming no exceptions are thrown. If, however, the request doesn't connect within the specified time, you'll get a SocketTimeoutException. Of course, if the server rejects the request, you'll still get a ConnectionException with a message of connection refused.

The following program demonstrates the differences in the timeout support. There are five ways to run the program:

  • Run with no parameters, that is:
    java EchoClientTest 
    
    The program tries to connect to port 7, that is, the ECHO service, on your local machine. If it isn't running, you get a connection refused message. If it is running, the program connects to the ECHO service. For each line that you type, the program displays the response from the server. That response is exactly what was sent, hence the name ECHO service.

  • Run with one parameter, for example:
    java EchoClientTest web.mit.edu 
    
    The program tries to connect to port 7 on whatever host you specify. If you have an ECHO service running inside your firewall, this option would be how you specify it. Or, if you don't have an ECHO service running that you are aware of, you can connect to the one at Massachusetts Institute of Technology at their web.mit.edu server. Of course, the point of the exercise isn't to find an existing one, but to connect to one that will timeout.

  • Run with two parameters, for example:
    java EchoClientTest web.mit.edu 9000
    
    The program uses the first parameter as the host. The second parameter then serves as an alternate port for connection. Unless you pick a well known port like 80 (which is for HTTP/web requests), the connection request should be rejected, and you'll get a Connection exception.

  • Run with three parameters, for example:
    java EchoClientTest web.mit.edu 7 5000 
    
    This tries out the new 1.4 way of setting the connect timeout value. The third parameter is the timeout setting in miliseconds. Try not to set too small a value because it won't give the receiving end a chance to accept the request. Try to find a value that is reasonable for your situation. If the server doesn't respond with a valid connection within the specified time, the program continues by throwing a SocketTimeoutException from which you can recover.

    For example, the command:
    java EchoClientTest web.mit.edu 7 5000
    
    specifies a 5 second timeout. Assuming that the server is up and running at MIT, the connection will likely be established. If so, anything you type is echoed back until you type quit. Typing quit causes the program to quit (after the echo).

    By comparison, if you enter the command:
    java EchoClientTest web.mit.edu 7 1
    
    the connect timeout is set so low that the connection won't likely happen. In this case, you get the timeout exception.

  • Run the program with four parameters, for example:
    java EchoClientTest web.mit.edu 9000 1 x
    
    The fourth parameter can be anything, it is just meant to serve as a flag. The program will use the setSoTimeout method to set the socket's read timeout setting. This setting has no effect when making a connection, so you'll always get a ConnectionException if the server doesn't connect you in time. You'll also notice that the timeout value is essentially ignored at connection time. Remember, it only affects read operations after the connection is already established.
import java.io.*;
import java.net.*;
import java.util.*;

public class EchoClientTest {

  BufferedReader reader;
  PrintWriter writer;
  int port;
  int timeout;
  Socket socket;
  SocketAddress socketAddress;
  String host;

  private static final int ECHO_PORT = 7;

  public EchoClientTest() {
    this("localhost", ECHO_PORT);
  }

  public EchoClientTest(String host) {
    this(host, ECHO_PORT);
  }
  
  public EchoClientTest(String host, int port) {
    this.host = host;
    this.port = port;
    if (getSocketNoTimeout()) {
      doWork();
    }
  }


  public EchoClientTest(
      String host, int port, int timeout) {
    this.host = host;
    this.port = port;
    this.timeout = timeout;
    if (getSocketConnectTimeout()) {
      doWork();
    }
  }
  
  public EchoClientTest(
      String host, int port, int timeout, boolean b) {
    this.host = host;
    this.port = port;
    this.timeout = timeout;
    if (getSocketSetTimeout()) {
      doWork();
    }
  }

  public boolean getSocketNoTimeout() {
    try {
      System.out.println("Not connected, waiting...");
      socket = new Socket(host, port);
      System.out.println(
        "Connected. Enter 'quit' to end.");
    } catch (UnknownHostException e) {
      System.err.println(
        "Don't know about host: " + host + ".");
      return false;
    } catch (IOException ioe) {
      System.err.println(
        "Connect: " + ioe.getMessage());
      return false;
    }
    return true;
  }

  public boolean getSocketConnectTimeout() {
    try {
      System.out.println("Not connected, waiting...");
      socketAddress = 
         new InetSocketAddress(host, port);
      socket = new Socket();
      socket.connect(socketAddress, timeout);
      System.out.println(
        "Connected. Enter 'quit' to end.");
    } catch(UnknownHostException e) {
      System.err.println("Don't know about host: " + 
        host + ".");
      return false;
    } catch(SocketTimeoutException ste) {
      System.err.println("Timeout: " +
        ste.getMessage());
      return false;
    } catch(IOException ioe) {
      System.err.println("Connect: " +
        ioe.getMessage());
      return false;
    }
    return true;
  }

  public boolean getSocketSetTimeout() {
    try {
      socketAddress = 
         new InetSocketAddress(host, port);
      socket = new Socket();
      try {
        socket.setSoTimeout(timeout);
      } catch (SocketException se) {
        System.err.println("Could not set timeout: " +
          se.getMessage());
        return false;
      }
      System.out.println("Not connected, waiting...");
      socket.connect(socketAddress);
      System.out.println(
        "Connected. Enter 'quit' to end.");
    } catch (UnknownHostException e) {
      System.err.println("Don't know about host: " +
        host + ".");
      return false;
    } catch (SocketTimeoutException ste) {
      System.err.println("Timeout: " +
        ste.getMessage());
      return false;
    } catch (IOException ioe) {
      System.err.println("Connect: " +
        ioe.getMessage());
      return false;
    }
    return true;
  }

  public void doWork() {
    try {
      writer = new PrintWriter(
        socket.getOutputStream(), true);
      reader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()));
    } catch (IOException e) {
      System.err.println(
        "Couldn't get I/O for the connection to: " +
        host + ".");
      return;
    }

    try {
      BufferedReader stdIn = new BufferedReader(
        new InputStreamReader(System.in));
      String userInput;

      while ((userInput = stdIn.readLine()) != null) {
        writer.println(userInput);
        System.out.println("echo: " +
          reader.readLine());
        if (userInput.equals("quit")) {
          return;
        }
      }

      writer.close();
      reader.close();
      stdIn.close();
      socket.close();
    } catch(IOException ioe) {
      System.err.println("IOException: " +
        ioe.getMessage());
      return;
    }
  }

  public static void main(String args[]) {
    int thePort = 0;
    int theTimeout = 0;

    if (args.length == 1 && args[0].equals("?")) {
      System.out.println(
        "No args: localhost, port 7,  no timeout.");
      System.out.println(
        "1 arg: arghost, port 7, no timeout.");
      System.out.println(
        "2 args: argHost, argPort, no timeout.");
      System.out.println(
        "3 args: argHost, argPort, argTimeout, immediate connect.");
      System.out.println(
        "4 args: argHost, argPort, argTimeout, argAny - set, then connect.");

      return;
    }

    System.out.println("Start time: " + new Date());

    if (args.length == 0) {
      new EchoClientTest();
    } else {
      String theHost = args[0];
      //set up port, timeout, if sent
      if (args.length > 1) {
        try {
          thePort = Integer.parseInt(args[1]);
          if (args.length > 2) {
            theTimeout = Integer.parseInt(args[2]);
          }
        } catch(NumberFormatException nfe) {
          System.out.println(
             "Invalid port or timeout value.");
          return;
        }
      }

      if (args.length == 1) {
        new EchoClientTest(theHost);
      } else if (args.length == 2) {
        new EchoClientTest(theHost, thePort);
      } else if (args.length == 3) {
        new EchoClientTest(
          theHost, thePort, theTimeout);
      } else if (args.length == 4) {
        new EchoClientTest(
          theHost, thePort, theTimeout, true);
      }
    }
    System.out.println("End time: " + new Date());
  }
}

For cases where a connect timeout isn't specified, the default timeout is specific to the operating system or kernel setting on the machine to which you are connecting.

Overall, the combined new and old settings allow more flexible socket creation, binding, and connection. Use accordingly, and your programs should never sit waiting without a way out.

For more information on timeouts in socket connections, see "Networking: New Features and Enhancements".

Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Core Java Technologies Tech Tips
November 19, 2002


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_27254874792533250@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Dec 17 13:22:18 2002 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id gBHIMIN25037 for ; Tue, 17 Dec 2002 13:22:18 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id gBHINixC016860 for ; Tue, 17 Dec 2002 13:23:57 -0500 (EST) Date: 17 Dec 2002 09:28:09 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <27254874792533250@hermes.sun.com> Subject: Core Java Technologies Tech Tips , Dec. 17, 2002 (Programmer Challenge) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 19404 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text December 17, 2002    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, December 17, 2002. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM). This issue of the Tech Tips is the last of the year. To close the year out, this issue presents a programmer challenge. The challenge tests your ability to use some features covered in past Tech Tips.

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

Pixel

PROGRAMMER CHALLENGE

The programming challenge is as follows: create a "Find File" program that searches for files in a user-specified directory, and whose content fits a user-specified search pattern. The program should display the matching set of files for each search query. The user should be able to select a file in the list of files that satisfy the search criteria. If a file is selected, the program should display its contents, and highlight areas of the content that match the search pattern. In addition, the program should log all search queries.

Here's a more detailed set of instructions:

  1. Create the primary user interface for the application. The interface should have an input field for the directory and an input field for the search pattern (that is, a regular expression). In addition:

    - Offer a Browse button to assist in directory selection by using a JFileChooser. Refer to the June 15, 1999 Tech Tip titled "File Choosers". You'll need to set the file selection mode to DIRECTORIES_ONLY to limit selection to directory names.

    - Offer the option of searching subdirectories.

    - Place a JTabbedPane in the middle of the user interface to display the search results.

    - Offer a Submit button that triggers the searching of files in the directory that have content matching the regular expression.

    If you coded this step correctly, your program should display something like this



  2. When the user presses the Submit button (or presses the Enter key), the program should:

    - Add a tab to the JTabbedPane. The tab label should be the search expression. Refer to the July 12, 2001 Tech Tip titled "JTabbed Pane". Consider setting the tab layout policy to SCROLL_TAB_LAYOUT, so all the tabs appear on one row.

    - Add every file in the path (and subdirectories if appropriate) to a JList within that tab.

    - Offer a Remove button that closes a tab if a user is done with the search results.

    If you coded this step correctly, your program should display something like this after the user presses the Submit button or presses Enter.



  3. Add code that checks to see if any file contains the regular expression entered into the Expression field. Refer to the October 8, 2002 Tech Tip titled "Using Regular Expression Groups" describes how to use regular expression groups. You'll need to change the examples in the tip to look in a file. After the pattern is found anywhere in the file, the program can stop reading the rest of the file.

    Consider using the NIO buffers and channels to read from the file. This is explored in the June 4, 2002 Tech Tip titled "Programming With Buffers".

    If you coded this step correctly, your program should display something like this:



  4. If a user selects a particular file, display the file in a JTextPane. Highlight the area(s) in the file that match the regular expression. Refer to the August 21, 2002 Tech Tip titled "Displaying Text in Multiple Styles". You'll need to use the start and end indices available from the Matcher to find the area to highlight. Remember to highlight each area matched, not just the first. Also, instead of inserting a string, use the setCharacterAttributes method of DefaultStyledDocument to change the attributes of the matched area.

    There is one extra thing you'll need to add to your program that hasn't been covered in previous Tech Tips. Your program will need to handle differences in the line separator characters across platforms. On disk, the line separator characters are whatever is in the file. Typically, \n for Unix (Solaris/Linux), \r\n for Windows, and \r for the Mac. The regular expression library deals with these accordingly. The problem occurs when you try to map file positions to the position of the text in the JTextPane. In memory, no matter what platform, the end-of-line indicator is always \n. That means that file positions won't map to in-memory positions, without a little bit of extra work. That little bit of extra work is defined in javax.swing.text.DefaultEditorKit, in the setting for EndOfLineStringProperty. By setting this to always be \n, the two positions will match accordingly. For more information about this, see the javadoc for DefaultEditorKit. In the meantime, set the property to \n when it is two characters for this to work:
              document.putProperty(
                 DefaultEditorKit.EndOfLineStringProperty, "\n");
       
    This means that when you getText from the component, it will have only a \n, not the platform-specific line. You can find positions there, and use those same positions when you set the character attributes for the component.

    If you coded this step correctly, your program should display something like this:



  5. As a final task, use the Logging API to log each search performed. Refer to the October 22, 2002 Tech Tip titled "Filtering Logged Messages". You won't need to filter any messages, but the framework for logging can be found in that tip.

    Depending on the information you log, you should see text that looks something like this:
           Dec 17, 2002 1:31:59 PM 
               project.Search submitButton_actionPerformed
           INFO: Pattern: 
               John\sZukowski / Directory: /home/eo86671/tech_tips
      
    You can find one possible solution to the challenge at: http://java.sun.com/jdc/JDCTechTips/2002/tts1217.txt.

    If you're looking for more of a challenge, here are a few more things you can try:

  6. Provide support for case-insensitive search.

  7. Allow the user to search by date, such as files newer than five days old, or files created between 1 May 2002 and 4 May 2002.

  8. Allow the user to search by size, that is, either a maximum or minimum size.

  9. Allow the user to search only through files that match a certain naming pattern, such as "*.java" files.

  10. Consider changing the program to search a web site. Have the user enter a base URL and "spider" the site (that is, follow the links) until the program finds the desired text pattern.

Solutions for these added steps are left as an exercise to the reader. Search through the tips to find even more features that you can add to the program.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please send me newsletters in text.
Please unsubscribe me from this newsletter.
From env_28120324-1080880557@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Jan 14 13:08:52 2003 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0EI8pN23505 for ; Tue, 14 Jan 2003 13:08:51 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0EIAxqh018043 for ; Tue, 14 Jan 2003 13:11:02 -0500 (EST) Date: 14 Jan 2003 09:55:09 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <28120324-1080880557@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, January 14, 2003 (JSP Error Pages, Preventing Repeated Operations) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 35840 Enterprise Java Technologies Tech Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text January 14, 2003    

In this Issue

WELCOME to the Java 2TM, Enterprise Edition (J2EETM) Tech Tips, January 14, 2003. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EETM).

This issue covers:

.JavaServer PagesTM (JSPTM) Error Pages
.Preventing Repeated Operations

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the J2EE Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for these tips. The context root for the application is ttjan2003, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms: http://developer.java.sun.com/berkeley_license.html

Pixel

JavaServer Pages (JSP) Error Pages

Few things make an application look less polished and professional than a server's default exception page. Even the most well-designed page usually shows the stack trace and exception name, and makes your application look broken. Your application might indeed have a bug, but that's no reason for it to look bad, as well.

The J2EE platform offers a great deal of control over how to format error information when a Web component throws an unexpected exception. Ideally, every Web component properly catches and handles all application and system exceptions that can occur. But in the real world, accidents happen. The JSP error page lets you catch, present, and report exceptions gracefully, instead of presenting the user with a technical, and possibly confusing, stack trace.

Defining An HTML Error Page

Web components such as servlets and JSP pages may throw exceptions to indicate error conditions. Usually, a Web component catches and handles its own exceptions, as well as exceptions from the other components it uses. When a Web component receives or generates an exception that it doesn't catch, the exception is passed to the Web container (part of the J2EE server). If an error page is defined for that exception, the request is directed to the error page's URL.

The Web application deployment descriptor uses the <error-page> tag to define Web components that handle errors. The simplest way to handle an error is to define an HTML page for the exception, and associate that HTML page with the exception it reports. This example, from this month's sample code, shows how to define an HTML page that reports a NullPointerException:

  <!-- Catch a system error using an HTML page -->
  <error-page>
    <exception-type>java.lang.NullPointerException
    </exception-type>
    <location>/NPEerror.html</location>
  </error-page>

This deployment descriptor entry means that whenever a Web component throws a NullPointerException, the Web container serves the document NPerror.html, which simply reports the error. The page can be designed to have the same look and feel as the rest of your application, so the user isn't confused or annoyed by a sudden change in the interface.

The Web application isn't limited to system exceptions such as NullPointerException, though. The next example in the sample Web application deployment descriptor defines an error page for a developer-defined application exception:

   <!-- Catch a system error using an HTML page -->
   <error-page>
     <exception-type>
     com.elucify.tips.jan2003.AppException1a
     </exception-type>
     <location>/AE1Aerror.html</location>
   </error-page>

Note that in the Web deployment descriptor, you have to provide a fully-specified class name for the exception. (In the sample code, the application exception classes are all subclasses of class "ApplicationException1", which extends java.lang.Exception.) The source code for ApplicationException1a used above looks like this:

    package com.elucify.tips.jan2003;
    public class AppException1a extends AppException1 {
        public AppException1a() {
            super("AppException1a");
        }
    }

A simple HTML page is fine for simple errors, but most of the time, you want to provide information about what the problem actually was. The way to do that is to report the error using a JSP page.

Using JSP Pages As Error Pages

JSP pages, being Web components, allow you to report not only that an error occurred, but also what went wrong. The deployment descriptor definition for a JSP error page looks like this:

   <!-- Report an error using a JSP page -->
   <error-page>
     <exception-type>
     com.elucify.tips.jan2003.AppException1b
     </exception-type>
      <location>/AE1Berror.jsp</location>
  </error-page>

The definition of the page is identical to the definition for an HTML error page, except that the <location> defines a JSP page instead. The JSP page that formats the error uses the <% @page %> shown below:

    <%@page isErrorPage="true" %>
    <HTML>
    <HEAD>
    <TITLE>Application Error 1b</TITLE>
    ...

The string isErrorPage="true" causes the Web container to define a new implicit variable, "exception", that the JSP page can use in scriptlets or in custom tags. For example, the error page for the current example uses the "exception" object to report the name of the class that caused the exception:

    <%= exception.getClass().getName() %>

Servlets and custom tags may access the exception object by calling PageContext.getException(). (You'll learn more about directing errors to servlets later in this tip.)

Letting A Page Define Its Error Page

Sometimes you want to take complete control of a page's exception handling. The errorPage attribute of the @page directive provides a URL to a Web component that handles the exception reporting for an individual page. If a JSP page defines errorPage, all exceptions thrown are directed to that page, even if web.xml specifically defines an error page for that page. In the example, the JSP page ThrowAppException1c.jsp defines the file "AE1Cerror.jsp" as its error page, as shown below. Keep in mind that the page shown here throws the exception. The page that reports the exception is AE1Cerror.html. (For the purposes of formatting this tip, the <%@page ...> tag below is shown on two lines. For JSP versions before 2.0, it needs to be on one line.)

    <%@page import="com.elucify.tips.jan2003.AppException1c" 
        errorPage="AE1Cerror.html" %>
    <%
            if (true) {
              throw new AppException1c();
            }
    %>

The @page attribute overrides all other exception handling except explicit try/catch clauses in the source page.

Reporting Exception Superclasses

The J2EE platform documentation defines a large number of exceptions. Writing a Web page to handle each one would quickly become tedious. Fortunately, the J2EE platform allows you define a single error page for a superclass of a group of extensions. When the Web container receives an exception, it looks for error page for that specific exception. If the Web container doesn't find that error page, it looks for an error page for the exception's superclass. It continues looking up the inheritance tree until it finds an error page, or until it reaches Throwable.

In the the sample code, the Web deployment descriptor doesn't define an error page for ApplicationException1d, but it does define an error page for ApplicationException1:

    <!-- Note absence of an error page -->
    <!-- for Application Errors 1c and 1d -->

    <!-- Catch a whole class of errors -->
    <error-page>
      <exception-type>
      com.elucify.tips.jan2003.AppException1
      </exception-type>
      <location>/AE1error.jsp</location>
    </error-page>

The code above defines the error page /AE1error.jsp for any exception of type AppException1. This includes all subclasses of AppException1 (such as AppException1d) that do not define an error page elsewhere. The error page here simply reports the exception and exception type that occurred:

    <%@page isErrorPage="true"%>
    <HTML>
    ...
    An Application Error 1 has occurred.<br>
    The error class is
    
    <%= exception.getMessage(); %>
    ...

Using Servlets As Error Pages

For maximum flexibility, even a servlet can serve as an error page. A servlet error page has the same syntax as a JSP error page. The <location> is just the servlet's <servlet-path>, as defined in web.xml:

   <!-- Catch errors by error code, -->
   <!-- redirecting to a servlet -->
   <error-page>
     <error-code>404</error-code>
     <location>/errorServlet</location>
   </error-page>

Notice above that instead of <exception-type>, this tag defines <error-code>. The Web can identify system errors in the Web tier either by Java exception type, as you've seen before, or by HTTP error code. The example above defines servlet /errorServlet as the exception handler for 404 ("File Not Found") errors. Both the <exception-type> and the <error-code> tags can be used with any Web resource in the application.

When the Web container receives or generates an exception or system error, it initializes several variables as request attributes. The sample code exception handler servlet ErrorServlet reports the values of these attributes:

    public class ErrorServlet extends HttpServlet {
        ...
        protected static String[] vars = {
                "javax.servlet.error.status_code",
                "javax.servlet.error.exception_type",
                "javax.servlet.error.message",
                "javax.servlet.error.exception",
                "javax.servlet.error.request_uri"
            };

        // Handle post request
        public void doPost(HttpServletRequest req, 
            HttpServletResponse res)
            throws IOException, ServletException {
            ...
            // Print vars
            for (int i = 0; i < vars.length; i++) {
                out.println(
                    "<TR><TD>" + vars[i] + "</TD><TD>" +
                    req.getAttribute(vars[i]) + 
                    "</TD></TR>");
            }
            ...
        }
    }

The meanings of these attributes are defined in the Servlet 2.3 specification. If the source of the exception was a JSP page, the Web container also stores the exception as a request attribute called "javax.servlet.jsp.jspException" (ErrorServlet reports these, too.)

The ErrorServlet shown here might be better implemented as a JSP page that uses custom tags instead of scriptlets. A more common use of an error servlet is as an "error controller". An error controller servlet could examine the exception or error information it receives, log the information, send an email or page to maintenance staff, and then forward the request to a logical place in the application.

Using Error Pages From Servlets

So far, all of the examples shown demonstrate how to use error pages when the source of the exception is a JSP page. However, servlets can use existing error pages to format their exceptions and errors, as well. The trick is to set the request attribute "javax.servlet.jsp.jspException" to the exception you want reported, and then forward the HTTP request to the URL for the error page. The sample code example below forwards an exception from one servlet (called ForwardingErrorServlet) to the ErrorServlet from the previous example:

    public class ForwardingErrorServlet 
        extends HttpServlet {
           ...

        // Handle post request
        public void doPost(HttpServletRequest req, 
            HttpServletResponse res)
            throws IOException, ServletException {

            // Create an exception to forward 
            // to an error page
            try {
                Object o = null;
                Class c = o.getClass();
            } catch (NullPointerException npe) {
                req.setAttribute(
                    "javax.servlet.jsp.jspException",
                         npe);
                RequestDispatcher rd = 
                    req.getRequestDispatcher(
                        "/errorServlet");
                rd.forward(req, res);
            }
        }
    }

This example could just as easily forward to an HTML or JSP page. You need to be careful when forwarding, though. If you open a PrintWriter in a servlet and then try to forward, the forward will fail.

There are several key points to remember when using the JSP error page. The Web container always uses the most specific error page defined for the page that caused the error. The error page may be any Web component (not just HTML or JSP pages). Consider using a servlet to log and/or report errors, and then forward to a JSP page that formats the exceptions or errors.

Pixel
Pixel

Preventing Repeated Operations

Many online operations, especially those involving money, must always happen either zero or one times. It's common for naive users to click things in the user interface twice. For example, an impatient user might click a Purchase button repeatedly. This does not mean that the user wants to make the same purchase multiple times. And consider the case where a user opens a new browser window. To which window should the session belong?

This tip presents a simple strategy for ensuring that once the server receives a POST request from an HTML form, it processes that request exactly once. The key is to generate a token, that is, a unique symbol that can be embedded as a hidden input in the form being processed. The token may be a string or a simple random number (as in the case shown in the sample code), it may also include information such as the originating URL and the name of the form. The servlet puts a copy of the token in a hidden field in the form, and keeps a copy on the server. Later, when the user POSTs the form to the server, the servlet tries to look up the token. If it has a copy of the token, it deletes the server-side copy of the token and performs the operation. If the servlet can't find the token, then some other invocation of the servlet must already have serviced that request, and the servlet produces an error message.

The sample code, OneShotServlet.java, demonstrates this technique. Its doGet method generates a token (a random number), saves the token as a session attribute, and serves a simple form.

    public void doGet(HttpServletRequest req, 
        HttpServletResponse res)
            throws IOException, ServletException {
        PrintWriter pw = res.getWriter();
        res.setContentType("text/html");
        
        int token = _random.nextInt();
        int value = _random.nextInt(1000);
        
        // Store token in session scope
        HttpSession session = req.getSession();
        String stoken = String.valueOf(token);
        session.setAttribute(
            stoken, String.valueOf(value));

        // Create form, putting token in hidden field
        pw.println(
            "<HTML><HEAD><TITLE>One-Shot Servlet</TITLE></HEAD>");
        pw.println("<BODY BACKGROUND=white>");

        pw.println(
            "Please type the following number into the box and " +
                   "click <i>Submit</i>: " + value);
        pw.println(
            "<form action=\"oneShotServlet\" " +
                   "method=\"post\">");
        pw.println(
            "<input type=\"hidden\" name=\"_token\" value=\"" +
                   stoken + "\">");
        pw.println("<B>Input:</B>");
        pw.println(
            "<input type=text name=\"num\" width=\"40\"><br>");
        pw.println("<input type=submit value=Submit>");
        pw.println("</form></BODY></HTML>");
    }

In the form, the servlet includes a hidden field that contains the token string. The value of the session attribute is another random number. The form gives the user a random number between 0 and 999 (the "value") and asks the user to copy the number into a text input element in an HTML form. When the user clicks Submit, the form calls back to the servlet's doPost method, shown below:

    // Handle post request
    public void doPost(HttpServletRequest req, 
        HttpServletResponse res)
            throws IOException, ServletException {

        res.setContentType("text/html");
        PrintWriter out = res.getWriter();
                
        out.println(
            "<HTML><HEAD><title>Demonstrate One Shot Servlet" +
                    "</TITLE></HEAD>");
        out.println("<BODY>");

        // Get the token, if it exists
        String stoken = req.getParameter("_token");
        HttpSession session = req.getSession();
        String stored_value = null;
        String value = req.getParameter("num");

        // Remove stored token from session
        synchronized (this) {
            stored_value = 
                (String)session.getAttribute(stoken);

            // Remove token from session 
            // so others can't use it,
            // then get the number posted by the user
            if (stored_value != null) {
                session.removeAttribute(stoken);
            }
        }

        // If the token is not there, 
        // it has already been "consumed"
        if (stored_value == null) {
            out.println(
                "Sorry, you can't use that form more than once.");
        } else {

            if (stored_value.equals(value)) {
                out.println(
                    "You copied the number correctly");
            } else {
                out.println(
                    "That wasn't the original number!");
            }

            out.println(
                "<p>Now hit the BACK button on your browser and " +
                        "try to re-post the form");
        }

        out.println("</BODY></HTML>");

    }

    }

The doPost method gets the token from the hidden form field (called "_token") and gets the value provided by the user ("num"). It then checks to see if the token named in the hidden form variable still exists as a session attribute. If it does exist, the servlet immediately removes it, and continues with the business operation (comparing the original number with the number the user typed). If the token does not exist, the servlet responds with an error message. Notice that the combined operation of finding and removing the token from session state is synchronized. This avoids race conditions between multiple clients using the same session.

Be aware that this servlet might not operate properly if the servlet is marked "distributed", or if the servlet implements SingleThreadModel. The "synchronized" block only prevents the code from being executed by multiple threads within the same JVM. Distributed servlets can run in multiple JVMs, so in some cases, race conditions can occur that would cause the servlet to operate incorrectly. Implementing SingleThreadModel is discouraged, for reasons explained in the Enterprise Java BluePrints.

This example uses a single servlet to demonstrate the concept in a single source file. A real implementation would probably use JSPs and custom tags, because that solution would be much more maintainable, loggable, and reusable. Keeping the tokens in session scope works well for small applications with low load, that only run on one machine. If more than one machine is involved, this solution requires distributed session state. Another option would be to store the keys as entity beans with exclusive locking.

Pixel
Pixel

Running the sample code

Download the sample archive for these tips. The application's context root is ttjan2003. The downloaded EAR file also contains the complete source code for the sample.

You can deploy the application archive (ttjan2003.ear) in the J2EE Reference Implementation using the deploytool program:

    $J2EE_HOME/deploytool -deploy ttjan2003.ear localhost

Replace localhost with the name of the host on which the server is installed. For a standard installation on a single machine, the hostname typically (and literally) is localhost. You can access the application at http://localhost:8000/ttjan2003.

For a J2EE-compliant implementation other than the Reference Implementation, use your J2EE product's deployment tools to deploy the application on your platform.

See the index.html welcome file for instructions on running the application.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

This document is protected by copyright.

Enterprise Java Technologies Tech Tips
January 14, 2003


Sun, Sun Microsystems, Java, Java Developer Connection, JavaServer Pages, JSP, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please unsubscribe me from this newsletter.
From env_27870936-2120574471@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Jan 10 13:05:46 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0AI5kN02810 for ; Fri, 10 Jan 2003 13:05:46 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0AI7cxC024248 for ; Fri, 10 Jan 2003 13:07:53 -0500 (EST) Date: 10 Jan 2003 09:09:39 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <27870936-2120574471@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Jan. 10, 2003 (Using Charsets and Encodings, Using Reflection to Create Class Instances) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 33993 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text January 10, 2003    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, January 10, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Using Charsets and Encodings
Using Reflection To Create Class Instances

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

Pixel
Pixel

USING CHARSETS AND ENCODINGS

Suppose that you're doing some Java programming, and have need to write characters to a file:

    import java.io.*;
    
    public class Encode1 {
        public static void main(String args[]) 
            throws IOException {
                Writer writer = new FileWriter("out");
                writer.write("testing");
                writer.close();
        }
    }

When you run this program in the United States in the SolarisTM Operating Environment or on the Windows platform, the result is a text file "out" of 7 bytes. This is what you would expect.

But there is an important issue here. Java characters are 16-bit, that is, each character is two bytes long. The Encode1 program writes a 7-character string to a file, and the result is a 7-byte file. You might ask: what happened to the other bytes, shouldn't there be 14 bytes written?

This issue falls under the title "character encodings". The problem is how to map between 16-bit characters representing Java data, and 8-bit bytes stored in data files. And in fact, it's trickier than simply "widening" or "narrowing" the character between 8 and 16 bits because there are literally hundreds of different character encoding schemes in use around the world. This means that the specific sequence of 8-bit bytes needed to represent a particular Java string changes from platform to platform and from locale to locale.

The Java system solves this problem by allowing you to choose the particular encoding scheme that's required when writing out characters. It also provides a reasonable default encoding based on your platform and locale. The Java system supports default encodings for performing I/O, as in the example above. In addition, you can also specify other named encodings ("charsets"). These encodings are described by string names, such as "UTF-8", and by instances of the java.nio.charset.Charset class. Charset is abstract, so the actual instances are objects of subclasses of Charset.

In the Encode1 example, one way of solving the encoding problem is to always write two bytes out for each character. However the file will have null bytes interspersed. Another approach is to throw away the high byte of each Java character. This will work in the example above, but it wouldn't work if you tried to write a string of Greek or Japanese instead..

What actually happens in this example is that the second approach is used -- the high byte is discarded. If you change the output line in the Encode1 program from:

    writer.write("testing");

to:

    writer.write("testing\u1234");

the total output length will be 8 bytes instead of 7, even though the Unicode character \u1234 cannot be represented using a single byte.

""Discard" in the previous discussion can have a couple of meanings. If the high byte of a Java character is 0, as is the case for characters representing 7-bit ASCII, then discard means to omit the high byte. However, another meaning applies to the situation where you have a Java character that is not mappable using a particular encoding. In such a case the character (two bytes) may be replaced by a default substitution byte. In the case above, \u1234 is replaced with 0x3f.

Let's now look at how to use charsets, mappings between characters and bytes. One basic question you might have is: what charsets are available? Here's a program that displays a list:

    import java.nio.charset.*;
    import java.util.*;
    
    public class Encode2 {
        public static void main(String args[]) {
            Map availcs = Charset.availableCharsets();
            Set keys = availcs.keySet();
            for (Iterator iter = 
                keys.iterator();iter.hasNext();) {
                    System.out.println(iter.next());
                }
        }
    }

The output should look something like this (but without the "*" character):

    ISO-8859-1*
    ISO-8859-15
    US-ASCII*
    UTF-16*
    UTF-16BE*
    UTF-16LE*
    UTF-8*
    windows-1252

The "*" is shown here to identify charsets that must be supported on all Java platforms.

Another basic question: what is the default charset on my local system? Here's a program that displays the name of the default:

    import java.io.*;
    import java.nio.charset.*;
    
    public class Encode3 {
        public static void main(String args[]) 
            throws IOException {
                FileWriter filewriter = 
                    new FileWriter("out");
                String encname = 
                    filewriter.getEncoding();
                filewriter.close();
                System.out.println(
                    "default charset is: " + encname);
    
                /*
                Charset charset1 = 
                    Charset.forName(encname);
                Charset charset2 = 
                    Charset.forName("windows-1252");
                if (charset1.equals(charset2)) {
                    System.out.println(
                        "Cp1252/windows-1252 equal");
                }
                else {
                    System.out.println(
                        "Cp1252/windows-1252 unequal");
            }
            */
        }
    }

When you run this program, you might see a result like this:

    default charset is: Cp1252

Notice that this charset is not on the list of required charsets that every Java implementation must support. There is no requirement that the default charset must be one of the required charsets. This example also has some commented-out logic that shows how you can determine whether two charsets are equal or not. It turns out that "windows-1252" and "Cp1252" are in fact names for a single charset. The logic is commented out because there is no requirement that the Cp1252 charset be supported, and so the logic here might not be meaningful to you.

You may have seen other ways to get the default local charset name, such as querying the "file.encoding" system property. This approach might work, but this property is not guaranteed to be defined on all Java platforms.

In the Encode3 program, Charset.forName is used to find the Charset object for a string name such as "US-ASCII". Here's another example that uses this technique:

    import java.nio.charset.*;
    
    public class Encode4 {
        public static void main(String args[]) {
            if (args.length != 1) {
                System.out.println(
                    "missing charset name");
                System.exit(1);
            }
    
            String charsetname = args[0];
            Charset charset;
    
            try {
                charset = Charset.forName(charsetname);
                System.out.println(
                    "charset lookup successful");
            }
            catch (UnsupportedCharsetException exc) {
                System.out.println(
                    "unknown charset: " + charsetname);
            }
        }
    }

If you run the program, like this:

    $ java Encode4 XYZ

it will check whether "XYZ" is a supported Charset on the local system, and if so, obtain the Charset object.

Given all this background, how do you actually make use of charsets? Here's a rework of the first example, Encode1:

    import java.io.*;
    
    public class Encode5 {
        public static void main(String args[]) 
            throws IOException {
                FileOutputStream fileoutstream =
                    new FileOutputStream("out");
                Writer writer = new OutputStreamWriter(
                    fileoutstream, "UTF-8");
                writer.write("testing");
                writer.close();
        }
    }

The Encode1 program is not portable. It applies the default charset, which can vary based on platform and locale. By contrast, the Encode5 program uses a standard charset (UTF-8). As mentioned earlier, the default encoding used in the Encode1 example discards the high byte of Java characters. Using the UTF-8 encoding solves this problem. If you change the output line in the Encode program from:

    writer.write("testing");

to:

    writer.write("testing\u1234");

it still works. And UTF-8 has the advantage of handling 7-bit ASCII in a graceful way.

Here's another example. It shows how you can convert Java strings to byte vectors, specifying an encoding:

    import java.io.*;
    
    public class Encode6 {
        public static void main(String args[])
        throws UnsupportedEncodingException {
            String str = "testing";
    
            byte bytevec1[] = str.getBytes();
            byte bytevec2[] = str.getBytes("UTF-16");
    
            System.out.println("bytevec1 length = " +
                bytevec1.length);
            System.out.println("bytevec2 length = " +
                bytevec2.length);
        }
    }

The output on your system should look something like this:

    bytevec1 length = 7
    bytevec2 length = 16

The first conversion applies the default charset. The second conversion uses the UTF-16 charset.

There's one final thing to discuss about character encodings. You might wonder what a typical mapping or encoding algorithm really looks like. Here is some actual code taken from DataOutputStream.writeUTF. It's used to map a character vector into a byte vector:

    for (int i = 0; i < strlen; i++) {
        c = charr[i];
        if ((c >= 0x0001) && (c <= 0x007F)) {
            bytearr[count++] = (byte) c;
        }
        else if (c > 0x07FF) {
            bytearr[count++] = 
                (byte) (0xE0 | ((c >> 12) & 0x0F));
            bytearr[count++] = 
                (byte) (0x80 | ((c >>  6) & 0x3F));
            bytearr[count++] = 
                (byte) (0x80 | ((c >>  0) & 0x3F));
        }
        else {
            bytearr[count++] = 
                (byte) (0xC0 | ((c >>  6) & 0x1F));
            bytearr[count++] = 
                (byte) (0x80 | ((c >>  0) & 0x3F));
        }
    }

Characters are taken from charr, converted into 1-3 bytes, and written into bytearr. Characters in the range 0x1 - 0x7f (7-bit ASCII) are mapped into themselves. Characters with value 0x0 and in the range 0x80 - 0x7ff are mapped into two bytes. All other characters are mapped into three bytes.

For more information about charsets and encodings, see section 9.7.1, Character Encodings, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes. Also see the documentation for Supported Encodings and Charset. The document Unicode Transformation Formats: UTF-8 & Co. is another good place to learn about charsets and encodings.

Pixel
Pixel

USING REFLECTION TO CREATE CLASS INSTANCES

Imagine that you're doing some Java programming, and you need to create a new instance of the A class. You write some code like this:

    A aref = new A();

Pretty obvious, right?

Suppose, however, you take a step further and specify that the name of the class is found in a string made available at run time. It's still possible to proceed, like this:

    String classname; // can be either A, B, or C

    A aref = null;
    B bref = null;
    C cref = null;

    if (classname.equals("A"))
        aref = new A();
    else if (classname.equals("B"))
        bref = new B();
    else
        cref = new C();

This code works, but it's cumbersome. Also, it can't be expanded much further without major effort.

There's another approach that works much better in this kind of situation. The basic idea is that you use Class.forName to obtain a java.lang.Class object for a class whose string name you specify. java.lang.Class is a class whose instances represent Java types, such as classes and interfaces and arrays. After you obtain a java.lang.Class instance, you can call newInstance to create a new object of the class represented by the java.lang.Class instance. The code looks like this:

    Class cls = Class.forName(classname);

    Object obj = cls.newInstance();

This sequence creates an object of the class whose string name is classname.

After you have a java.lang.Class instance, you can also find out other things about the represented class, for example, what methods and fields it contains. You can look up methods by name, and use reflection to call these methods.

Let's look at an example to make these ideas a little more concrete. The example uses java.lang.Class and reflection to implement a class and method exerciser. The idea is that you have some classes and methods, and you'd like to write a driver program to test them. For example, for this input:

    $ java NewDemo A string1 string2 @ f2 string3 string4 string5

the driver creates an object of class A, using string1/string2 as string arguments to the A constructor. The driver then calls A.f2 for the created object, using string3/string4/string5 as arguments to the f2 method.

Note that the driver program doesn't know anything about the A class. It's written in a general way to work with any class. The driver looks up and manipulates class and method names using java.lang.Class and reflection.

Here's what the code looks like:

    import java.lang.reflect.*;
    
    public class NewDemo {
        Class cls;
    
        Object obj;
    
        Constructor ctor;
        Object ctorargs[];
    
        Method meth;
        Object methargs[];
    
        String args[];
        int divpos;
    
        // parse input of the form:
        //
        //  classname arg1 arg2 ... 
        //   @ methodname arg1 arg2 ...
    
        public NewDemo(String a[]) throws 
            ClassNotFoundException, 
            NoSuchMethodException {
    
            args = a;
    
            // search for @ divider in input
    
            divpos = -1;
            for (int i = 0; i < args.length; i++) {
                if (args[i].equals("@")) {
                    divpos = i;
                    break;
                }
            }
            if (divpos < 1 || divpos + 1 == args.length) {
                throw new IllegalArgumentException(
                    "bad syntax");
            }
    
            // load appropriate class 
            // and get Class object
    
            String classname = args[0];
            cls = Class.forName(classname);
    
            // find the constructor, 
            // if arguments specified for it
    
            if (divpos > 1) {
                Class ptypes[] = new Class[divpos - 1];
                for (int i = 0; i < ptypes.length; i++) {
                    ptypes[i] = String.class;
                }
                ctor = cls.getConstructor(ptypes);
    
                // set up the constructor arguments
    
                ctorargs = new Object[divpos - 1];
                for (int i = 0; i < ctorargs.length; i++) {
                    ctorargs[i] = args[i+1];
                }
            }
    
            // find the right method
    
            String methodname = args[divpos + 1];
            int firstarg = divpos + 2;
            Class ptypes[] = 
                new Class[args.length - firstarg];
            for (int i = 0; i < ptypes.length; i++) {
                ptypes[i] = String.class;
            }
            meth = cls.getMethod(methodname, ptypes);
    
            // set up the method arguments
    
            methargs = new Object[ptypes.length];
            for (int i = 0; i < methargs.length; i++) {
                methargs[i] = args[firstarg + i];
            }
        }
    
        // create an object of the specified class
    
        public void createObject() throws 
            InstantiationException,
            IllegalAccessException, 
            InvocationTargetException {
        
            // if class has no-arg constructor, 
            // use it
    
            if (ctor == null) {
                obj = cls.newInstance();
            }
    
            // otherwise use constructor with arguments
    
            else {
                obj = ctor.newInstance(ctorargs);
            }
        }
    
        // call the method and display its return value
    
        public void callMethod() throws 
            IllegalAccessException,
            InvocationTargetException {
    
            Object ret = meth.invoke(obj, methargs);
            System.out.println("return value: " + ret);
        }
    
        public static void main(String args[]) {
    
            // create a NewDemo instance 
            // and call the method
    
            try {
                NewDemo nd;
    
                nd = new NewDemo(args);
                nd.createObject();
                nd.callMethod();
            }
    
            // display any resulting exception
    
            catch (Exception e) {
                System.out.println(e);
                System.exit(1);
            }
        }
    }

Here is a test class you can use with the demo:

    public class A {
        public A() {
            System.out.println("call: A.A()");
        }
        public A(String s1, String s2) {
            System.out.println(
                "call: A.A(" + s1 + "," + s2 + ")");
        }
        public void f1() {
            System.out.println("call: A.f1()");
        }
        public double f2(
            String s1, String s2, String s3) {
            System.out.println("call: A.f2(" + s1 + "," + s2 +
                    "," + s3 + ")");
            return 12.34;
        }
    }

You need to compile this class in the usual way.

The NewDemo constructor is used to parse the input line, to find the java.lang.Class object for the specified class, and to find the appropriate constructor and method. Then createObject is called to create an instance of the class. Finally, callMethod is used to actually call the method for the class instance.

The constructor and method are found by creating a java.lang.Class vector that contains the types of each parameter to the constructor or method. This example takes the liberty of assuming that all parameters are of String type, and thus the corresponding java.lang.Class object is "String.class". Then getConstructor and getMethod are used to find the actual constructor or method to use.

If you run the driver, by saying:

    java NewDemo A @ f1

The output is:

    call: A.A()
    call: A.f1()
    return value: null

Here are additional driver runs:

    java NewDemo A @ f2 str1 str2 str3 

    java NewDemo A str4 str5 @ f1

    java NewDemo A str6 str7 @ f2 str8 str9 str10

And here are their respective results:

    call: A.A()
    call: A.f2(str1,str2,str3)
    return value: 12.34

    call: A.A(str4,str5)
    call: A.f1()
    return value: null

    call: A.A(str6,str7)
    call: A.f2(str8,str9,str10)
    return value: 12.34

Some examples of driver runs with bad input are:

    java NewDemo
    java NewDemo A
    java NewDemo A @
    java NewDemo A str1 @ f1
    java NewDemo A @ f1 str1
    java NewDemo B @ f1
    java NewDemo A str11 str12 @
    java NewDemo A @ f3 str1

The results are:

    java.lang.IllegalArgumentException: bad syntax
    java.lang.IllegalArgumentException: bad syntax
    java.lang.IllegalArgumentException: bad syntax
    java.lang.NoSuchMethodException
    java.lang.NoSuchMethodException: f1
    java.lang.ClassNotFoundException: B
    java.lang.IllegalArgumentException: bad syntax
    java.lang.NoSuchMethodException: f3

The techniques illustrated here are extremely powerful, and allow you to manipulate types and methods by name at run time. These techniques are used by tools such as interpreters, debuggers, and object exercisers.

For more information about using reflection to create class instances see section 11.2.1, The Class class, and section 11.2.6, The Method Class, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please unsubscribe me from this newsletter.
From slide-user-return-3872-gcf=indiana.edu@jakarta.apache.org Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Jan 22 05:10:15 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0MAAFN01112 for ; Wed, 22 Jan 2003 05:10:15 -0500 (EST) Received: from exchange.sun.com (exchange.sun.com [192.18.33.10]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0MACZwe020884 for ; Wed, 22 Jan 2003 05:12:35 -0500 (EST) Received: (qmail 22934 invoked by uid 97); 22 Jan 2003 10:13:38 -0000 Mailing-List: contact slide-user-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Slide Users Mailing List" Reply-To: "Slide Users Mailing List" Delivered-To: mailing list slide-user@jakarta.apache.org Received: (qmail 22909 invoked by uid 98); 22 Jan 2003 10:13:37 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Message-Id: <5.1.0.14.0.20030122101048.046d3d00@mail> X-Sender: mark@mail X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Wed, 22 Jan 2003 10:11:57 +0000 To: "Slide Users Mailing List" From: Mark Menzies Subject: More on J2EE Connectors and Managed Transactions within EJB's Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; format=flowed X-Spam-Rating: 208.185.179.12.available.above.net 1.6.2 0/1000/N Content-Length: 24486 Okay, following my question to the developers list about J2EE Connectors we have done some work trying to get Slide working from EJB's within JBoss. Just to recap, we want to use Slide for repository type functions but want to leave all transaction handling behaviour to a 'managed transaction' within an EJB container (JBoss). Here's what we did : Using the nightly release from 1/1/2003, built a slide-kernel and slide-stores jar. Modified the Domain.xml file to use the J2EE Stores (see below) Wrote a simple test stateless session bean to create a collection and then entry within the Store. Created an EAR and deployed it within JBoss. The first problem was that JBoss could not find the Domain.xml so we unjar'd slide-kernel.jar and modified slide.properties so that org.apache.slide.domain=c:\\Domain.xml (i.e. references the exact location of the domain.xml file) then jar'd the files back into slide-kernel.jar The next problem we had was that the setAutoCommit( false ) within J2EEStore.java (line 522) was causing an Exception to be thrown. This is apparently an invalid thing to do within managed transactions. After modifying this class so that the set auto commit wasn't called we finally get a problem with other commit's being called within our transaction which leads to a HeuristicMixedException being thrown. (See attached Log Messages). It seems that some auto-initialisation is taking place when we get the namespace token and this is trying to call commit which is breaking the managed transaction. I guess my question therefore has three parts : 1) Has anyone got Slide working within managed transactions in a J2EE container? 2) Does this seem to be the correct way to achieve what we want or is there some other way? 3) Are there any plans to implement the Java Connectors API in the near future, and more importantly is this considered a necessity IF managed transactions are to be used? Thanks in advance for any negative, positive, brief or in depth feedback on this. I eagerly await your response, Yours, Mark Menzies ---------------------------- OUR DOMAIN.XML FILE ---------------------------------- jdbc/BrandStore jdbc/BrandStore false /actions /users guest /files true true slideroles.basic.RootRole slideroles.basic.UserRole slideroles.basic.GuestRole true /history /workspace /workingresource checkout-checkin true forbidden forbidden ------------------------ END OF OUR DOMAIN.XML FILE ------------------------------ ------------------------ OUR LOG MESSAGES ------------------ 2003-01-21 17:22:43,896 INFO [STDOUT] --[21/01/2003 17:22:43] CONSTRUCTED- Implementation of RepositoryInterface that uses Jakarta-Slide to store content 2003-01-21 17:22:43,906 INFO [STDOUT] --[21/01/2003 17:22:43] SlideStorage- About to create : Repository Asset [567baa0496a62e27#1a32e0#f2e170b8da#-7fd9]: john/Marks Test Asset (rev none) 2003-01-21 17:22:43,926 INFO [STDOUT] 21 Jan 2003 17:22:43 - org.apache.slide.common.Domain - INFO - Auto-Initializing Domain 2003-01-21 17:22:43,996 INFO [STDOUT] 21 Jan 2003 17:22:43 - org.apache.slide.common.Domain - INFO - Domain configuration : {org.apache.slide.lock=true, org.apache.slide.versioncontrol=true, org.apache.slide.debug=false, org.apache.slide.search=true, org.apache.slide.security=true, org.apache.slide.domain=c:\Domain.xml} 2003-01-21 17:22:44,046 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - INFO - Initializing Domain 2003-01-21 17:22:44,046 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - INFO - Domain configuration : {org.apache.slide.lock=true, org.apache.slide.versioncontrol=true, org.apache.slide.debug=false, org.apache.slide.search=true, org.apache.slide.security=true, org.apache.slide.domain=c:\Domain.xml} 2003-01-21 17:22:44,046 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - INFO - Domain parameters: {auto-version=checkout-checkin, historypath=/history, checkin-fork=forbidden, workingresourcepath=/workingresource, workspacepath=/workspace, default=slide, auto-version-control=true, logger=org.apache.slide.util.logger.SimpleLogger, checkout-fork=forbidden} 2003-01-21 17:22:44,056 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - INFO - Initializing namespace : slide 2003-01-21 17:22:44,076 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - WARNING - Loading of create_store_listener class failed: org.apache.slide.webdav.util.UriHandler 2003-01-21 17:22:44,086 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Loading namespace definition 2003-01-21 17:22:44,126 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Node store: slidestore.j2ee.J2EEDescriptorsStore 2003-01-21 17:22:44,146 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Security store references nodestore 2003-01-21 17:22:44,146 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Lock store store references nodestore 2003-01-21 17:22:44,146 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Revision descriptors store references nodestore 2003-01-21 17:22:44,146 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Revision descriptor store references nodestore 2003-01-21 17:22:44,146 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Content store: slidestore.j2ee.J2EEContentStore 2003-01-21 17:22:44,166 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Registering Store j2ee (class org.apache.slide.store.StandardStore) with parameters {} on scope / 2003-01-21 17:22:44,216 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Initializing Store j2ee(org.apache.slide.store.StandardStore) 2003-01-21 17:22:44,267 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - WARNING - Loading of redirector class failed: org.apache.slide.webdav.util.DeltavUriRedirector 2003-01-21 17:22:44,297 INFO [STDOUT] 21 Jan 2003 17:22:44 - slidestore.j2ee.J2EEDescriptorsStore - INFO - Loading and registering datasource jdbc/BrandStore 2003-01-21 17:22:44,297 INFO [STDOUT] 21 Jan 2003 17:22:44 - slidestore.j2ee.J2EEContentStore - INFO - Loading and registering datasource jdbc/BrandStore 2003-01-21 17:22:44,307 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Loading namespace slide parameters 2003-01-21 17:22:44,317 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - WARNING - Loading of standard live properties class failed: org.apache.slide.webdav.util.resourcekind.AbstractResourceKind 2003-01-21 17:22:44,327 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Loading namespace slide base data 2003-01-21 17:22:44,347 INFO [STDOUT] Not setting autoCommit to false as we are in a managed transaction! 2003-01-21 17:22:44,347 INFO [STDOUT] CONNDEBUG: Got connection successfully 2003-01-21 17:22:44,597 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.transaction.SlideTransaction - WARNING - Commit failure: Resource manager slidestore.j2ee.J2EEDescriptorsStore@1f139b Error code XA_RBCOMMFAIL in Transaction 1 xid RMI TCP Connection(15)-192.168.203.228-1043169764327-1- in thread RMI TCP Connection(15)-192.168.203.228 2003-01-21 17:22:44,597 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - ERROR - Unable to read Namespace base configuration file : 2003-01-21 17:22:44,597 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - ERROR - javax.transaction.HeuristicMixedException 2003-01-21 17:22:44,597 ERROR [STDERR] javax.transaction.HeuristicMixedException 2003-01-21 17:22:44,597 ERROR [STDERR] at org.apache.slide.transaction.SlideTransaction.commit(SlideTransaction.java:379) 2003-01-21 17:22:44,597 ERROR [STDERR] at org.apache.slide.transaction.SlideTransactionManager.commit(SlideTransactionManager.java:230) 2003-01-21 17:22:44,597 ERROR [STDERR] at org.apache.slide.common.Namespace.loadBaseData(Namespace.java:807) 2003-01-21 17:22:44,597 ERROR [STDERR] at org.apache.slide.common.Domain.initNamespace(Domain.java:850) 2003-01-21 17:22:44,597 ERROR [STDERR] at org.apache.slide.common.Domain.init(Domain.java:478) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.apache.slide.common.Domain.selfInit(Domain.java:783) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.apache.slide.common.Domain.accessNamespace(Domain.java:280) 2003-01-21 17:22:44,607 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.obtainNamespaceAccessToken(SlideStorage.java:179) 2003-01-21 17:22:44,607 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.setupSlide(SlideStorage.java:120) 2003-01-21 17:22:44,607 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.create(SlideStorage.java:481) 2003-01-21 17:22:44,607 ERROR [STDERR] at uk.co.avenida.internal.brandStore.RepositorySession.create(RepositorySession.java:503) 2003-01-21 17:22:44,607 ERROR [STDERR] at test.ejb.SlideTestBean.doStuff(SlideTestBean.java:110) 2003-01-21 17:22:44,607 ERROR [STDERR] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:660) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:77) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:107) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:178) 2003-01-21 17:22:44,607 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:60) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:130) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:203) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.ejb.StatelessSessionContainer.invoke(StatelessSessionContainer.java:313) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.ejb.Container.invoke(Container.java:712) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:517) 2003-01-21 17:22:44,617 ERROR [STDERR] at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:381) 2003-01-21 17:22:44,617 ERROR [STDERR] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,617 ERROR [STDERR] at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241) 2003-01-21 17:22:44,617 ERROR [STDERR] at sun.rmi.transport.Transport$1.run(Transport.java:152) 2003-01-21 17:22:44,617 ERROR [STDERR] at java.security.AccessController.doPrivileged(Native Method) 2003-01-21 17:22:44,617 ERROR [STDERR] at sun.rmi.transport.Transport.serviceCall(Transport.java:148) 2003-01-21 17:22:44,617 ERROR [STDERR] at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:465) 2003-01-21 17:22:44,617 ERROR [STDERR] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:706) 2003-01-21 17:22:44,617 ERROR [STDERR] at java.lang.Thread.run(Thread.java:484) 2003-01-21 17:22:44,617 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Namespace - INFO - Loading namespace slide configuration 2003-01-21 17:22:44,627 INFO [STDOUT] 21 Jan 2003 17:22:44 - slidestore.j2ee.J2EEDescriptorsStore - INFO - No id for current thread (Thread[RMI TCP Connection(15)-192.168.203.228,5,RMI Runtime]) - called outside transaction? 2003-01-21 17:22:44,627 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - ERROR - org.apache.slide.structure.ObjectNotFoundException: No object found at /actions 2003-01-21 17:22:44,627 ERROR [STDERR] org.apache.slide.structure.ObjectNotFoundException: No object found at /actions 2003-01-21 17:22:44,627 ERROR [STDERR] at slidestore.j2ee.J2EEDescriptorsStore.retrieveObject(J2EEDescriptorsStore.java:209) 2003-01-21 17:22:44,627 ERROR [STDERR] at org.apache.slide.store.StandardStore.retrieveObject(StandardStore.java:171) 2003-01-21 17:22:44,627 ERROR [STDERR] at org.apache.slide.common.NamespaceConfig.getActionNode(NamespaceConfig.java:1107) 2003-01-21 17:22:44,627 ERROR [STDERR] at org.apache.slide.common.NamespaceConfig.initializeNamespaceConfig(NamespaceConfig.java:597) 2003-01-21 17:22:44,627 ERROR [STDERR] at org.apache.slide.common.Namespace.loadConfiguration(Namespace.java:888) 2003-01-21 17:22:44,627 ERROR [STDERR] at org.apache.slide.common.Domain.initNamespace(Domain.java:855) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.apache.slide.common.Domain.init(Domain.java:478) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.apache.slide.common.Domain.selfInit(Domain.java:783) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.apache.slide.common.Domain.accessNamespace(Domain.java:280) 2003-01-21 17:22:44,637 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.obtainNamespaceAccessToken(SlideStorage.java:179) 2003-01-21 17:22:44,637 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.setupSlide(SlideStorage.java:120) 2003-01-21 17:22:44,637 ERROR [STDERR] at uk.co.avenida.internal.brandStore.storage.SlideStorage.create(SlideStorage.java:481) 2003-01-21 17:22:44,637 ERROR [STDERR] at uk.co.avenida.internal.brandStore.RepositorySession.create(RepositorySession.java:503) 2003-01-21 17:22:44,637 ERROR [STDERR] at test.ejb.SlideTestBean.doStuff(SlideTestBean.java:110) 2003-01-21 17:22:44,637 ERROR [STDERR] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:660) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:77) 2003-01-21 17:22:44,637 ERROR [STDERR] at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:107) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:178) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:60) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:130) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:203) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.StatelessSessionContainer.invoke(StatelessSessionContainer.java:313) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.ejb.Container.invoke(Container.java:712) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:517) 2003-01-21 17:22:44,647 ERROR [STDERR] at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:381) 2003-01-21 17:22:44,647 ERROR [STDERR] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,647 ERROR [STDERR] at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241) 2003-01-21 17:22:44,647 ERROR [STDERR] at sun.rmi.transport.Transport$1.run(Transport.java:152) 2003-01-21 17:22:44,647 ERROR [STDERR] at java.security.AccessController.doPrivileged(Native Method) 2003-01-21 17:22:44,647 ERROR [STDERR] at sun.rmi.transport.Transport.serviceCall(Transport.java:148) 2003-01-21 17:22:44,647 ERROR [STDERR] at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:465) 2003-01-21 17:22:44,647 ERROR [STDERR] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:706) 2003-01-21 17:22:44,647 ERROR [STDERR] at java.lang.Thread.run(Thread.java:484) 2003-01-21 17:22:44,657 INFO [STDOUT] 21 Jan 2003 17:22:44 - org.apache.slide.common.Domain - INFO - Domain initialization complete 2003-01-21 17:22:44,657 INFO [STDOUT] --[21/01/2003 17:22:44] SlideStorage- Obtained Domain NamespaceAccessToken with name slide from Namespace slide 2003-01-21 17:22:44,657 INFO [STDOUT] --[21/01/2003 17:22:44] SlideStorage- Setting up helpers and tokens. 2003-01-21 17:22:44,657 INFO [STDOUT] 21 Jan 2003 17:22:44 - slidestore.j2ee.J2EEDescriptorsStore - INFO - No id for current thread (Thread[RMI TCP Connection(15)-192.168.203.228,5,RMI Runtime]) - called outside transaction? 2003-01-21 17:22:44,667 INFO [STDOUT] 21 Jan 2003 17:22:44 - slidestore.j2ee.J2EEDescriptorsStore - INFO - No id for current thread (Thread[RMI TCP Connection(15)-192.168.203.228,5,RMI Runtime]) - called outside transaction? 2003-01-21 17:22:44,677 INFO [STDOUT] java.lang.NullPointerException 2003-01-21 17:22:44,677 INFO [STDOUT] at org.apache.slide.security.SecurityImpl.checkCredentials(SecurityImpl.java:406) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.apache.slide.structure.StructureImpl.retrieve(StructureImpl.java:224) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.apache.slide.structure.StructureImpl.retrieve(StructureImpl.java:170) 2003-01-21 17:22:44,677 INFO [STDOUT] at uk.co.avenida.internal.brandStore.storage.SlideStorage.doesCollectionExist(SlideStorage.java:253) 2003-01-21 17:22:44,677 INFO [STDOUT] at uk.co.avenida.internal.brandStore.storage.SlideStorage.create(SlideStorage.java:488) 2003-01-21 17:22:44,677 INFO [STDOUT] at uk.co.avenida.internal.brandStore.RepositorySession.create(RepositorySession.java:503) 2003-01-21 17:22:44,677 INFO [STDOUT] at test.ejb.SlideTestBean.doStuff(SlideTestBean.java:110) 2003-01-21 17:22:44,677 INFO [STDOUT] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:660) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:77) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:107) 2003-01-21 17:22:44,677 INFO [STDOUT] at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:178) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:60) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:130) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:203) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.ejb.StatelessSessionContainer.invoke(StatelessSessionContainer.java:313) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.ejb.Container.invoke(Container.java:712) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:517) 2003-01-21 17:22:44,687 INFO [STDOUT] at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:381) 2003-01-21 17:22:44,687 INFO [STDOUT] at java.lang.reflect.Method.invoke(Native Method) 2003-01-21 17:22:44,687 INFO [STDOUT] at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241) 2003-01-21 17:22:44,687 INFO [STDOUT] at sun.rmi.transport.Transport$1.run(Transport.java:152) 2003-01-21 17:22:44,687 INFO [STDOUT] at java.security.AccessController.doPrivileged(Native Method) 2003-01-21 17:22:44,687 INFO [STDOUT] at sun.rmi.transport.Transport.serviceCall(Transport.java:148) 2003-01-21 17:22:44,697 INFO [STDOUT] at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:465) 2003-01-21 17:22:44,697 INFO [STDOUT] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:706) 2003-01-21 17:22:44,697 INFO [STDOUT] at java.lang.Thread.run(Thread.java:484) --------- END OF OUR LOG MESSAGES ------- At 14:31 20/01/2003 +0000, Mark Menzies wrote: >Hi all, > >We have a requirement to access a slide store through EJBs in a >transactional manner and have the operations on the slide store enrolled >into the container transaction provided by the EJB container. > >Does anyone have any experience of doing this they would be willing to share? > >Kind Regards, > >Mark. Mark Menzies Mark.Menzies@avenida.co.uk Avenida Technologies Limited http://www.avenida.co.uk -- To unsubscribe, e-mail: For additional commands, e-mail: From env_29907656-1639308733@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Feb 11 12:10:42 2003 X-UIDL: f,6"!L58!!EdD"!LYV!! Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h1BHAfF15008 for ; Tue, 11 Feb 2003 12:10:41 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h1BHCsww023397 for ; Tue, 11 Feb 2003 12:13:05 -0500 (EST) Date: 11 Feb 2003 08:58:15 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <29907656-1639308733@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, February 11, 2003 (Creating Parsers With JAXP, Referencing Enterprise Beans) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 35610 Status: RO Enterprise Java Technologies Tech Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text February 11, 2003    

In this Issue

Welcome to the Enterprise JavaTM Technologies Tech Tips, for February 11, 2003. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EETM).

This issue covers:

.Creating Parsers with JAXP
.Referencing Enterprise Beans

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the J2EE Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample archive for these tips. The context root for the application is ttfeb2003, and the index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms.

.

Creating Parsers with JAXP

One of the major strengths of J2EE is its vendor-neutral, integrated support for XML. This month's tip focuses on how to use the JavaTM API for XML (JAXP). JAXP provides a built-in set of interfaces for creating and configuring XML parsers in J2EE applications. This tip assumes you are familiar with the SAX and DOM interfaces to XML documents, and with basic XML terminology.

JAXP gives you complete control over creating both SAX and DOM parsers. JAXP resides in package javax.xml.parsers, which contains the following four classes:

  • DocumentBuilder - a DOM parser, which creates an object of type org.w3c.dom.Document
  • DocumentBuilderFactory - a class that creates DOM parsers
  • SAXParser - a SAX parser, which traverses an XML document, calling back to developer-defined code
  • SAXParserFactory - a class that creates SAX parsers

There are four steps to parsing an XML document through JAXP, for either SAX or DOM:

  1. Get a reference to a factory interface.
  2. Configure the factory to produce the kind of parser you need.
  3. Create the parser.
  4. Use the parser to parse the document.

If you download the sample archive, ttfeb2003.ear, you'll see that it includes a servlet, ParseXMLServlet. The servlet allows you to construct and configure either a DOM or SAX parser, and apply it to an XML document. The code prints a summary of what the parser encounters. So you can experiment with different parser settings and error conditions. The examples in this tip all come from the source code in the sample archive. Because SAX parsing is somewhat simpler than DOM parsing, let's first look at the steps for constructing and using SAX parsers. After that, let's investigate DOM parsing.

Getting and Using SAX Parser

The SAX parser interface contains a static method "newInstance" that returns a reference to the corresponding factory class. Getting a reference to the SAXParserFactory is as simple as calling this method:

  SAXParserFactory spf =
    SAXParserFactory.newInstance();

The next step is to configure the factory. This identifies the features for the parser. A SAXParserFactory has three methods for setting parser features:

  • void setNamespaceAware(boolean awareness) - If set to true, the factory will create a namespace-aware parser
  • void setValidating(boolean validating) - If set to true, the factory will create a parser that validates XML against a DTD
  • void setFeature(String name, boolean value) - Sets vendor-specific features in a SAX 2 parser

The ParseXMLServlet sample code creates a SAX parser, and allows you to turning namespaces or validation on or off. That way you can see how these features affect parser operation. Here's the code that turns namespaces and validation on or off:

  boolean isNamespaceAware =
    req.getParameter("JAXP_NamespaceAware") != null;
  boolean isValidating =
    req.getParameter("JAXP_Validating") != null;
  
  spf.setNamespaceAware(isNamespaceAware);
  spf.setValidating(isValidating);

The final two steps are to create the SAX parser, and use it to parse the file:

  SAXParseHandler sph = new SAXParseHandler(out);
  try {
    SAXParser sp = spf.newSAXParser();
    InputSource isrc = getInputSource(req);
    sp.parse(isrc, sph);

  } catch (ParserConfigurationException pce) {
    throw new ServletException(pce);
  } catch (SAXException sx) {
    ; // Continue and report error
  }

The sample code calls newSAXParser() to create the requested SAXParser. If the parser can't be created for some reason, the factory class throws a ParserConfigurationException. The SAXParser's "parse" method takes an org.xml.sax.InputSource object, which can be constructed from any java.io.Reader (in this case, it's a StringReader for a POST parameter). The parser's second argument is an object that extends class org.xml.sax.helpers.DefaultHandler. It is in this object that you need to implement application-specific functionality. In the case of the sample code, the parser prints parsing events and errors, formatted as HTML, to the HTTP response.

Creating a DOM Parser

Creating a DOM parser follows same four steps described in "Getting and Using a SAX parser". However, the class and method names are different for DOM parsers. Another difference is when the user code (that is, the code you define) is executed. With a SAX parser, user code is "called back" during the parse. There is no call back for DOM parsing. A DOM parser parses an XML document, and returns an interface to an org.xml.dom.Document. The Document interface provides a tree interface to the XML document. Instead of passively being called back by the parser, the user code must explicitly traverse the tree.

To create a DOM parser, you need to first acquire a reference to a DocumentBuilderFactory:

  // Get document builder factory instance
  DocumentBuilderFactory dbf =
    DocumentBuilderFactory.newInstance();

Just as with a SAX parser, the next step is to configure the parser factory. A DocumentBuilder has many more options than a SAXParser. In addition to setValidating and setNamespaceAware, DocumentBuilderFactory also allows you to configure the following features:

  • void setCoalescing(boolean value) - If set, the parser combines all adjacent Text nodes and CDATA section nodes into a single Text node in the Document tree. If not set, CDATA sections may appear as separate nodes in the tree.
  • void setExpandEntityReferences(boolean value) - If set, document entity references are expanded with their content. If not set, they are left as entity reference nodes.
  • void setIgnoringComments(boolean value) - If set, comments in the XML file do not appear in the Document tree; otherwise, they do.
  • void setIgnoringElementContentWhitespace(boolean value) - If set, "ignorable" white space (for example, the white space between elements and processing instructions) does not appear in the Document tree; otherwise, it does.

DOM documents do not have "features" like SAX 2, so DocumentBuilderFactory has no setFeature method.

As with the SAX parser, the final two steps are to create the parser, and use the parser to parse the document:

  SAXErrorHandler errorHandler = new SAXErrorHandler();
  // Get parser
  DocumentBuilder db = dbf.newDocumentBuilder();
  db.setErrorHandler(errorHandler);
  out.println("Successfully created document builder<br>");
  
  // Get input source
  InputSource isrc = getInputSource(req);
  
  // Parse input source
  document = db.parse(isrc);

The document builder factory method, newDocumentBuilder, creates the DocumentBuilder. The DocumentBuilder is the DOM parser. Parser method setErrorHandler takes a developer-defined object that implements interface org.xml.sax.ErrorHandler (in this case, it's an instance of class SAXErrorHandler). The parser calls the error handler when errors occur. Developer-defined code can then report the error and try to recover, or throw an exception. The parser method "parse" takes only an InputSource as input, and returns a DOM Document.

You'll notice that these DOM parser methods take SAX interfaces (ErrorHandler and InputSource). This is because virtually all DOM parsers that implement JAXP use SAX "under the hood" to break up the input XML, and use the resulting event stream to build the DOM tree representation.

Running the Sample Code

Download the sample archive for these tips. The application's context root is ttfeb2003. The downloaded EAR file also contains the complete source code for the sample.

You can deploy the application archive (ttfeb2003.ear) in the J2EE Reference Implementation using the deploytool program:

	
	$J2EE_HOME/deploytool -deploy ttfeb2003.ear localhost

Replace localhost with the name of the host on which the server is installed. For a standard installation on a single machine, the hostname typically (and literally) is localhost. You can access the application at http://localhost:8000/ttfeb2003.

For a J2EE-compliant implementation other than the Reference Implementation, use your J2EE product's deployment tools to deploy the application on your platform.

When you run the application you should see a user interface that includes the following:

  • A text field in which to enter XML you want to parse
  • Radio buttons for selecting SAX or DOM parsing
  • Checkboxes for turning namespace awareness and validation on or off
  • Checkboxes to set various DOM-only features

Experiment by running the application multiple times, each time using different settings.

For example, suppose you entered the following XML for parsing:

  <movies>
    <movie>
       <title>
          Gone With the Wind
       </title>
       <actors>
           <actorName> 
              Vivien Leigh
           </actorName>
           <actorName> 
              Clark Gable
           </actorName>
       </actors>
       <description>
           A movie classic set during the Civil War.
       </description>
    </movie>
  </movies>

Here's part of what the output would look like if you select SAX, but don't turn on the namespace-aware or validate XML features:

SAX, namespace-aware and validate turned off

If you turn on the namespace-aware or validate XML features, you should see the following added to the output:

SAX, namespace-aware and validate turned on

Here's part of what the output would look like if you select DOM, and check all features (including DOM-only features):

DOM, all features checked

For further information about JAXP, see the JAXP Tutorial.

.
.

Referencing Enterprise Beans

Business entities often need to be able to reference one another to perform useful work. For example, an Invoice object usually needs to be able to access its associated LineItem objects.

This tip covers three methods for referencing between enterprise beans. The best way to maintain references between enterprise beans is by using container-managed relationships (CMR). The first method explain how to maintain references between beans using CMR. The second and third methods explain how to maintain references between beans when CMR is not available. The first two methods apply only to entity beans, while the last one applies both to entity beans and session beans. In this discussion, a "source" bean is where a relationship starts, and a "target" bean is where the relationship ends.

Method I. Use Container-Managed Relationships

The easiest way for one entity bean to reference another entity bean is to use container-managed relationships, or CMR. Container-managed relationships was introduced in the December 10, 2002 issue of the Enterprise Java Technologies Tech Tips.

With CMR, you first model the relationship between a source bean and a target bean using accessors in the source bean's interface. Accessors are like the "setter" and "getter" methods used by traditional JavaBeansTM components and CMP entity beans. Unlike a conventional accessor, which returns a primitive type or a serializable object, a CMR accessor returns a reference to another entity bean. You need to describe the relationship in the bean's deployment descriptor. Based on the description, the container manages the implementation of the relationship between the beans.

For example, a Person object might have two relationships to other Person objects, one for each parent.

Person object-to-Person object relationships

These relationships between the source bean and the two target beans could be represented in the bean's local interface as two pairs of accessors, like this:

  public interface Person extends EJBLocalObject {
         // ... other methods

         public Person getMother();
         public void setMother(Person mom);
         public Person getFather();
         public void setFather(Person dad);
  }

These accessor methods would also appear in the bean implementation class:

  public abstract class PersonBean implements EntityBean
  {
         // ... other method implementations
        
         // CMR property accesssors
         public abstract Person getMother();
         public abstract void setMother(Person mom);
         public abstract Person getFather();
         public abstract void setFather(Person dad);
  }

Notice that the bean implementation class and the accessor methods are declared to be abstract. This is what makes using CMR so easy -- you simply declare the methods. There's no need to write implementations for these methods. The container writes the implementation based on the description of the relationship that appears in the deployment descriptor.

Container-managed relationships can even be used for relationships between a bean and many other beans. For example, an Invoice bean might have a relationship to multiple LineItem beans.

The CMR approach has some limitations:

  • Because CMR is available only for local entity beans, this method won't work for remote interfaces or non-entity beans.
  • Clients of local bean interfaces are always co-located inside the same JVM as the beans themselves, so enterprise beans and Web components are the only objects that can access local entity beans.
  • If your server is older than version 2.0, you won't have access to local interfaces or CMR. Most users of EJB technology have upgraded to version 2.0 or above, so this is not a limitation for most people.

Method II. Store the Bean's Primary Key, and Use the Bean's Home Interface to Find the Corresponding Instance

This is the method most enterprise bean developers already understand and use. The source bean maintains the primary key of the target bean as a property. When the source bean needs to access the target bean, it first acquires the target bean's Home interface, using JNDI. It then uses a finder method in the Home interface to get the component interface to the target bean.

For example, imagine that a Person bean needs to access another Person bean that represents that Person's mother. Assume that a Person's primary key is some arbitrary string (a passport number, for example).

Accessing a target bean through the primary key

The implementation code for a Person bean to get a reference to the corresponding mother bean looks like this:

  public class PersonBean extends EJBObject {
     // ... other methods

     // A CMP accessor to get the primary
     // key for the mother bean
     public abstract String getMotherPrimaryKey();

     // Return a reference to the Mother bean
     public Person getMother() {
        String motherPK = getMotherPrimaryKey();
        Person motherPerson = null;

        // If mother is known, look it up.
        if (motherPK != null) {
           try {
              // Get JNDI initial context
              InitialContext context = 
                new InitialContext();
   
              // Get home interface
              Object motherObject =
                 context.lookup(
                   "java:comp/env/ejb/Person");
   
              // Remote-interface-safe type cast 
              // to home interface
                PersonHome personHome =
                 (PersonHome)PortableRemoteObject.narrow(
                   object, PersonHome.class);
   
            // Find mother
              motherPerson = 
                personHome.findByPrimaryKey(motherPK);
           } catch (NamingException nex) {
              ...
           } catch (RemoteException rex) {
              ...
           } catch (FinderException fex) {
              motherPerson = null;
           }

           return motherPerson;
     }
  }

The PersonBean example shows how to access a remote entity bean. Local interfaces provide superior performances to remote interfaces, and so are usually preferable. Remote interfaces should be used in the minority of cases where location transparency is important. If the getMother method shown above were accessing a local interface instead of a remote interface, the call to PortableRemoteObject.narrow could be replaced with a simple typecast of the motherObject to interface PersonHome.

Maintaining references between beans by keeping their primary keys is not the most efficient technique, but it is the most flexible. It works for both local and remote interfaces, and also works for any enterprise Java client that can use enterprise beans. Compare the code samples for methods I and II: CMR improves performance, and the code is much easier to write.

Method III. Use a Handle to the Instance

This method works only for remote interfaces, but will work for both entity and session beans. A Handle is a persistable reference to an enterprise bean. Note, though, that persisted bean Handles are not portable. The serialized representation of a reference to an enterprise bean is specific to the application server.

The J2EE standard interface javax.ejb.EJBObject, which all entity and session bean remote interfaces must extend, contains a method called getHandle(). This method returns a Handle object. The Handle object is a serializable (and therefore persistable) reference to an entity or session bean. Because a Handle is Serializable, it can be written to a file (by a Web component, for example), transmitted across a network for use by another program, or saved in a database field. A Handle is a good way to pass a reference to an EJB remote interface from one program (or one tier) to another. The following example code shows how an application client could send a Handle to a UserProfile entity bean to another application component. (The method "sendBytes()" uses a messaging system such as JMS to send the bytes to the other component.)

Using a Handle
   UserProfile profile = getUserProfile(); 

   Handle handle = profile.getHandle();
   ByteArrayOutputStream baos
      = new ByteArrayOutputStream();
   ObjectOutputStream oos =
      new ObjectOutputStream(baos);
   oos.writeObject(handle);
   oos.close();
   byte[] bytes = baos.toByteArray();
   sendBytes(bytes);   

A Handle has a single method, getEJBObject(), that returns the remote interface of the bean instance that originally produced the handle. The following example code retrieves an object handle from the component above (using method receiveBytes), and uses it to get the entity bean corresponding to the handle.

   byte[] bytes = receiveBytes();
   ByteArrayInputStream bais =
      new ByteArrayInputStream(bytes);
   ObjectInputStream ois =
      new ObjectInputStream(bais);
   Handle handle =
      (Handle)ois.readObject();
   Object o =
      handle.getEJBObject();
   UserProfile profile = 
      PortableRemoteObject.narrow
         (o, UserProfile.class);

Note that the data sent across the network in the example code above is a reference to the bean, not the state of the bean. The data sent through the network is not the bean data itself, it is data that the server uses to locate the enterprise bean instance that the Handle references. If the bean no longer exists when getEJBObject() is called, an exception is thrown.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA.

This document is protected by copyright.

Enterprise Java Technologies Tech Tips
February 11, 2003


Sun, Sun Microsystems, Java, Java Developer Connection, JavaServer Pages, JSP, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_29329233473361925@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Jan 31 18:01:26 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0VN1QN13225 for ; Fri, 31 Jan 2003 18:01:26 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0VN3rYp003422 for ; Fri, 31 Jan 2003 18:03:55 -0500 (EST) Date: 31 Jan 2003 14:40:33 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <29329233473361925@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 28170 Java(TM) Technology Fundamentals Newsletter
pixel
pixel
header
    January 31, 2003    

In this Issue

imageJavaTM Programming Language Basics
imageJava Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageFor More Information

Pixel

Java Programming Language Basics

Understanding Inner Classes

The Java programming language is class based. Everything you do must live within a class. Classes can be defined in many different ways. Typically, classes are defined at what you can think of as the top level of a file:

class X {

}

But, that isn't the only way. Classes can be defined inside of other classes, as in the following:

class X {
    class Y {
    }
}

This second form of class is called an inner class because the class is defined inside another class. There are four different types of inner classes: top-level, member, local, and anonymous.

Top-level inner classes are just like other outer class definitions. The key differences are that the class is declared within another class, and the inner class gets the static keyword added before the class keyword:

class OuterClass {
    static class InnerClass {
    }
}

When class X is compiled, two .class files are generated, one for InnerClass and one for OuterClass.

This leads us to the all-important question: How do you reference inner classes? Because inner classes are defined within outer classes, you can't just use the name of the inner class on its own (unless you're within the outer class). Instead, top-level inner classes require you to prefix the inner class name with the outer class name. For instance, in the previous example, to reference InnerClass, you use the name OuterClass.InnerClass. Naming is easily done; just place a period between the outer and inner class names.

Why would anyone use inner classes in this manner? By placing a top-level class (or interface) within another class, you're telling users that the inner class is related to the outer class that contains it.

For instance, the java.util.Map interface provides a data structure for key-value pairs. The interface has an inner interface named Entry, representing each key-value pair entry within the map. By defining Entry within the Map interface, the Entry interface is logically connected to the Map interface. It clarifies the role of Entry for users of Map and doesn't cause confusion with other classes named Entry related to other data structures.

Definitions for top-level classes (and interfaces) can have access modifiers to restrict availability. Just like with methods and variables, you can use any of the access modifiers: private, protected, public, and the default unnamed access. Using the modifiers with inner classes work similarly as with methods and variables.

The second form of inner class is called a member class. You create one by not using the keyword static. The key difference between a member class and top-level class is that with a member class you have access to the member fields and methods of the enclosing class. That means that each instance of the inner class is tied to one and only one instance of the outer class.

class OuterClass {
    class InnerClass {
    }
}

>From the inner class, if you need access to the current instance of the outer class, you specify the class name followed by a period and the this keyword, as in OuterClass.this. The this keyword provides access to potentially hidden methods and fields where both the inner and outer class use the same named method or variable.

For instance, in the following class definition, both the inner and outer classes share a variable named count. In order to access the outer class's variable, you must prefix the variable name with the outer class name and this.

class OuterClass {
   int count = 0;
   class InnerClass {
     int count = 10000;
     public void display() {
       System.out.println("Outer: " + OuterClass.this.count);
       System.out.println("Inner: " + count);
     }
   }
}

The third type of classes isn't defined at the top-level within a class. Instead, they are defined within methods. These are typically called local classes, like local variables. The benefit of using local classes is being able to define classes where you use them and to better limit their accessibility. If a class is only defined within a method, then it isn't accessible outside the method.

Does this seem counterproductive? If the class isn't accessible outside the method, why do you need to define a class in the first place? Typically, what happens is the local class is defined to implement an interface. What is exposed outside the method is the interface, typically as a return value.

Here's an example method that contains several local inner classes:

public ActionListener getListener(int type) {
   class TypeOneListener implements ActionListener {
     public void actionPerformed(ActionEvent e) {
       System.out.println("Got One");
     }
   }
   class TypeTwoListener implements ActionListener {
     public void actionPerformed(ActionEvent e) {
       System.out.println("Got Two");
     }
   }

   ActionListener returnValue = null;
   switch(type) {
     case 1:
       returnValue = new TypeOneListener();
       break;
     case 2:
       returnValue = new TypeTwoListener();
       break;
   }
   return returnValue;
}

When using local inner classes, any variables local to the method that are accessed from within the inner class must be declared final.

The final type of inner class to describe is called anonymous classes. In the local classes example, the classes named TypeOneListener and TypeTwoListener were defined. However, since the class names are inaccessible to everyone outside the outer class definition, the need to name them seems unnecessary. Instead of having to come up with names for the local classes, you can just define them in place:

returnValue = new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       System.out.println("Got Three");
     }
};

What you are doing here is saying "new InterfaceName()", which is essentially saying "call the constructor for the interface." It isn't the interface itself here, but the implementation of that interface. Imagine an unnamed class that extends Object and implements the interface name. Since the class has no name, you can't actually call a constructor. What you must do though is implement every method of the interface in the definition. Otherwise, you won't have a valid implementation and the code won't compile.

Notice that trailing semicolon at the end. Since the inner class definition is a part of the assignment statement, the semicolon is required to end the assignment statement.

You'll find these anonymous inner classes a popular feature in IDE tools. Tools such as JBuilder generate the code to connect the event handling code of components. When you create the code by hand, be sure to match up the parentheses and braces.

Test what you learned about inner classes by taking an online quiz.

Pixel
Pixel

Java Bits

Providing Functionality in Separate Classes

The article above showed you how to use inner classes to provide the functionality of a component within the same class, but sometimes you'll want to put that functionality in an entirely separate class. You may want to use separate classes when there is a lot of code, or to keep the UI separate from functionality for troubleshooting and modularity.

Providing functionality of components in separate classes is an easy four step process:

  1. When registering the component as a listener, instantiate the class that contains the code for functionality with the keyword new.

    For instance:

    save.addActionListener(new Handler1());

  2. Make sure the class that provides functionality implements the proper interface.

    Such as:

    public class Handler1 implements ActionListener

  3. The class that provides functionality should be declared public, or a part of the same package.

    public class Handler1 implements ActionListener

  4. Implement the required methods for that interface.

    // actionPerformed must be implemented for the ActionListener
    // interface.
    public void actionPerformed (ActionEvent ae)
    

For example, in the following application, the GUI code that builds the frame and two buttons is in the TestButton class. The functionality for the buttons is in two separate classes: Handler1 and Handler2.

Download the three classes listed below, and compile the TestButton class. In this process, all three classes compile.

TestButton.java
Handler1.java
Handler2.java

When you click either of the buttons, text prints to the console.

When the application runs, it should look something like the example below:

Pixel
Pixel

Making Sense of the Java Class Libraries

JPasswordField Class

The JPasswordField is a lightweight component similar to a text field, but it does not reveal the original characters. Instead, by default it displays the character * for each key typed. The * can be changed to some other character.

Like a text field, JPasswordField has several constructors you may call:

  • JPasswordField() -- constructs a JPasswordField with null starting text string, and 0 column width.
  • JPasswordField(Document doc, String txt, int columns) -- constructs a new JPasswordField that uses the given text storage model and the specified number of columns.
  • JPasswordField(int columns) -- constructs a new empty JPasswordField with the specified number of columns.
  • JPasswordField(String text) -- constructs a new JPasswordField initialized with text in the field.
  • JPasswordField(String text, int columns) -- constructs a new JPasswordField initialized with text and columns.

When a user types in the field, the character * appears unless you call the setEchoChar(char c) to change it. For example:

JPasswordField jpf = new JPasswordField(15);
jpf.setEchoChar('#');

The snippet above creates a JPasswordField object 15 columns wide. When a user types into the field, the character # appears for each key pressed instead of the default * character.

To retrieve the text a user did typed, call the getPassword method. In the following example, the getPassword method is called as a new String and assigned to the variable entrdpwd.

String entrdpwd = new String(jpf.getPassword());

The PasswordTest application creates a frame with a PasswordField. Type in a password, and the yellow text field at the bottom of the frame displays if your entry was correct or incorrect. After three tries, the application automatically shuts down.

Download the code

When you compile and run this application, you should get a result that appears something like the figure below:

Pixel
Pixel

Program Challenge

Using inner classes, create the following program completely in the main method of the solution class.

  1. Create a frame with a button that has a label that provides a number.
  2. Increase by one the value of the number, when the button is selected.
  3. Override its frameInit method to have its default close operation be EXIT_ON_CLOSE.

See a possible solution to the Challenge:

Pixel
Pixel

For More Information

Inner Classes

Anonymous Classes

Class PasswordField

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SETM development kit.

Pixel
Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please unsubscribe me from this newsletter.
From env_30930519430183006@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri Feb 28 17:34:55 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h1SMYtC09186 for ; Fri, 28 Feb 2003 17:34:55 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h1SMbb4V010772 for ; Fri, 28 Feb 2003 17:37:38 -0500 (EST) Date: 28 Feb 2003 14:17:30 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <30930519430183006@hermes.sun.com> Subject: February Core Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 18315 Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Standard Edition (J2SETM).


Product and Technology Releases

The following J2SE products and technologies were recently released.

JSR-000022 JAINTM SLEE API Proposed Final Draft 2 Specification 1.0
JSR 22 has refined its focus on the Service Logic Execution Environment. The JAIN Service Creation and Service Logic Execution Environment Specifications are targeted towards the service providers, equipment manufactures, software vendors and network providers for the purpose of creating service creation and execution platform using Java component factories.

JSR-000141 Session Description Protocol (SDP) API Public Review Draft 2 Specification
The SDP API version 1.0 will enable the proper encoding and decoding of SDP messages and allow a user to get, set or modify any element of a field or description in a SDP message.


Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

Java Web Start, US downloads, followed up by International

Java Communications API

JavaBeansTM Development Kit (BDK) 1.1

Java 3DTM 1.3 API

Java Advanced Imaging API 1.1.2 Beta Tutorial Demo


In The Spotlight

JMS Courier Provides Vendor-Independent C++ Integration into JMS. Codemesh Inc., a leading supplier of language interoperability tools, released the final version of JMS Courier Release 2.0 for integrating Java Message Service (JMS) and C++. Regardless of your current or planned JMS implementation, you can use JMS Courier to merge your C++ applications into it.


Java Developer's Marketplace

WebRenderer Revolutionizes Java Programming.
An innovative web content browser component specifically developed for the Java programming language has been released to worldwide availability. WebRenderer is a fast and robust component facilitating HTML document rendering with a single line of code. Interfaces can now be produced easily and rapidly, saving development time and cost while adding a dynamic focus.


Industry News and Announcements

Java Application Verification Kit: Testing Applications and Showing Credibility.
The Java AVK is a component of the Java Verification Program. It provides developers with the specific guidelines and rules based on J2EE that are used to test applications for portability across a variety of application servers. Correct use of J2EE platform APIs is checked and exceptions are identified and reported.

For more information, visit: http://java.sun.com/j2ee/verified or email: verification-sales@sun.com

pixel
pixel pixel pixel
February 28, 2003

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles & Quizzes

Tech Tips

Chat

Servlet and JavaServer Pages Technologies
Tune in to hear new developments in Servlet and JavaServer Pages technologies with guests Marty Hall and Mark Roth on March 11 at 11:00 A.M. PST/7:00 P.M. GMT

Books

Core Java 2, Volume 1: Fundamentals, 6/e
The best-selling guide for serious programmers of Java technology fully updated for the Java 1.4 SDK! Get it today.

Newsletters

Java Technology Fundamentals
Learn how to use inner classes and the JPasswordField class.


Events

  • Code Camp
    Handler Demo and Download
    This demo will show how to use the SOAP Message Handlers with Java API for XML-based RPC (JAX-RPC) 1.0_01 and run on Java Web Services Developer Pack (Java WSDP) v1.0_01 and/or Sun ONE Application Server 7.0. Demo software included.

  • March is Java Web Services Education Month!
    Tune in and get everything you need to ignite your programming experience with Web Services. Sun's vision, strategies, product downloads, rich educational resources, book and course discounts, hands-on tutorials live interaction with Web Services experts, and much more. This offer lasts during the month of March only, 2003.

  • Sun Technology Audiocast
    Java Platform Performance Tuning with Doris Chen
    The Java Platform Performance WebCamp will show experienced developers how to decide when to optimize performance, and how to use profiling tools to analyze performance and memory problems. Developers will learn about recommended best practices for writing applets, client applications, server applications, and servlets.

  • Sun Net Talk
    Accessing the World of Java Technology: Using ColdFusion MX for Sun ONE Software ColdFusion MX, a server scripting environment for rapid application development, now runs on Sun ONE Application Server 7. Find out more at the live event, on Wednesday, March 5, 2003, 9-10am PST/12pm-1pm EST.

  • Sun Net Talk
    Java Technology & XML All Star Roundtable Listen to Java technology and XML visionaries James Gosling's and Bill Smith's thoughts about today's realities and tomorrow's directions, then join in on the live Q&A session -- a rare opportunity indeed. Friday, March 14, 2003, 9-10:30am PST/12-1:30pm ET

  • Sun Tech Days: A Developer Conference
    March 21-22, 2003, Bangalore, India. Come learn first-hand from industry insiders about several new technological developments including the latest about web services programming with J2EE and leading edge Sun ONE Studio tools, which will simplify your development tasks.

  • Sun Security Summit 2003
    March 4-5, Washington D.C., U.S.

  • The Evolving Solaris Kernel: Past, Present, and Future
    March 5, Sacramento, CA, U.S.

  • MassWIT's Women's Leadership Conference 2003
    March 6, Burlington, MA, U.S.

  • CeBIT 2003
    March 12 - 19, Hannover, Germany

  • Java University Program at Web Services Edge
    March 18 - 20, Boston, MA, U.S.

  • OpenOffice.org Conference
    March 20-21, Hamburg Germany

  • SunNetwork Conference
    April 8-9, Shanghai, People's Republic of China

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://developer.java.sun.com/berkeley_license.html
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Feedback? Send your comments on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe:
You can subscribe to other JDC publications on the JDC Newsletters and Publications page, including:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You may also unsubscribe using our one-click unsubscribe facility, see the link at the end of this email.

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA. This document is protected by copyright. For more in formation, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, Java, Java Developer Connection, JavaBeans, Java 3D, JAIN, JavaServer Pages, JSP, J2EE, J2ME, Java Community Process and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Core Java Technologies Newsletter
February 27, 2003


Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_29522374-941463575@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Feb 4 12:34:29 2003 X-UIDL: h$g"!P=l"!kgZ!!-k0!! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h14HYTN01226 for ; Tue, 4 Feb 2003 12:34:29 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h14Hb3Hc019841 for ; Tue, 4 Feb 2003 12:37:05 -0500 (EST) Date: 4 Feb 2003 08:46:35 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <29522374-941463575@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Feb. 4, 2003 (Variable Argument Lists, Floating-Point Arithmetic) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27938 Status: RO Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text February 4, 2003    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, February 4, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Using Variable Argument Lists
Some Things You Should Know About Floating-Point Arithmetic

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

Pixel
Pixel

USING VARIABLE-LENGTH ARGUMENT LISTS

If you've done much C or C++ programming, you might have encountered some code that looks similar to this:

    #include <stdarg.h>
    #include <stdio.h>
    
    void dumpList(int n, ...) {
        va_list ap;
    
        va_start(ap, n);
    
        printf("count = %d: ", n);
        while (n-- > 0) {
            int i = va_arg(ap, int);
            printf("%d ", i);
        }
        printf("\n");
    
        va_end(ap); 
    }
    
    int main() {
        dumpList(1, 1);
    
        dumpList(3, 1, 2, 3);
    
        return 0;
    }

The dumpList function declares a single parameter (n), followed by an ellipsis (...). The ellipsis specifies that a variable number of additional parameters are present. This means that a caller of dumpList can pass an arbitrary number of arguments in addition to the first int argument. The various va_x types and functions are used to extract the parameter values in the dumpList function.

The output of this C program is:

    count = 1: 1 
    count = 3: 1 2 3 

The C/C++ variable argument mechanism is quite useful in certain contexts. But the mechanism is error-prone, because it defeats type checking. For example, if the second dumpList call is changed to:

    dumpList(3, 1, 2, 3.4);

the result is something like this:

    count = 1: 1 
    count = 3: 1 2 858993459

The demo program assumes that an int argument has been passed, when in fact a double (3.4) is passed.

The Java language has no direct equivalent to this feature. However, it's still sometimes useful to be able to pass a variable number of arguments to a method. This tip looks at several ways of doing that.

The first approach you might think of is to overload the dumpList method, like this:

    public class VarDemo1 {
        static void dumpList(Object obj1) {
            System.out.println(obj1);
        }
    
        static void dumpList(Object obj1, Object obj2) {
            System.out.println(obj1 + " " + obj2);
        }
    
        static void dumpList(Object obj1, Object obj2,
        Object obj3) {
            System.out.println(
               obj1 + " " + obj2 + " " + obj3);
        }
    
        public static void main(String[] args) {
            Object obj1 = new Integer(1);
            Object obj2 = new Integer(2);
            Object obj3 = new Integer(3);
    
            dumpList(obj1);
            dumpList(obj1, obj2, obj3);
        }
    }

The idea is that you have a variable number of object references to be passed as arguments, and dumpList methods are defined for each case. This approach will certainly work, but has some serious problems. One problem is that the approach is not general. The VarDemo1 program defines dumpList methods to handle one, two, or three arguments. But what if you have ten arguments that you want to pass? Do you keep adding new dumpList methods?

Another problem is that there can be a lot of code duplication between the various overloaded methods. This duplication implies a long-term maintenance headache.

A second approach to handling variable argument lists is to use an Object[] array, like this:

    public class VarDemo2 {
        static void dumpList(Object[] list) {
            for (int i = 0; i < list.length; i++) {
                System.out.print(list[i] + " ");
            }
            System.out.println();
    
            //list[0] = new Integer(4);
        }
    
        public static void main(String[] args) {
            Object[] veclist1 = {new Integer(1)};
            Object[] veclist2 = {new Integer(1),
                new Integer(2), new Integer(3)};
    
            dumpList(veclist1);
            dumpList(veclist2);
        }
    }

This approach works quite well. One example of its use is the java.text.MessageFormat class:

    import java.text.*;
    
    public class VarDemo3 {
        public static void main(String[] args) {
            String fmt = 
               "Error at line {0} of file {1}: {2}";
    
            Object[] arglist = {new Integer(37),
                "abc.java", "missing ("};
    
            String msg = 
               MessageFormat.format(fmt, arglist);
    
            System.out.println("msg = " + msg);
        }
    }

This class is a rough equivalent to the printf function illustrated in the first demo above. The embedded "{0}" and so on in the format string are references to the arguments passed to the format method in the Object[] array.

When you run this program, the result is:

    msg = Error at line 37 of file abc.java: missing (

The array approach works fairly well, but one drawback is that the called method can modify the array contents. The commented line of code in the VarDemo2 program illustrates this point. In general, such modification is undesirable.

A final approach uses the collections framework, like this:

    import java.util.*;
    
    public class VarDemo4 {
        static void dumpList(List list) {
            System.out.println(list);
    
            //list.set(0, new Integer(4));
        }
    
        public static void main(String[] args) {
            List list = new ArrayList();
    
            list.add(new Integer(1));
            list.add(new Integer(2));
            list.add(new Integer(3));
    
            list = Collections.unmodifiableList(list);
    
            dumpList(list);
        }
    }

This approach solves the problem of modifying the passed-in argument list. If you uncomment the "list.set" line, and run the program, it will give an exception. The exception is triggered because the list has been wrapped in an unmodifiable view, using Collections.unmodifiableList.

Using the collections framework has other advantages. For example, notice that the top of the dumpList method prints the whole list using a single statement, rather than using a loop. In general, by using collection features it's easier to operate on lists as lists, rather than an element at a time. Note that the collections framework has features for treating Object[] arrays as lists (Arrays.asList) and converting lists to arrays (ArrayList.toArray).

For more information about using variable argument lists, see section 16.6, List, 16.8.2, The Unmodifiable Wrappers, and 16.9, The Arrays Utility Class, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes.

Pixel
Pixel

SOME THINGS YOU SHOULD KNOW ABOUT FLOATING-POINT ARITHMETIC

Suppose that you are doing some Java programming involving floating-point calculations. Suppose too that your code takes the value 0.1 and adds it to itself a couple of times, like this:

    public class Fp1 {
        public static void main(String[] args) {
            double val1 = 0.1;
            double val2 = 0.3;
    
            double d = val1 + val1 + val1;
    
            if (d != val2) {
                System.out.println("d != val2");
            }
    
            System.out.println(
               "d - val2 = " + (d - val2));
        }
    }

Everyone knows that:

    0.1 + 0.1 + 0.1 == 0.3

at least in mathematical terms. But when you run the Fp1 program, you discover that this equality no longer holds. The program output looks like this:

    d != val2
    d - val2 = 5.551115123125783E-17

This result seems to indicate that 0.1 + 0.1 + 0.1 differs from 0.3 by about 5.55e-17.

What is wrong here? The problem is that IEEE 754 floating-point arithmetic, as found in the Java language, doesn't use decimals to represent numbers. Instead it uses binary fractions and exponents. To understand what this means in practice, consider trying to write various decimal fractions as the sum of a series of powers of two:

    0.5 = 1/2

    0.75 = 1/2 + 1/4

    0.875 = 1/2 + 1/4 + 1/8

    0.1 = 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + ...

The last series is infinite, which means that 0.1 is not exactly representable in floating-point format. The infinite series must be cut off at some point, rounded, and so on, in order to be represented in a 64-bit double value. This process results in some amount of error.

There are several ways to fix the equality testing problem illustrated above. You could check that d and val2 are close in value rather than exactly equal. Or you could use the BigDecimal class, and opt out of floating-point arithmetic entirely.

Here's another example where floating-point works differently from what you'd expect when applying math rules:

    public class Fp2 {
        public static void main(String[] args) {
            double val1 = 12345.0;
            double val2 = 1e-16;
    
            if (val1 + val2 == val1) {
                System.out.println(
                   "val1 + val2 == val1");
            }
        }
    }

The result of the Fp2 program is:

    val1 + val2 == val1

In mathematical terms, if:

    a > 0 && b > 0

then:

    a + b != a

But this program demonstrates behavior that violates this rule. The problem is with the precision of floating-point values. The precision is the actual number of bits used to represent the value (the binary fraction), and is distinct from the range of values that can be expressed using floating-point. For Java double values, there are 53 bits of precision, or about 16 decimal digits. The example above implies a precision of approximately 20 digits, since the addition can be rewritten as:

    1.2345e+4 + 1e-16

Because the precision of double values is not sufficient to represent the result of this addition, the 1e-16 is effectively ignored.

Here's another example that illustrates how the laws of math are violated:

    public class Fp3 {
        public static void main(String[] args) {
            double d1 = 1.6e308;
            double d2 = d1 * 2.0 / 2.0;
    
            System.out.println(d1);
            System.out.println(d2);
        }
    }

If d1 is multiplied and then divided by 2.0, the result should be d1, right? Unfortunately not. The result is actually this:

    1.6E308
    Infinity

The initial multiplication d1 * 2.0 overflows, and the division by 2.0 comes too late to do any good. The maximum double value is approximately 1.8e308. Multiplying 1.6e308 by 2.0 results in 3.2e308, which becomes positive infinity.

Let's look at another facet of floating-point arithmetic. If you've used integer arithmetic much, you know that division by zero triggers an ArithmeticException. But what about similar usage with floating-point? Here's an example:

    public class Fp4 {
        public static void main(String[] args) {
            System.out.println(1.0 / -0.0);
            System.out.println(1.0 / 0.0);
    
            System.out.println(0.0 / 0.0);
        }
    }

When you run this program, the output is:

    -Infinity
    Infinity
    NaN

The program throws no exceptions for floating-point division by zero. When a positive or negative value is divided by zero, the result is an infinity.

This example shows that there is, in fact, more than one zero value. There are negative and positive zeros. The sign of the zero is taken into account in deciding whether the result of the division is negative or positive infinity.

What about the third division, 0.0 / 0.0? The result of this operation is the value NaN (not a number).

Negative and positive zeros and NaN have some odd properties. Let's look at another example to help clarify this:

    public class Fp5 {
        public static void main(String[] args) {
            double d1 = -0.0;
            double d2 = +0.0;
            if (d1 < d2) {
                System.out.println("-0.0 < +0.0");
            }
    
            double d3 = 0.0 / 0.0;
            if (d3 == d3) {
                System.out.println("d3 == d3");
            }
        }
    } 

If you run the Fp5 program, you'll see that it prints nothing. As you saw in the previous example, the sign of a zero is propagated, for example 1.0 / -0.0 == -Infinity and 1.0 / +0.0 == +Infinity. But that's not the same as saying that -0.0 < +0.0, as the example above demonstrates (d1 is not less than d2, and so nothing is printed). Whether -0.0 comes "before" +0.0 depends on your perspective.

The Fp5 program also illustrates the point that NaN values are unordered, so that d3 is not equal to itself. This is the way that you write a method to tell whether a value is NaN. If the value is not equal to itself, then it is NaN. Such methods actually already exist -- see the Float.isNan and Double.isNaN methods.

Let's look at a final example that illustrates the ordering of some of the odd floating-point values discussed so far:

    public class Fp6 {
        static double[] list = {
            Double.NEGATIVE_INFINITY,
            -0.0,
            +0.0,
            Double.MIN_VALUE,
            Double.MAX_VALUE,
            Double.POSITIVE_INFINITY
        };
    
        public static void main(String[] args) {
            for (int i = 0; i < list.length; i++) {
                System.out.println(list[i]);
            }
        }
    }

The result of running the program is:

    -Infinity
    -0.0
    0.0
    4.9E-324
    1.7976931348623157E308
    Infinity

The list presents -0.0 before +0.0. As already mentioned, whether -0.0 really comes before +0.0 depends on your perspective.

NaN is not on the list because it is not ordered with respect to other values.

Note that Double.MAX_VALUE and Double.POSITIVE_INFINITY are distinct values.

This tip looked at a few of the properties of floating-point arithmetic. It pays to be careful when using floating-point because it behaves differently than you might expect if you simply apply the laws of mathematics.

For more information about floating-point arithmetic, see section 4.2.3, Floating-Point Types, Formats, and Values, in "The JavaTM Language Specification Second Edition" by Gosling, Joy, Steele, and Bracha. Also see the following IEEE-754 documents: Storage Layout and Ranges of Floating-Point Numbers and IEEE-754 Floating-Point Conversion

Pixel
Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please unsubscribe me from this newsletter.
From env_311930301300324184@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Mon Mar 3 16:59:55 2003 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h23LxtC20558 for ; Mon, 3 Mar 2003 16:59:55 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.8/8.12.1/IUPO) with SMTP id h23M2gYY010654 for ; Mon, 3 Mar 2003 17:02:42 -0500 (EST) Date: 3 Mar 2003 13:46:03 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <311930301300324184@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 31702 Java(TM) Technology Fundamentals Newsletter
pixel
pixel
header
    February 28, 2003    

In this Issue

imageJavaTM Programming Language Basics
imageJava Bits
imageMaking Sense of the Java Class Libraries
imageProgram Challenge
imageTake Online Quizzes
imageFor More Information

Pixel

Java Programming Language Basics

Understanding Applets

When Java technology was first announced, the biggest promise was in something called applets, little programs that ran within the browser to make web pages more interactive. Think back to 1995 here, where most web pages were static, and dynamic content consisted of Perl scripts that ran through the Common Gateway Interface (CGI). There wasn't much in the way of fancy, animated graphics, and any user interaction required another request-response cycle to go back to the web server. At the time, a company named Netscape dominated the browser market and was the first to license the Java runtime for their Navigator browser. Microsoft signed on and added their own virtual machine to support the execution of these Java programs in their browser, too.

Jump ahead a few years, and the world is again looking at applets as a way of deploying embedded programs for the browser. Since Sun's Java Plug-in can upgrade the old and incompatible virtual machine built into Internet Explorer to the latest Java Runtime Environment (JRE) through the Get Java Technology for your Desktop program, developers have again been embracing applet-based solutions.

But what exactly is an applet? Technically speaking, an applet is any class that extends from the Applet class in the java.applet package. That's literally it. There is certainly more to applets, but once you have this subclass, you can add it to a web page by identifying it within an <APPLET> - </APPLET> tag set. The browser will then load the applet class and display it in the designated space.

You also have the methods init, start, stop, and destroy. Since Applet is a subclass of java.awt.Component, the paint method is also of interest for drawing the display area. The key five methods work as follows:

  • init - called when the browser loads the main Applet class into the system. Typically, applets don't have a constructor. Instead, their one-time initialization code is here.
  • start - called when the applet should start execution, when the user visits the page containing the applet.
  • stop - called when the applet should stop execution, when the user is viewing a web page other than the page containing the applet.
  • destroy - called when the browser decides to unload the applet. Resources can be reclaimed here, but you have no control over when destroy is called.
  • paint - called when the browser determines the applet's display area is invalid.

To demonstrate, the following applet prints to the console when each of the five methods is called. The paint method also is used to paint a message on the display. For each time the paint method is called, the number increases. This does lead to the question of where messages written to the console can be found. This differs from browser to browser and sometimes from version to version. With Internet Explorer 6.0, the Sun Java Console is under the Tools menu. With the Microsoft runtime and IE6, the console is under the View menu. With the Netscape 7.0 and Mozilla browsers, you'll find the Java console under the Web Development menu (under the Tools menu).

Now the applet:

import java.awt.*;
import java.applet.*;

public class FirstApplet extends Applet {
        public void init() {
                System.out.println("In init()");
        }
        public void start() {
                System.out.println("In start()");
        }
        public void stop() {
                System.out.println("In stop()");
        }
        public void destroy() {
                System.out.println("In destroy()");
        }
        public synchronized void paint(Graphics g) {
                System.out.println("In paint()");
                g.drawString("Painting...", 50, 50);
        }
}

You compile the applet, just like any other source file:

javac FirstApplet.java

This creates FirstApplet.class, assuming the file has no errors.

Running an applet is a little different than with standalone programs. Instead of providing a main method to run once the file is loaded, you need to provide an HTML file to load the applet. This is where the <APPLET> tag comes into play. Here is what the tag definition looks like:

<APPLET
    // Required
    CODE = appletClass or 
    OBJECT = serializedApplet
    HEIGHT = pixels
    WIDTH = pixels  

    // Options
    CODEBASE = codebaseURL
    ARCHIVE = archiveList
    ALT = alternateText
    NAME = instanceName
    ALIGN = alignment
    HSPACE = pixels
    VSPACE = pixels  
>
<PARAM NAME = attribute1 VALUE = value1>
<PARAM NAME = attribute2 VALUE = value2>
 ...
Alternate HTML
</APPLET>

For the applet, the loader file would look like the following, and should be located in the same directory as the .class file:

<APPLET
    code=FirstApplet
    height=200
    width=200>
</APPLET>

The code attribute identifies the class name to load. The width and height attributes are self explanatory, stating the desired display size. If the .class file for the applet uses a different base directory than the HTML loader file, you'd need to specify the CODEBASE to tell the browser where to based its search path.

Place the tag in any HTML file and load that file into the browser.

Here's an example method that contains several local inner classes:

NOTE: If you are using Microsoft's virtual machine, Microsoft's Java console might display a NoClassDefFoundError. If you don't have the Java Plug-in installed, and run the applet with Microsoft's VM, it won't load because the .class file format has changed over time. To force the .class file to be compatible with the older Microsoft VM, don't use any features newer than version 1.1.4 and compile with the -target option:

javac -target 1.1 FirstApplet.java

Of course, if you have the Plug-in installed, you won't run into this problem. Just compile the source and tell the browser to load the HTML file and you'll see the applet running. It's that simple.

Pixel
Pixel

Java Bits

Running Threads in Applets

You learned about threads in the October issue of Java Technology Fundamentals. Making use of threads in applets is much the same, with a few concepts to keep in mind.

  • When creating an applet, you extend the Applet class. So, to make use of threads, implement the Runnable interface or define the thread as an inner Thread class.
    public class Example extends Applet implements Runnable
  • Create a new Thread object inside of the applet's start method. (Thread also has a start method, but these are two different methods.)

  • Because you implemented Runnable, you must provide a run method for your class. This method is called by the thread object to perform its actions when the thread starts.

The following applet demonstrates scrolling text that runs on its own thread, allowing you to type into a text field while the text scrolls. If the scrolling text were not on a separate thread, the text would hog the CPU, and you wouldn't be able to type into the text field.

import java.applet.*;
import java.awt.*;

public class ExampleThreads extends Applet implements Runnable
  {
     String text = "An example of text scrolling in its own thread.";
     TextField field;
     Thread thread;
     boolean running;
     
     public void init()
       { //open init
        Font fnt = new Font("Monospaced", Font.BOLD, 26);
        setFont(fnt);
        FontMetrics fm = getFontMetrics(fnt);
        int spaceWidth = fm.charWidth(' ');
        int panelWidth = getSize().width;
        int numSpaces = panelWidth / spaceWidth + 1;
     
        //Add spaces around the text as needed
        for (int i = 0; i < numSpaces; ++i)
          { text = text + ' '; }
        
        field = new TextField("Type Here");
        add(field);
       } //close init
       
     public void start()
      {
        if (thread == null)
         {
           thread = new Thread(this);
           running = true;
           thread.start();
         }
      }
      
     public void run()
      {
        while (running)
         {
           text = text.substring(1, text.length())
                        +text.charAt(0);
           repaint();
           
           try
             {
               Thread.sleep(100);
              }
              
              catch (InterruptedException e)
               {}
              }
             }
             
      public void stop()
       {
         if (thread != null)
          {
            running = false;
            thread = null;
           }
        }
        
      public void paint(Graphics g)
       {
         g.drawString(text, 0, 150);
        
       }
 }

Create the following HTML page to run with appletviewer or in your browser:

<html>
  <head>
  <title>Test Program</title>
  </head>

   <body>
    <applet 
      code="ExampleThreads.class" 
      width="400" 
      height="200">
    </applet>
   </body>
</html>

When the application runs, it should look something like the example below:

Pixel
Pixel

Making Sense of the Java Class Libraries

Applet, Image, and the MediaTracker Classes

The article above shows how some information is passed to the applet through the HTML page, such as the location of the class file and the height and size of the applet itself. In addition to passing information about the applet itself and its source file, you can also pass it optional parameters using the PARAM tags and getParameter method from the Applet class.

For instance, you might want to display images, or other objects, in your applet. To use images with applets, you must first associate the image with the Image abstract class. Then by passing parameters through the HTML file, you can pass information about how many images you intend to display and their names.

For instance, if you wanted to display four images, you can begin with this:

Image images = new Image[4];

The Image class also has getWidth and getHeight methods that return the size of images in pixels.

The PARAM tag, as shown above, uses the following syntax:

<PARAM NAME = attribute1 VALUE = value1>

So you could create a PARAM tag that tells the applet how many images there are with:

<PARAM NAME = number VALUE=4>

Then go on to name the images in the PARAM tage in the HTML file with:

<PARAM NAME = image1 VALUE=seahorse.jpg>
<PARAM NAME = image2 VALUE=rockfish.jpg>
<PARAM NAME = image3 VALUE=tubesnout.jpg>
<PARAM NAME = image4 VALUE=seabass.jpg>

Which would look like the following example in an HTML file:

You tell the applet to get the parameters with the getParameter method. When you pass a String into the getParameter method, it returns the value of the named parameter in the HTML tag.

For instance:

getParameter("image1");

returns the String seahorse.jpg.

To get the location of applet resources, such as an image, call the getCodeBase method, which returns the URL. In addition you must get the image object itself with the getImage method so that it can be painted on the screen:

getImage(getCodeBase(), "CoLogo.jpg");

To do something more complicated than simply display an image (such as flipping through images) you can use the MediaTracker class to manage and monitor the status of loading images. The MediaTracker class is a utility class used to track the status of a number of media objects.

To construct a MediaTracker object, call the MediaTracker constructor and pass in the Component that draws your images.

For instance:

ImagePanel p = new ImagePanel();
MediaTracker tracker = new MediaTracker(p);

Once you've created the MediaTracker object, have it track a specific image by calling its addImage (Image image, int ID) method. In addition, each image can be assigned a unique identifier. This identifier controls the priority order in which the images are fetched. It can also identify unique subsets of the images that can be waited on independently. Images with a lower ID are loaded in preference to those with a higher ID number.

For example:

tracker.addImage(image, IMAGE_ID);

To find out if the image is loaded and ready to be painted, call one of the following methods:

  • checkAll - Checks to see if all images being tracked by this media tracker have finished loading.
  • checkAll(boolean load) - Checks to see if all images being tracked by this media tracker have finished loading.
  • checkID(int id) - Checks to see if all images tracked by this media tracker that are tagged with the specified identifier have finished loading.
  • statusAll(boolean load) - Calculates and returns the bitwise inclusive OR of the status of all media that are tracked by this media tracker.
  • waitForAll() - Starts loading all images tracked by this media tracker.
  • waitForAll(long ms) - Starts loading all images tracked by this media tracker.

For instance:

int status = tracker.statusALL();
if (status & MediaTracker.COMPLETE)
  System.out.println("Images have been loaded"); 

The MediaTracker class has other methods and constants that are useful for managing images.

Pixel
Pixel

Program Challenge

ImageLoop Applet

You need images for this example. Write an applet cycles through images like a picture album.

  1. Make the applet accept an unlimited number of parameters following the naming pattern of Image1, Image2, Image3, and so forth.
  2. Write parameters to represent the name of an image file.
  3. Make the applet cycle through the image, displaying each like a picture album.

See a possible solution to the Challenge

Pixel
Pixel

Take Online Quizzes

Applets Quiz

Test what you learned about applets in this issue by taking an online quiz:

Inner Classes Quiz

Test what you learned about inner classes.

Pixel
Pixel

For More Information

Writing Applets

Threads in Applets

Creating a Threaded Slide Show Applet

Installation for Conventional Applets (Microsoft Window Only)

Class MediaTracker

Pixel
Pixel

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SETM development kit.

Pixel
Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the JavaTM Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054

Sun, Sun Microsystems, Java, J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
image
image
Please unsubscribe me from this newsletter.
From env_312672002138525722@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Mar 4 07:28:28 2003 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h24CSRC06415 for ; Tue, 4 Mar 2003 07:28:28 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.8/8.12.1/IUPO) with SMTP id h24CVEYY003664 for ; Tue, 4 Mar 2003 07:31:14 -0500 (EST) Date: 4 Mar 2003 04:31:01 -0800 From: "JDC Bug Watch" To: gcf@indiana.edu Message-Id: <312672002138525722@hermes.sun.com> Subject: Bug Change Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Beyond Email Content-Length: 291 The bug 4406429 has been updated. To view the the complete bug report visit the following url: http://developer.java.sun.com/developer/bugParade/bugs/4406429.html To use our one-click unsubscribe facility, select the following URL: http://bulkmail.sun.com/unsubscribe?312672002138525722 From env_31670973-1226171047@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Mar 4 23:43:42 2003 X-UIDL: 'i@!!1`@!![B_!!;(I"! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h254hgC27390 for ; Tue, 4 Mar 2003 23:43:42 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.8/8.12.1/IUPO) with SMTP id h254kTYY025482 for ; Tue, 4 Mar 2003 23:46:29 -0500 (EST) Date: 4 Mar 2003 20:31:04 -0800 From: "Wireless Developer J2ME Tech Tips" To: gcf@indiana.edu Message-Id: <31670973-1226171047@hermes.sun.com> Subject: J2ME Tech Tips, March 4, 2003 (Scraping HTML Pages for Content with MIDP, OTA Provisioning with the J2ME Wireless Toolkit) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 43630 Status: RO Wireless Technical Tips: March 04, 2003
pixel
pixel
header
    March 04, 2003        

In this Issue

WELCOME to the Wireless Developer Java[tm] 2 Platform, Micro Edition (J2ME[tm]) Tech Tips, for March 04, 2003.

Scraping HTML Pages for Content with the Mobile Information Device Profile
Over-the-Air Provisioning with the J2ME Wireless Toolkit

You can view these J2ME Tech Tips on the Web, Scraping HTML Pages for Content with the Mobile Information Device Profile and Over-the-Air Provisioning with the J2ME Wireless Toolkit

Pixel

Scraping HTML Pages for Content with the Mobile Information Device Profile

by Eric Giguere
March 04, 2003

Download the source: [Webscraping.zip], [quote.zip]

On occasion, you may find that the only way to obtain certain information is to extract it from a page of HTML on a web site, in a procedure commonly called page scraping. It's similar to extracting data from an XML document, but HTML's syntax is much looser than XML's, so you can't use an XML parser to parse HTML pages. The code presented here parses an HTML page inside a servlet or directly from a Mobile Information Device Profile (MIDP) application.

The first thing you need to do is define some helper classes to hold the various parts of an HTML page. You're only interested in three kinds of data: tags, comments, and text. Because they're all page elements, you define Element to serve as a base class:

// Marker class for page elements.

package webscraper;

public class Element {
}

The Text class is the simplest subclass:

// Defines a page element for holding text
// outside of any tag or comment.

package webscraper;

public class Text extends Element {
    private String text;

    public Text( String text ){
        this.text = text;
    }

    public String getText(){
        return text;
    }

    public String toString(){
        return getText();
    }
}

The Comment class is identical to Text except that its toString() method adds the character sequences that start and end an HTML comment:

// Defines a page element for holding an
// HTML comment.

package webscraper;

public class Comment extends Element {
    private String text;

    public Comment( String text ){
        this.text = text;
    }

    public String getText(){
        return text;
    }

    public String toString(){
        return "<!--" + getText() + "-->";
    }
}

The Tag class is more complicated because it needs to parse the contents of a tag, the parts between the "< and > characters, into a tag name and a set of attributes:

// Defines a page element for holding an HTML tag.
// The tag name and the attributes are stored
// separately, the latter using an instance of
// Attributes.

package webscraper;

public class Tag extends Element {
    private boolean    isEnd;
    private String     name = "";
    private Attributes attributes;

    // Create an HTML tag. Pass in the content of the
    // tag, i.e. for the tag "<body bgcolor=#ffffff>"
    // pass in "body bgcolor=#ffffff".

    public Tag( String tagContent ){
        tagContent = tagContent.trim();
        int len = tagContent.length();
        if( len > 0 ){
            int start = 0;
            if( tagContent.charAt( 0 ) == '/' ){
                isEnd = true;
                ++start;
            }
            while( start < len &&
                   tagContent.charAt( start ) <= ' ' ){
                ++start;
            }
            int end;
            for( end = start; end < len; ++end ){
                if( tagContent.charAt( end ) <= ' ' ) break;
            }
            name = tagContent.substring( start, end );
            if( end < len ){
                attributes = new Attributes(
                             tagContent.substring( end ) );
            }
        }
    }

    public Attributes getAttributes(){
        return attributes;
    }

    public String getName(){
        return name;
    }

    // Whether or not the tag is an end tag.

    public boolean isEndTag(){
        return isEnd;
    }

    public String toString(){
        StringBuffer buf = new StringBuffer();
        buf.append( '<' );
        if( isEnd ) buf.append( '/' );
        buf.append( name );
        if( attributes != null ){
            buf.append( ' ' );
            buf.append( attributes.toString() );
        }
        buf.append( '>' );
        return buf.toString();
    }
}

Tag uses a helper class to store the tag attributes. Oddly enough, Attributes is the most complicated of all these classes because HTML allows so much flexibility. This class does the attribute parsing in a lazy manner to conserve memory:

package webscraper;

import java.util.*;

// Defines a class for holding and parsing the
// attributes of an HTML tag. Note that the
// attributes are not parsed until they are
// actually needed.

public class Attributes {
    private String attrs;
    private String attrsLower;
    private Hashtable hashtable;

    // Pass in the attribute string from inside the
    // tag, i.e. if the tag is "<body bgcolor=#ffffff>"
    // pass in the " bgcolor=#ffffff" part.

    public Attributes( String attrs ){
        if( attrs == null ) attrs = "";
        this.attrs = attrs.trim();
        attrsLower = this.attrs.toLowerCase();
    }

    public boolean exists( String name ){
        return( get( name ) != null );
    }

    public String get( String name ){
        name = name.toLowerCase();

        // Delay the parsing by checking if the attribute
        // name is in the attribute set.

        if( hashtable == null ){
            if( attrsLower.indexOf( name ) == -1 ){
                return null;
            }

            parse();
        }

        return (String) hashtable.get( name );
    }

    // Parse the attributes. Unlike XML, HTML attributes
    // don't need a value and the value may or may not
    // be quoted, so parsing is tricky.

    private void parse(){
        Vector       tokens = new Vector();
        int          len = attrs.length();
        char         ch;
        char         delim = ' ';
        boolean      inWord = false;
        boolean      inString = false;
        StringBuffer buf = new StringBuffer( len );

        // Split the attribute string into tokens

        for( int i = 0; i <= len; ++i ){
            if( inWord ){
                ch = ( i < len ? attrs.charAt(i) : ' ' );
                if( ch <= ' ' || ch == '=' ){
                    if( buf.length() > 0 ){
                        tokens.addElement( buf.toString() );
                        buf.setLength( 0 );
                    }
                    
                    if( ch == '=' ){
                        tokens.addElement( "=" );
                    }

                    inWord = false;
                } else {
                    buf.append( ch );
                }
            } else if( inString ){
                ch = ( i < len ? attrs.charAt(i) : delim );
                if( ch == delim ){
                    tokens.addElement( buf.toString() );
                    buf.setLength( 0 );
                    inString = false;
                } else {
                    buf.append( ch );
                }
            } else {
                ch = ( i < len ? attrs.charAt(i) : ' ' );
                if( ch == '\'' || ch == '"' ){
                    delim = ch;
                    inString = true;
                } else if( ch > ' ' ){
                    buf.append( ch );
                    inWord = true;
                }
            }
        }

        // Now store the attributes as name-value pairs
        // in a hashtable. If an attribute does not have
        // a value, the empty string is used as its value.

        hashtable = new Hashtable();
        int tlen = tokens.size();
        String name = null;
        boolean nextIsValue = false;
        for( int i = 0; i < tlen; ++i ){
            String tok = (String) tokens.elementAt( i );
            if( nextIsValue ){
                hashtable.put( name, tok );
                name = null;
                nextIsValue = false;
            } else if( name == null ){
                name = tok.toLowerCase();
            } else if( !tok.equals( "=" ) ){
                hashtable.put( name, "" );
                name = tok.toLowerCase();
            } else {
                nextIsValue = true;
            }
        }

        if( name != null ){
            hashtable.put( name, "" );
        }
    }

    public String toString(){
        return attrs;
    }
}

With these classes in place you can now build a general-purpose HTML parsing class. PageScraper splits an input stream into a set of page elements:

package webscraper;

import java.io.*;
import java.util.*;

// Parse an input stream into page elements.

public class PageScraper {
    private Reader reader;

    // These variables implement a simple lookahead

    private int    first;
    private int    second = -1;
    private int    third = -1;
    private int    fourth = -1;

    // Convenience method for parsing a string.

    public PageScraper( String text ) throws IOException {
        this( new ByteArrayInputStream( text.getBytes() ) );
    }

    // Parse an input stream.

    public PageScraper( InputStream in ) throws IOException {
        reader = new InputStreamReader( in );
        first = reader.read();
        if( first != -1 ) second = reader.read();
        if( second != -1 ) third = reader.read();
        if( third != -1 ) fourth = reader.read();
    }

    // Advance to the next character in the stream.

    private void next() throws IOException {
        if( first != -1 ){
            first = second;
            second = third;
            third = fourth;
            fourth = reader.read();
        }
    }

    // Advance n characters into the stream.

    private void next( int n ) throws IOException {
        while( n-- > 0 ){
            next();
        }
    }

    // Returns the next page element. Use the instanceof
    // operator to determine if it's a Tag, Comment, or
    // Text.

    public Element readElement() throws IOException {
        StringBuffer buf = new StringBuffer();
        boolean      inTag = false;
        boolean      inComment = false;

        while( first != -1 ){
            if( inTag ){
                if( first == '>' ){
                    next();
                    break;
                }
            } else if( inComment ){
                if( first == '-' && second == '-' &&
                    third == '>' ){
                    next( 3 );
                    break;
                }
            } else if( first == '<' ){
                if( buf.length() > 0 ) break;

                if( second == '!' && third == '-' &&
                    fourth == '-' ){
                    inComment = true;
                    next( 4 );
                    continue;
                } else {
                    inTag = true;
                    next();
                    continue;
                }
            }

            buf.append( (char) first );
            next();
        }

        String content = buf.toString();

        if( inTag ){
            return new Tag( content );
        } else if( inComment ){
            return new Comment( content );
        } else if( content.length() > 0 ||
                   first != -1 ){
            return new Text( content );
        } else {
            return null;
        }
    }
}

The parsing is done incrementally, by invoking readElement() to get the next page element. For example, this code...

...
try {
    String html = "<!-- a page --><HTML>\n" +
                  "<body bgcolor=#FFFFFF>" +
                  "<P>Hah!\n" +
                  "</body></html>";

    PageScraper sc = new PageScraper( html );
    Element e;
    while( ( e = sc.readElement() ) != null ){
        System.out.println( e.getClass().getName() + ": " +
                            e.toString() );
    }
}
catch( java.io.IOException ioe ){
}
...

...produces the following output on the console:

Comment: <!-- a page -->
Tag: <HTML>
Text: 

Tag: <body bgcolor=#FFFFFF>
Tag: <P>
Text: Hah!

Tag: </body>
Tag: </html>

You're almost ready to start parsing some web pages. All you need now is the ability to make an HTTP request and get a web page as an input stream. How you do this depends on how you structure the application. In the ideal scenario your MIDlet delegates the parsing to a servlet, thereby offloading most of its work to an external machine. The MIDlet sends a command to the servlet, perhaps a request for a stock quote:

...
HttpConnection conn;
String url = "http://www.mywebserver.com/quote/mostrecent";

conn = Connector.open( url + "?tag=SUN" );
...

Here's an example of how you could implement such a servlet; Controller parses Yahoo's free quote service:

package quote;

import webscraper.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * A simple example of a servlet that responds to an input
 * stream sent to it by a MIDP client.
 */

public class Controller extends HttpServlet {
    private static final String QuoteURL =
                       "http://finance.yahoo.com/q?s=";

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

      String tag = request.getParameter( "tag" );
      Double val = null;

      if( tag != null ){
        InputStream is = null;

        try {
          is = new URL( QuoteURL + tag ).openStream();
          PageScraper page = new PageScraper( is );
          boolean foundFont = false;
          boolean foundBold = false;

          while( true ){
             Element e = page.readElement();
             if( e == null ) break;

             if( foundFont && foundBold ){
                 foundFont = false;
                 foundBold = false;

                 if( e instanceof Text ){
                     String num = e.toString();
                     try {
                         val = Double.valueOf( num );
                         break;
                     }
                     catch( NumberFormatException nfe ){
                     }
                 }
             } else if( foundFont ){
                 if( e instanceof Tag ){
                    Tag t = (Tag) e;
                    if( t.getName().equalsIgnoreCase( "b" ) ){
                        foundBold = true;
                    }
                 } else {
                    foundFont = false;
                  }
              } else if( e instanceof Tag ){
                  Tag t = (Tag) e;
                  if( t.getName().equalsIgnoreCase( "font" )){
                      foundFont = true;
                  }
              }
           }
       }
       catch( IOException e ){
           System.out.println( "Exception " + e );
       }
       finally {
           if( is != null ){ is.close(); }
       }
    }

    // Set the response headers and data...
    String send = ( val != null ? val.toString() : "error" );

    response.setContentType( "text/plain" );
    response.setContentLength( send.length() );
    response.setStatus( response.SC_OK );
    PrintStream out = 
            new PrintStream( response.getOutputStream() );
    out.print( send.toString() );
    out.close();
  }
}

Note that this servlet looks for the pattern <font><b>number, which is not a very robust test. A full implementation would check for more.

If the application is unable to use a servlet as a proxy, it can still connect to a web server and parse the page itself. You use MIDP's HttpConnection class, of course, and define a PageLoader class to hide all the boring details:

import java.io.*;
import javax.microedition.io.*;

// A helper class that manages the HTTP connection for
// loading a page. Uses the HttpConnectionHelper class
// to automatically handle redirects.

public class PageLoader
             implements HttpConnectionHelper.Callback {
    private HttpConnection conn;
    private InputStream    in;
    private Throwable      error;
    private int            rc;

    public PageLoader(){
    }

    // Call close when done with the page.

    public synchronized void close(){
        if( in != null ){
            try { in.close(); } catch( Exception e ){}
            in = null;
        }

        if( conn != null ){
            try { conn.close(); } catch( Exception e ){}
            conn = null;
        }

        error = null;
    }

    public HttpConnection getConnection() { return conn; }

    public Throwable getException() { return error; }

    public InputStream getInputStream() { return in; }

    public int getResponseCode() { return rc; }

    // Loads the page by forming the HTTP request. Returns
    // true if HTTP_OK is returned, false if any other
    // response code is returned or an exception occurs.

    public synchronized boolean loadPage( String url ){
        close();

        try {
            conn = HttpConnectionHelper.connect( url, this );
            rc = conn.getResponseCode();

            if( rc == HttpConnection.HTTP_OK ){
                in = conn.openInputStream();
            }
        }
        catch( Throwable e ){
            error = e;
        }

        return ( in != null );
    }

    // The callback for the HttpConnectionHelper that sets
    // up the connection properties for a new HttpConnection
    // object.

    public void prepareRequest( String originalURL,
                   HttpConnection conn ) throws IOException
    {
        conn.setRequestMethod( HttpConnection.GET );
        conn.setRequestProperty( "User-Agent",
               "Profile/MIDP-1.0 Configuration/CLDC-1.0" );
        conn.setRequestProperty( "Content-Language",
                                 "en-US" );
        conn.setRequestProperty( "Accept", "text/html" );
        conn.setRequestProperty( "Accept-Charset",
                                 "iso-8859-1" );
        conn.setRequestProperty( "connection", "close" );
    }
}

Note that PageLoader uses the HttpConnectionHelper class defined in a previous J2ME Tech Tip, "Making HTTP Connections with MIDP," to handle automatically the HTTP redirections that occur often on major web sites.

Finally, you define a MIDlet that uses all these classes. This particular MIDlet first prompts the user for a URL (defaulting to http://wireless.java.sun.com as an example), loads the page, then parses and displays all the <meta> tags it finds on the page:

import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import webscraper.*;

// A MIDlet that uses the PageLoader and PageScraper
// classes to extract all the META tags from the
// start of an arbitrary page. The use is prompted
// for a URL, the page is loaded and parsed, and the
// tag values are displayed in a list.

public class ScraperTest extends MIDlet
                 implements CommandListener,
                            Runnable {

    private Display         display;
    private PageLoader      loader = new PageLoader();
    private String          url =
                        "http://wireless.java.sun.com";

    public static final Command exitCommand =
                         new Command( "Exit",
                                      Command.EXIT, 1 ); 
    public static final Command okCommand =
                         new Command( "OK",
                                      Command.OK, 1 );

    public ScraperTest(){
    }

    // Process commands. If the OK command is invoked,
    // need to determine which screen was active.

    public void commandAction( Command c,
                               Displayable d ){
        if( c == exitCommand ){
            exitMIDlet();
        } else if( c == okCommand &&
                   d instanceof Prompter ){
            // Start the page loading....
            url = ((Prompter) d).getString();
            if( url.indexOf( "://" ) == -1 ){
                url = "http://"+ url;
            }
            display.setCurrent( new Wait() );
        } else if( c == okCommand &&
                   d instanceof Lister ){
            display.setCurrent( new Prompter() );
        }
    }

    protected void destroyApp( boolean unconditional )
                       throws MIDletStateChangeException {
        exitMIDlet();
    }

    // Displays an error message using an alert.

    private void error( String title, String msg,
                        Throwable e ){
        Alert a = new Alert( title );
        if( msg == null && e != null ){
            msg = "Exception: ";
        }
        a.setString( msg +
                ( e != null ? e.toString() : "" ) );
        a.setType( AlertType.ERROR );
        display.setCurrent( a, new Prompter() );
    }

    public void exitMIDlet(){
        notifyDestroyed();
    }

    public Display getDisplay(){ return display; }

    // Start by prompting the user...

    protected void initMIDlet(){
        display.setCurrent( new Prompter() );
    }

    protected void pauseApp(){
    }

    // Does the actual parsing. Invoked indirectly by
    // the wait screen using display.callSerially.
    // Loads the page and then parses it for the META
    // tags.

    public void run(){
        if( loader.loadPage( url ) ){
            Wait w = (Wait) display.getCurrent();
            w.update( "Parsing..." );
            try {
                PageScraper sc = new
                       PageScraper( loader.getInputStream() );
                Element e;
                Lister list = new Lister();
                while( ( e = sc.readElement() ) != null ){
                    if( !( e instanceof Tag ) ) continue;
                    Tag t = (Tag) e;
                    String name = t.getName();

                    if( t.isEndTag() ){
                        if( name.equals( "head" ) ){
                            break;
                        }
                    } else {
                        if( name.equals( "meta" ) ){
                            list.append( t.toString(), null );
                        } else if( name.equals( "body" ) ){
                            break;
                        }
                    }
                }

                loader.close();
                display.setCurrent( list );
            }
            catch( Exception e ){
                error( "Parsing error", null, e );
            }
        } else {
            Throwable e = loader.getException();
            String msg = null;
            if( e == null ){
                msg = "HTTP status code " +
                      loader.getResponseCode();
            }
            loader.close();
            error( "Cannot load page", msg, e );
        }
    }

    protected void startApp()
                      throws MIDletStateChangeException {
        if( display == null ){ 
            display = Display.getDisplay( this );
            initMIDlet();
        }
    }

    // A simple class that prompts for a URL.

    class Prompter extends TextBox {
        Prompter(){
            super( "Enter a URL:", url,
                   200, 0 );
            addCommand( okCommand );
            addCommand( exitCommand );
            setCommandListener( ScraperTest.this );
        }
    }

    // Displays our list of tags. The tags are
    // added to the list in the run method.

    class Lister extends List {
        Lister(){
            super( "Meta tags:", List.IMPLICIT );
            addCommand( okCommand );
            setCommandListener( ScraperTest.this );
        }
    }

    // Asks the user to the wait while a lengthy
    // operation takes place. The operation does not
    // start until the canvas has been painted once,
    // at which point display.callSerially is invoked
    // to start it.

    class Wait extends Canvas {
        boolean called = false;
        String  msg = "Connecting...";

        // Draw the message on screen.... fancier code
        // would center and wrap the text...

        protected void paint( Graphics g ){
            g.setColor( 255, 255, 255 );
            g.fillRect( 0, 0, getWidth(), getHeight() );
            g.setColor( 0, 0, 0 );
            g.drawString( msg, 0, 0,
                          Graphics.TOP | Graphics.LEFT );

            if( !called ){
                display.callSerially( ScraperTest.this );
                called = true;
            }
        }

        // Update the string and immediately repaint
        // the screen.

        public void update( String newMsg ){
            msg = newMsg;
            repaint( 0, 0, getWidth(), getHeight() );
            serviceRepaints();
        }
    }
}

This MIDlet also demonstrates the use of the Display.callSerially() method to ensure that an operation is performed after a Canvas has had a chance to paint itself.

It would be better practice, however, to do the page loading and parsing on a separate thread, using the techniques shown in "Making HTTP Connections Using Background Threads." Otherwise, the user interface will be unresponsive during the network communication.

Pixel
Pixel

Over-the-Air Provisioning with the J2ME Wireless Toolkit

by Eric Giguere
March 04, 2003

The complete application development cycle for the Mobile Information Device Profile (MIDP) environment involves more than just coding and debugging your applications. It's also vital to deploy your application in a way that makes it easy for a user to download and install it, in a process called provisioning. If your application is hard to acquire and install, it won't be a success.

While developers are comfortable with using a serial or USB connection to download applications to a wireless device, most users don't have the equipment or the skills to do the same. Users want to download applications wirelessly, the same way they send and receive messages or browse the Internet. This ability is referred to as over-the-air user-initiated provisioning, OTA for short.

OTA for MIDP devices was first described in an addendum to the MIDP 1.0 specification, although technically it was not part of the specification itself but just a recommendation by the MIDP 1.0 expert group. This addendum was revised and formally incorporated into the MIDP 2.0 specification. To be MIDP 2.0-compliant, devices must support OTA provisioning, so now is the time to make sure your MIDlets are properly packaged for wireless installation.

The easiest way is to use the J2ME Wireless Toolkit, which incorporates a small provisioning server that emulates a production OTA environment. Available in version 2.0 Beta 2 and later versions of the toolkit, this nice feature enables you to get an idea of whether a server will provision a device with your application successfully without the hassle of setting up and configuring a local web server to act as an OTA server. Some MIDP 2.0 features - like the push registry - are available only to applications downloaded via OTA. If your application uses those features, the built-in OTA server is a critical tool of the development process.

To use the OTA server, start the KToolbar application and open an existing project such as the demos project that ships with the toolkit. Instead of clicking the Run button on the toolbar, choose the Project menu, then the Run via OTA item. The emulator starts, but does not immediately open the MIDlet suite to let you select which MIDlet to launch. Instead, the emulator launches its application management software (AMS), the system software that manages the installation and removal of MIDlet suites. At the same time, KToolbar activates its built-in OTA server. Click the Apps button on the emulator to activate the AMS.

The AMS's main screen lists MIDlet suites already installed - there will be none the first time you run it, of course. At the top of the list is an item labeled Install Application. Select this item, click the Menu button, and choose Launch from the menu to start the application installer. The installer prompts you for the URL of an HTML file containing a link to the MIDlet suite's Java? application descriptor (JAD). KToolbar automatically generates this HTML file for you, placing it in the project's bin directory, and initializes the installer with its URL, which will look like this:

http://localhost:1364/demos/bin/demos.html

The first part of the URL is the address of KToolbar's OTA server, which is really just a stripped-down web server. The URL may differ from this example. The installer doesn't care what it's connecting to - you can change the URL if you want to test the installation process from an actual web server, for example.

Click the Menu button and select Go to start the installation process. The installer fetches the HTML file and parses it, looking for links ending in .jad, the standard extension for JAD files. If there are multiple links, it prompts you to choose the one you want. The installer then downloads the JAD file, displays the MIDlet suite's size, version, and vendor, and asks you to approve installation of the suite.

Once you confirm you want to proceed, the installer fetches the suite's JAR file. The JAR file's location comes from the MIDlet-Jar-URL property in the descriptor. By default, this value is a relative URL like demos.jar, although when you actually deploy your own application you must change this to the absolute URL of the provisioning web server; for example, http://www.mycompany.com/downloads/demos.jar. After downloading the JAR file, the installer verifies the contents of the MIDlet suite, prompting the user to confirm any permissions the suite requires in order to run. After the verification process is complete, the application is installed and is ready to run.

The J2ME Wireless Toolkit simplifies OTA testing, but eventually you'll need to test provisioning of actual devices from an actual web server. You'll need to deploy your application on a public server, one that is accessible to the general Internet population, and the server will need to be configured with the following MIME type mappings: the .jad file extension must map to the text/vnd.sun.j2me.app-descriptor type and the .jar extension to the application/java-archive type. Note that versions 4.0 and higher of the Tomcat server already include these mappings in their conf/web.xml files.

Once the server is properly configured, place the application descriptor and the MIDlet suite on the server and create an HTML page with a link to the JAD. You may also need to create an equivalent WML or XHTML page for microbrowser users - some devices may allow OTA provisioning to be initiated directly from a microbrowser instead of indirectly, through the AMS.

Before attempting to install the application on your device, however, test it with the toolkit's emulator. You can launch the emulator in provisioning mode directly, by using the OTA Provisioning item in the J2ME Wireless Toolkit 2.0 folder. Then follow the steps described above, supplying the appropriate URL. Once you've verified that things are working in the emulator, try it on an actual device.

Pixel
Pixel

About the Author:

Eric Giguere is a software developer for iAnywhere Solutions, a subsidiary of Sybase, where he works on Java technologies for handheld and wireless computing. He holds BMath and MMath degrees in Computer Science from the University of Waterloo and has written extensively on computing topics.

Pixel
Pixel

Was this Newsletter helpful?
  Very Helpful
  Helpful
  No Value
    Comments:

Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Wireless Technologies Newsletter to: wd-webmaster@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allttips/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.

Sun, Sun Microsystems, Java, Java Developer Connection, J2ME, JAIN, and PersonalJava are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
pixel
pixel
Please unsubscribe me from this newsletter.
From env_317759981096911725@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Mar 11 17:19:04 2003 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h2BMJ4C18124 for ; Tue, 11 Mar 2003 17:19:04 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.8/8.12.8/IUPO) with SMTP id h2BMLwuc026970 for ; Tue, 11 Mar 2003 17:21:58 -0500 (EST) Date: 11 Mar 2003 14:10:50 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <317759981096911725@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, March 11, 2003 (Changing JAXP Parser Classes, Using JMS Queues) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 32601 Enterprise Java Technologies Tech Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text March 11, 2003    

In this Issue

Welcome to the Enterprise JavaTM Technologies Tech Tips, for March 11, 2003. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EETM).

This issue covers:

.Changing the JAXP Parser Classes
.Using JMS Queues

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample code for the Using JMS Queues tips. Any use of this code and/or information below is subject to the license terms.

.

Changing the JAXP Parser Classes

The February 11, 2003 issue of the Enterprise Java Technologies Tech Tips contained a tip that explained how to use the Java API for XML Processing (JAXP). The tip mentioned that JAXP is vendor-neutral. It also showed how to use JAXP's built-in set of interfaces to create and configure XML parsers in J2EE applications. This tip extends that discussion by explaining what vendor-neutral means in JAXP, and how to change the parsers that JAXP configures and constructs.

If you look closely at the JAXP interfaces in standard extension package javax.xml.parsers, you'll notice that the classes are all marked "abstract". This is because the parsers and parser factories are implemented by classes outside of the package. JAXP's vendor independence comes from this separation. The abstract classes DocumentBuilderFactory and SAXParserFactory each implement one method: newInstance. This method creates a new instance of the factory class. The package is vendor-neutral because the newInstance method looks in several places for the name of a class that fully implements the abstract factory interface.

JAXP comes pre-configured to use a default set of classes for parsers and parser factories. Which class is used depends on the application server vendor. To change the parser used by an application, you need to tell JAXP the fully-qualified class name of the parser factory (SAXParserFactory or DocumentBuilderFactory) to use. There are three ways to do this:

  • Set a system property. The system property javax.xml.parsers.SAXParserFactory can be set to the fully-qualified class name of your alternative SAX parser factory. The system property javax.xml.parsers.DocumentBuilderFactory can be set to the class name of the alternative DOM parser factory. System properties are set when the application server starts. See your application server's documentation for details. For the J2EE Reference Implementation, you can simply set the system property on the command line using the -D option.

  • Specify classes in the file $JAVA_HOME/lib/jaxp.properties. You can set the same two properties (javax.xml.parsers.SAXParserFactory and javax.xml.parsers.DocumentBuilderFactory) using standard properties notation in a file called jaxp.properties in the lib directory of your J2EE platform main directory. For example, here are two lines the the files that identify classes for alternative SAX and DOM parsers:

    javax.xml.parsers.SAXParserFactory=com.myco.parsers.MySAXFactory
    javax.xml.parsers.DocumentBuilderFactory=com.myco.parsers.MyDOMFactory

  • Specify the classes as an entry in the services directory of a JAR file. The JAR file specification defines a directory called META-INF/services that JAXP checks to find definitions of parser factories. JAXP uses the fully-qualified class names found in the files META-INF/services/javax.xml.parsers.SAXParserFactory and META-INF/services/javax.xml.parsers.DocumentBuilderFactory as the parser factory classes, if those files exist.

Why not just specify the application in a deployment descriptor? The most obvious reason is that deployment descriptors are XML files. It would be difficult to get the XML parser name without first parsing the XML file! The second reason is that not all J2EE technologies use deployment descriptors. For example, the JMS sample program in the next tip, Using JMS Queues, uses J2EE technology, but no deployment information is required. The techniques described above for changing the parser used by an application, can be used in any application deployment scenario.

For further information about JAXP, see the JAXP Tutorial.

.
.

Using JMS Queues

The Java Messaging Service (JMS) is a vendor-neutral set of APIs for reliable messaging between programs. In client-server computing, a client program contacts a server and requests a service. By contrast, messaging applications send messages between cooperating programs. Some programs (in so-called "peer-to-peer applications") exchange messages directly with one another (JXTA uses this model).

Examples of these two types of networking appear in the following figure.

figure 1

JMS provides a middleware message broker that provides reliable, transactional message delivery between programs.

The following figure illustrates point-to-point messaging, the type of message delivery covered in this tip.

figure 2

Although these figures show the message producers and consumers as physical machines, they can also be cooperating processes running on one or many machines.

A JMS provider is a program that implements the JMS service contracts in terms of the JMS public interfaces. The J2EE platform specification requires that platform implementations include a JMS provider.

Most people are familiar with the client-server model of messaging, where a client program contacts a server and requests a service, data, or both. The client then receives a reply, usually synchronously. By contrast, JMS provides a richer messaging model with the following high-level features:

  • Reliable message delivery. A message receiver does not have to be running when the sender sends the message. The next time the receiver is available, the message is delivered.

  • Point-to-point or publish/subscribe messaging models. Message transmission may be one-to-one or one-to-many.

  • Transactions. Message delivery can be made part of a distributed transaction.

  • Synchronous or asynchronous delivery. A message producer may or may not wait for an acknowledgement from the receiver.

  • Object-oriented messaging. Rather than sending structured data using protocols, JMS allows objects to be sent between clients.

  • Legacy integration. JMS is designed to integrate with underlying third-party messaging systems.

The tip explains how to use JMS message queues to implement simple, reliable point-to-point messaging between two processes. Publish/subscribe messaging will be covered in a later edition of the Enterprise Java Technologies Tech Tips.

JMS Queue Terminology

JMS uses the concept of a message queue to implement point-to-point messaging. In point-to-point messaging, there is always exactly one message producer and one message consumer. Unless the sender defines a timeout for the message, there is no time dependence in point-to-point messaging. A message consumer can receive a message sent at any time in the past by a message producer, even if the consumer wasn't running when the message was queued.

The following figure shows a point-to-point messaging scenario.

figure 3

The JMS provider is a messaging server that handles message persistence, timeout, redelivery, transaction rollbacks, and other services provided by JMS. In the case of the J2EE SDK, the JMS provider is part of the j2ee server program. A message producer sends objects to a queue that is maintained by the JMS server. A message consumer receives messages from the queue and acknowledges their receipt.

The JMS specification defines several types of objects used to send messages between processes:

  • JMS administered objects. There are are two kinds of JMS administered objects: destinations and connection factories. Both are created by a system administrator using environment management tools.

  • Destination. This is a server-side object through which messages may be sent and received. A JMS Queue is one type of destination.

  • Connection factory. This is a server-side object that configures and creates a connection to a specific destination. A JMS connection factory for a JMS Queue is of type QueueConnectionFactory.

  • Connection. This is a virtual connection to a JMS provider (not to a destination). It is used to create sessions. A connection for accessing queues is of type QueueConnection.

  • Session. This is a potentially transactional work unit of message transmission and receipt. A session is used to create messages, message producers, and message consumers. A session used to access queues is of type QueueSession.

  • Message. This is an object that can be sent through a message destination to a message consumer. Message types vary by the sort of object being sent. For example, the sample code provided for this tip uses TextMessage objects.

  • Message producer. This is an object used by a JMS client program to send a message to a destination. The program acquires the message producer object from a session. A program can send Messages to a Queue using a message producer of type QueueSender.

  • Message consumer. This is an object used by a JMS client program to receive messages from a destination. The program acquires the message receiver object from a session. A program can receive Messages from a Queue using a message consumer of type QueueReceiver.

That's quite a few new terms. Now let's look at how to send a message. The steps below show examples taken from the sample code provided with this tip. (See the section Running the Sample Code for instructions on how to download and run the sample code.) However, before you run the sample code, you need to configure the server (see the Configuring the Server section).

Sending Messages

The J2EE Reference Implementation comes pre-configured with a queue connection factory (called QueueConnectionFactory) and a queue (called jms/Queue). If you are using a JMS server other than the Reference Implementation, or if you want to experiment with changing the names of the connection queue factory and/or the queue, see the section Configuring the Server.

Here are the steps in sending a Message through a JMS queue. Code snippets from the sample program, TestQueue, illustrate the steps.

  1. Get a reference to a QueueConnectionFactory by looking it up by name with JNDI:
    protected static String qfactoryName =
       "jms/queue/TechTipsQueueConnectionFactory";
    ...
    try {
    // Get JNDI context
    InitialContext ctx = new InitialContext();
    // Get connection factory 
    QueueConnectionFactory qcf =
       (QueueConnectionFactory)ctx.lookup(qfactoryName);
    
  2. Get a QueueConnection from the QueueConnectionFactory, and get a QueueSession from the connection. Look up the queue by name in JNDI:
     // Get a connection to the queue
     qc = qcf.createQueueConnection();
     // Get a session from the connection
     QueueSession qs = qc.createQueueSession(
         false, Session.AUTO_ACKNOWLEDGE);
    // Get a queue
    Queue q = (Queue)ctx.lookup(queueName);
    
  3. Use the QueueSession to create a QueueSender, passing the Queue as an argument. (The QueueSender is an association between a QueueSession and a particular queue.):
    // Use the session to create a QueueSender 
    // and a TextMessage.
    QueueSender qsnd = qs.createSender(q);
    

    The QueueSender can now be used to send messages to the Queue.

  4. Create Message objects (subclasses of type Message), and use the QueueSender's send method to send them to the destination. The sample program acquires a TextMessage object from the Session. It then packages each of the program arguments into the TextMessage, and sends it to the queue using the QueueSender. Notice that the same TextMessage can be used multiple times.
    TextMessage tm = qs.createTextMessage();
    
    // For each argument (after the first), 
    // send the argument string as a text message.
    for (int i = 2; i < args.length; i++) {
        tm.setText(args[i]);
        qsnd.send(tm);
    }
    
  5. Close the QueueConnection. It's good practice to close the connection in the finally clause of a try/finally block. This step is important: forgetting to close QueueConnections can cause resource leaks on the server:
    } finally {
        if (qc != null) {
            qc.close();
        }
    }
    

    To send a message to a message queue, use the TestQueue program (in the default package) with the argument "send", for example:

    $ java TestQueue send jms/queue/MyTestQueue a b c d
    Java(TM) Message Service 1.0.2 Reference 
    Implementation (build b14)
    Sent: 'a'
    Sent: 'b'
    Sent: 'c'
    Sent: 'd'
    

Receiving Messages

The TestQueue program follows these steps for receiving a message:

  1. and 2. The first two steps of receiving a message from a queue are identical to those for sending: look up the connection factory, get a QueueConnection and QueueSession, and look up the Queue.


  2. Get a QueueReceiver from the QueueSession:
    QueueReceiver qrcv = qs.createReceiver(q);
    
  3. Receive the message from the Queue. The sample program enters a loop where it receives messages from the queue and prints them to standard output.
    qc.start();
    Message m = qrcv.receive(10000);
    while (m != null) {
        if (m instanceof TextMessage) {
            TextMessage tm = (TextMessage)m;
            System.out.println("Received text: '" +
                               tm.getText() + "'");
        } else {
            System.out.println("Received a " +
                            m.getClass().getName());
        }
        m = qrcv.receive(100);
    } finally {
       if (qc != null) {
           qc.close();
        }
    }
    

    The call to the QueueConnection's start method tells the connection to begin receiving messages. The QueueReceiver receive method takes an argument of the number of milliseconds to wait for a message to arrive. If no message is delivered within the timeout value, the method returns null. The program reads and prints received messages until the message queue remains empty for 100 milliseconds. A finally clause at the end of the try/finally block closes the QueueConnection as in the previous example.

To receive the messages in the message queue, use the TestQueue program with the argument "recv", for example:

$ java TestQueue recv jms/queue/MyTestQueue
Java(TM) Message Service 1.0.2 Reference 
Implementation (build b14)
Received text: 'a'
Received text: 'b'
Received text: 'c'
Received text: 'd'

Configuring the Server

If you are not using the Reference Implementation, or if you want to change the queue and/or queue connection factory names, you need to configure the JMS provider using the platform's administration tools. After a queue or connection factory is created, it remains in the server installation, and survives server restarts. Some platform implementations might provide extension APIs for clients to create destinations and connection factories programmatically.

The tool for creating administered objects in the J2EE SDK is j2eeadmin. To configure the server:

  1. Start the application server.
  2. Create a message queue, giving it a JNDI name. (Do this only once.) To create a new message queue in the J2EE SDK, first decide on a name for your message queue. It can be convenient for administration purposes to choose a name that indicates that the queue is used by JMS, for example, jms/MyTestQueue. Then execute the command:
    j2eeadmin -addJmsDestination <queuename> queue
       
    Replace <queuename> with the actual name of the message queue.
    
  3. The connection factory name QueueConnectionFactory is hard-wired into the sample program, so to tell the program to use a different connection factory name, you have to change the source code and recompile. For example, in TestQueue.java:
    // Change this variable's value to change the 
    // connection factory name
    protected static String qfactoryName =
        "QueueConnectionFactory"
    

    After you recompile, use j2eeadmin (or your server's tool) to create a connection factory, giving it a JNDI name, like this:

    j2eeadmin -addJmsFactory jms/MyQueueConnectionFactory
    

    To list connection factories, use:

    j2eeadmin -listJmsFactory
    

    and to list destinations, use:

    j2eeadmin -listJmsDestination
    

For a platforms other than the J2EE SDK, use your J2EE product's deployment tools to create the required message queue and connection factory on your platform.

Running the Sample Code

Download the sample archive for these tips. The JAR file contains the complete source code for the sample program, both as a Java program file and formatted as HTML. You can use the command jar xvf ttmar2003.jar to extract the contents of the sample jar into your working directory. Be sure the J2EE server is running before running the sample program.

Run the sample program several times. Try sending several batches of messages without receiving, and examine the order of the output.

The sample program provides a starting place for you to experiment with JMS queues. Explore the APIs of the JMS interfaces used. For example, change the program to use the three different forms of receive. Explore transactional message delivery, or try sending Message objects of various types. JMS has many features, and using it skillfully can improve your application designs.

For further information about JMS, see the Java Message Service Tutorial.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA.

This document is protected by copyright.

Enterprise Java Technologies Tech Tips
March 11, 2003


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_323184791421113265@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Mon Mar 24 13:47:57 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h2OIlvC26231 for ; Mon, 24 Mar 2003 13:47:57 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.8/8.12.8/IUPO) with SMTP id h2OIp4od029527 for ; Mon, 24 Mar 2003 13:51:04 -0500 (EST) Date: 24 Mar 2003 10:38:42 -0800 From: "Wireless Developer Newsletter" To: gcf@indiana.edu Message-Id: <323184791421113265@hermes.sun.com> Subject: Wireless Developer Newsletter March 24, 2003 Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 18068 Wireless Developer Newsletter: March 24, 2003

Welcome to the Wireless Developer Newsletter, to which you subscribed. Here you'll find links to the latest wireless technologies and products, learn about resources for wireless developers, get the latest wireless news, and more.

What would you like to see on the site? Have an idea for a Tech Tip? What would you like to see in Java Live! Chats? Use the feedback form at the end of this newsletter to send us your comments.


Product and Technology Releases

Several wireless products and technologies were recently released:

JSR 75: PDA Optional Packages for the J2ME Platform Proposed Final Draft (March 4)
This JSR will produce optional packages for features that are commonly found on PDAs and other mobile devices in the J2ME space: one package for Personal Information Management (PIM) access, and one package for accessing file systems through the Generic Connection Framework (GCF).

JSR 124: J2EE Client Provisioning Specification Proposed Final Draft (March 4)
This JSR aims to define a Java standard that partitions server applications that provision client applications in such a way that the details of any one client provisioning model are abstracted and standardized.

JSR 172: J2ME Web Services Specification Public Review
The purpose of this specification is to define an optional package that provides standard access from J2ME to web services.


Hot Downloads

Currently the most frequently downloaded wireless products and technologies are:

Java 2 Platform Micro Edition, Wireless Toolkit 2.0 Beta 2

Java 2 Platform Micro Edition, Wireless Toolkit 1.0.4

MIDP for Palm OS 1.0

MIDP for Palm OS 1.0 Documentation

Java Card 2.2 Development Kit


Events

CeBIT:
Hannover, Germany, March 12-19

Sun Tech Days:
Bangalore, India, March 21-22

Motocoder Entertainment Workshop:
London, England, April 15-16


Java User Groups (JUGs)

There are over 900 established Java User Groups worldwide. Find one near you at this url:
http://servlet.java.sun.com/jugs


.
. . .
March 24, 2003

Resources

. .

Learn more about wireless products and technologies through the following resources:

  • J2EE Web services sample application for Sun ONE Application Server and Sun ONE Studio
    The sample application has been designed to introduce the features of Sun ONE Application Server 7 and to demonstrate the use of the Java API for XML-based RPC (JAX-RPC) to implement Web services. It comes with full source code and documentation, so you can experiment with the Sun ONE products and tools, and learn how to use them effectively to build your own enterprise solutions.

  • Featured Question: When I click on the Run button in the J2ME Wireless Toolkit, it uses the package I've just created, right?

  • J2ME Tech Tip: Scraping HTML Pages for Content with MIDP
    On occasion, you may wish to extract information from a page of HTML on a web site, in a procedure commonly called "page scraping." The code presented here parses an HTML page inside a servlet or directly from a Mobile Information Device Profile (MIDP) application.

  • J2ME Tech Tip: OTA Provisioning with the J2ME Wireless Toolkit
    This tech tip shows how to use "Run via OTA" feature in the J2ME Wireless Toolkit version 2.0 to test the deployment of MIDlets in an over-the-air provisioning environment.

  • Go To Market: New Developer Program Guide
    New guide from Softwired AG added this month.

  • JDC Chat: J2ME Web Services, March 25
    Jon Ellis, Mark Young, and Enrique Ortiz discuss J2ME Web Services
    March 25, 11:00 A.M. PST/7:00 P.M. GMT

  • Articles: Read the following new articles on the Wireless Developer site:

    • Future Java Technology for the Wireless Services Industry This article provides an overview of the JSRs related to the CLDC and the MIDP now under way, and provides an eye-opener to wireless Java developers who want to know what the future of wireless Java technology holds.

    • The JDBC Optional Package for CDC-Based J2ME Applications This article presents an overview of JDBC optional packages and shows where they fit in the J2ME architecture, and then explores the JDBC optional package in more detail, comparing and contrasting it with JDBC 3.0.

    • SMS - Short but Sweet This article presents an overview of Short Message Service (SMS), which is an out-of-band packet-delivery and low-bandwidth message-transfer technology.

    • An Overview of JSR 124: J2EE Client Provisioning This article provides an overview of J2EE Client Provisioning. Often referred to as vending machines, provisioning portals provide an easy, centralized mechanism for deploying applications to a variety of client platforms.

    • Using Threads in J2ME Applications This article describes the basic understanding of how to use threads for effective J2ME applications.

Industry News

  • Sun Announces Telecom Service Delivery Framework (March 17)
    Sun Microsystems unveiled its next-generation Telecom Service Delivery Framework, designed to allow network equipment providers, carriers, and service providers to deliver innovative services like messaging, m-Commerce, location-based services, games and pictures, to consumers and enterprises quickly and more profitably. Sun is redefining the economics of convergent computing by extending its vision of any time, anywhere, on any device, to enable the Personal Network.

  • QUALCOMM Announces Java Technology Support for Mobile Station Modem Chipsets (March 13)
    QUALCOMM Incorporated announced an agreement with Sun Microsystems, to develop and distribute J2ME virtual machine technologies. These J2ME technologies will be compatible with select QUALCOMM CDMA Technologies (QCT) Mobile Station Modem (MSM) chipsets, the Binary Runtime Environment for Wireless (BREW) Application Programming Interface (BREWapi), and system software for wireless devices. Support for J2ME will allow preexisting Java applications to run on select QCT MSM chipsets, beginning with members of the 6xxx family of chipset solutions, and will have optimized performance through the use of the MSM's Launchpad suite of multimedia and other advanced technologies. Support for the Java runtime environment will also make QCT's chipsets compatible with other Java technology- compliant devices.
.
.
.
Was this Newsletter helpful?
  Very Helpful
  Helpful
  No Value
    Comments and Suggestions:


IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

FEEDBACK
Comments? Send your feedback on the Wireless Developer Newsletter to: wd-webmaster@sun.com

SUBSCRIBE/UNSUBSCRIBE
- To subscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at the end of this email.

ARCHIVES: You'll find the Wireless Developer Newsletter archives at:
http://wireless.java.sun.com/allnewsletters/wireless/

COPYRIGHT
Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA
This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
.
Please unsubscribe me from this newsletter.
From env_28441744-1797264288@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Jan 22 19:44:00 2003 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0N0i0N22687 for ; Wed, 22 Jan 2003 19:44:00 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0N0kGqr008311 for ; Wed, 22 Jan 2003 19:46:22 -0500 (EST) Date: 22 Jan 2003 15:47:40 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <28441744-1797264288@hermes.sun.com> Subject: Core Java Technologies Tech Tips, Jan. 22, 2003 (Reading Files from JARs, Into to JMX) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 31276 Core Java Technologies Technical Tips
image
image
Core Java Technologies Technical Tips
image
   View this issue as simple text January 22, 2003    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, January 22, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

Reading files from Java Archives (JARs)
Getting Started with the JavaTM Management Extensions (JMXTM)

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

Pixel
Pixel

READING FILES FROM JAVA ARCHIVES (JARS)

Java archive (JAR) files are the standard way of packaging Java technology-based solutions. They allow a developer to package all relevant content (.class, image, sound, and support files) in a single file. The JAR format supports compression, authentication, and versioning, among many other features.

Getting files out of JAR files can be a tricky task, but it doesn't have to be. This tip shows you how to get a file out of a JAR file, by first getting a directory of files in the JAR file, and then pulling out a specific one.

If you are familiar with the popular ZIP format, JAR files aren't much different. JAR files provide a way of packaging multiple files into one, where each file may be compressed separately. What the JAR file adds is something called a manifest which allows a developer to provide additional information about the content. For example, the manifest can indicate which file in the JAR file to run to start an application, or the version of a library.

The Java 2 SDK, Standard Edition provides a jar tool that allows you to read and write JAR files from the console. However there might be times when you need to read and write JAR files from within your programs. (This tip will only cover reading JAR files from within a program.) The good news is that you can do this, and you don't have to worry about the decompression, because the library handles it for you. The classes you need are in the java.util.jar package. The main class here is JarFile which is a reference to the .jar file itself. Each individual file within the bigger file is referenced by a JarEntry.

To get started, you create a JarFile instance by passing the location to the constructor. This could be in the form of a String or a File:

    JarFile jarFile = new JarFile("thefile.jar");

or

    File file = new File("thefile.jar");
    JarFile jarFile = new JarFile(file);

There are other constructors for authentication support and marking the file for deletion. However those constructors will not be covered here.

After you have a reference to the JAR file, you can read the directory of its contents. The entries method of JarFile returns an Enumeration of all the entries. From each entry, you can then get its attributes from the manifest file, any certificate information, and any other information specific to the entry such as its name or size.

  Enumeration enum = jarFile.entries();
  while (enum.hasMoreElements()) {
    process(enum.nextElement());
  }

As previously mentioned, each individual entry is a JarEntry. This class has methods such as getName, getSize, and getCompressedSize.

Let's illustrate how to use these features in a program. The following program displays the name, size, and compressed size of the contents of a JAR file you specify. (This is similar to what the jar command does when you specify it with the "t" and "v" options.)

   import java.io.*;
   import java.util.*;
   import java.util.jar.*;

   public class JarDir {
     public static void main (String args[]) 
         throws IOException {
       if (args.length != 1) {
         System.out.println(
            "Please provide a JAR filename");
         System.exit(-1);
       }
       JarFile jarFile = new JarFile(args[0]);
       Enumeration enum = jarFile.entries();
       while (enum.hasMoreElements()) {
         process(enum.nextElement());
       }
     }

     private static void process(Object obj) {
       JarEntry entry = (JarEntry)obj;
       String name = entry.getName();
       long size = entry.getSize();
       long compressedSize = entry.getCompressedSize();
       System.out.println(
           name + "\t" + size + "\t" + compressedSize);
     }
   }

If you run the JarDir program with the jce.jar file that comes with J2SE 1.4.1, you should see output that looks something like this (with more files shown where the ... is):

META-INF/MANIFEST.MF    5315    1910
META-INF/4JCEJARS.SF    5368    1958
META-INF/4JCEJARS.DSA   2207    1503
META-INF/       0       2
javax/  0       0
javax/crypto/   0       0
javax/crypto/interfaces/        0       0
javax/crypto/interfaces/DHKey.class     209     185
javax/crypto/interfaces/DHPublicKey.class       265     215
javax/crypto/interfaces/DHPrivateKey.class      267     215
javax/crypto/interfaces/PBEKey.class    268     224
javax/crypto/SecretKey.class    167     155
...

Notice the META-INF lines at the start of the output. This is the manifest and security certificate information. The entries with a 0 size are not files, but rather directories.

To actually read a specific file from a JAR file, you must get the InputStream for the entry. This is different than the JarEntry. That's because the JarEntry only contains information about the entry, not the actual contents of that entry. This is similar to the distinction between File and FileInputStream. Accessing File never opens the file, it just reads the information about it from the directory. Here's how to get the InputStream for the entry:

   InputStream input = jarFile.getInputStream(entry);

After you have an input stream, you can just read it like any other stream. In the case of a text stream, remember to use a Reader to get characters from the stream. For byte-oriented streams such as image files, just read directly.

The following program demonstrates reading from a JAR file. Call the program with the name of a JAR file followed by the file name to read. The file to be read must have a text file type.

   import java.io.*;
   import java.util.jar.*;

   public class JarRead {
     public static void main (String args[]) 
         throws IOException {
       if (args.length != 2) {
         System.out.println(
           "Please provide a JAR filename and file to read");
         System.exit(-1);
       }
       JarFile jarFile = new JarFile(args[0]);
       JarEntry entry = jarFile.getJarEntry(args[1]);
       InputStream input = jarFile.getInputStream(entry);
       process(input);
     }

     private static void process(InputStream input) 
         throws IOException {
       InputStreamReader isr = 
      new InputStreamReader(input);
       BufferedReader reader = new BufferedReader(isr);
       String line;
       while ((line = reader.readLine()) != null) {
         System.out.println(line);
       }
       reader.close();
     }
   }

Suppose you had a text file named spider.txt in a JAR file named myfiles.jar. Suppose too that spider.txt contained the following text:

   The itsy bitsy spider 
   Ran up the water spout
   Down came the rain and
   Washed the spider out 

You could display the contents of the text file from the JAR file like this:

   java JarRead myfiles.jar spider.txt   

For more about JAR files, see the JAR file specification.

Pixel
Pixel

GETTING STARTED WITH THE JAVA MANAGEMENT EXTENSIONS (JMX)

The Java Management Extensions (JMX) offers a framework for the management and monitoring of resources. It is not yet a standard part of the Java 2 Standard Edition, but the reference implementation works with J2SE 1.4 and is a part of the JavaTM 2 Enterprise Edition (J2EETM) 1.4 specification currently in beta.

The purpose of JMX is to manage and monitor resources. Resources can be physical, for example small network devices, or logical, for example installed applications. You define the pieces in objects called MBeans. These objects contain the managable resources. The resources could be something like JavaBean component properties. The MBeans are then exposed to JMX agents. The agents know how to get the state of the resources through MBeans, and are permitted to change them if exposed in a writable fashion. The agents are then accessible through a distributed layer, typically through a client using HTML or the Simple Network Management Protocol (SNMP). This allows you to control the settings of the devices without having to run to equipment closets or create custom management tools for applications.

This tip isn't meant to present a complete discussion of the how and why of the JMX architecture. Instead, it's designed to give you a quick, "hands-on" information about using JMX over the lifetime of a program. To get started, you need the binaries for the JMX version 1.2 reference implementation. You can download the binaries from the JMX home page. There is just one version for all platforms. Unpack the files into a working directory.

There are two JAR files in the download: lib/jmxri.jar and lib/jmxtools.jar. The jmxri.jar file represents the reference implementation. These are the standard JMX classes, and can be found in the javax.management package. The jmxtools.jar file is the JMX toolkit. These represent unsupported classes that Sun provides for development. Both of these JAR files will need to be in your CLASSPATH. For simplicity sake, just copy these to the jre/lib/ext directory under the installation directory for your Java Runtime Environment (JRE).

If your JRE directory is C:\j2sdk1.4.1\jre\lib\ext, then the copy command would be as follows:

copy lib\*.jar \j2sdk1.4.1\jre\lib\ext

(If you don't want these available after this tip, remember to remove the files from the jre\lib\ext directory when done.)

Next, let's define an interface for the operations you want the MBean to perform. Typically, custom interfaces are used, but aren't required. However, they make things simpler as you move into more complicated JMX behaviors, so let's use one here. (If you don't create a custom interface, you must implement javax.management.DynamicMBean.) The MBean will have one read-write resource to manage (a message). It will also have a read-only counter of the number of times that resource changed, and a reset mechanism to reinitialize the counter value. (Imagine counting the number of IP addresses a network box had over the course of a week.) Here's the definition of the interface:

   public interface HelloMBean {
     public String getMessage();
     public void setMessage(String message);
     public int getChangeCount();
     public void resetCounter();
   }

The first three methods look like they access JavaBean component properties (called "attributes" in JMX). In fact, they do access properties. The last method is simply a random method thrown in to show that everything defined in the interface doesn't have to be property-related. JMX supports executing any method, not just the getting and setting of properties.

The implementation of this interface is rather simple:

   public class Hello implements HelloMBean {
     private String message;
     private int changeCount;
  
     public String getMessage() {
       return message;
     }
  
     public void setMessage(String message){
       this.message = message;
       changeCount++;
     }
  
     public int getChangeCount() {
       return changeCount;
     }
  
     public void resetCounter() {
       changeCount = 0;
     }
   }

Notice the naming convention of the concrete class. The interface name follows the name of [ClassName]MBean, so the class is just [ClassName], replacing [ClassName] with the specific name. This is similar to the naming convention of getter and setter methods for attributes.

So far, you haven't seen any JMX-specific code, but that is about to change. The MBean Server needs to communicate with the MBeans. That communication is done by registering various agents with the server. Then, anyone using an appropriate client interface can execute any of the methods of the exposed interface, in this case, HelloMBean.

The MBean server is aptly named MBeanServer. You get the server from the MBeanServerFactory. You can either name your server or call createMBeanServer with no arguments to get the default domain.

   MBeanServer server = 
      MBeanServerFactory.createMBeanServer();

Next, you register your MBeans with the server. Each bean is registered in the form domain:key1=XXX1,key2=XXX2, where key1 is an attribute name and XXX is the associated value (and domain is replaced by the domain name). Think of it like naming an instance of a class. Before the :, the domain names a unique namespace for the instances. Typically, these are named similar to packages to ensure uniqueness, using reverse DNS names (for example, com.sun.java).

So, if you wanted to create and register two MBeans named hello1 and hello2, of type Hello, you could use the following code:

   HelloMBean hello1 = new Hello();
   ObjectName helloObjectName = new ObjectName(
     "HelloServer:type=Hello,name=hello1");
   server.registerMBean(hello, helloObjectName);
   HelloMBean hello2 = new Hello();
   ObjectName helloObjectName2 = new ObjectName(
     "HelloServer:type=Hello,name=hello2");
   server.registerMBean(hello2, helloObjectName2);

For simplicity, the domain name here is just HelloServer, because there is no chance of conflicts in the example.

A program with this much in it would be sufficient to support JMX. However, you wouldn't be able to see much. To see something more, you need a client interface. However instead of providing your own client interface, use the jmxtools.jar part of the download.

Within jmxtools.jar is the HtmlAdaptorServer. This gives you an HTML view into the MBean server. You need to create and register the server just like a regular MBean. However there is one exception: you have to tell the server what port to listen on. This example uses port 8082. If this port is not available for you, choose another and make the necessary code changes. Then, you can connect the HTML adaptor to the MBean server and access the MBeans.

   HtmlAdaptorServer adapterServer = 
     new HtmlAdaptorServer();
   ObjectName adapterObjectName = new ObjectName(
      "HelloServer:name=htmladapter,port=8082");
   adapterServer.setPort(8082);
   server.registerMBean(
      adapterServer, adapterObjectName);
   adapterServer.start();

The complete server program follows, with explicit catching of all the possible exceptions:

 import com.sun.jdmk.comm.*;
 import javax.management.*;

 public class HelloAgent {
    public static void main(String args[]) {
     MBeanServer server = 
       MBeanServerFactory.createMBeanServer();
     HtmlAdaptorServer adaptorServer = 
        new HtmlAdaptorServer();
     HelloMBean hello1 = new Hello();
     HelloMBean hello2 = new Hello();
     try {
       ObjectName helloObjectName1 = new ObjectName(
         "HelloServer:type=Hello,name=hello1");
       server.registerMBean(hello1, helloObjectName1);
       ObjectName helloObjectName2 = new ObjectName(
         "HelloServer:type=Hello,name=hello2");
       server.registerMBean(hello2, helloObjectName2);
       ObjectName adaptorObjectName = new ObjectName(
          "HelloServer:type=htmladaptor,port=8082");
       adaptorServer.setPort(8082);
       server.registerMBean(
          adaptorServer, adaptorObjectName);
       adaptorServer.start();
     } catch (MalformedObjectNameException e) {
       System.out.println("Bad object name");
       e.printStackTrace();
     } catch (InstanceAlreadyExistsException e) {
       System.out.println("Already exists");
       e.printStackTrace();
     } catch (MBeanRegistrationException e) {
       System.out.println("Registration problems");
       e.printStackTrace();
     } catch (NotCompliantMBeanException e) {
       System.out.println("Registration problems");
       e.printStackTrace();
     }
   }
 }

You should now compile the three classes and run the HelloAgent program:

javac HelloMBean.java Hello.java HelloAgent.java
java HelloAgent

The HelloAgent program will not return. It is running the application, including maintaining the current state of your MBeans. To access the server you can use any HTML client to connect to the appropriate port. To manage the agent, point your browser to http://localhost:8082/.

Your browser should display a screen that lists the HelloServer and its three MBeans (two Hello beans and the HTML adaptor):

  • hello1
  • hello2
  • htmladapter

Clicking on one of the beans allows you to change or monitor its settings.

To demonstrate, try changing the message property and watch the change count increase.

Also clear the change count.

Clicking on the MBeanServerDelegate bean will show you information about the server.

There is much more to JMX than what this tip covered. This tip was designed to get you started so you can see how you might configure and monitor your Java solutions when they are deployed. Instead of developing custom solutions for exposing the management interface to the system configuration, simply use JMX.

For more information about JMX, and for access to other JMX resources, visit the JMX home page.

Pixel
Pixel

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

Pixel
Pixel
Pixel

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, JMX, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
Please unsubscribe me from this newsletter.
From env_28823994-560439422@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Jan 28 14:28:47 2003 Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0SJSlN00864 for ; Tue, 28 Jan 2003 14:28:47 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0SJVBqh028328 for ; Tue, 28 Jan 2003 14:31:13 -0500 (EST) Date: 28 Jan 2003 11:16:45 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <28823994-560439422@hermes.sun.com> Subject: January Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 19642 Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Enterprise Edition (J2EETM).


Early Access

The following J2EE products and technologies were made available through the Early Access Release Program this month.

J2EE Platform 1.4 Beta
The J2EE 1.4 platform introduces new APIs which implement core Web services protocols stack. It also introduces new Management and Deployment APIs, new versions of the JavaServer Pages, Enterprise JavaBeansTM (EJBTM), and Connector APIs.


Product and Technology Releases

The following J2EE products and technologies were recently released.

Java BluePrints Adventure Builder Sample Application v1.0
With real, working code illustrating the BluePrints guidelines, the Java Adventure Builder Demo reduces the learning curve of the J2EE 1.4 platform, enabling you to deliver complete end-to-end solutions with faster time-to-market.


Hot Downloads

The following are currently the most frequently downloaded J2EE products and technologies.

Java Pet Store Sample Application v1.3.1

Java Servlet API Class Files v2.3

J2EE v1.3.1 Release

Java Web Services Developer Pack v10_01

Java Web Services Tutorial v10_01

pixel
pixel pixel pixel
January 28, 2003

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.

Industry News and Announcements

  • Customers Reap the Benefits of Oracle® E-Business Suite Running on Sun
    Sun and Oracle announced that Darden Restaurants, PaeTec Communications, Telmar Network Technology and The University of Northern Iowa have selected Oracle E-Business Suite running on the Sun Solaris Operating Environment. Solaris is a key component of Sun Open Net Environment (Sun ONE), an open integratable product portfolio enabling the development and delivery of Java Web services. All four joint customers presented their success stories in the Sun booth at Oracle AppsWorld in San Diego last week.
  • Chick-fil-A Standardizes on Together ControlCenter for Java Development.
    TogetherSoft Corporation announced that Chick-fil-A, Inc., one of the nation's largest privately held restaurant chains, leverages Together ControlCenter software for Java application development. TogetherSoft's award winning Java IDE and product functionality enables Chick-fil-A's development teams to manage the entire Java application lifecycle with Together ControlCenter.

In The Spotlight

  • Sun Microsystems Brings Added Value to Linux and Open Source
    Sun announced a broad range of products, programs, and industry awards for Linux that support the company's expansion into the x86 server marketplace. Highlights include new offerings of the Sun ONE software stack on Linux, including the immediate availability of both Sun ONE Application Server 7 and the recent delivery of Sun ONE Directory Server 5.1 on Linux. To date, Sun has delivered seven Sun ONE products on Linux, up from only two products that were available six months ago.

Java Developer's Marketplace

  • CollabNet Announces Participation in Borland Software Corporation Partner Program
    CollabNet, a leading provider of collaborative software development solutions, announced it has joined the Borland Technology Partner Program. In addition, CollabNet is intending to qualify Borland JBuilder to utilize source code repositories within the CollabNet SourceCast environment designed to allow Borland JBuilder developers to achieve the benefits of collaborative software development while continuing to use the JBuilder IDE.
pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, Java, Java Developer Connection, JavaBeans, JSP, JavaServer Pages, JavaOne, JNDI, JDBC, Enterprise JavaBeans, EJB, J2EE, J2ME, J2SE and Solaris Operating Environment (SPARC Platform Edition) are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

ORACLE is a registered trademark of Oracle Corporation.

All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. in the United States and other countries. Products bearing SPARC trademarks are based upon an architecture developed by Sun Microsystems, Inc.


Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_29054432628149002@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Jan 30 14:44:01 2003 X-UIDL: i=1"!d!O"!4J]!!#IE!! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h0UJi1N17569 for ; Thu, 30 Jan 2003 14:44:01 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h0UJkUHW005659 for ; Thu, 30 Jan 2003 14:46:31 -0500 (EST) Date: 30 Jan 2003 10:54:40 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <29054432628149002@hermes.sun.com> Subject: January Core Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 16466 Status: RO Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Standard Edition (J2SETM).


Early Access Releases

The following J2SE products and technologies were recently made available through the Early Access Release Program.

Java 3DTM 1.3 API
This API provides a set of object-oriented interfaces that enable developers to build, render, and control the behavior of 3D objects and visual environments. In Java 3D 1.3.1 beta, we have added new functionality to support dynamic video resize, specificially targeted for SUN framebuffer: XVR-4000, and a bunch of bug fixes to earlier release.

Java Advanced Imaging Image I/O Tools 1.0 RC
Provides reader, writer, and stream plug-ins for the Java Image I/O Framework and Image I/O-based read and write operations for Java Advanced Imaging.


Product and Technology Releases

The following J2SE products and technologies were recently released.

JSR-000121 Application Isolation API Specification
An API for initiating and controlling computations isolated from each other to varying degrees. Some API semantics are similar to those of ThreadGroup.

JSR-000123 JAINTM Service Provider Presence and Availability Management API
This API will provide Java APIs to disseminate and manage presence information securely across heterogeneous networks and applications. The APIs allow user preferences and enterprise policies to control the dissemination of presence information to address privacy and security concerns. It is based on the PAMforum v1.0 specifications and its adoption in Parlay 3.0.


Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

J2SE 1.3.1_06

J2SE 1.4 Documentation, in Japanese

Java Web Start, US downloads, followed up by International

Java Communications API

JavaBeansTM Development Kit (BDK) 1.1

pixel
pixel pixel pixel
January 30, 2003

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles & Quizzes

  • Bringing SVG Power to Java Applications
    Learn how to build SVG libraries and applications on top of the Java platform. The article takes you step-by-step through an example that uses the ILOG JViews Component Suite (a Java 2DTM and Swing-based two-dimensional graphics library).

  • Java Development with Ant Quiz
    Based on the book Java Development with Ant showcased in the Bookshelf, this quiz tests your Ant knowledge with questions like what happens when you overwrite a property and what an XDoclet is.

  • java.sun.com Quiz
    Test your knowledge of Java technology topics covered recently on java.sun.com.

  • Bringing your Java Application to Mac OS X
    Learn how to tweak your Java application to make it friendlier to Mac OS X users.

  • Advanced Imaging Image I/O API RC 1.0
    An introduction to the Java Advanced Imaging Image I/O Tools 1.0 RC.

  • Coding from Scratch
    Virtual reality pioneer Jaron Lanier discusses the need to fundamentally re-think the way developers write software.

Tech Tips

Chat

High Performance GUIs with the JFC/Swing API
Learn how to boost the performance of applications that have Swing-based GUI components. Get insights from Java Performance Manager, Steve Wilson, JFC/Swing technical lead, Scott Violet, and Java 2D API engineer, Chet Haase. Read the transcript of this chat, held on January 21, 2003.

Newsletters

Java Technology Fundamentals
Learn about interfaces, how to create Font objects, and how to create list menus from the JComboBox and JList classes.


Events

  • Sun Technology Audiocast
    Mo(o)re Technology Trends
    Continuing with themes presented in "Technology Trends," this session covers current computer industry trends and the complexities many of these trends engender. Topics include the Semantic Web, mobile processes, JavaSpacesTM and Project JXTA.

  • Code Camp
    The "Java Media Programming" Code Camp
    This code camp introduces the Media APIs available for the J2SE platform. It also provides a high level technical overview of all of the Media APIs, then delves in to details of Java 2D, JMF, and Java 3D with several code level demo programs (source provided).

  • Sun Tech Days

    • Feb. 3-4, 2003, London, UK
    • Feb. 26-28, 2003, Yokohama, Japan

    Covers the SunTM ONE architecture, J2EETM, and Web Services.


Industry News and Announcements

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://developer.java.sun.com/berkeley_license.html
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Comments? Send your feedback on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA

Sun, Sun Microsystems, Java, Java Developer Connection, J2EE, J2SE, JMX, JAIN, Java 2D, JMF, Java 3D, JCP, JavaBeans, JavaSpaces, Solaris Operating Environment(SPARC Platform Edition), and Java Community Process are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. in the United States and other countries. Products bearing SPARC trademarks are based upon an architecture developed by Sun Microsystems, Inc.


Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_30415860922731312@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Thu Feb 20 17:42:28 2003 X-UIDL: i-:"!JT8"!eVh!!_T'"! Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h1KMgSC07459 for ; Thu, 20 Feb 2003 17:42:28 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h1KMix5W028547 for ; Thu, 20 Feb 2003 17:44:59 -0500 (EST) Date: 20 Feb 2003 14:01:07 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <30415860922731312@hermes.sun.com> Subject: Core Java Technologies Tech Tips (Choosing a Collections Framework Implementation, Providing a Scalable Image Icon) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 30961 Status: RO Core Java Technologies Technical Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text February 20, 2003    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, February 20, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

.Choosing A Collections Framework Implementation
.Providing a Scalable Image Icon
.An Addition to Last Month's Tip on Reading Files From JARs

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

.
.

CHOOSING A COLLECTIONS FRAMEWORK IMPLEMENTATION

The Collections Framework has been a part of the Java 2 Platform, Standard Edition (J2SE) since version 1.2. The framework offers a series of classes, interfaces, and implementations for working with collections of data. You can produce different behaviors by choosing different implementations of the core interfaces. This tip examines some considerations in choosing the right implementation for your needs.

First, understand that to minimize the programming changes required when changing to a different interface implementation, your programs should typically access the interface, not the specific implementations. In other words, typically use:

   List list = new ArrayList();
   Set set = new HashSet();
   Map map = new TreeMap();

Don't use:

   ArrayList list = new ArrayList();
   HashSet set = new HashSet();
   TreeMap map = new TreeMap();

This allows you to change the collection implementation without affecting the rest of your code.

The key three interfaces of the framework are Set, List, and Map. A Set offers a collection of unique elements. A List provides ordered access (by index), but it doesn't guarantee uniqueness. The Map interface is different than the other two. Instead of just offering a collection of single elements, a Map provides a collection of key-value pairs. Based on a key, you find its value through a lookup operation. In other words, it's similar to checking for the phone number of a friend.

There are three concrete Set implementations that are part of the Collection Framework: HashSet, TreeSet, and LinkedHashSet. All three implementations provide a collection of unique elements. Typically, you use HashSet, which maintains its collection in an unordered manner. If this doesn't suit your needs, you can use TreeSet. A TreeSet keeps the elements in the collection in sorted order. For example, if a set of names (Mary, John, and Sam) are in a Set, a TreeSet iterates through the elements in an ordered fashion: John, Mary, and Sam. By comparison, the order of elements in a HashSet is undefined. Finally, there is LinkedHashSet. While HashSet has an undefined order for its elements, LinkedHashSet supports iterating through its elements in the order they were inserted. It maintains a secondary linked list ! to manage insertion order. Understand that the additional features provided by TreeSet and LinkedHashSet add to the runtime costs.

The List interface offers two such concrete implementations: ArrayList and LinkedList. There is a third implementation, Vector, but it is part of the historical collection classes. (These are classes from an earlier release. They're provided as a retrofit into the collections framework, and are typically avoided with newer programs.) Of the newer classes, the ArrayList provides a collection backed by an array. It provides quick indexed access to its elements, and works best when elements are only added and removed at the end. To make this happen, ArrayList performs an internal move operation when an element is added or removed. By comparison, LinkedList is best when add and remove operations happen anywhere, not only at the end. LinkList doesn't do an internal move operation for an element insert or remove, it just manipulates reference pointers. But LinkedList's added flexibility comes at an added cost -- it results in much slower indexed operations. So if you frequently access random elements, for example, you often make requests like "give me the value of element N", using an ArrayList is better. But if you frequently add and remove elements from positions other than the end, LinkedList is better.

The final core interface is Map. There are five implementations of Map provided as part of the framework: HashMap, TreeMap, LinkedHashMap, IdentityHashMap, and WeakHashMap. There is also one historical implementation: Hashtable. While there are more implementations here, it's actually easier to choose the right implementation for your needs:

  • By default, choose HashMap. Typically, it serves the most needs.

  • Choose the TreeMap implementation if you need to maintain the keys of the map in a sorted order. However, if you only need the keys sorted when you are done with the Map or need to generate a report, sometimes it's better to simply keep everything in a HashMap while adding, and create a TreeMap at the end:

    Map map = new HashMap();
    // Add and remove elements from unsorted map
    map.put("Foo", "Bar");
    map.put("Bar", "Foo");
    map.remove("Foo");
    map.put("Foo", "Baz");
    // Then sort before displaying elements
    // in sorted order
    map = new TreeMap(map);
    This avoids the overhead of maintaining the map sort, and leaves the burden of sorting to the end.

  • LinkedHashMap works like the LinkedHashSet. It maintains the ability to traverse the map elements in insertion order. Typically, maps use the equals method to check if an element is in the Map.

  • IndentityHashMap uses == to check for equality of elements. Use IndentityHashMap in those (probably rare) cases where you need strict reference equality.

  • WeakHashMap is rarely used. It keeps its keys as weak references. A weak reference allows a program to maintain a reference to an object, but it doesn't prevent the object from being considered for reclamation by the garbage collector. If the only access to the key is through the weak reference, the garbage collector can get rid of the key-value entry. If you don't need weak references, avoid the WeakHashMap.

As is the case with Vector, the Hashtable is typically avoided in newer programs in favor of HashMap.

The pointers offered in this tip should help you choose a Collections Framework interface implementation. Although sometimes the best way to choose between two implementations is to run them both and compare the results. If you're unsure which of two implementations to choose, write a quick test program that manipulates each interface 10 or 20 thousand times. Then see which one works better for your specific requirements.

For more information about the Collections Framework, see "The Collections Framework."

.
.

PROVIDING A SCALABLE IMAGE ICON

The Icon interface in JFC/Swing provides a flexible way to include images with GUI components such as buttons and labels. By simply implementing the three methods in the interface, you can make anything be the image for a component.

  public interface Icon {
    public void paintIcon(Component c,
                          Graphics g,
                          int x,
                          int y);
    public int getIconWidth();
    public int getIconHeight();
  }

However there's a scalability problem here -- the width and height of the image must be fixed. The ImageIcon class provides an Icon implementation that works with Image files. If the size of the Image in the file isn't the size of the Icon you want, you must manually scale an Image before making the Icon.

This tip presents an Icon implementation that does the scaling for you. The implementation lets the image scale itself when it is time to paint the icon. That way, you can adjust what the scaling factors are without creating multiple Image or Icon objects.

There are two ways to scale an Image object. The Image class offers a getScaledInstance that lets you create a cached version of the Image for drawing:

  getScaledInstance(int width, int height, int hints)

Or you can scale the image "on the fly" at drawing time with the drawImage methods:

  drawImage(Image image, int x, int y, int width, 
      int height, ImageObserver observer) 
  drawImage(Image image, int x, int y, int width, 
      int height, Color bgcolor, ImageObserver observer) 

Let's first look at getScaledInstance. The getScaledInstance method works by taking a new size and a hint about how to do the scaling. There are five constants in the Image class that define how to do the scaling:

  • SCALE_DEFAULT to use the default algorithm
  • SCALE_FAST to favor speed over smoothness
  • SCALE_SMOOTH to favor smoothness over speed
  • SCALE_REPLICATE to use the ReplicateScaleFilter for scaling
  • SCALE_AREA_AVERAGING to use AreaAveragingScaleFilter for scaling

While there are five constants here, there are really only two settings. The SCALE_FAST constant offers the same behavior as SCALE_REPLICATE. The SCALE_SMOOTH constant offers the same behavior as SCALE_AREA_AVERAGING. And with Image being an abstract class, SCALE_DEFAULT provides the default of the two scaling mechanisms for a specific Image implementation.

What do the scaling operations do? SCALE_REPLICATE copies lines when scaling up, and removes lines when scaling down. SCALE_AREA_AVERAGING looks at neighboring pixels to get a smoother look when scaling in either direction.

It might seem sensible to scale an Image once with getScaledInstance, and repeatedly draw the scaled Image with a version of drawImage that doesn't do scaling. However, there are several factors that should be considered that actually favor doing on-the-fly scaling with the drawImage versions that scale. The technology behind on-the-fly scaling is continually improving, and as hardware acceleration through D3D and OpenGL becomes available, the performance difference approaches zero. The key factor is the extra memory required to cache scaled instances. With on-the-fly scaling, there is no caching. For a large image, multiple megabytes can be involved here. If you cache multiple images, memory usage adds up quickly. A third difference has to do with some implementation deficiencies in the Toolkit image code, but that isn't obvious from the sample application without "digging under the covers".

Here's a demonstration of an Icon that scales. The following ImageIconScalable class subclasses ImageIcon and adds a setScaledSize method that lets you change the size of the drawn Image. Use -1 for a width and height to reset the dimensions back to the original size. The bulk of the code offers constructors to match with those of ImageIcon.

import java.awt.*;
import javax.swing.*;
import java.net.*;

public class ImageIconScalable extends ImageIcon {

  int width = -1;
  int height = -1;

  public ImageIconScalable() {
    super();
  }

  public ImageIconScalable(byte imageData[]) {
    super(imageData);
  }
  
  public ImageIconScalable(byte imageData[],
                 String description) {
    super(imageData, description);
  }
  
  public ImageIconScalable(Image image) {
    super(image);
  }
  
  public ImageIconScalable(Image image,
                 String description) {
    super(image, description);
  }
  
  public ImageIconScalable(String filename) {
    super(filename);
  }
  
  public ImageIconScalable(String filename,
                 String description) {
    super(filename, description);
  }
               
  public ImageIconScalable(URL location) {
    super(location);
  }
  
  public ImageIconScalable(URL location,
                 String description) {
    super(location, description);
  }

  public int getIconHeight() {
    int returnValue;
    if (height == -1) {
      returnValue = super.getIconHeight();
    } else {
      returnValue = height;
    }
    return returnValue;
  }

  public int getIconWidth() {
    int returnValue;
    if (width == -1) {
      returnValue = super.getIconWidth();
    } else {
      returnValue = width;
    }
    return returnValue;
  }

  public void paintIcon(Component c,
                        Graphics g,
                        int x,
                        int y) {
    if ((width == -1) && (height == -1)) {
      g.drawImage(getImage(), x, y, c);
    } else {
      g.drawImage(getImage(), x, y, width, height, c);
    }
  }

  public void setScaledSize(int width,
                            int height) {
    this.width = width;
    this.height = height;
  }
}

To test the new scaling ability, the following test program takes an image file name from the command line and places it in a button. The display gives you the opportunity to make the size of the image larger or smaller.

IISTest

Select different size multipliers. Notice that the icon size changes without reloading the Image icon. One line worth mentioning specifically is the call to revalidate the button that contains the scalable ImageIcon:

    jbImage.revalidate();

Because the added setScaledSize method doesn't change any properties of the component associated with the icon, the program needs to manually notify the component that its state changed. This both redraws the component and revalidates the display. This affects the button size, because the width and height changed.

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class IISTest extends JFrame 
                    implements ActionListener {

  ImageIconScalable imageIcon;

  JButton    jbDiv2,
             jbDiv4,
             jbMult2,
             jbOrig,
             jbImage;

  public IISTest(String filename) {
    setTitle("IISTest");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    imageIcon = new ImageIconScalable( 
      getClass().getResource(filename));
    jbDiv2 = new JButton("Div2");
    jbDiv4 = new JButton("Div4");
    jbMult2 = new JButton("Mult2");
    jbOrig = new JButton("Original");
    jbImage = new JButton(imageIcon);

    jbDiv2.addActionListener(this);
    jbDiv4.addActionListener(this);
    jbMult2.addActionListener(this);
    jbOrig.addActionListener(this);
    JPanel jpNorth = new JPanel();
    jpNorth.add(jbDiv2);
    jpNorth.add(jbDiv4);
    jpNorth.add(jbMult2);
    jpNorth.add(jbOrig);

    JPanel jpCenter = new JPanel();
    jpCenter.add(jbImage);

    Container cp = getContentPane();
    cp.add(jpNorth, BorderLayout.NORTH);
    cp.add(jpCenter, BorderLayout.CENTER);
    setSize(400, 400);
    show();
  }

  public void doChange(
      int proportion, boolean multiply) {
    int width = imageIcon.getIconWidth();
    int height = imageIcon.getIconHeight();
    if (multiply) {
      imageIcon.setScaledSize(
          width * proportion, 
          height * proportion); 
    } else {
      imageIcon.setScaledSize(
          width / proportion, 
          height / proportion); 
    }
  }
    
  public void actionPerformed(ActionEvent ae) {
    JButton source = (JButton)ae.getSource();
    if (source.equals(jbDiv2)) {
      doChange(2, false);
    } else if(source.equals(jbDiv4)) {
      doChange(4, false);
    } else if(source.equals(jbMult2)) {
      doChange(2, true);
    } else if(source.equals(jbOrig)) {
      imageIcon.setScaledSize(-1, -1);
    }
    // Changing "icon" without changing icon
    // So, need to revalidate associated component(s)
    jbImage.revalidate();
  }

  public static void main(String args[]) {
    if (args.length != 1) {
      System.err.println(
         "Please provide an image file name to load");
    } else {
      new IISTest(args[0]);
    }
  }
}
.
.

AN ADDITION TO LAST MONTH's TIP ON READING FILES FROM JARS

The January 22, 2003 tip "Reading files from Java Archives (JARs)" discussed the use of the JarFile class to read files from within a JAR file. You should note that the JarFile class is useful for reading files from a JAR when the files are not in the class path. The JarFile class is also useful for reading files from a JAR when you want to specify the target JAR file. However, if the JAR file is in the class path, there is a simpler way of reading from it. You can use:

  URL url = ClassLoader.getSystemResource(name);

or

  InputStream stream = 
     ClassLoader.getSystemResourceAsStream(name);

These techniques allow you to read a file out of a JAR file that is located in your class path. You don't need to specify the JAR filename.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, CA 95054 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_30768160-1596348766@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Feb 25 17:31:39 2003 X-UIDL: KPX!!,a%#!K7Y!!@KZ!! Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h1PMVdC06204 for ; Tue, 25 Feb 2003 17:31:39 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.1/8.12.1/IUPO) with SMTP id h1PMYHgd029963 for ; Tue, 25 Feb 2003 17:34:19 -0500 (EST) Date: 25 Feb 2003 14:22:20 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <30768160-1596348766@hermes.sun.com> Subject: February Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 18548 Status: RO Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise JavaTM Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the JavaTM 2 Platform, Enterprise Edition (J2EETM).


Product and Technology Releases

The following J2EE products and technologies were recently released.

JSR-000152 JavaServer Pagestm(JSPtm)
Proposed Final Draft 2 Specification v2.0 Incorporates the use of JSP to author custom actions, and adds expression language support into the container. Additionally, incorporates erratas and clarifications as well as opportunistic improvements and a few incremental features.

JSR-000141 Session Description Protocol (SDP) API
Public Review Draft 2 Specification 20030103 API The SDP API version 1.0 will enable the proper encoding and decoding of SDP messages and allow a user to get, set or modify any element of a field or description in a SDP message.


Hot Downloads

The following are currently the most frequently downloaded J2EE products and technologies.

Java Web Services Developer Pack v10_01

Java Web Services Tutorial v10_01

J2EE Tutorial v1.3.1

Java Servlet API Class Files v2.3

JavaServer Pages Standard Tag Library Specification


In the Spotlight

Java BluePrints Adventure Builder Sample Application v1.0.
Available for download from the Java BluePrints Program, the Java Adventure Builder Sample Application v1.0 is the first release of the new Java BluePrints application. This early access release is a native J2EE 1.4 application that runs on the J2EE 1.4 Beta Software Developer Kit.


Industry News, Features & Announcements

Java Application Verification Kit: Testing Applications and Showing Credibility.
The Java AVK is a component of the Java Verification Program. It provides developers with the specific guidelines and rules based on J2EE that are used to test applications for portability across a variety of application servers.
For more information, visit: http://java.sun.com/j2ee/verified or email: verification-sales@sun.com

OpenOffice.org 1.0.2 Beta Software Development Kit(SDK)
The new SDK is an add-on for the existing OpenOffice.org v1.0.2. It provides the necessary tools and documentation for programming the OpenOffice.org APIs and creating your own extensions (UNO components) for OpenOffice.org, including the new Developer's Guide.

Download Sun(tm) ONE Application Server 7, Standard Edition
Sun ONE Application Server 7, Standard Edition is a J2EE 1.3 compliant product, offering a full range of features for developing Java web services. It's free for development and evaluation. The download will install as a 60 day license.

pixel
pixel pixel pixel
February 25, 2003

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources. pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Comments? Send your feedback on the Enterprise Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Sun, Sun Microsystems, Java, Java Developer Connection, JavaServer Pages, JSP, J2EE, J2ME and J2SE, Advanced JSP, Java Verified, and Servlets Programming are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_31390079424851887@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Mar 4 15:33:57 2003 X-UIDL: e'A"!m+0!!VeK!!MPR"! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h24KXvC16752 for ; Tue, 4 Mar 2003 15:33:57 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.8/8.12.1/IUPO) with SMTP id h24KahYa012591 for ; Tue, 4 Mar 2003 15:36:44 -0500 (EST) Date: 4 Mar 2003 11:12:38 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <31390079424851887@hermes.sun.com> Subject: Core Java Technologies Tech Tips (Using Runtime.exec, Programming With File Attributes) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 34287 Status: RO Core Java Technologies Technical Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text March 04, 2003    

In this Issue

Welcome to the Core JavaTM Technologies Tech Tips, March 4, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SETM).

This issue covers:

.Using Runtime.exec to Invoke Child Processes
.Programming With File Attributes

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.

.
.

USING RUNTIME.EXEC TO INVOKE CHILD PROCESSES

Suppose that you are writing a Java application, and you need to obtain the contents of a directory, that is, all the files and subdirectories found within the directory.

You're running on a UNIX system, and you're familiar with the ls command. So you decide to invoke ls from within your Java code. This tip illustrates how to do this, and it also describes why it's probably a bad idea. A command like ls is not portable. Even if the command was portable, there is a simple replacement that uses only Java library features, and thus works across multiple platforms.

Here is what the code looks like:

    import java.io.*;
    
    public class ExecDemo1 {
        static void listDirContents1(String dir)
        throws IOException {
    
            // start the ls command running
    
            Runtime runtime = Runtime.getRuntime();
            Process proc = runtime.exec(
                "ls" + " " + dir);
    
            // put a BufferedReader on the ls output
    
            InputStream inputstream =
                proc.getInputStream();
            InputStreamReader inputstreamreader =
                new InputStreamReader(inputstream);
            BufferedReader bufferedreader =
                new BufferedReader(inputstreamreader);
    
            // read the ls output
    
            String line;
            while ((line = bufferedreader.readLine()) 
                      != null) {
                System.out.println(line);
            }
        
            // check for ls failure
    
            try {
                if (proc.waitFor() != 0) {
                    System.err.println("exit value = " +
                        proc.exitValue());
                }
            }
            catch (InterruptedException e) {
                System.err.println(e);
            }
        }
    
        static void listDirContents2(String dir) {
    
            // create File object for directory
            // and then list directory contents
    
            String[] list = new File(dir).list();
            int len = (list == null ? 0 : list.length);
            for (int i = 0; i < len; i++) {
                System.out.println(list[i]);
            }
        }
    
        public static void main(String[] args) 
            throws IOException {
                if (args.length != 1) {
                    System.out.println(
                        "missing directory");
                    System.exit(1);
                }
            listDirContents1(args[0]);
            listDirContents2(args[0]);
        }
    }

When you run the ExecDemo1 program, specify a directory, for example:

    java ExecDemo1 /home/techtips

Your results should list the contents of the directory, perhaps something like this:

    AttrDemo1.java
    AttrDemo2.java
    AttrDemo3.java
    AttrDemo4.java
    AttrDemo5.java
    ExecDemo1.class
    ExecDemo1.java
    ExecDemo2.java
    prev
    prev2
    x
    .
    .
    .
    (repeat all of above)

The list is repeated because two methods that produce the file list are used. Each method illustrates a different approach. The first file list is produced by listDirContents1. The repetition is produced by listDirContents2.

Unfortunately, this program will work only on UNIX or Linux systems, or on systems that emulate UNIX with tools such as the MKS Toolkit available on Windows. That's because of the dependency the program has on the ls command.

Runtime.exec is used to create a Process object (Process is abstract, so actually an object of a Process subclass is created). The process runs the ls command. Note that no pathname is specified for ls. The Java system apparently observes the local PATH environment variable, although this is not mentioned in the documentation. Giving a complete path is safer, though it assumes that the ls command can be found in the same place on every system where you run your application. The previous example assumes that the ls command is found in the PATH, typically in a directory such as /bin or /usr/bin (the same assumption is made for the next example which uses the wc command). This issue is an example of the kinds of dependencies you must sort through when using Runtime.exec.

In the ExecDemo1 example, the argument to Runtime.exec is a string. There are other forms of the exec method that are available. For example, one form takes an array of string arguments, and another supports the setting of environment variables. If a string is specified as an argument, it is broken into individual tokens using StringTokenizer.

Input to and output from the child process are managed through streams, available through the Process object. For example, the standard output of the child process is treated as an input stream. This stream is read in the parent in order to obtain the output from the child process.

The waitFor method is used to wait for child process completion, and to obtain the exit status of the process. By convention, a status of 0 indicates success.

The listDirContents2 method shows another way to list directory contents. This approach uses only Java library features. It uses a lot less code, and is much more portable. So listDirContents1 cannot be recommended as a useful approach.

However, suppose that after you've studied the example above, you are still convinced that invoking ls is a good idea, and because your application runs only on UNIX and Windows systems, you think that with a slight tweak, you can make this code portable. Specifically, you decide to somehow detect what kind of system you're on. If it's a Windows system, you'll use the "dir" command to obtain a directory listing.

Unfortunately, this sort of straightforward substitution won't work. On at least some Windows systems, such as Windows 2000, dir is not an executable command. Instead it's built into the command processor or shell. So in doing the substitution for ls, you need to say:

    cmd /c dir

which means "invoke the command processor and execute a single command (dir) and then exit the command processor". On both UNIX and Windows systems, many commands are shell built-ins, and so this technique is required.

Let's look at another example to illustrate these ideas:

    import java.io.IOException;
    
    public class ExecDemo2 {
    
        static void doExec1() throws IOException {
    
            // use pipes and I/O redirection
            // but without using a shell
    
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("ls | wc >out1");
        }
    
        static void doExec2() throws IOException {
    
            // invoke a shell and give command to it
    
            Runtime runtime = Runtime.getRuntime();
            String[] args = 
                new String[]{"sh", "-c", "ls | wc >out2"};

            Process p = runtime.exec(args);
        }
    
        public static void main(String[] args) throws IOException {
            doExec1();
            doExec2();
        }
    }

In this ExecDemo2 program, the command to be executed is:

    ls | wc >out1

This is UNIX shell syntax which says "run the ls command, direct its output to the wc command, and direct the output of the wc command to a file out1". The wc command counts the numbers of lines, words, and characters in its input.

When you run ExecDemo2, out1 is not created, and doExec1 fails. However doExec2 succeeds, and the contents of out2 are something like this:

    13      13     168 

The problem with doExec1 is that Runtime.exec invokes actual executable binary programs. Syntax such as | and > are part of a particular command processor, and are only understood by that processor. ls is executed, but the rest of the shell command is not. However, doExec2 succeeds because it invokes a command processor or shell (sh), and gives the shell the input containing the | and > characters. Note that Runtime.exec could have been invoked with a single string argument like this:

    "sh -c 'ls | wc >out2'"

However StringTokenizer will split this string apart without observing the single inner quotes.

These examples serve to illustrate the type of issues you will encounter if you use Runtime.exec. It's a good idea to ask yourself some hard questions before you start using this feature. In particular, you need to determine whether there's a way to accomplish the same end using standard Java features only.

Runtime.exec makes the most sense when you're invoking a large, complex application such as a word processor or web browser, that is, an application that isn't feasible to implement using Java features.

For more information about using Runtime.exec, see section 18.2, Creating Processes, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes.

.
.

PROGRAMMING WITH FILE ATTRIBUTES

A file attribute is a characteristic of a file, for example its read and write permissions, its length, or whether it is a directory. The java.io.File class supports setting and querying file attributes. This tip looks at some of these attributes.

Java file attributes are a subset of what is available on a particular system like UNIX or Windows. There are some attributes that an underlying system such as UNIX supports that the Java system does not. At the same time, using the attributes made available in the File class means that your applications are more portable than if you use underlying facilities.

Another general point about Java file attributes concerns security. The techniques illustrated in this tip might be under the control of a security manager (assuming one is installed). This means that you might not be allowed to use the techniques. For example, in order to directly set the modification time on a file, your program must be able to pass the security checks of the security manager's checkWrite method.

The first type of attribute is one you might consider obvious: the name of a file. But there are a couple of interesting things to consider here. Let's look at an example:

    import java.io.*;
    
    public class AttrDemo1 {
        public static void main(String[] args) 
            throws IOException {
                File testfile = new File("." +
                    File.separatorChar + "testfile1");
                testfile.createNewFile();
    
                System.out.println(
                    "name = " + testfile.getName());
    
                System.out.println(
                    "path = " + testfile.getPath());
    
                System.out.println("absolute path = " +
                    testfile.getAbsolutePath());
    
                System.out.println("canonical path = " +
                    testfile.getCanonicalPath());
        }
    }

The AttrDemo1 program creates a file testfile1 with a contrived pathname. The pathname has a ./ or .\ in front of the name, to refer to the current directory. A single dot (".") refers to the current directory on UNIX and Windows systems, but isn't necessarily supported on other systems. But this particular example assumes that a file pathname makes use of this convention.

If you run the program on a Windows systems, the output should look something like this:

    name = testfile1
    path = .\testfile1
    absolute path = G:\JOB\work\.\testfile1
    canonical path = G:\JOB\work\testfile1

The first line of output is the result of calling File.getName, and is the last name in a file's pathname. The second line comes from the File.getPath method, and is the pathname of the file. The pathname is a series of directories with separators like / or \ between them, ending with a final name. File.pathSeparatorChar specifies the separator character for a given system.

The third and fourth lines are absolute pathnames. These are typically determined by resolving against a current working directory. In this example, the current directory is G:\JOB\work.

Every pathname that specifies an existing directory or file has a unique canonical form. The canonical form is typically derived by eliminating . and .. in the pathname, resolving symbolic links, and converting drive letters (in Windows) to a standard case. In the AttrDemo1 example, the redundant \.\ in the pathname is converted to \.

Let's look at another kind of attribute: file modification times. Here's an example:

    import java.io.*;
    import java.util.*;
    
    public class AttrDemo2 {
        public static void main(String[] args) 
            throws IOException {
                File testfile = new File("testfile2");
                testfile.delete();
                testfile.createNewFile();
    
                long modtime = testfile.lastModified();
                System.out.println(
                    "last modification time #1 = " +
                    new Date(modtime));
    
                testfile.setLastModified(0);
                modtime = testfile.lastModified();
                System.out.println(
                    "last modification time #2 = " +
                    new Date(modtime));
        }
    }

The output looks something like this:

    last modification time #1 = Wed Feb 12 14:05:34 MST 2003
    last modification time #2 = Wed Dec 31 17:00:00 MST 1969

The lastModified method returns the time in standard Java format. This is the number of milliseconds since 1/1/1970 0000 GMT. The second line of output above shows the result of setting the time to 0. The result references the year 1969, because MST (Mountain Standard Time) has a -0700 correction to GMT.

The File.length method is used to find the length of a file. Normally you might not think of file length as an attribute you can set, but it is possible using RandomAccessFile. Here's some code that shows how to do this:

    import java.io.*;
    
    public class AttrDemo3 {
        public static void main(String[] args) 
            throws IOException {
                File testfile = new File("testfile3");
                testfile.delete();
                testfile.createNewFile();
    
                System.out.println(
                    "length #1 = " + testfile.length());
    
                RandomAccessFile raf =
                    new RandomAccessFile(
                        "testfile3", "rw");
                raf.setLength(100);
                raf.close();
    
                System.out.println("length #2 = " + 
                    testfile.length());
        }
    }

The output is:

    length #1 = 0
    length #2 = 100

This approach might be useful in a case where you want to preallocate a certain number of fixed-length records in a file.

Another area that's important is read and write permissions on a file. For example, you might want to mark a file as being read-only, so that it cannot be written. Here's an example that illustrates this point:

    import java.io.*;
    
    public class AttrDemo4 {
        public static void main(String[] args) 
            throws IOException {
                File testfile = new File("testfile4");
                testfile.delete();
                testfile.createNewFile();
    
                if (testfile.canRead()) {
                    System.out.println(
                        "file can be read #1");
                }
                if (testfile.canWrite()) {
                    System.out.println(
                        "file can be written #1");
                }
    
                testfile.setReadOnly();
    
                if (testfile.canRead()) {
                System.out.println(
                    "file can be read #2");
                }
                if (testfile.canWrite()) {
                System.out.println(
                    "file can be written #2");
                }
        }
    }

The output is:

    file can be read #1
    file can be written #1
    file can be read #2    

The program creates a file. Initially it's possible to both read and write the file. Then the program makes the file read-only. The canRead method returns true, but canWrite returns false.

There is also a File.isHidden method, to check whether a file has its hidden attribute set. For UNIX systems, a file is considered hidden if its name starts with a dot ("."). On Windows systems, there is a specific Windows file system attribute that you can set to mark a file as hidden.

Let's look at a final example. A common programming task is to go through a file directory structure on disk and enumerate all the files found in that structure. One attribute that hasn't been discussed is the contents of a directory. If a File object refers to a directory, then that directory has entries in it, that is, names of other directories and files. It's possible to recursively go through these entries and make a list of all the pathnames that are found.

Here's what the code looks like:

    import java.io.*;
    import java.util.*;
    
    class DirTreeWalker {
        private List filelist = new ArrayList();
    
        private void getFiles(File file) 
            throws IOException {
                if (file.isDirectory()) {
                    String[] entries = file.list();
                    int maxlen = (entries == 
                        null ? 0 : entries.length);
                    for (int i = 0; i < maxlen; i++) {
                        getFiles(
                            new File(file, entries[i]));
                }
            }
                else if (file.isFile()) {
                    filelist.add(
                        file.getCanonicalPath());
                }
        }
    
        public DirTreeWalker(String filename) 
            throws IOException {
                getFiles(new File(filename));
        }
    
        public List getList() {
            return filelist;
        }
    }
    
    public class AttrDemo5 {
        public static void main(String[] args) 
            throws IOException {
                if (args.length != 1) {
                    System.err.println(
                        "missing argument");
                    System.exit(1);
                }
    
            DirTreeWalker dtw = 
                new DirTreeWalker(args[0]);
            List list = dtw.getList();
    
            for (int i = 0, size = list.size(); 
                i < size; i++) {
                    System.out.println(list.get(i));
            }
        }
    }

A typical invocation of this program is:

    java AttrDemo5 /techtips

for UNIX systems, and

    java AttrDemo5 C:\

for Windows systems. The program displays all the file pathnames under the specified starting directory. Here are a few typical lines of output:

    C:\arcldr.exe
    C:\arcsetup.exe
    C:\AUTOEXEC.BAT
    C:\boot.ini

In this program, the getFiles method is called with a File object. If the File object refers to a plain file, its canonical path is added to the ArrayList list. If it's a directory, then File.list is called to get the contents of the directory. For each entry in the directory, a new File object is constructed based on the current path passed in to getFiles and the entry in the directory. Then getFiles is called recursively with this object.

You should not assume that if isDirectory is false, then isFile is true, and vice versa. If the File object references a nonexistent file, neither is true. Also, it's worth noting that the directory attribute of a file is not something you can directly set -- it's set for you by virtue of creating a directory using File.mkdir.

For more information about programming with file attributes, see section 15.6.3, The File Class, in "The JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about JavaTM programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core JavaTM Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EETM).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2METM).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, CA 95054 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

UNIX is a registered trademark in the United States and other countries, exclusively licensed through X/Open Company, Ltd. UNIX est unemarque enregistree aux Etats-Unis et dans d'autres pays e licenciee exclusivement par X/Open Company Ltd.

Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_32036595-283266493@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Mar 18 15:56:43 2003 X-UIDL: %1*"!Cd*!!5U@!!Em\"! Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h2IKuhC16024 for ; Tue, 18 Mar 2003 15:56:43 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.8/8.12.8/IUPO) with SMTP id h2IKxcHM000013 for ; Tue, 18 Mar 2003 15:59:41 -0500 (EST) Date: 18 Mar 2003 11:31:14 -0800 From: "JDC Tech Tips" To: gcf@indiana.edu Message-Id: <32036595-283266493@hermes.sun.com> Subject: Core Java Technologies Tech Tips, March 18, 2003 (Dragging Text and Images with Swing, Discovering the Calling Method Name) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 34733 Status: RO Core Java Technologies Technical Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text March 18, 2003    

In this Issue

Welcome to the Core Java Technologies Tech Tips, March 18, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

.Dragging Text and Images with Swing
.Discovering the Calling Method Name

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

.
.

DRAGGING TEXT AND IMAGES WITH SWING

One of the more welcome features of J2SE version 1.4 are the enhancements to the Drag and Drop and data transfer facilities. These facilities are defined in the java.awt.dnd package with some help from the java.awt.datatransfer package. These APIs give you the ability to transfer any object (not just strings) between a Java Runtime Environment (JRE) and itself, another JRE, or an application native to the runtime platform. Earlier versions of J2SE required you to control all aspects of the drag gestures, such as what to do when the user click-drags a mouse over a component and drops it over another component. With the newer release of J2SE, a lot of the work is done for you.

The simplest way to add drag and drop support to a program is to use the setDragEnabled method. To drag-enable a Swing component, you simply call the setDragEnabled method, with an argument of true, on the component. The component must be one that supports drag operations. The components that provide this support are JColorChooser, JFileChooser, JList, JTree, JTable, and all the JTextComponent classes except JPasswordField. The following program demonstrates this approach. The program drag-enables a JList and two JTextArea components. You can select an item from the JList and then drop it in the JTextArea, or you can select content from one JTextArea and drop it in the other JTextArea.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import java.text.*;
    import java.util.*;

    public class Drag1 {
      public static void main(String args[]) {
        JFrame frame = new JFrame("Drag");
        frame.setDefaultCloseOperation(
            JFrame.EXIT_ON_CLOSE);
        Container content = frame.getContentPane();
        JPanel inner = new JPanel(new BorderLayout());
        JTextArea top = new JTextArea(5, 40);
        top.setDragEnabled(true);
        JScrollPane topScroll = new JScrollPane(top);
        inner.add(topScroll, BorderLayout.NORTH);
        JTextArea bottom = new JTextArea(5, 40);
        bottom.setDragEnabled(true);
        JScrollPane bottomScroll = 
            new JScrollPane(bottom);
        inner.add(bottomScroll, BorderLayout.SOUTH);
        content.add(inner, BorderLayout.CENTER);
        DateFormatSymbols symbols = 
            new DateFormatSymbols(Locale.US);
        JList list = new JList(symbols.getWeekdays());
        list.setDragEnabled(true);
        JScrollPane leftScroll = new JScrollPane(list);
        content.add(leftScroll, BorderLayout.WEST);
        frame.pack();
        frame.show();
      }
    }

Drop works here because Swing has arranged for any component with a TransferHandler to automatically receive a drop target. Swing provides default TransferHandler objects to some components so that they support drop "out of the box". These components are JColorChooser and all the JTextComponent classes (including JPasswordField).

While setDragEnabled allows you to turn on and off drag support, the actual mechanism of importing and exporting data is supplied by Swing's TransferHandler class. TransferHandler is responsible for all data transfer into and out of a component. Specifically, TransferHandler handles the export of data for drag, cut, and copy, as well as the import for drop and paste. As mentioned above, Swing provides default TransferHandler implementations for some components. You can replace this default implementation with a TransferHandler of your own design by calling setTransferHandler on the component. This works together with setDragEnabled to allow for easy Drag and Drop customization. (Note that when you replace a TransferHandler, you not only change the behavior of Drag and Drop, but also cut, copy, and paste).

Components that don't support setDragEnabled still support a TransferHandler. But you'll be required to do a little more work to initiate a drag, such as supplying a MouseListener that watches for a drag gesture and calling the TransferHandler's exportAsDrag method.

One type of custom TransferHandler exposes the current setting of a property as a draggable object. To use it, you create a TransferHandler that identifies the property name, and associate it with the start drag gesture you define for that component (such as mousePress). The TransferHandler handles the rest. Here's a program that uses a TransferHandler to drag-enable a text label for a JLabel component. Run the program and drag the label into the JTextField.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;

    public class Drag2 {
      public static void main(String args[]) {
        JFrame frame = new JFrame("Drag");
        frame.setDefaultCloseOperation(
            JFrame.EXIT_ON_CLOSE);
        Container content = frame.getContentPane();
        JTextField top = new JTextField();
        content.add(top, BorderLayout.NORTH);
        JLabel label = new JLabel("Drag Me");
        label.setTransferHandler(
            new TransferHandler("text"));
        MouseListener listener = new MouseAdapter() {
          public void mousePressed(MouseEvent e) {
            JComponent c = (JComponent)e.getSource();
            TransferHandler th = c.getTransferHandler();
            th.exportAsDrag(c, e, TransferHandler.COPY);
          }
        };
        label.addMouseListener(listener);
        content.add(label, BorderLayout.SOUTH);
        frame.setSize(100, 100);
        frame.show();
      }
    }

How about dragging and dropping images, in other words "transferring" images? That's more complicated than moving text around. To transfer an image, you need to create a TransferHandler object that supports the DataFlavor of imageFlavor. A DataFlavor is an object that represents the data format of an object being transferred, that is, as it would appear on a clipboard during a drag and drop operation. In an image transfer, the transfer is done under a particular data flavor. This allows the receiver to determine what formats the transferable object can move. The receiver can compare that with the formats it supports receiving, and then find the richest format available for the transfer. To do this, you need to create a custom TransferHandler implementation.

To demonstrate transferring images, let's define a TransferHandler object that supports transferring images from a JLabel to or from anywhere.

In the TransferHandler object, you need to define what type of operations are supported. Use the getSourceActions method to do that. The available operations defined in the TransferHandler class are: NONE, COPY, MOVE, and COPY_OR_MOVE. In this example, let's assume that the image shouldn't be removed from the JLabel, so specify COPY as the supported operation:

    public int getSourceActions(JComponent c) {
      return TransferHandler.COPY;
    }

Next, implement the canImport method to check if a given set of flavors can be imported into the potential drop target. To do this, you need to first create an array of supported flavors:

    public static final DataFlavor flavors[] = 
      {DataFlavor.imageFlavor};

Then, in the canImport method, you check if the component drop target supports the flavor. If it can, return true, if not false.

    public boolean canImport(
        JComponent comp, DataFlavor flavor[]) {
      if (!(comp instanceof JLabel)) {
        return false;
      }
      for (int i=0, n=flavor.length; i<n; i++) {
        for (int j=0, m=flavors.length; j<m; j++) {
          if (flavor[i].equals(flavors[j])) {
            return true;
          }
        }
      }
      return false;
    }

Next, define the createTransferable method. This is called when something wants to be placed on the clipboard or used in a drag operation. However, no data is really placed on the clipboard just yet. Instead, a reference to a Transferable object is placed on the clipboard. The Transferable implementation does the actual copy. Notice that the Transferable implementation is an anonymous inner class here. It will simply return the Image just saved as the transferable data.

    public Transferable createTransferable(
        JComponent comp) {

        if (comp instanceof JLabel) {
          JLabel label = (JLabel)comp;
          Icon icon = label.getIcon();
          if (icon instanceof ImageIcon) {
            final Image image = ((
                ImageIcon)icon).getImage();
            final JLabel source = label;
            Transferable transferable = 
                new Transferable() {

              public Object getTransferData(
                  DataFlavor flavor) {
                if (isDataFlavorSupported(flavor)) {
                    return image;
                }
                return null;
              }

              public DataFlavor[] getTransferDataFlavors() {
                return flavors;
              }

              public boolean isDataFlavorSupported(
                  DataFlavor flavor) {
                return flavor.equals(
                    DataFlavor.imageFlavor);
              }
            };
            return transferable;
          }
        }
      return null;
    }

The last part is support for a paste operation. To get an image, you can paste it to replace the existing image on the JLabel. Remember that the Java platform supports GIF, JPEG, and PNG. As long as an image in one of those formats is on the system clipboard, it can be pasted onto the associated JLabel. This is done with the importData method:

    public boolean importData(
        JComponent comp, Transferable t) {
      if (comp instanceof JLabel) {
        JLabel label = (JLabel)comp;
        if (t.isDataFlavorSupported(flavors[0])) {
          try {
            Image image = (
                Image)t.getTransferData(flavors[0]);
            ImageIcon icon = new ImageIcon(image);
            label.setIcon(icon);
            return true;
          } catch (UnsupportedFlavorException ignored) {
          } catch (IOException ignored) {
          }
        }
      }
      return false;
    }

Putting all this together, gives the following ImageSelection class definition:

    import java.awt.*;
    import java.awt.image.*;
    import java.awt.datatransfer.*;
    import java.io.*;
    import javax.swing.*;


    public class ImageSelection extends TransferHandler {


      private static final DataFlavor flavors[] = 
          {DataFlavor.imageFlavor};


      public int getSourceActions(JComponent c) {
        return TransferHandler.COPY;
      }


      public boolean canImport(
          JComponent comp, DataFlavor flavor[]) {
            if (!(comp instanceof JLabel)) {
              return false;
            }
        for (int i=0, n=flavor.length; i<n; i++) {
          for (int j=0, m=flavors.length; j<m; j++) {
            if (flavor[i].equals(flavors[j])) {
              return true;
            }
          }
        }
        return false;
      }


      public Transferable createTransferable(
          JComponent comp) {

        if (comp instanceof JLabel) {
          JLabel label = (JLabel)comp;
          Icon icon = label.getIcon();
          if (icon instanceof ImageIcon) {
            final Image image = ((
                ImageIcon)icon).getImage();
            final JLabel source = label;
            Transferable transferable = 
                new Transferable() {

              public Object getTransferData(
                  DataFlavor flavor) {
                if (isDataFlavorSupported(flavor)) {
                    return image;
                }
                return null;
              }

              public DataFlavor[] getTransferDataFlavors() {
                return flavors;
              }

              public boolean isDataFlavorSupported(
                  DataFlavor flavor) {
                return flavor.equals(
                    DataFlavor.imageFlavor);
              }
            };
            return transferable;
          }
        }
        return null;
      }

      public boolean importData(
          JComponent comp, Transferable t) {
        if (comp instanceof JLabel) {
          JLabel label = (JLabel)comp;
          if (t.isDataFlavorSupported(flavors[0])) {
            try {
              Image image = (
                  Image)t.getTransferData(flavors[0]);
              ImageIcon icon = new ImageIcon(image);
              label.setIcon(icon);
              return true;
            } catch (UnsupportedFlavorException ignored) {
            } catch (IOException ignored) {
            }
          }
        }
        return false;
      }
    }

After the ImageSelection class is defined, you can create a program that supports transferring images. The following program does just that.

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.datatransfer.*;
    import javax.swing.*;

    public class DragImage {

      public static void main(String args[]) {

        JFrame frame = new JFrame("Drag Image");
        frame.setDefaultCloseOperation(
            JFrame.EXIT_ON_CLOSE);
        Container contentPane = frame.getContentPane();

        final Clipboard clipboard =
          frame.getToolkit().getSystemClipboard();

        final JLabel label = new JLabel();
        if (args.length > 0) {
          Icon icon = new ImageIcon(args[0]);
         label.setIcon(icon);
        }
        label.setTransferHandler(new ImageSelection());

        MouseListener mouseListener = 
            new MouseAdapter() {
          public void mousePressed(MouseEvent e) {
            JComponent comp = (JComponent)e.getSource();
            TransferHandler handler = 
                comp.getTransferHandler();
            handler.exportAsDrag(
                comp, e, TransferHandler.COPY);
          }
        };
        label.addMouseListener(mouseListener);

        JScrollPane pane = new JScrollPane(label);
        contentPane.add(pane, BorderLayout.CENTER); 

        JButton copy = new JButton("Copy");
        copy.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
          // fire TransferHandler's built-in copy 
          // action with a new actionEvent having 
          // "label" as the source
          Action copyAction = 
              TransferHandler.getCopyAction();
          copyAction.actionPerformed(
            new ActionEvent(
               label, ActionEvent.ACTION_PERFORMED,
              (String)copyAction.getValue(Action.NAME),
              EventQueue.getMostRecentEventTime(),
              0));
         }
        });

        JButton clear = new JButton("Clear");
        clear.addActionListener(new ActionListener() {
          public void actionPerformed(
              ActionEvent actionEvent) {
            label.setIcon(null);
          }
        });
    
        JButton paste = new JButton("Paste");
        paste.addActionListener(new ActionListener() {
          public void actionPerformed(
              ActionEvent actionEvent) {
            // use TransferHandler's built-in 
            // paste action
            Action pasteAction = 
               TransferHandler.getPasteAction();
            pasteAction.actionPerformed(
               new ActionEvent(label,
              ActionEvent.ACTION_PERFORMED,
              (String)pasteAction.getValue(Action.NAME),
              EventQueue.getMostRecentEventTime(),
              0));
            }
        });

        JPanel p = new JPanel();
        p.add(copy);
        p.add(clear);
        p.add(paste);
        contentPane.add(p, BorderLayout.SOUTH);

        frame.setSize(300, 300);
        frame.show();
      }
    }

Notice how the copy and paste actions are just reusing the built-in behavior of the TransferHandler. By simply passing in the appropriate object to act as the source of the ActionEvent, the TransferHandler will invoke the exportToClipboard and importDate methods on that component, respectively. See the javadoc for the TranferHandler class for more information on these methods. It is always possible to manually do this copy and paste behavior. However, since the system provides the behavior for you, why not reuse it? You just have to create the Action.

Specify an image in the command line when you run the program. That will put an initial image into the JLabel. For example:

 
    java DragImage myimage.gif  

The program supports five different copy/paste operations. The Copy button copies the image on the screen's JLabel to the system clipboard. The Paste button copies the image from the system clipboard to the JLabel. The Clear button clears the current image from the JLabel. The last two operations aren't obvious. One of these is that you can initiate a drag operation from the JLabel and drop it in anywhere that permits dropping images of the flavor supported by the Java runtime. For instance, you can drop an image into Microsoft Excel, but not Word. The other operation that isn't obvious is dropping an image onto the JLabel. When you do that, you'll see the image displayed on the JLabel. Try dragging an image from your browser onto the JLabel, and see what happens.

For more information about the the Drag and Drop enhancements in J2SE release 1.4, see "Drag and Drop".

.
.

DISCOVERING THE CALLING METHOD NAME

A common request for developers working with J2SE prior to version 1.4 was to programmatically determine the current location in a program, that is the current method. Typically, developers made this request for logging purposes. Developers still ask the same question today, that is, with J2SE v 1.4. However getting the answer is much more straightforward.

The old way of finding the current location in a program involved generating an exception, printing the stack trace to an in-memory buffer, and then reading back the trace to find out the specific information you were after. After removing the extraneous characters from the line, you're left with the specific method name, as shown here.

    import java.io.*;

    public class ManualDump {
      public static void main(String args[]) 
          throws IOException {
            Throwable t = new Throwable();
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            t.printStackTrace(pw);
            String input = sw.getBuffer().toString();
            StringReader sr = new StringReader(input);
            BufferedReader br = new BufferedReader(sr);
            br.readLine(); // Exception name
            String line = br.readLine();
            int paren = line.indexOf('(');
            line = line.substring(0, paren);
            int period = line.lastIndexOf('.');
            line = line.substring(period+1);
            System.out.println("Method: " + line);
          }
    }

Running ManualDump displays:

    Method: main     

While the old way still works with J2SE version 1.4, there is a much cleaner way to parse stack dumps. A new feature in J2SE version 1.4 is the Chained Exception Facility. This facility allows you to say that Exception X was the cause of Exception Y. The facility also gives you the ability to go beyond printing a stack trace -- instead, you can get the trace and "print" it yourself. You simply call the new getStackTrace method of Throwable. This returns an array of StackTraceElement objects. A part of the class definition is the getMethodName method. The StackTraceElement at index zero is the current method:

    public class AutoDump {
      public static void main(String args[]) {
        Throwable t = new Throwable();
        StackTraceElement elements[] = t.getStackTrace();
        String method = elements[0].getMethodName();
        System.out.println("Method: " + method);
      }
    }

Running AutoDump displays:

    Method: main  

With getStackTrace you can completely recreate the results of printStackTrace, or generate your own style of output. You are not limited to getting the method name.

You might think that with StackTraceElement you have everything you need, and technically you do. However, there is one more thing worth mentioning. If you are getting the method name for logging purposes, don't forget about the Java Logging APIs. The classes found in the java.util.logging package let you log away, and record what the current method is. More importantly the Java Logging APIs allow you to do that without you having to manually discover the method. These APIs were covered in the October 2002 issue of the Core Java Technologies Tech Tips in the tip titled "Filtering Logged Messages". You can look at the source for the getSourceMethodName method of LogRecord to see code similar to that used in the AutoDump example to fetch the given method name.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Core Java Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, CA 95054 USA.


This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html


Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks or registered trademarks (http://www.sun.com/suntrademarks/) of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_324912802111163371@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Mon Mar 24 15:28:31 2003 Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h2OKSVC28816 for ; Mon, 24 Mar 2003 15:28:31 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.8/8.12.8/IUPO) with SMTP id h2OKVWof019611 for ; Mon, 24 Mar 2003 15:31:34 -0500 (EST) Date: 24 Mar 2003 11:14:48 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <324912802111163371@hermes.sun.com> Subject: March 2003 Core Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 14467 Core Java Technologies Newsletter
Core Java Header

Welcome to the new Core Java Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the Java 2 Platform, Standard Edition (J2SE).


Early Access

The following J2SE products and technologies were made available through the Early Access Release Program this month.

Java Access Bridge 1.0.3 Beta 2
This makes it makes it possible for a Windows based Assistive Technology to get at and interact with the Java Accessibility API.

The Java Advanced Imaging API
The Java Advanced Imaging API provides a set of object-oriented interfaces that support a simple, high-level programming model which allows developers to manipulate images easily.

JavaHelp 2.0 Beta
JavaHelp 2.0 Beta is a full-featured, platform-independent, extensible help system that enables developers and authors to incorporate online help in applets, components, applications, operating systems, and devices. This release, a reference implementation for JSR-97, is a major update to the JavaHelp 1.0 Specification.


Product and Technology Releases

The following J2SE products and technologies were recently released.

JSR-000116 SIP Servlet API Specification 1.0 Final Release
The SIP Servlet API defines a high-level extension API for SIP servers. It enables SIP applications to be deployed and managed based on the servlet model.

Java Communications API 2.0.3
The API can be used to write platform-independent communications applications for technologies such as voice mail, fax, and smartcards. This version of the Java Communications API contains support for RS232 serial ports and IEEE 1284 parallel ports.


Hot Downloads

The following are currently the most frequently downloaded J2SE products and technologies.

Java Web Start, US downloads, followed up by International

Java Advanced Imaging Tutorial

JavaBeans Bean Builder

Java Communications API

Java 3D 1.3 API

pixel
pixel pixel pixel
March 27, 2003

Resources

Learn more about, and get "hands-on" training for J2SE technologies through the following resources.

Technical Articles & Quizzes

Tech Tips

Tutorial

Trail: Essential Java Classes
This trail discusses classes from the Java platform that are essential to most programmers. It focuses on classes in the java.lang and java.io packages, including Thread, Throwable and Exception, and the Reader, Writer, InputStream, and OutputStream classes from java.io.

Chat

Java Servlet and JavaServer Pages (JSP) technologies
Read the chat transcripts from this March 11 chat with Marty Hall and Mark Roth.

Books

Java Look and Feel Design Guidelines: Advanced Topics
This book provides advanced guidelines for user interfaces based on the Java Foundation Classes (JFC) with the Java look and feel.

Newsletters

Java Technology Fundamentals Newsletter
Learn how to create applets, threads in applets, and how to use the MediaTracker class.

Events


Java Developer's Marketplace

Sun Education Course: Advanced Object-Oriented Programming
The Advanced Object-Oriented Programming class introduces students to object interaction, including messaging, association, and composition, OO analysis and design using the unified modeling language (UML).


In The Spotlight

Java 2 SDK, version 1.4.1_02 Now Available
A release of the J2SE v1.4 software is available to the Java community! Download it today!

pixel
pixel
pixel
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://developer.java.sun.com/berkeley_license.html
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/

Feedback? Send your comments on the Core Java Technologies Newsletter to: jdc-webmaster@java.sun.com

Subscribe/Unsubscribe:
You can subscribe to other JDC publications on the JDC Newsletters and Publications page, including:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Enterprise Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with enterprise Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You may also unsubscribe using our one-click unsubscribe facility, see the link at the end of this email.

ARCHIVES: You'll find the Core Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/jdc_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA. This document is protected by copyright. For more in formation, see: http://java.sun.com/jdc/copyright.html

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.



Sun Microsystems, Inc.
pixel
Please unsubscribe me from this newsletter.
From env_328928631383757158@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Wed Apr 2 14:52:51 2003 X-UIDL: >o+"!U:1"!\R6!!2W;"! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h32JqpC26476 for ; Wed, 2 Apr 2003 14:52:51 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h32Ju8nM012677 for ; Wed, 2 Apr 2003 14:56:09 -0500 (EST) Date: 2 Apr 2003 11:52:41 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <328928631383757158@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 31988 Status: RO Java Technology Fundamentals Newsletter
pixel
pixel
header
    March 31, 2003    

In this Issue

imageJava Programming Language Basics: Understanding Applets, Part 2
imageJava Bits: Applet Security
imageMaking Sense of the Java Class Libraries: Creating Menus
imageProgram Challenge: Create an applet
imageTake an Online Quiz: Test what you learned
imageNew to Java Technology Programming Center Updates: Introducing Java Technology Workbook
imageFor More Information: Read articles, Tech Tips, trails, and tutorials that provide more information on the topics discussed here.

.

Java Programming Language Basics

Understanding Applets, Part 2

Previously, you learned that developing applets involved subclassing the java.applet.Applet class. This holds for all applets meant to run inside web browsers, no matter what. Sometimes though, when creating your own applets, you don't subclass the Applet class directly. Instead, you subclass a different class, which has subclassed the applet. This allows you to share common code and manage some behavior from a common parent class. Good object-oriented design stuff.

One instance you could implement this is would be when creating an applet that needs to use the Swing component classes. Those applets shouldn't subclass Applet directly but instead should subclass the javax.swing.JApplet class. By subclassing JApplet, the new class works more easily within the Swing framework. However, there are some differences between the two that you should be aware of.

Typically, one adds components to an applet with the add method, as in applet.add(component) or applet.add(component, constraints). With Swing applets, this isn.'t the case. Swing applets contain a single component or content pane. Instead of adding components to the applet itself, you need to add it to the content pane with applet.getContentPane().add(component) or applet.getContentPane().add(component, constraints).

A side effect of this difference is that Swing applets can have menus, whereas regular applets can't (without coding a menu yourself). Some other side effects of this content pane are some layout manager differences. With the standard Applet subclass, the default layout manager for the component is a FlowLayout. That means that as you add components, they are sized to their preferred size, and set out like a typewriter with word wrap, a line at a time, and only if the whole word (component) fits before moving down to the next line.

Because JApplet. as an internal content pane, there is a different layout manager by default, a BorderLayout, allowing you to layout components in the different areas of the screen. In both cases, you can change the layout manager away from the default. The key thing is the default is different in each. There are some other minor differences, but those are the most visible.

To create a simple Swing applet with a handful of components in it, you might do the following:

import java.awt.*;
import javax.swing.*;

public class SwingApplet extends JApplet {

   public void init() {

     Container contentPane = getContentPane();
     contentPane.add(new JButton("North"), BorderLayout.NORTH);
     contentPane.add(new JButton("South"), BorderLayout.SOUTH);
     contentPane.add(new JButton("West"), BorderLayout.WEST);
     contentPane.add(new JButton("East"), BorderLayout.EAST);
     contentPane.add(new JButton("Center"), BorderLayout.CENTER);
   }
}
.
.

Java Bits

Applet Security

Because applets are programs intended to run within a web browser, severe restrictions are placed on what the applet can do, to protect the environment where they execute. Without these restrictions, applets could be a direct vehicle for someone to interfere with your system.

Java programs are run within a controlled environment called a sandbox and managed by a security manager, an object that provides methods that determine what an applet can and cannot do. Along with the security manager, a security policy defines what the applet's limitations are. One part of this the policy file.

A policy file is an ASCII text file and can be composed via a text editor or the graphical Policy Tool utility (policytool). The system policy file is by default located at:

java.home/lib/security/java.policy (Solaris)
java.home\lib\security\java.policy (Win32)

Unless the policy file states otherwise, an applet cannot:

  • Have access to files on the local computer.
  • Invoke other programs on the local computer.
  • Communicate with any computer other than the computer that maintains the HTML page for the applet.

When the applet is launched, it must be launched with the policy file to gain access. Sometimes the permissions in the policy file require an applet be signed to gain access to some URLs and not signed for access to others. All unsigned applets are run under the standard applet security model.

If usePolicy is NOT DEFINED in the java.policy file, then a signed applet has the AllPermission permission if Java Plug-in can verify the signers, and the user agrees to granting the AllPermission permission when prompted.

If usePolicy is DEFINED, then a signed applet has only the permissions defined in java.policy and no prompting occurs.

As of version J2SE 1.4, the Java Plug-In allows you to set applet behavior, including signing applets, and setting options for debugging.

A signed applet is accompanied by a certificate, which identifies the applet signer and prevents others from tampering with the applet. Certificates are issued by Certificate Authorities, such as the U.S. Postal Service or Verisign.

For signing of applets, the jarsigner tool is used:

  • Jarsigner - a tool that is shipped as part of the Java 2 SDK.
    Command is jarsigner.

A digital signature is a string of bits that is computed from some data (the data being "signed") and the private key of an entity, a person or company. Like a handwritten signature, a digital signature has many useful characteristics:

  • Its authenticity can be verified through a computation that uses the public key corresponding to the private key used to generate the signature.

  • It cannot be forged, assuming the private key is kept secret.

  • It is a function of the data signed and thus can't be claimed to be the signature for other data as well.

  • The signed data cannot be changed; if it is, the signature will no longer verify as being authentic.

In order for an entity's signature to be generated for a file, the entity must first have a public/private key pair associated with it, and also one or more certificates authenticating its public key. A certificate is a digitally signed statement from one entity, saying that the public key of some other entity has a particular value.

The jarsigner tool uses key and certificate information from a keystore to generate digital signatures for JAR files. A keystore is a database of private keys and their associated X.509 certificate chains authenticating the corresponding public keys.

The keytool utility is used to create and administer keystores.

The following are basic steps in setting up an applet. Not all steps are necessary. It depends on the applet and what access you want it to have:

  1. Create and Compile the applet

  2. Create a JAR file for the applet classes
    For example:
    jar cvf SignedApplet.jar SignedAppletDemo.class

  3. Generate Keys
    For example:
    keytool -genkey -alias signFiles -keystore susanstore -keypass kpi135 -dname "cn=jones" -storepass ab987c

  4. Sign the JAR file
    For example:
    jarsigner -keystore susanstore -storepass ab987c -keypass kpi135 -signedjar SSignedApplet.jar SignedApplet.jar signFiles
    (Or use Java Plug-In Control Panel)

  5. Export the Public Key Certificate
    For example:
    keytool -export -keystore susanstore -storepass ab987c -alias signFiles -file SusanJones.cer
    (Or use Java Plug-In Control Panel)

  6. Import the Certificate as a Trusted Certificate
    For example:
    keytool -import -alias susan -file SusanJones.cer -keystore raystore -storepass abcdefgh
    (Or use Java Plug-In Control Panel)

  7. Create the policy file policytool or text editor

    Using the Policy Tool saves typing and eliminates the need for you to know the required policy file syntax, thus reducing errors. (See For More Information)

  8. Run the applet
    appletviewer -J-Djava.security.policy=Write.jp
    (Note: the policy file has been saved as Write.jp)
.
.

Making Sense of the Java Class Libraries

Creating Menus

Menus are common in most applications, and allow users to navigate and use different features in an application. Fortunately, menus are easily created for applets.

The Java API provides the following classes to use to create menus:

  • JMenuBar - Groups together JMenu instances.

  • JMenu - Represents a menu title that is contained within the menu bar. It also holds a collection of JMenuItem instances and other submenus.

  • JMenuItem - A menu item, displayed as a word or phrase. Clicking a JMenuItem produces an ActionEvent.

Menu items can also include instances of the following classes:

  • JCheckBoxMenuItem - This class depicts an off or on state with a graphical check mark or other glyph for check boxes.

  • JRadioButtonMenuItem - This class also depicts an off or on state with graphical radio buttons that are placed in a group. Only one option can be selected at a time if the radio buttons are in a group.

Constructing a menu takes only a few steps:

  1. Create a menu bar object by calling the JMenuBar constructor:

    JMenuBar mb = new JMenuBar();

  2. Create a menu object by calling the JMenu constructor and providing a string for the menu name:

    JMenu help = new JMenu("Help");

  3. Call the JMenuBar add method to add the menu to the menu bar:

    mb.add(help);

  4. Create items for the menu by calling the JMenuItem constructor and providing a String for the items titles:

    JMenuItem about = new JMenuItem("About");

  5. Register items with listeners as necessary:

    about.addActionListener(new java.awt.event.ActionListener());

  6. Once your menus are complete, set the menu bar in the applet by calling the setJMenuBar method:

    setJMenuBar(mb);

The following class illustrates the concepts above by creating an applet with three menus. The Help menu has a menu item called About that when selected pops up a JOptionPane window. The Colors menu demonstrates radio buttons used within menus.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SwingApplet extends JApplet{

 JMenuBar mb;
 JRadioButtonMenuItem rb;
 
   public void init() {
     Container c = getContentPane();
     c.setBackground(Color.WHITE);
     
     //Create a menu bar.
     mb = new JMenuBar();
     
     //Create a menu.
     JMenu file = new JMenu("File");
     
     //Add menu items to the menu.
     file.add(new JMenuItem("Open"));
     //Add a line separator
     file.addSeparator();
     file.add(new JMenuItem("Save"));
     file.add(new JMenuItem("Close"));
     //Add the File menu and items to the
     //menu bar.
     mb.add(file);
     
     //Create another menu called Help.   
     JMenu help = new JMenu("Help");
     //Create a menu item with and register
     //it with a listener.    
     JMenuItem about = new JMenuItem("About");
     help.add(about);
     about.addActionListener(new java.awt.event.ActionListener(){
       public void actionPerformed(ActionEvent e) {
         about_actionPerformed(e);
         }
       }); 
     //Add the Help menu and items to the menu bar
     mb.add(help);
     
     //Create a menu called Colors that will have a 
     //submenu with radio buttons.     
     JMenu subMenu= new JMenu("Colors");
     
     ButtonGroup group = new ButtonGroup();
     subMenu.add(rb = new JRadioButtonMenuItem("Blue", true));
     group.add(rb);
     subMenu.add(rb = new JRadioButtonMenuItem("Red"));
     group.add(rb);
     subMenu.add(rb = new JRadioButtonMenuItem("White"));
     group.add(rb);
     subMenu.add(rb = new JRadioButtonMenuItem("Black"));
     group.add(rb);
     //Add to menu bar.
     mb.add(subMenu);
        
     //Set the menu bar in the applet.
     setJMenuBar(mb);
   }
    //Provides the functionality of the About menu item.
    public void about_actionPerformed(ActionEvent e) {
      JOptionPane.showMessageDialog(this,"Swing Applet, 1.0.");
      }
}

When the applet class is run in appletviewer or your browser, you should see the following:

Source code

.
.

Program Challenge

Write an applet that loads pages from anywhere on the web and saves HTML content on the local hard drive. The applet needs to be signed and trusted such that network access to anywhere is permissible as is access to the local file system. The applet screen should only show the page within a JTextArea with load and save options available within a menu.

See a possible solution to the Challenge

.
.

Take an Online Quiz

Test what you learned about creating menus and applet security.

.
.

New to Java Technology Programming Center

Introducing Java Technology Workbook! The best way to learn programming is by programming. This online workbook has exercises and the solutions to challenge your Java programming knowledge. Each month a new exercise will be added to this section of the web site.

Java Technology Workbook

.
.

For More Information

Policy Tool

Java Plug-in 1.4 Developer Guide Contents

Signed Applets, Browsers, and File Access

Applet Security FAQ

Lesson: Quick Tour of Controlling Applets

.
.

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SE development kit.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Java Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
image
image
Please unsubscribe me from this newsletter.
From env_334626171738619524@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue Apr 15 11:22:53 2003 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h3FGMrC08517 for ; Tue, 15 Apr 2003 11:22:53 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h3FGQOnM005083 for ; Tue, 15 Apr 2003 11:26:24 -0500 (EST) Date: 15 Apr 2003 09:13:07 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <334626171738619524@hermes.sun.com> Subject: Enterprise Java Technologies Tech Tips, April 15, 2003 (Publish/Subscribe Messaging, Using DOM) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 46787 Enterprise Java Technologies Tech Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text April 15, 2003    

In this Issue

Welcome to the Enterprise Java Technologies Tech Tips for April 15, 2003. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EE).

This issue covers:

.Publish/Subscribe Messaging With JMS Topics
.Using the Document Object Model

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample code. The context root for the application is ttapr2003. The index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms.

.

PUBLISH/SUBSCRIBE MESSAGING WITH JMS TOPICS

The tip Using JMS Queues in the March 11, 2003 issue explained how to use Java Messaging Service (JMS) Queues for point-to-point messaging. The tip that follows explains how to implement publish/subscribe messaging using JMS Topics.

Publish/Subscribe Messaging

In publish/subscribe messaging, a single publisher sends each message to multiple subscribers with a single method call. Between the publisher and subscriber is a messaging server. In JMS, the messaging server is called a "JMS provider". The publisher sends messages to the JMS provider. Subscribers receive messages from the JMS provider.

This arrangement is illustrated in the following figure.

PubSub

In JMS, publish/subscribe messaging uses a JMS-managed object called a Topic to manage message flow from publishers to subscribers. JMS publishers are called message producers, and JMS subscribers are called message consumers. A message producer acquires a reference to a JMS Topic on a server, and sends messages to that Topic. When a message arrives, the JMS provider is responsible for notifying all message consumers subscribed to that Topic. The JMS provider (optionally) receives acknowledgment of the message receipt each time it sends the message.

This is illustrated below.

PublishSubscribe

Publish/subscribe messaging using JMS Topics is similar to point-to-point messaging in several ways. The following properties apply to both kinds of messaging:

  • Messaging can be object-oriented, allowing entire objects to be sent as messages.
  • Messaging can be transactional.
  • Messaging can be synchronous or asynchronous.
  • Messaging can be integrated with underlying third-party products.
  • A message may be sent to a message consumer (that is, a QueueReceiver or TopicSubscriber) that is not running at the time the message is sent.
  • A function call that sends a message returns as soon as the message is delivered to the queue or topic.
  • Message receipt can be acknowledged explicitly or automatically.

There are also several differences between point-to-point and publish/subscribe messaging:

  • Publish/subscribe messaging is one-to-many, while point-to-point messaging is one-to-one.
  • A published message is delivered only to current subscribers of a Topic. A client receives only those messages published after the client subscribes to a Topic. By contrast, in point-to-point messaging, a persistent message sits in a Queue until either it times out, or until some receiver comes along to retrieve the message.
  • Persistent messages in publish/subscribe messaging are provided by "durable subscriptions". The JMS provider stores messages that can't be delivered to a subscriber because the subscriber is unavailable for some reason. The stored messages are delivered the next time the subscriber connects. This ensures delivery of all messages published after the client subscribes to a Topic -- even if the subscriber isn't always running. If a subscription isn't durable, any messages published while the subscriber is down are never delivered to the subscriber.

Neither publish/subscribe messaging nor point-to-point messaging is superior to the other. Rather, they are complementary tools, used for different purposes. Point-to-point messaging is often used where the message receiver has a unique identity within a system. Publish/subscribe messaging is more often used when several agents in a system need to know when an event or condition occurs.

The JMS messaging model is very similar to event listeners in conventional Java 2 programming. Point-to-point messaging is like a unicast event listener model. Publish-subscribe messaging is like a multicast listener model. The difference between traditional Java event listeners and JMS (other than programming syntax) is that the event sources and listeners are called message producers and consumers, respectively. JMS message producers and consumers can run in different address spaces, or even on different machines. JMS messaging also provides a much higher level of service than does the traditional event listener model. Nevertheless, the basic messaging model is the same.

The sample code for this tip, comprises three programs:

  1. A servlet, PublishWeatherServlet, that publishes an XML-formatted weather report to a JMS Topic
  2. A command-line Java application, WeatherReceiver, that subscribes to the Topic and prints the XML messages it receives.
  3. A GUI application client, WeatherClient, that parses and graphically displays the data in the XML message.

Here's a screen shot of an HTML page and Web form for publishing the weather report, a terminal session running the command-line subscriber, and the GUI application.

screenshot
Click here to Enlarge

Publishing a Message To A Topic

The PublishWeatherServlet servlet receives POST parameters from an HTML form, formats them as XML, and uses a JMS Topic to publish the resulting XML document to all listeners. Much of the code in this servlet is dedicated to receving the POST parameters and formatting them as an XML document. The interesting part of the code is in the publish method. This method takes a single String argument containing the XML text to be published. Let's examine the publish method in detail, and see how it publishes to a JMS Topic:

  1. Get a TopicConnectionFactory and a Topic.
          protected void publish(String text) {
          
             TopicConnectionFactory tcf = null;
             Topic topic = null;
          
             try {                  
                Context jndiContext = new InitialContext();
                tcf = (TopicConnectionFactory)
                   jndiContext.lookup(
                   "java:comp/env/jms/TopicConnectionFactory");
                topic = (Topic) jndiContext.lookup(
                   "java:comp/env/jms/Topic");
             } catch (NamingException nameEx) {
                System.err.println(nameEx.toString());
             }
    
    This code uses the Java Naming and Directory Interface (JNDI) API to look up two objects on the JMS provider: a Topic and a TopicConnectionFactory. The servlet will send the message to the Topic. The TopicConnectionFactory will be used to create a connection to the JMS provider. Note the names the servlet uses to look up these objects. Remember that the JNDI API names of all objects in a J2EE application should begin with "java:comp/env/".

  2. Create a Connection, Session, and Publisher.
          TopicConnection tc = null;                        
          
          try {   
             tc = tcf.createTopicConnection();
             TopicSession ts =
                tc.createTopicSession(
                   false, Session.AUTO_ACKNOWLEDGE);
             TopicPublisher tp =
                ts.createPublisher(topic);
    
    This code uses the TopicConnectionFactory acquired from the JNDI API to create a TopicConnection. The TopicConnection can then be used to create a TopicSession. The arguments to create TopicSession tell the connection to create a TopicSession that is not transactional, and that automatically acknowledges message receipt. (If message delivery were transactional, all messages sent in the same TopicSession would form a unit of work that could be committed or rolled back.) The Session is then used to create a TopicPublisher, which acts as the channel through which messages can be published.

    Note that the J2EE 2.0 Specification indicates that the transactionality and acknowledgement of JMS messaging is managed by the J2EE container. This means that these arguments are ignored if the code is running within a container. Unfortunately, not all vendors comply with this requirement. If transactions, acknowledgement, or both are important for your application, be sure to check your product documentation. Alternatively, test the behavior of these arguments yourself. These arguments should work as expected outside of a container.

  3. Create and publish the message.
             TextMessage textMessage =
                ts.createTextMessage();
             textMessage.setText(text);
             tp.publish(textMessage);
             ...
      } // End of method publish
    
    Publishing the message is simple. The TopicSession acts as a factory to create a new TextMessage. The code sets the text of the TextMessage to the string containing the XML to send. It then uses the TopicPublisher to publish the message to the Topic.

That's all there is to it. The JMS provider is responsible for delivering the message to all subscribers.

Subscribing to a Topic and Receiving Messages

The command-line program, WeatherReceiver, subscribes to a Topic and prints any messages it receives from the Topic. To simplify matters, the process of subscribing to a Topic is encapsulated in the auxiliary class SubscriptionHelper. The WeatherReceiver class acts as an asynchronous message receiver, and actually performs the printing.

  1. Subscribing to a Topic

    The following code, from class SubscriptionHelper, creates a subscription to a Topic:
         protected TopicConnection _tc;
         ...
         
         public SubscriptionHelper(String tcfName,
                                String topicName,
                                MessageListener listener) {
    
            // Get references to topic connection factory 
            // and topic.
            _tc = null;
            TopicConnectionFactory tcf = null;
            Topic topic = null;
    
            try {
               InitialContext ic = new InitialContext();
               tcf = (TopicConnectionFactory)
                  ic.lookup(tcfName);
               topic = (Topic) ic.lookup(topicName);
            } catch (NamingException e) {
               System.err.println(e.toString());
               e.printStackTrace(System.err);
            }
    
            try {
               // Create a connection and so on
               // Subscribe self to topic--messages will be
               // delivered to this.onMessage()
               _tc = tcf.createTopicConnection();
               TopicSession ts = 
                  _tc.createTopicSession(
                    false, Session.AUTO_ACKNOWLEDGE);
               TopicSubscriber tsub = 
                 ts.createSubscriber(topic);
               tsub.setMessageListener(listener);
            } catch (JMSException e) {
               System.err.println(e.toString());
               e.printStackTrace(System.err);
               close();
            }
         }
    
    Most of the SubscriptionHelper class is identical to the publisher code. It uses the JNDI API to acquire references to a Topic and TopicConnectionFactory, and creates TopicConnection and TopicSession objects. But instead of creating a TopicPublisher, this class creates a TopicSubscriber, and sets the TopicSubscriber's message listener to the MessageListener that was passed in. After this point, whenever that Topic receives a message, the message is delivered to the onMessage method of the MessageListener. Because a callback in used in this way, this example demonstrates asynchronous message reception.

  2. Receiving Messages

    The only requirement to receive messages is that the class implement interface javax.jms.MessageListener. The WeatherReceiver class is itself a MessageListener. The MessageListener interface has only method: onMessage. The WeatherReceiver's onMessage method appears below:
         public class WeatherReceiver implements 
            MessageListener {
     
            // Print a weather message when it is received
            public void onMessage(Message message) {
               try {
                   if (message instanceof TextMessage) {
                      TextMessage m = (TextMessage) message;
                      System.out.println(
                         "--- Received weather report");
                      System.out.println(m.getText());
                      System.out.println("----------");
                   } else {
                      System.out.println(
                         "Received message of type " +
                          message.getClass().getName());
                   }
              } catch (JMSException e) {
                 System.err.println(e.toString());
                 e.printStackTrace(System.err);
              }
           }
           ...
           public static void main(String[] args) {
    
              if (args.length != 2) {
                 System.out.println(
                    "Usage: WeatherReceiver " +
                    "topicConnectionFactorName topicName");
                 System.exit(1);
              }
    
             // Create a receiver, then set it up to listen 
             // for messages on the topic. Then wait for 
             // messages and print them as they come in.
             WeatherReceiver wr = new WeatherReceiver();
             SubscriptionHelper sh =
                new SubscriptionHelper(args[0], args[1], wr);
          
             // Wait for publications...
             System.out.println(
               "Waiting for publications to topic " + 
               args[1]);
             sh.waitForMessages();
          }
    
    The WeatherReceiver's main method creates a WeatherReceiver instance and a SubscriptionHelper instance. It passes the SubscriptionHelper the WeatherReceiver and the names of the Topic and TopicConnectionFactory that the application should use (these are specified on the command line). The SubscriptionHelper instance creates the subscription. It then registers the WeatherReceiver as the message consumer for messages from the Topic.

    The onMessage method simply casts received Messages to class TextMessage, where appropriate, and prints the received XML document.

    Note that using JMS listeners in the Web tier is a bad idea. In fact, it's disallowed by the J2EE 1.3 Reference Implementation. Server-side JMS listeners are appropriately modeled as Message Driven Beans in the EJB tier.

Deploying the Web Application

Publish/subscribe messaging code is easy with JMS. However, the deployment descriptor presents an issue that requires resolution. PublishWeatherServlet is a Web component that looks up external components using the JNDI API. Web components look up external resources (such as Topics and TopicConnectionFactories) using a coded name. The deployment descriptor must define these coded names as resource references or resource environment references. The following excerpt from the Web application's deployment descriptor web.xml defines the coded names used by the servlet. (This code appears after <welcome-file-list> in web.xml.)

   <!-- JMS topics and connection factories used -->
   <resource-env-ref>
     <resource-env-ref-name>
       jms/Topic
     </resource-env-ref-name>
     <resource-env-ref-type>
       javax.jms.Topic
     </resource-env-ref-type>
   </resource-env-ref>

   <resource-ref>
     <res-ref-name>
       jms/TopicConnectionFactory
     </res-ref-name>
     <res-type>
       javax.jms.TopicConnectionFactory
     </res-type>
     <res-auth>
       Container
     </res-auth>
   </resource-ref>

The resource-env-ref block defines the name "jms/Topic" as being of type javax.jms.Topic. The string "jms/Topic" is the string used to look up the Topic ("java:comp/env/jms/Topic"), with the "java:comp/env/" part deleted. The deployment tools for a product allow the application deployer to map this name to a Topic in the environment.

In the case of the J2EE Reference Implementation, this mapping is already configured in the Web archive in the file META-INF/sun-j2ee-ri.xml. This file is the Web application's runtime deployment descriptor. The runtime deployment descriptor is vendor-specific both in name and in content.

The resource-ref block defines the name, type, and authorization mode for the TopicConnectionFactory. Usually, a deployer would use deployment tools to associate the coded name jms/TopicConnectionFactory with a TopicConnectionFactory in the platform. The J2EE Reference Implementation comes preconfigured with a TopicConnectionFactory called jms/TopicConnectionFactory in the JNDI namespace.

.
.

USING THE DOCUMENT OBJECT MODEL

The WeatherReceiver described in the tip "Publish/Subscribe Messaging With JMS Topics" above receives XML messages from a publisher, and prints those messages to the screen. But one of the major reasons to format data as XML is to be able to separate the pieces of data in the file and use them in various places.

The tip Creating Parsers with JAXP in the February 11, 2003 issue explained how to use JAXP to create a DocumentBuilder class that can parse an XML document, returning an object of type org.w3c.dom.Document. The tip that follows explains how to use the Document Object Model (DOM) APIs to get information from a parsed XML Document.

DOM Concepts

XML markup can be represented as a tree of nodes. Each node can represent a feature in the XML such as an element, an attribute, a comment, or a piece of text. A tree of these objects forms a model of the XML document. The Document Object Model is a set of APIs that provide programmatic access to a virtual tree of nodes that represent XML document features.

A JAXP DocumentBuilder parses a character stream formatted in XML notation, and returns an object that implements interface org.w3c.dom.Document. The Document object represents the entire XML document as one object, but the objects within the XML document are accessible through the Document methods. The virtual tree represented by the Document object is often called a DOM tree.

The DOM has quite a number of interfaces, all of which reside in package org.w3c.dom (as defined by the World Wide Web Consortium, W3C). A few of the interfaces are of special interest:

  • The Node interface is the highest-level interface in the DOM. Almost every interface in the DOM extends Node. A Node simply represents a distinct feature in the input XML. A Node has exactly one parent node, zero or more sibling nodes, and zero or more child nodes. Methods of interface Node, which its subinterfaces inherit, allow a programmer to access the parent, child, and siblings of any Node in a DOM tree.
  • The Document interface represents an entire XML document. It is usually created by an XML parser. It contains the top-level element, and can also contain nodes for the XML declaration, processing instructions, and DTD elements.
  • The Element interface represents a tag in an XML document. Its parent Node is the Node that contains it (the containing Node is the Document, in the case of the top-level tag). An Element's sibling nodes are all nodes that share that parent, and its child nodes are all tags that it contains. Elements are frequently accessed by their tag name. Attributes are modeled separately.
  • The CharacterData interface represents character data that is not in a tag. CharacterData has three subinterfaces: Text, which represents Text nodes; CDATASection, which represents CDATA; and Comment, which (optionally) represents comments. Parser settings determine whether or not comments appear in the parser output.

Many DOM methods have return type NodeList. A NodeList does not represent a feature in an XML document, but rather represents a list of Nodes. Interface NodeList has two methods: getLength, which returns the number of items in the list; and item, which returns the nth item in the list (numbered from 0 to getLength-1). Methods that access attributes return a NamedNodeMap instead.

You can explore the DOM interfaces for yourself in the documentation for package org.w3c.dom, which is a part of the standard J2EE distribution.

Getting Data from a DOM Tree

The WeatherClient sample program that was introduced in the tip "Publish/Subscribe Messaging With JMS Topics" receives an XML document from a Topic in exactly the same way as the WeatherReceiver described in that tip. But instead of printing the XML, as WeatherReceiver does, WeatherClient parses the XML as a DOM tree. WeatherReceiver then uses pieces of data from the tree to create HTML, which it then displays in a Swing GUI. Receiving the XML and parsing it have already been covered in other tips, such as Creating Parsers with JAXP, so this section focuses on how the WeatherReceive program accesses the data in the DOM tree.

The WeatherClient's onMessage method receives the XML and parses it with a DocumentBuilder, resulting in a DOM tree rooted in the Document variable doc. The following code from class WeatherClient gets the top-level element from the document. Then three methods pull different subsets of data out of that element, and return the data subsets formatted as HTML. Each of the three HTML display panels in the application gets different HTML.

      if (doc != null) {
         Element e = doc.getDocumentElement();
         // Set the HTML for the first panel
         _panels[0].setText(getCurrentConditionsHtml(e));
         _panels[1].setText(getForecastHtml(e));
         _panels[2].setText(getDetailedForecastHtml(e));
         pack();
      }

A sample of the beginning of the XML message received by the program appears below.

   <weather-report>
     <current>
       <conditions>
         <sky>C</sky>
         <temp>15</temp>
         <humidity>23</humidity>
         <wind>
           <speed>14</speed>
           <dir>SW</dir>
         </wind>
       </conditions>
     </current>
     ... <!-- Followed by "forecast" and "detailed
     ...  forecast elements" -->
   </weather-report>

The top-level Element returned by getDocumentElement() is the top-level tag, <weather-report>. Method getCurrentConditionsHtml pulls pieces of text out of the XML and formats them as HTML for display in the GUI. The method first creates a PrintWriter that writes to a String, so the resulting XML can be returned as a String.

   // Get "current conditions" from document
   protected String getCurrentConditionsHtml(
     Element top) {
      StringWriter sw = new StringWriter(4096);
      PrintWriter pw = new PrintWriter(sw);
      Element current, conditions, el;

      pw.println("<HTML><BODY><CENTER>");
      pw.println("<TABLE BORDER=0>");
      current = getFirstMatchingElement(
         top, "current");
      conditions = getFirstMatchingElement(
         current, "conditions");

The code then gets the first element matching the name "current". Then it gets the first element matching the name "conditions" under "current". At this point, the method has a handle to the object representing the tag <conditions> in the XML excerpt above. The next section of code formats the display of the condition of the sky:

      el = getFirstMatchingElement(conditions, "sky");
      String sky = getMergedTextChildren(el);
      sky = getSkyDescription(sky);
      pw.println(
        "<TR><TD BGCOLOR=BLUE COLSPAN=2 ALIGN=CENTER>");
      pw.println("<H1><FONT COLOR=\"WHITE\">");
      pw.println(sky);
      pw.println("</FONT></H1></TD></TR>");

Because the Element "conditions" contains only one Element called "sky", the <sky> Element can be retrieved by name, using method getFirstMatchingElement. Method getMergedTextChildren gets the contents of the element as a string. That string is then formatted as HTML.

Method getFirstMatchingElement is defined in WeatherClient as follows:

   static protected Element getFirstMatchingElement(
                             Node n, String nodeName) {
      NodeList nl;
      Element el = null;

      if (n instanceof Element) {
         el = (Element)n;
      }

      if ((el != null) &&
          (nl = el.getElementsByTagName(nodeName)) 
          != null &&
          nl.getLength() != 0) {
         el = (Element)(nl.item(0));
         return el;
      }
      return null;
   }

The first line ensures that what was passed in was an element, and typecasts the Node to an Element. If the Element is non-null and contains (however far down the tree) nodes with the requested name, the first of these nodes is returned. Otherwise, the method returns null.

Method getMergedTextChildren combines all non-comment CharacterData nodes (Text nodes and CDATASection nodes) into a single string. The text contained inside the sky element is composed of CharacterData nodes, not Elements. Method getMergedTextChildren combines the zero or more Text and CDATASection nodes under the node passed in to a single string.

   protected static String getMergedTextChildren(
                                           Element e) {
      NodeList nl = e.getChildNodes();
      String result = "";
      for (int i = 0; i < nl.getLength(); i++) {
         Node n = nl.item(i);
         if (n instanceof Text) {
            result = result + ((Text)n).getData();
         } else if (n instanceof CDATASection) {
            result = result + 
            ((CDATASection)n).getData();
         }
      }
      return result;
   }

These methods are used multiple times in the code to simplify working with the DOM.

Making It Easier On Yourself

You might have noticed that the DOM interfaces are somewhat clumsy to use. The reason DOM seems to require a great deal of coding to do something simple is because it was designed to interoperate with many different source languages. Not all of these languages have a syntax that is as succinct as Java. Fortunately, there are other solutions:

  • Create your own suite of auxiliary methods (the approach taken in the sample above) and handle such problems yourself.
  • Use stylesheets to transform the XML from one format to another, instead of manipulating them programmatically.
  • Consider a free, open-source interface such as JDOM, which simplifies XML coding. While the DOM was designed for multiple platforms and language bindings, JDOM is designed to make writing code that manipulates XML trees in memory as easy as possible in Java. While it is not part of the J2EE distribution, it is freely available, will work with J2EE installations, and is backward-compatible with the DOM interfaces.
.
.

RUNNING THE SAMPLE CODE

The sample code for the tips consists of two archives: an EAR file containing a Web application, and a JAR file containing two application clients. For convenience, the JAR file is packaged inside the EAR file. Visit the application context root (see below) and follow the instructions to download the application client JAR file from the Web application.

The Web application publishes from the Web tier to both application clients in the Client Tier. Running both clients, or even multiple copies of both clients simultaneously, helps to demonstrate the one-to-many nature of publish/subscribe messaging.

Publishing: Download the sample archive for these tips. The application's context root is ttapr2003. The downloaded EAR file also contains the complete source code for the sample.

You can deploy the application archive (ttapr2003.ear) in the J2EE Reference Implementation using the deploytool program:

    $J2EE_HOME/deploytool -deploy ttapr2003.ear localhost

Replace localhost with the name of the host on which the server is installed. For a standard installation on a single machine, the hostname typically (and literally) is localhost. You can access the application at http://localhost:8000/ttapr2003. Visiting this URL in a Web browser will present you with an HTML form that you can use to publish weather reports. The servlet publishes to the JMS Topic called "jms/Topic", and uses the Topic Connection Factory called "jms/TopicConnectionFactory" (these are the names of the default topic and connection factory that come pre-configured with the Reference Implementation).

Also, use deploytool to undeploy the application when you're finished with it. The -uninstall argument of deploytool takes the application name, not the EAR file name, as an argument:

    deploytool -uninstall Apr2003 localhost

For a J2EE-compliant implementation other than the Reference Implementation, use your J2EE product's tools to deploy the application on your platform, and then undeploy it when you're finished with it.

Receiving XML Text: The sample code also contains a JAR file, ttapr2003.jar, that receives messages from the topics listed above. To run the WeatherReceiver on the command line, be sure that ttapr2003.jar is in your classpath, and execute the following command:

   java com.elucify.tips.apr2003.WeatherReceiver

Using the GUI: The sample JAR ttapr2003.jar also contains a Swing GUI. To use it, be sure that the jar file is in your path, and execute:

   java com.elucify.tips.apr2003.WeatherClient

Either of the two receivers can be configured to use a different TopicConnectionFactory and Topic by providing their JNDI names on the command line.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: jdc-webmaster@sun.com

Subscribe to other Java developer Tech Tips:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SE).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/index.html


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA.

This document is protected by copyright.

Enterprise Java Technologies Tech Tips
April 15, 2003


Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_346379131285273175@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri May 2 13:34:18 2003 Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h42IYIC07162 for ; Fri, 2 May 2003 13:34:18 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h42Ic7nM021806 for ; Fri, 2 May 2003 13:38:07 -0500 (EST) Date: 2 May 2003 11:20:09 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <346379131285273175@hermes.sun.com> Subject: Java(TM) Technology Fundamentals Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 32897 Java Technology Fundamentals Newsletter
.
.
Java Technology Fundamentals Newsletter header
    April 30, 2003    

In this Issue

imageJava Programming Language Basics: Using Sorting in Applications
imageJava Bits: Identify Culturally Dependent Data
imageMaking Sense of the Java Class Libraries: The Collator and CollationKey Classes
imageProgram Challenge: Create a Sorting Application
imageTake an Online Quiz: Test what you learned
imageNew to Java Technology Programming Center Updates: SunEd Web and Instructor Led Java Technology Courses
imageFor More Information: Read articles, Tech Tips, trails, and tutorials that provide more information on the topics discussed here.

.

Java Programming Language Basics

Using Sorting in Applications

Sorting support is built into the standard libraries of the Java platform. You can make your own classes sortable, and redesign third-party classes to be sortable if they weren't originally.

Support for sorting starts with the Comparable interface. A single method interface defined in the java.lang package:

public interface Comparable {
     public int compareTo(Object o);
}

If a class implements the Comparable interface, it is directly sortable. That's really all there is to sorting a series of instances of the system classes that implement the interface. Those systems classes are as follows:

BigDecimal, BigInteger, Byte, ByteBuffer, Character, CharBuffer, Charset, CollationKey, Date, Double, DoubleBuffer, File, Float, FloatBuffer, IntBuffer, Integer, Long, LongBuffer, ObjectStreamField, Short, ShortBuffer, String, URI

To demonstrate, the following program sorts a series of String objects that are commandline arguments. It uses the sort method of the java.util.Arrays class to reorder the elements of the command-line argument array.

import java.util.Arrays;

public class SortArgs {
   public static void main(String args[]) {
     printArray(args, "Before");
     Arrays.sort(args);
     printArray(args, "After");
   }
   private static void printArray(String array[], String header) {
     System.out.println("\n\n" + header);
     for (int i=0, n=array.length; i<n; i++) {
       System.out.println(i + ": " + array[i]);
     }
   }
}

If you were to run the program with the following command line:

java SortArgs one two three four five

You'd get the following results:

Before
0: one
1: two
2: three
3: four
4: five

After
0: five
1: four
2: one
3: three
4: two

It really is that simple to sort system classes.

For your own classes, you can implement Comparable. As you'll recall in the interface, the compareTo method returns an int. By providing a compareTo method that returns the proper value when comparing two instances of your own class, you can make your classes Comparable. And what are those return values? The easy one is for when two classes are equal. That causes compareTo to return a value of zero (0). When the specific instance of the class is logically less than the passed in instance, compareTo returns a negative number (like -1). That leaves > to be a positive number. One other thing needs to be added though. The compareTo method is only defined to work when comparing equivalent classes. If the object passed in isn't equvalent, a ClassCastException is thrown.

To demonstrate, let us define a Name object with a first name and last name. Name is sortable with last name first. So, in the compareTo method, you essentially need to bundle two compareTo calls, one for each variable, where the second is only called if the first is equal.

public class Name implements Comparable {
   private String lastName;
   private String firstName;
   public Name(String first, String last) {
     firstName = first;
     lastName = last;
   }
   public int compareTo(Object o) {
     // This automatically throws exception if wrong type
     Name other = (Name)o;
     int returnValue = lastName.compareTo(other.lastName);
     if (returnValue == 0) {
       returnValue = firstName.compareTo(other.firstName);
     }
     return returnValue;
   }

   public String toString() {
     return "Name[" + lastName + "," + firstName + "]";
   }
}

To test the program, the following example creates several names, sorts them, and prints out the before and after sorted order.

import java.util.Arrays;

public class SortName {
   public static void main(String args[]) {
     Name names[] = {
       new Name("John", "Doe"),
       new Name("Jane", "Doe"),
       new Name("Mary", "Jane"),
       new Name("Mary", "Doe"),
       new Name("John", "Smith"),
       new Name("Mary", "Smith"),
     };
     printArray(names, "Before");
     Arrays.sort(names);
     printArray(names, "After");
   }

   private static void printArray(Name array[], String header) {
     System.out.println("\n\n" + header);
     for (int i=0, n=array.length; i<n; i++) {
       System.out.println(i + ": " + array[i]);
     }
   }
}

Notice how the results show the names sorted in proper order.

Before
0: Name[Doe,John]
1: Name[Doe,Jane]
2: Name[Jane,Mary]
3: Name[Doe,Mary]
4: Name[Smith,John]
5: Name[Smith,Mary]


After
0: Name[Doe,Jane]
1: Name[Doe,John]
2: Name[Doe,Mary]
3: Name[Jane,Mary]
4: Name[Smith,John]
5: Name[Smith,Mary]

The last thing to mention is what to do when you need to sort instances of a class where the original class designer didn't implement Comparable, or if you don't like the sort order originally defined. By creating your own java.util.Comparator (or reusing one previously defined), you can define your own sorting mechanism.

For instance, by default, instances of the String class are sorted in case sensitive order, so that Smith, sMith, and smith are not equivalent. If you'd like to sort in a case insensitive manner, you can ask the String class for its CASE_INSENSITIVE_ORDER Comparator.

By making a quick change to the SortArgs program, and adding the optional second argument of a Comparator to the Arrays.sort call, the following code demonstrates the use of a Comparator:

import java.util.Arrays;
import java.util.Comparator;

public class SortArgs2 {
   public static void main(String args[]) {
     printArray(args, "Before");
     Arrays.sort(args);
     printArray(args, "After");
     Comparator comp = String.CASE_INSENSITIVE_ORDER;
     Arrays.sort(args, comp);
     printArray(args, "Insensitive");
   }
   private static void printArray(String array[], String header) {
     System.out.println("\n\n" + header);
     for (int i=0, n=array.length; i<n; i++) {
       System.out.println(i + ": " + array[i]);
     }
   }
}

A command line as follows:

java SortArgs2 one2 One3 oNe1 ONE Two

generates the following results:

Before
0: one2
1: One3
2: oNe1
3: ONE
4: Two


After
0: ONE
1: One3
2: Two
3: oNe1
4: one2


Insensitive
0: ONE
1: oNe1
2: one2
3: One3
4: Two

Notice the difference between the original After results and the Insensitive results.

For those classes that aren't Comparable, you define a Comparator and provide that to the Arrays.sort method. Or, as previously mentioned, just change the default sort order.

To demonstrate, add getFirstName and getLastName methods to the Name class:

public class Name implements Comparable {
   private String lastName;
   private String firstName;
   public Name(String first, String last) {
     firstName = first;
     lastName = last;
   }
   public String getFirstName() {
     return firstName;
   }
   public String getLastName() {
     return lastName;
   }
   public int compareTo(Object o) {
     // This automatically throws exception if wrong type
     Name other = (Name)o;
     int returnValue = lastName.compareTo(other.lastName);
     if (returnValue == 0) {
       returnValue = firstName.compareTo(other.firstName);
     }
     return returnValue;
   }

   public String toString() {
     return "Name[" + lastName + "," + firstName + "]";
   }
}

Now, change the original name-sorting example to do first name first, instead of the original last name first. The compare method of Comparator works similarly to the compareTo method of Comparable, returning signed numbers to determine positioning. The one difference being that compareTo takes two arguments, instead of one, as both objects to compare must be passed in for comparison.

import java.util.Arrays;
import java.util.Comparator;

public class SortName2 {
   public static void main(String args[]) {
     Name names[] = {
       new Name("John", "Doe"),
       new Name("Jane", "Doe"),
       new Name("Mary", "Jane"),
       new Name("Mary", "Doe"),
       new Name("John", "Smith"),
       new Name("Mary", "Smith"),
     };
     printArray(names, "Before");
     Comparator comp = new Comparator() {
       public int compare(Object o1, Object o2) {
         // This automatically throws exception if wrong type
         Name first = (Name)o1;
         Name second = (Name)o2;
         int returnValue = 
           first.getFirstName().compareTo(second.getFirstName());
         if (returnValue == 0) {
           returnValue = 
           first.getLastName().compareTo(second.getLastName());
         }
         return returnValue;
       }
     };
     Arrays.sort(names, comp);
     printArray(names, "After");
   }

   private static void printArray(Name array[], String header) {
     System.out.println("\n\n"+header);
     for (int i=0, n=array.length; i<n; i++) {
       System.out.println(i + ": " + array[i]);
     }
   }
}

Running the sample program now produces the following output:

Before
0: Name[Doe,John]
1: Name[Doe,Jane]
2: Name[Jane,Mary]
3: Name[Doe,Mary]
4: Name[Smith,John]
5: Name[Smith,Mary]


After
0: Name[Doe,Jane]
1: Name[Doe,John]
2: Name[Smith,John]
3: Name[Doe,Mary]
4: Name[Jane,Mary]
5: Name[Smith,Mary]

Since the toString method hasn't changed, last names are still printed first. However, notice that the names are now sorted with first name first, not last.

.
.

Java Bits

Identify Culturally Dependent Data
by Monica Pawlan

To internationalize an application, the first thing you need to do is identify the culturally dependent data in your application. Culturally-dependent data is any data that varies from one culture or country to another. Text is the most obvious and pervasive example of culturally dependent data, but other things like number formats, sounds, times, and dates should be considered too.

Read More

.
.

Making Sense of the Java Class Libraries

The Collator and CollationKey Classes

Applications sort through text by performing frequent string comparisons. If your application audience is limited to people who speak English, you can perform string comparisons with the String.compareTo method, which performs a binary comparison of the Unicode characters within the strings.

For most languages, however, this binary comparison is reliable because the Unicode values do not correspond to the relative order of the characters.

Fortunately, the Collator class enables your application to perform String comparisons for different languages. Using the predefined collation rules provided by the Collator class, you can sort strings in a locale-independent manner.

Collator is an abstract base class. Subclasses implement specific collation strategies. Other subclasses may be created to handle more specialized needs.

Like other locale-sensitive classes, you can use the static factory method, getInstance, to obtain the appropriate Collator object for a given locale.

The following example shows how to compare two strings using the Collator for the default locale.

// Compare two strings in the default locale
   Collator myCollator = Collator.getInstance();
     if( myCollator.compare("dog", "DOG") < 0 )
         System.out.println("dog is less than DOG.");
     else
         System.out.println("dog is greater than or equal to DOG.");

A CollationKey represents a String under the rules of a specific Collator object. Comparing two CollationKeys returns the relative order of the Strings they represent. Using CollationKeys to compare Strings is generally faster than using Collator.compare. When the Strings must be compared multiple times, it's more efficient to use CollationKeys.

You can not create CollationKeys directly. Create them by calling Collator.getCollationKey. You can only compare CollationKeys generated from the same Collator object.

Collator.compare examines only as many characters as it needs, which makes it faster when doing single comparisons.

The following example shows how CollationKeys might be used to sort a list of Strings.

// Create an array of CollationKeys for the Strings to be sorted.
Collator myCollator = Collator.getInstance();
CollationKey[] keys = new CollationKey[3];
keys[0] = myCollator.getCollationKey("Tom");
keys[1] = myCollator.getCollationKey("Dick");
keys[2] = myCollator.getCollationKey("Harry");
sort( keys );
//...
// Inside body of sort routine, compare keys this way
if( keys[i].compareTo( keys[j] ) > 0 )
// swap keys[i] and keys[j]
//...
// Finally, when we've returned from sort.
System.out.println( keys[0].getSourceString() );
System.out.println( keys[1].getSourceString() );
System.out.println( keys[2].getSourceString() );
.
.

Program Challenge

Create a Sorting Application

Create a program that offers the ability to sort the lines in a JTextArea.

Use one of the following options:

  • Regular String sorting, using its built in Comparable interface
  • Case-insensitive Comparator
  • A Collator

See a possible solution to the Challenge

.
.

Take an Online Quiz

Test what you learned about sorting.

.
.

New to Java Technology Programming Center

SunEd Web and Instructor Led Java Technology Courses

The Fundamentals of the Java Programming Language course focuses on the significance of object-oriented programming, the keywords, and constructs of the Java programming language, and the steps required to design and develop and test simple Java programs.

Web-based
Instructor led

.
.

For More Information

Comparing Strings

Class Collator

Sorting Arrays

Essentials of the Java Programming Language

.
.

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SE development kit.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Java Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
image
image
Please unsubscribe me from this newsletter.
From env_351725051117065157@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Tue May 13 16:57:33 2003 X-UIDL: F&_!!^!e"!:kO!!m_&#! Return-Path: Received: from round.uits.indiana.edu (round.uits.indiana.edu [129.79.1.72]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h4DLvXC03295 for ; Tue, 13 May 2003 16:57:33 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by round.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h4DM1X0R008928 for ; Tue, 13 May 2003 17:01:34 -0500 (EST) Date: 13 May 2003 14:49:39 -0800 From: "Enterprise Java Technologies Newsletter" To: gcf@indiana.edu Message-Id: <351725051117065157@hermes.sun.com> Subject: Enterprise Java Tech Tips, May 13, 2003 (Java Logging, HTTP Request Forwarding/Redirecting/Including) Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 36167 Status: RO Enterprise Java Technologies Tech Tips
.
.
Core Java Technologies Technical Tips
.
   View this issue as simple text May 13, 2003    

In this Issue

Welcome to the Enterprise Java Technologies Tech Tips for May 13, 2003. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java 2 Platform, Enterprise Edition (J2EE).

This issue covers:

.Java Logging with J2EE
.HTTP Request Forwarding, Redirecting, and Including

These tips were developed using Java 2 SDK, Standard Edition, v 1.4 and Java 2 SDK, Enterprise Edition, v 1.3.1 (Reference Implementation).

This issue of the Tech Tips is written by Mark Johnson, president of elucify technical communications, and co-author of Designing Enterprise Applications with the Java 2, Enterprise Edition, 2nd Edition. Mark Johnson runs an open forum for discussion of the tips.

You can download the sample code. The context root for the application is ttmay2003. The index.html welcome file indicates how to use the sample code. Any use of this code and/or information below is subject to the license terms.

.

JAVA LOGGING WITH J2EE

Many applications, especially enterprise applications, require logging facilities. Application logs help service engineers troubleshoot problems in the field, and can provide an audit trail for security analysis.

Originally, the Java platform contained few resources for application logging. Developers and administrators made do with println statements in log files, invented homegrown solutions, or turned to one of the many excellent (but mutually incompatible) logging products produced by commercial and open-source developers. Java 2 version 1.4 changed that with the introduction of the java.util.logger package.

This tip briefly explains the basics of Java logging, and provides sample code that sends application log messages to a standalone client by way of a Java Messaging Service (JMS) Topic. If you're unfamiliar with JMS, see the tip "Using JMS Queues" in the March 11, 2003 issue, and "Publish/Subscribe Messaging With JMS Topics" in the April 15, 2003 issue.

The java.util.logging Package

The Java logging package was initially created as a Java Specification Request (JSR-047), and is now a part of Java 2, Standard Edition (J2SE). Its requirements included the following features:

  • Minimal runtime performance impact
  • Runtime enabling/disabling of logging
  • Fine-grained control
  • Runtime logging service registration
  • Interoperation with existing logging services, such as system logs and legacy logging schemes
  • Display of high-priority messages to users when appropriate
  • Ability to handle internationalized logging messages
  • Ability to log objects, instead of logging only strings

Because the logging package is part of J2SE, it is available in the other Java platforms, including J2EE. Specifically, Java logging can be used from within application clients, servlets, JSP pages, enterprise beans, and connectors.

Logging Classes and Interfaces

The primary class in the logging facility is Logger. A Logger represents a sort of channel through which logging messages can be sent. Usually, each class has its own Logger.

A Logger is configured with a Level, this is a class that indicates the severity of the problem being reported and/or the level of detail required for that individual class. Each message sent to the Logger has an associated Level. The Logger only reports errors whose Level is the same or higher than the Logger's.

The highest logging Level is SEVERE, which indicates a severe problem -- often a fatal error. Other Level values (in decreasing order) are WARNING and INFO, for recoverable and informational messages, respectively. The CONFIG level indicates that a configuration event (such as reading a properties file) has occurred. A programmer can use Level values FINE, FINER, and FINEST to report successively more fine-grained logging messages. Service engineers can use these Level values to hide extraneous detail, or increase the level of logging detail, on a class-by-class basis. The default Level for a Logger is INFO.

A LogRecord is an object that represents a message that should be written to a log. It contains a variety of information, including the message to be printed, the name of the Logger to which it was originally sent, the Level and creation time and date of the message being sent, and the thread id of the caller.

An abstract class called Handler represents a class that knows how to represent a LogRecord in a way that is useful. The logging package contains some Handlers (such as ConsoleHandler, FileHandler, StreamHandler, and SocketHandler) that report LogRecords to various types of destinations. Each Logger can have multiple Handlers. Each Handler also has a Level, and discards any LogRecord whose Level is below its own. So, for example, a single Logger might have two Handlers: one that writes to a log file on a disk, and another that sends Logging messages to a system administrator's pager. The disk log Handler could be configured with the Level FINEST, and so it would write all log messages to disk. By contrast, the pager log Handle! r might report only SEVERE log messages.

The Formatter class (and any subclasses it defines) converts a LogRecord to a String for printing. For example, the XMLFormatter subclass of Formatter writes a LogRecord as well-formed XML. Developers can write custom Formatter classes.

Finally, the Filter interface allows a programmer to write a method (isLoggable), which allows programmatic control of which LogMessages are discarded or printed.

Sample Code

The sample code for this tip demonstrates how to set up a Logger, and use it to send XML-formatted log messages from the Web tier, over JMS, to a standalone JMS client.

The sample code for this tip comprises a servlet and a standalone client. The servlet is called LogDemoServlet. The standalone client is called LoggingReceiver. The standalone client listens for messages being published to a JMS topic, and prints any TextMessages it receives. The sample application contains an HTML form for a user to post data to the LogDemoServlet.

Tip 1

Notice that the form prompts the user to download a JAR file, and then run that file as a standalone client. The user needs to do this before posting data through the form.

The servlet responds by publishing an XML-formatted message to a Topic. If the LoggingReceiver is running, the user sees the XML-formatted messages printed on the screen.

For example:

   <?xml version="1.0" encoding="MacRoman" standalone="no"?>
   <!DOCTYPE log SYSTEM "logger.dtd">
   <log>
   <record>
      <date>2003-05-05T23:51:20</date>
      <millis>1052200280257</millis>
      <sequence>0</sequence>
      <logger>com.elucify.tips.may2003.LogDemoServlet</logger>
      <level>INFO</level>
      <class>com.elucify.tips.may2003.LogDemoServlet</class>
      <method>doPost</method>
      <thread>10</thread>
      <message>quest= { 'Johnny' }
       FavoriteColor= { 'Violet' }
       name= { 'Johnny' }
   </message>
   </record>

The key component in the sample code is the servlet LogDemoServlet. This servlet simply formats its POST parameters as a string, and logs that string to the Logger each time the servlet is called. The beginning of the method doPost sets up the Logger:

    // Handle post request
    public void doPost(HttpServletRequest req, 
        HttpServletResponse res)
        throws IOException, ServletException {

        res.setContentType("text/html");
        PrintWriter pw = res.getWriter();

        // Get POST parameters and write them as 
        // "variable=value" to a ByteArrayOutputStream
        String postParams = getPostParams(req);

        ByteArrayOutputStream bos = 
            new ByteArrayOutputStream();
        Logger logger = Logger.getLogger(
            this.getClass().getName());

The servlet sets the content type, gets a Writer, and formats the POST parameters. It then creates a Logger by calling static method Logger.getLogger(this.getClass().getName()). This method returns the existing Logger of that name, or creates one lazily if it did not already exist. The code uses the fully-specified class name of the servlet class. This is a common convention for ensuring that the names of the various Loggers in a system do not collide.

By default, the Logger writes any messages it creates to the standard output of whatever code it is running. For example, Web-tier messages typically go to the Web server log file.

The second half of the doPost method adds a new Handler to the Logger. Each time a message is logged to the Logger, the Logger sends the message to both Handlers (assuming the message's Log level is high enough). Here is the second half of the doPost method:

        // Format logging messages as XML, 
        // store in byte array
        StreamHandler sh = new StreamHandler(
            bos, new XMLFormatter());
        logger.addHandler(sh);
        logger.log(Level.INFO, postParams);
        sh.flush();
        
        // Send contents of buffer as JMS message 
        // to listeners
        publish(bos.toString());

        pw.println(
            "Logging messages sent to subscribers");
    }

A StreamHandler is a handler that uses a Formatter to format a LogRecord as a string, and writes it to an OutputStream. In this case, the OutputStream is a ByteArrayOutputStream, so the results of the logging are written into memory. This method also uses an XMLFormatter so that the LogRecords are written as XML. The call to addHandler adds the new StreamHandler to the Logger, and then sends a log message containing the formatted POST parameters to the Logger. The Logger sends the message to all of its Handlers, including the new StreamHandler. The call to flush() ensures that all written bytes are flushed to the ByteArrayOutputStream. Finally, the ByteArrayOutputStream is converted to an XML string. The string is published to a JMS Topic by the! publish method. A description of how to send messages to JMS Topics (using this same publish method) appears in the tip "Publish/Subscribe Messaging With JMS Topics" in the April 15, 2003 issue.

To run the sample code for this tip see "Running the Sample Code" below.

.
.

HTTP REQUEST FORWARDING, REDIRECTING, AND INCLUDING

One of the things that makes Web applications so powerful is their ability to link between and aggregate information resources. The J2EE platform offers three related, yet distinct, ways for a Web component at a specific URL to use data from other URLs to create a response. This tip examines this capability by exploring request forwarding, URL redirection, and inclusion using the Java Servlet API.

Request Forwarding

Request forwarding allows a component to send a request to one URL in an application and have it processed by a component at a different URL in the same application. This technique is commonly used in Web-tier controller servlets which examine data in a Web request and direct the request to the appropriate component for processing.

A servlet can forward an HTTP request it has received using the method javax.servlet.RequestDispatcher.forward. The component that receives the forwarded request can process the request and produce a response, or it can forward the request to yet another component. The ServletRequest and ServletResponse objects from the original request are passed to the component that is the target of the forward. This gives the target component access to the entire request context. Requests may be forwarded only to components within the same application context root, never between applications.

The sample code for this tip involves an HTML form in the index.html file of the sample application. A user selects a source file name from a select list and clicks the submit button (which is labeled "Go").

Tip 2

This corresponds to item 1 in the Tip 2 form.

The form is POSTed to the DispatchDemoServlet, which handles the processing of all three examples for this tip. Request forwarding is handled by the doForward method of the servlet, which appears below.

   protected void doForward(HttpServletRequest req,
                            HttpServletResponse res)
      throws IOException, ServletException {
      
      String name = req.getParameter("name");

      // Look up the site by name
      String url = (String)_p.get(name);
      if (url == null) {
         url = "errorPage.html";
      }

      // Get the request dispatcher -- request will be 
      // dispatched to this URL.
      RequestDispatcher rd =
         req.getRequestDispatcher(url);

      // Forward to requested URL
      rd.forward(req, res);
   }

The POST parameter 'name' indicates the symbolic name of the file requested by the user. The method looks up the URL for that file in a hash table. (The hash table was loaded from a properties file in the application archive.) The method then gets a RequestDispatcher object from the HttpServletRequest object. The RequestDispatcher is implemented by the Web container. The invocation rd.forward instructs the Web container to call the Web component at the given URL. The result of the request is whatever content is returned by the component at that URL.

URL Redirection

URL redirection is similar to request forwarding, but with some important differences. A Web component can redirect a request to any URL, not just URLs in the same application context. But the contents of the original request, such as POST parameters, are lost. This is because the server is not involved in the process of redirecting the request, as is the case with request forwarding. URL redirection works by using the Refresh feature of the HTTP META header. Essentially, the server returns a META tag that tells the browser to go somewhere else entirely. At that point, any data POSTed to the original URL is lost.

URL redirection can be accomplished by directly manipulating HTTP headers, but the preferred way is to use the method javax.servlet.ServletRequest.sendRedirect. This method's single argument is the destination URL of the redirect.

The sample code for URL redirection uses the second form in index.html file for the sample application. A user selects from several URLs on the java.sun.com site, and clicks Go. This corresponds to item 2 in the Tip 2 form.

The form posts the selected form name to DispatchDemoServlet, which calls its method doRedirect, shown below.

   protected void doRedirect(HttpServletRequest req,
                             HttpServletResponse res)
      throws IOException, ServletException {
      
      String name = req.getParameter("name");

      // Look up the site by name
      String url = (String)_p.get(name);
      if (url == null) {
         url = "errorPage.html";
      }

      // Redirect request
      res.sendRedirect(url);
   }

As is the case with the doForward method that does request forwarding, the doRedirect method looks up the URL for the redirect using a symbolic name selected from the form by the user. The doRedirect method then calls the HttpServletResponse's sendRedirect method, which structures and sets an HTTP header in the request and immediately returns. The browser receives an empty response, but because of the META header, promptly issues another request for the new URL.

Although this servlet produces an empty response, it is good practice to include a message explaining that the request is being redirected. It's also a good idea to provide a link to the redirection target in case the redirect fails. Older browsers might not implement the Refresh function, or the function might be turned off for security reasons. The link was left out of the example servlet to simplify the code.

Inclusion

So far, you've seen two ways of producing an alternate response to a request: request forwarding and URL redirection. By contrast, inclusion allows a Web component to aggregate data from several other Web components, and use the aggregated data to create a response. This technique is commonly used in template processors. Here a structured template (often a JSP page) is used to control the layout of a response. The content of each page area in the template comes from different URLs, and is assembled into a single page. This technique can provides a consistent look and feel to an application.

Content from multiple Web components can be included in a single response. To include the data from another URL in a response, get a RequestDispatcher for that URL, and call the RequestDispatcher's include method.

The sample code for inclusion uses a set of checkboxes, each of which indicates an HTML file in the application archive. Each HTML file corresponds to a color to be included in the output. A user selects a number of files by checking the boxes, and clicks Go. This corresponds to item 3 in the Tip 2 form.

The DispatchDemoServlet uses its doInclude method, shown below, to process the request.

   // Given a list of checked files, include each one of
   // them in the output to form a compound document
   protected void doInclude(HttpServletRequest req,
                            HttpServletResponse res)
      throws IOException, ServletException {
      String name = req.getParameter("name");

      // Get the request dispatcher -- request will be 
      // dispatched to this URL.
      RequestDispatcher rd;
      if ((rd = req.getRequestDispatcher("/header.html")) 
         != null) {
         rd.include(req, res);
      }

      String[] names = req.getParameterValues("color");
      String url;

      for (int i = 0; names != null && 
         i < names.length; i++) {
         if ((url = (String)_p.get(names[i])) == null) {
            continue;
         }
         if ((rd = req.getRequestDispatcher(url)) 
            != null) {
            rd.include(req, res);
         }
      }

      if ((rd = req.getRequestDispatcher("/footer.html")) 
         != null) {
         rd.include(req, res);
      }
   }
}

Notice how the doInclude method calls include several times. Each time it calls include, doInclude must get a RequestDispatcher for the appropriate URL. The method first includes the file /header.html. It then gets the names of the checkboxes in the list, and looks up the corresponding URLs in the hash table. For each URL it finds, doInclude acquires a RequestDispatcher for that URL, and includes the content from that URL in the output. The call to the include method writes the output for that URL to the HttpServletResponse object. Finally, doInclude writes the contents of the URL /footer.html (relative to the context root) to the output.

The selected files and their colors are then displayed to the user:

Demonstration of included files

To run the sample code for this tip see "Running the Sample Code" below.

.
.

RUNNING THE SAMPLE CODE

Download the sample archive for these tips. The application's context root is ttmay2003. The downloaded EAR file also contains the complete source code for the sample.

You can deploy the application archive (ttmay2003.ear) in the J2EE Reference Implementation using the deploytool program:

    $J2EE_HOME/deploytool -deploy ttmay2003.ear localhost

Replace localhost with the name of the host on which the server is installed. For a standard installation on a single machine, the hostname typically (and literally) is localhost. You can access the application at http://localhost:8000/ttmay2003.

The sample code for the first tip requires you to download a JAR file, and then run that file as a standalone client. Click the link in Step 1 of the example, and save the JAR file. Then issue the following command on the command line:

    java com.elucify.tips.may2003.LoggingReceiver

Be sure to either put the JAR file in your CLASSPATH, or add it using the java command's "-classpath" option.

Also, before running the sample code for the first tip, you need to give the sample code permission to set logging handlers. To do this, place the following line in the final "grant" block of the file $J2EE_HOME/lib/security.policy (do this before the closing curly brace):

    permission java.util.logging.LoggingPermission "control", "";

For a J2EE-compliant implementation other than the Reference Implementation, use your J2EE product's deployment tools to deploy the application on your platform.

See the index.html welcome file for instructions on running the application.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future technical tips, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: http://wwws.sun.com/contact/developer_feedback.jsp

Subscribe to other Java developer Tech Tips:

- Core Java Technologies Tech Tips. Get tips on using core Java technologies and APIs, such as those in the Java 2 Platform, Standard Edition (J2SE).
- Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).

To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page, choose the newsletters you want to subscribe to and click "Update".
- To unsubscribe, go to the subscriptions page, uncheck the appropriate checkbox, and click "Update".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://developer.java.sun.com/developer/EJTechTips/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA.

This document is protected by copyright.

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
.
.
Please unsubscribe me from this newsletter.
From env_35840715-82168469@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri May 30 14:35:46 2003 X-UIDL: `$4"!OD?"!bR:"!0b1"! Return-Path: Received: from genoa.uits.indiana.edu (genoa.uits.indiana.edu [129.79.1.71]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h4UJZjC12179 for ; Fri, 30 May 2003 14:35:45 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by genoa.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h4UJZgvW014304 for ; Fri, 30 May 2003 14:35:42 -0500 (EST) Date: 30 May 2003 12:20:54 -0800 From: "JDC New to Java Programming Center" To: gcf@indiana.edu Message-Id: <35840715-82168469@hermes.sun.com> Subject: Java Technology Fundamentals Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 27454 Status: RO Java Technology Fundamentals Newsletter
.
.
Java Technology Fundamentals Newsletter header
    May 30, 2003    

In this Issue

imageJava Programming Language Basics: JavaBean Basics
imageJava Bits: The Bean Builder
imageProgram Challenge: Beans Challenge
imageTake an Online Quiz: Test what you learned about JavaBeans
imageThe JavaOne Conference
imageFor More Information: Read articles, Tech Tips, trails, and tutorials that provide more information on the topics discussed here.

.

Java Programming Language Basics

JavaBean Basics

Once upon a time, the world was free of naming conventions and classes were created with methods and fields with any name desired. Typically, everything worked, but the comprehension of code suffered as some people liked one naming style and other people liked other naming styles.

Naming styles are how you design your class. One naming style, the Hungarian Naming Convention, requires you to prefix all variable names with their data type. For example iCount would be a variable of type int (the i) for storing a count.

The JavaBeans Component Architecture, while technically more complicated, defines a standard naming style for the class definitions of a JavaBean component. By following these naming styles, you can easily package the bean components and deliver them to users of the components.

You can package small bits of Java code called beans or components in new ways to create unique applications, and by following the conventions of the JavaBeans Component Architecture, you can create reusable components for the Java platform in ways the original designer never planned to create unique applications.

If you desire to create a reusable component for the Java platform (or something shareable outside the platform through such tools as the ActiveX Bridge), by following the conventions of the JavaBeans Component Architecture, you can create these components.

All this leads us to what those naming conventions are for creating reusable components under the JavaBeans Component Architecture. JavaBean components have several pieces, with properties and events being the two biggest parts.

A property in the JavaBeans component architecture world is defined to hold the current state of an object, in such a way that a tool like Sun ONE Studio can access and possibly modify that state. For instance, if the bean component to design was a student, that student must have state information for their name, list of classes, and prior grades, even if some people want to forget what those grades were.

If you wanted to define a student-like object that followed the JavaBean component model there are a handful of steps you must do. First off you must identify the properties of the object you wish to control. Here, for the student that might be their name, class list, and grade list.

  public class Student {
    public String name;
    public Subject subjects[];
    public Map grades;
  }

Assuming the appropriate classes were imported, this definition would be sufficient to create a Student and store their three bits of information: name, current subject list, and grades. However, there is one serious flaw here. Everything is defined to be public. After creating an instance of Student, to access that student's name, you would need to directly access the class' instance variable: name. If you ever wanted to change name into a first name and last name, then you would need to modify every place that directly accessed the variable.

Instead, the alternative is to create methods that hide the underlying representation of the data. For instance, you could create methods to get and set the name:

  public String name()
  public void name(String name)

By adding these two methods and changing the access modify of the variable to private, you've now hidden how to fetch and change a student's name. The naming style above has nothing to do with the JavaBeans Component Architecture. Instead, it just offers one way of naming the methods, one to get the value and the other to change it.

Instead of naming methods as the variable (and property) names, the JavaBeans Component Architecture has you name them with get and set as the prefix. So, for the name property, those methods look as such:

  public String getName()
  public void setName(String name)

By following this naming convention, a tool such as JBuilder could examine a class and provide a graphical way to view and modify such settings, or automate the generation of such classes by just providing a name and data type to create the appropriate methods. By visually programming, either by changing settings or generating classes, the chance of programming error is greatly reduced.

public class Student {
  private String name;
  private Subject[] subjects;
  private java.util.Map grades;

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Subject[] getSubjects() {
    return subjects;
  }
  public void setSubjects(Subject subjects[]) {
    this.subjects = subjects;
  }
  public java.util.Map getGrades() {
    return java.util.Collections.unmodifiableMap(grades);
  }
  public void setGrades(java.util.Map grades) {
    this.grades = grades;
  }
}

And, by following the naming conventions used by the JavaBeans Component Architecture, code comprehension improves immensely, as new developers don't have to learn local customs to become a productive team member.

There is one other added requirement for JavaBean components. That is, their state must be dynamically savable. This is done through the java.io.Serializable interface. By implementing the interface, and having all their property variables be Serializable, the whole class is. No methods need to be implemented. The interface just acts as a marker.

Note: There is more to the JavaBeans Component Architecture than just a series of naming conventions for class definitions. There is this whole runtime containment framework that allows you to discover the runtime context such that components defined properly can respond appropriately whether in an applet, application, or other environment.

.
.

Java Bits

The Bean Builder

The Bean Builder is a simple application that demonstrates new and emerging technologies within the Java Platform which allow the construction of applications using component assembly mechanisms. The Bean Builder extends the capabilities of the original BeanBox by demonstrating new techniques for persistence, layout editing and dynamic event adapter generation.

Bean Builder demonstrates the following technologies:

  • The new Long Term Persistence (LTP) mechanism for JavaBeans. This persistence mechanism will be described in more detail in the following section.
  • Design time meta information specified in javadoc format and generated as name-value pairs in BeanInfo classes.
  • Dynamic adapter generation to hook up events using the new Dynamic Proxy API that was introduced in Java 2 Platform, Standard Edition, release 1.3. See Dynamic Proxy Classes for details.
  • New JFC/Swing based Property Editors for editing: Fonts, Colors, Objects, Dimension, Insets, Rectangles, and so on.
  • Actions architecture based on javax.swing.Action interface. See Adding Actions to ActionEvent Sources for details.
  • A simple Jar classloader based on java.net.URLClassLoader that was introduced in release 1.2
  • Demonstrates the use of the new javax.swing.SpringLayout in release 1.4.

The Bean Builder requires J2SE v 1.4 or later to be installed in order to run. The full J2SE SDK should be used rather than the just the JRE since the Bean Builder uses the BeanInfo design time information (dt.jar) which ships with the J2SE SDK.

Designs created by the Bean Builder can be executed with the JRE.

If you already have Java Web Start and J2SE 1.4x installed on your system, you can start Bean Builder from The Bean Builder

.
.

Program Challenge

See a possible solution to the Challenge

.
.

Take an Online Quiz

Test what you learned about JavaBean Basics

.
.

The JavaOne Conference

If you're preparing to attend your first JavaOne Worldwide Developers Conference, you're in for an experience you won't soon forget. JavaOne submerges you in opportunities to learn about and discuss anything related to Java programming and technology.

Since the first show in 1994, the conference's general format hasn't changed very much. Consistently, the conference is a destination for developers interested in the Java programming language and technologies to exchange creative concepts and plans.

This year there are more than 55 technical sessions and Birds-of-a-Feather (BoF) sessions for beginners. Sessions and BoFs are the meat of the conference, full of practical explanations of the subject and are usually presented by the engineer(s) who helped architect or write the technical specification.

For four days, from early morning into the wee hours of night, your typical day includes having your senses bombarded with input, your mind stuffed with new ideas and career options, and your body rushed to make the next session or BoF. Start planning now, but be prepared to make many last-minunte decisions on which of several optional developer events to attend. The experience can be overwhelming, and there isn't enough time for everything you want to do - including sleep.

There's an easy way to keep track of all of the sessions and BoFs you want to attend; "My Schedule", a feature of the JavaOne Web site. It's on the left navigation bar under "Conference Login". With "My Schedule" you can select all of the sessions and BoFs you want to attend, and then have the list emailed to you in a chronological schedule easy to print out and carry or to leave in your Web profile.

You may also find a session road map helpful. This article lists the Top 10 Sessions for new to Java technology developers in chronological order.

In between sessions, visit the exhibition floor. It's full of businesses and resources who use Java technology for a profit. Talk about good job networking opportunities! Also, many booths hand out clever give-aways and "goodies", which in past years have included books, pocket-sized radios, face tattoos, T-shirts, and gummy tarantulas.

And don't forget to visit the Java Developer Connection booth. Come by, say "Hi" and give us some feedback on how we're doing and how we can do better.

.
.
.

For More Information

Using the BeanContext API

The Bean Builder

Bean Builder Tutorial

.
.

Downloading the Java 2 Platform

For most Java development, you need the class libraries, compiler, tools, and runtime environment provided with the J2SE development kit.

.
.
.

Reader Feedback

  Very worth reading    Worth reading    Not worth reading 

If you have other comments or ideas for future newsletters, please type them here:

 

Have a question about Java programming? Use Java Online Support.

.
.

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:

- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips) Get expert tips, sample code solutions, and techniques for developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html


Comments? Send your feedback on the Java Technology Fundamentals Newsletter to: dana.nourie@sun.com

Go to the subscriptions page to subscribe or unsubscribe to this newsletter.

ARCHIVES: You'll find the Java Technology Fundamentals Newsletter archives at:
http://developer.java.sun.com/developer/onlineTraining/new2java/supplements/


Copyright 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
image image

Please unsubscribe me from this newsletter.


From env_359943261641496360@hermes.sun.com Mon Jun 18 16:23:45 2007 Delivery-Date: Fri May 30 19:19:11 2003 X-UIDL: hgT!!Ul`!!4g""!gR$"! Return-Path: Received: from eldorado.uits.indiana.edu (eldorado.uits.indiana.edu [129.79.1.70]) by grids.ucs.indiana.edu (8.10.2+Sun/8.10.2) with ESMTP id h4V0JBC17493 for ; Fri, 30 May 2003 19:19:11 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by eldorado.uits.indiana.edu (8.12.9/8.12.9/IUPO) with SMTP id h4V0JADM016971 for ; Fri, 30 May 2003 19:19:10 -0500 (EST) Date: 30 May 2003 17:06:47 -0800 From: "JDC Editorial Staff" To: gcf@indiana.edu Message-Id: <359943261641496360@hermes.sun.com> Subject: May Enterprise Java Technologies Newsletter Mime-Version: 1.0 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Mailer: SunMail 1.0 Content-Length: 19861 Status: RO Enterprise Java Technologies Newsletter
Enterprise Java Technologies Header
pixel

Welcome to the new Enterprise Java Technologies Newsletter. Here you'll find links to the latest products, tools, resources, and events relating to development with the Java 2 Platform, Enterprise Edition (J2EE).


Product and Technology Releases

The following J2EE products and technologies were recently released:

Java Message Service API 1.1 Final
This maintenance release addresses the unification of the programming interfaces for the Point-to-Point and Pub/Sub messaging domains in the Java Message Service (JMS) API.

JSR-000188 Composite Capability/Preference Profiles (CC/PP) Processing Public Review Draft 0.5
To enable interoperability between web servers and access mechanisms, and to facilitate development of device-independent web applications, this specification will define a set of APIs for processing CC/PP information.

J2EE Management 1.0 Final Release
This specification includes standard mappings of the model to the Common Information Model (CIM), an SNMP Management Information Base (MIB), and to the Java object model through a server resident Enterprise JavaBeans (EJB) component, known as the J2EE Management EJB Component (MEJB). The MEJB provides interoperable remote access to the model from any standard J2EE application.

JNDI/LDAP Booster Pack 1.0
The booster pack contains support for a number of popular LDAP controls and extensions, groups, and Java RMI/CORBA objects. It replaces the booster pack that was bundled with the LDAP 1.2.4 service provider.


Hot Downloads

The following are currently some of the most frequently downloaded J2EE products and technologies:

Java Message Service (JMS) Tutorial

JavaServer Pages Standard Tag Library (JSTL) Specification

JavaMail 1.2 API

Java Web Services Developer Pack v1.1

Sun ONE Application Server 7, Standard Edition


Industry News & Announcements

SIMagine 2004 Developer Contest
Schlumberger, in association with Sun Microsystems and Samsung Semiconductors, invites you to take part in its 5th annual worldwide wireless developer contest. Develop wireless applications using (U)SIM cards based on Java technology.

New JCP Program Enhancements to Facilitate Broader Developer Participation
The Java Community Process (JCP) Program Management Office (PMO) and Executive Committees announced plans to introduce program enhancements through a new iteration of the Java Community Process--version 2.6.

GemStone Systems Teams with Sun Microsystems to Provide Largest Online Bank in South Africa with Increased Network Speed and Scalabilty
GemStone Systems announced that eBucks.com (Pty) Ltd., a Division of FirstRand Bank, will implement an integrated technology solution simplifying its architecture and manage data across the division's hardware and software systems. This system is cost effective and leverages Java technology.

pixel
pixel pixel pixel
May 30, 2003

Resources

Learn more about, and get "hands-on" training for, J2EE technologies through the following resources.
  • Technical Articles:
  • Tech Tips:
  • Books:
    • Applying Enterprise JavaBeans, Second Edition
      Written by the chief architect of the Enterprise JavaBean (EJB) specification, this book is an advanced programming guide and reference source updated and expanded to reflect the EJB 2.1 specification. It's an invaluable resource for IT personnel building in-house applications and for independent software vendors building applications for sale to enterprises.

  • Newsletter:
    • Java Technology Fundamentals Newsletter
      Learn to use sorting in applications, identify culturally dependent data in your application, and get current on web-based and instructor-led Java technology courses.

  • Events:
    • SUPERCOMM 2003
      June 1-5, Atlanta, Georgia, USA
      Visit the Sun Microsystems Partner Pavilion at SUPERCOMM 2003 to see how Sun makes the "Personal Network" a reality. Sun is hosting a Partner Pavilion and an executive briefing to highlight its vision and software offerings.

    • 2003 JavaOne Conference
      June 10-13, San Francisco, California, USA
      For the eighth year, the JavaOne Conference returns to San Francisco. The conference is the definitive source for the latest news and updates on Java technology developments directly from Sun Microsystems, the source of Java technology. Register to attend.

    • Java Communities in Action, a Celebration of Community Collaboration
      June 11, 6:00 p.m., Renaissance Parc 55 Hotel
      At Fifth and Market Streets, San Francisco, California, USA
      While you're at the JavaOne Conference, please join us Wednesday evening for a celebration of the JCP program, Jini Fest! and Project JXTA.

    • Apple's Worldwide Developer Conference 2003
      June 23-27, San Francisco, California, USA
      Don't miss this opportunity to meet with Apple engineers and hear the latest on developing and deploying your Java applications on Mac OS X, the only high-volume operating system to ship with Java 2.

    • Oracle AppsWorld
      June 23-26, London, UK
      Oracle AppsWorld is a conference and exhibition completely dedicated to Oracle E-Business Suite strategies, business processes, and technical directions. In just four days, you will acquire the tools and resources you need so you can outsmart, outrun, and outperform your competitors.

  • Java Developer's Marketplace:

  • Viewpoint

pixel
pixel
pixel
Important: Please read our Terms of Use, Privacy, Licensing and Trademark policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

Feedback: Submit your feedback on the Enterprise Java Technologies Newsletter to:
http://wwws.sun.com/contact/developer_feedback.jsp

Subscribe/Unsubscribe: Subscribe to other Java technology newsletters:

- Java Technology Fundamentals Newsletter. Learn the basics of the Java programming language and keep up-to-date on additions to the New-to-Java Programming Center.
- Core Java Technologies Newsletter. Learn about new products, tools, resources, and events of interest to developers working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest releases, tools, and resources for developers working on wireless and Java Card technologies and applications.

You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page
- To subscribe, visit the JDC Newsletters and Publications page, select the newsletters you want to subscribe to and click "Update".
- To unsubscribe, use our one-click facility. To completely unsubscribe from this newsletter, click here.

Archives: You'll find the Enterprise Java Newsletter archives at:
http://java.sun.com/jdc/techDocs/Newsletters/ej_newsletters.html

Copyright 1994 - 2003 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, CA 95054 USA This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.


Sun Microsystems, Inc.
pixel


Please unsubscribe me from this newsletter.