You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/
  Welcome to the Enterprise Java Technologies Tech Tips.
Enterprise Java Technologies
TECHNICAL TIPS
May 24, 2005
View this issue as simple text
In this Issue
 
Here you'll get tips on using Enterprise Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

» Creating a Simple Web Service Using JAX-RPC
» Using RELAX NG With JAXB

These tips were developed using the Java 2, Enterprise Edition, v 1.4 SDK. You can download the SDK at http://java.sun.com/j2ee/1.4/download.html.

This issue of the Tech Tips is written by Robert Eckstein, a staff member of java.sun.com.

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.

You can download the sample archive for the Creating a Simple Web Service Using JAX-RPC tip. You can download the sample archive for the Using RELAX NG With JAXB tip. Any use of this code and/or information below is subject to the license terms.

For more Java technology content, visit these sites:

java.sun.com - The latest Java platform releases, tutorials, and newsletters.

java.net - A web forum where enthusiasts of Java technology can collaborate and build solutions together.

java.com - Hot games, cool apps -- Experience the power of Java technology.

CREATING A SIMPLE WEB SERVICE USING JAX-RPC
 
A lot of articles have been written about web services and Java technology. Some of these articles have been quite extensive. Yet some people are still looking for a short, direct set of instructions that will help them create a web service using Java technology. This tip attempts to do that. It steps you through the process of building a simple web service and a client that accesses the service using the Java API for XML-based RPC (JAX-RPC). The steps are based on Chapter 8: Building Web Services with JAX-RPC in the J2EE 1.4 Tutorial. These are the basic steps to create a web service and its client:
  1. Code the service endpoint interface (SEI) for the service and its implementation class.
  2. Compile the SEI and implementation class.
  3. Generate the WSDL and mapping files.
  4. Package and deploy the service. Special tie classes (which are used to communicate with clients) are generated by the Application Server during deployment.
  5. Code the client class.
  6. Generate the stub files.
  7. Compile the client classes.
  8. Package the client.
Code the SEI and the Implementation Class

The starting point for developing a JAX-RPC web service is the service endpoint interface (SEI). This is simply a Java interface that declares the methods that a client can invoke on the service.

To make a web service available to clients through JAX-RPC, you need to create two Java classes: one that defines the SEI, and the other that implements the SEI. The source code for these two classes are provided in the sample code for this tip, ttmay2005-ws.jar. Here is a class that defines an SEI for a web service:
   package helloservice;
   import java.rmi.Remote;
   import java.rmi.RemoteException;

   public interface HelloIF extends Remote {
       public String sayHello(String s) throws RemoteException;
   } 
A service endpoint interface must conform to a few rules:
  • It extends the java.rmi.Remote interface.
  • It must not have constant declarations, such as public final static.
  • The methods must throw the java.rmi.RemoteException or one of its subclasses. (The methods can also throw service-specific exceptions.)
  • Method parameters and return types must be supported JAX-RPC types. (For a list of the JAX-RPC types.
Here is the implementation class. The class accepts a String parameter, and uses it to return a slightly modified String.
   package helloservice;
   public class HelloImpl implements HelloIF {

       public String message = "Hello there, ";
       public String sayHello(String s) {
           return message + s;
       }
   } 
Before going any further, you may wish to download the source code for this tech tip, a link to which may be found at the end of this document.

Compile the SEI Class and Implementation Class

After you create the SEI class and its implementation, you need to compile them. An easy way to do that is to use the ant build tool (http://ant.apache.org/). A build file for the web service (build.xml) is provided in the sample code for this tip. You can do the build by running ant in the same directory as the build file for the sample. Change your current directory to the ws/helloservice directory below where you installed the sample code. Then enter the following command:
   ant 
The first thing the build does is create a directory for the web service. It then compiles the files. The compile step is equivalent to executing the following javac commands:
   src\helloservice>javac -d ..\..\build -cp ..\
   ..\build HelloIF.java
   
   src\helloservice>javac -d ..\..\build -cp ..\..\
   build HelloImpl.java
(Note: Each command appears on two lines for formatting purposes. You should enter each command on one line.)

Generate the WSDL and Mapping Files

A WSDL file describes the web service. It's the WSDL file that tells a client what format to use in making a request to the service. wscompile is a tool packaged with the J2EE 1.4 SDK that provides a mapping between a JAX-RPC SEI and a WSDL file. You can run the wscompile tool to generate a WSDL file from an SEI or generate an SEI from a WSDL file. If you use ant to do the build for this tip, it runs the wscompile tool to create a WSDL file for the web service. The build also generates a mapping.xml file. The mapping file maps the WSDL definition of the web service to Java interfaces.

If you don't do an ant build, you can create the mapping.xml and WSDL files by running the following command inside the base directory:
   wscompile -define -mapping build\mapping.xml -d build 
   -nd build -classpath build config-interface.xml
(Again, the command appears on two lines for formatting purposes. You should enter it on one line.)

Here is what the flags in the wscompile command mean:
-classpath. Instructs the wscompile tool to read the SEI in the 
    build directory. 
-define. Instructs wscompile to create a WSDL.
-mapping. Instructs wscompile to create a mapping file  
-d. Instructs wscompile to write class files to the build 
    subdirectory. 
-nd. Instructs wscompile to write WSDL files to the build 
    subdirectory. 
When you run the wscompile tool, you also need to provide a wscompile configuration file that specifies information about the SEI. A configuration file is supplied with the sample code for this tip. The configuration file is named config-interface.xml, and contains the following:
   <?xml version="1.0" encoding="UTF-8"?>
   <configuration 
     xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
     <service 
         name="MyHelloService" 
         targetNamespace="urn:Foo" 
         typeNamespace="urn:Foo" 
         packageName="helloservice">
         <interface name="helloservice.HelloIF/>
     </service>
   </configuration>
This configuration file tells wscompile to create a WSDL file named MyHelloService.wsdl. The file also provides with the following information and instructions:
  • The service name is MyHelloService.
  • The SEI is helloservice.HelloIF.
  • Put the service classes in the helloservice package.
  • The WSDL target and type namespace is urn:Foo. Note that the choice for what to use for the namespaces is up to you. The role of the namespaces is similar to the use of Java package names, that is, to distinguish names that might otherwise conflict. For example, a company decides that all its Java code should be in the package com.wombat.*. Similarly, it can also decide to use the namespace http://wombat.com.
Package and Deploy the Service

Next you need to package and deploy the service. To do that, you need to specify details about the service in deployment descriptors. Web services can be implemented as servlets or stateless session beans. Web services implemented as servlets are packaged in Web Archive (WAR) files. The WEB-INF directory in the WAR file contains two standard deployment descriptor files for web applications (web.xml and sun-web.xml) and a special web services deployment descriptor file (webservices.xml). Web services implemented as stateless session beans are packaged in an EJB-JAR file, and the deployment descriptor files are in the META-INF directory.

If you use ant to do the build for this tip, it packages the services for you. Specifically, the build:
  • Creates a temporary directory to assemble the WAR contents.
  • Creates two subdirectories in the temporary directory: WEB-INF and build.
  • Creates two subdirectories in the WEB-INF directory: classes and wsdl.
  • Copies HelloIF.class and HelloImpl.class to the WEB-INF/classes directory.
  • Copies MyHelloService.wsdl to the WEB-INF/wsdl directory.
  • Copies the mapping.xml file to the build directory.
  • Creates the WAR file from the temporary directory. This puts the web.xml and sun-web.xml deployment descriptors, as well as the webservices.xml file, in the WEB-INF directory.
Alternatively, you can package the web service using the deploytool utility of the J2EE 1.4 Application Server.

After the WAR file is created, you can deploy it using the deploytool, or other application. If the deployment is successful, you should be able to view the WSDL file of the deployed service by requesting the URL http://localhost:8080/ttmay2005/hello?WSDL in a web browser. (We assume here that the Application Server is deployed on port 8080.) Be sure that you can do this because the wscompile command in the next section ("A Desktop Client") depends on downloading this XML file from the server in order to succeed.

Create the Client Class

After you deploy the web service, you can access it from a client program. HelloClient is a desktop client program provided with the sample code for this tip. It calls the sayHello method of the MyHelloService. It makes this call through a stub, a local object that acts as a proxy for the remote service. Because the stub is created at development time (as opposed to runtime), it is usually called a static stub. Here is the source code for HelloClient (notice the code for the static stub):

   package staticstub;

   import javax.xml.rpc.*;

   public class HelloClient {

       private static String endpointAddress =
           "http://localhost:8080/ttmay2005/hello";

       public static void main(String[] args) {

           System.out.println("Endpoint address = "
             + endpointAddress);

           try {
              Stub stub = createProxy();
              stub._setProperty
                (Stub.ENDPOINT_ADDRESS_PROPERTY,
                 endpointAddress); 
              HelloIF hello = (HelloIF)stub;
              System.out.println(hello.sayHello("Duke!"));
           } catch (Exception ex) {
              ex.printStackTrace();
           }
       }    

       private static Stub createProxy() {
           return 
               (Stub) (new MyHelloService_Impl().
                   getHelloIFPort());
       }
   }  

Generate the Stub Files

As mentioned previously, the client uses a local proxy called a stub to access the service. So before you can use the client to access the service, you need to generate the stub files. The way to do that is to use a tool such as wscompile. Just as you did earlier, you can run ant to invoke the wscompile tool. Change your current directory to the ttMay2005/helloclient directory below where you installed the sample code. Then enter the following command:
   ant stubs
The stubs task runs the wscompile tool with the following arguments:
   wscompile -gen:client -d build -classpath build 
    config-wsdl.xml 
This argument directs wscompile to read the MyHelloService.wsdl file that was generated earlier. The tool also generates files based on the information in the WSDL file and the command-line flags. In particular, the -gen:client flag instructs wscompile to generate stubs, runtime files such as serializers, and value types. The -d flag directs the tool to write the generated output to the build/staticstub subdirectory.

When you run the wscompile tool, you also need to provide a configuration file that specifies the location of the target WSDL file. A configuration file (config-interface.xml) is supplied with the sample code for this tip. Here are the contents of the config-interface.xml file:
   <configuration 
     xmlns="http//java.sun.com/xml/ns/jax-rpc/ri/config">
     <wsdl location="http://localhost:8080/ttmay2005/hello?WSDL" 
     packageName="staticstub"/>
   </configuration>
The packageName attribute specifies the Java package for the generated stubs. Notice that the location of the WSDL file is specified as a URL. This causes the wscompile command to request the WSDL file from the web service. Because of that, the web service must be correctly deployed and running for the command to succeed. If the web service is not running or if the port at which the service is deployed is different from the port in the configuration file, the command will fail.

Compile the Client Classes

The next step is to compile the client classes. You can do that for this tip by entering the following command:
   ant compile
The ant compile task compiles src/HelloClient.java, and writes the class file to the build subdirectory. It is equivalent to running the following command:
   javac -sourcepath src -d build staticstub.HelloClient.java
Package the Client

The past step in creating the client is to package the files created in the previous into a jar file. You can do that for this tip by entering the following command:
   ant jar
The ant jar task creates a file named ttmay2005.jar. Notice that except for the HelloClient.class, all the files in ttmay2005jar were created by wscompile. Also, note that wscompile generated the HelloIF.class based on the information it read from the MyHelloService.wsdl file which it downloaded from the application server.

Run the Client

Before you run the client, ensure that the following JAR libraries from the Java Web Services Developer Pack 1.5 download are in your classpath:
   jaxrpc/lib/jaxrpc-api.jar
   jaxrpc/lib/jaxrpc-spi.jar
   jaxrpc/lib/jaxrpc-impl.jar
   jwsdp-shared/lib/activation.jar
   jwsdp-shared/lib/mail.jar
   jwsdp-shared/lib/jax-qname.jar
   saaj/lib/saaj-api.jar
   saaj/lib/saaj-impl.jar
   jaxp/lib/endorsed/dom.jar
   jaxp/lib/endorsed/sax.jar
   jaxp/lib/endorsed/xalan.jar
   jaxp/lib/endorsed/xercesImpl.jar
Alternatively, you can use the following command to run the client which handles the classpath additions for you:
   ant run
In response, you should see the following in your command line window:
   [java] Endpoint address = http://localhost:8080/ttmay2005/hello
   [java] Hello Duke!
Additional Resources

For more information about JAX-RPC, see Chapter 8: Building Web Services with JAX-RPC in the J2EE 1.4 Tutorial.

Back to Top

USING RELAX NG WITH JAXB
 
The JAXB libraries in the Java Web Services Developer Pack (Java WSDP) 1.5 include functionality for RELAX NG. RELAX NG provides vocabularies for XML documents, and is a popular alternative to DTD or XML Schema. The RELAX NG specifications have been developed by the RELAX NG Technical Committee within OASIS (The Organization for the Advancement of Structured Information Standards). The support for RELAX NG in JAXB is currently experimental and is not officially supported. However, if you like to work with RELAX NG, it's nice to know that you can use it with JAXB, even experimentally. This tip describes how to use RELAX NG with JAXB.

Getting Up to Speed with RELAX NG

If you've used DTDs in the past, you know that the syntax of these documents can sometimes be rather cryptic. The RELAX NG standards provide an XML-based alternative to using DTDs for XML document validation. RELAX NG strives to provide more functionality than raw XML schemas. For example, here is a DTD:
   <!DOCTYPE addressBook [
   <!ELEMENT addressBook (card*)>
   <!ELEMENT card (name, email)>
   <!ELEMENT name (#PCDATA)>
   <!ELEMENT email (#PCDATA)>
   ]>
Here is an equivalent RELAX NG grammar:
   <element name="addressBook" 
     xmlns="http://relaxng.org/ns/structure/1.0">
     <zeroOrMore>
       <element name="card">
         <element name="name">
           <text/>
         </element>
         <element name="email">
           <text/>
         </element>
       </element>
     </zeroOrMore>
   </element>
It's safe to say that that RELAX NG syntax is the easier to follow of the two grammars. Now, consider the following XML document, from which we need to build a syntax:
   <?xml version="1.0" encoding="UTF-8"?>
   <book isbn="0345391802">
    <title>
  The Hitchhiker's Guide to the Galaxy
    </title>
    <author>Douglas Adams</author>
    <character>
     <name>Arthur Dent</name>
     <friend-of>Ford Prefect</friend-of>
    </character>
    <character>
     <name>Ford Prefect</name>
    </character>
   </book>
From this XML document, it's obvious that a book has an ISBN number, a title, an author, and one more more characters. But it also appears that each character has one or more personal characteristics. In other words, each document has a grammar associated with it, that goes something like this:
  A Book must have an ISBN number, a title, an author, and it 
  must have one or more characters.
Here is an example of a RELAX NG grammar that provides a vocabulary for the XML document:
   <?xml version="1.0" encoding="UTF-8"?>
   <grammar xmlns="http://relaxng.org/ns/structure/1.0">
     <start>
       <element name="book">
         <attribute name="isbn">
           <text/>
         </attribute>
       <element name="title">
         <text/>
       </element>
       <element name="author">
         <text/>
       </element>
       <zeroOrMore>
         <element name="character">
           <element name="name">
             <text/>
           </element>
           <optional>
             <element name="friend-of">
               <text/>
             </element>
           </optional>
         </element>
       </zeroOrMore>
     </start>
   </grammar>
This states that:
  • The grammar must consist of an element named book.
  • The <book> element must have an ISBN attribute associated with it, such as <book isbn="0345391802">.
  • In the book element, there must by a <title> and an <author> element.
  • There must be plain text inside ISBN attribute as well as inside the <title> and <author> elements.
  • There can be zero or more <character> elements.
  • Each <character> element has a <name> element, an optional <friend-of> element, a <since> element, and a <qualification> element. All four consist of ordinary text.
If you're familiar with XML, RELAX NG is easy to follow. In fact, you can think of RELAX NG as a DTD reformatted in XML.

RELAX NG Specifics

Let's examine the RELAX NG grammar more closely.

The <start> element specifies where the RELAX NG grammar should begin. There can be one or more <define> elements, where each <define> element has a name attribute. These defined elements can be referenced with a <ref> element that specifies the same name. So, for example:
   <grammar>

     <start>
       <ref name="AddressBook"/>
     </start>

     <define name="AddressBook">
       <element name="addressBook">
         <zeroOrMore>
           <ref name="Card"/>
         </zeroOrMore>
       </element>
     </define>

     <define name="Card">
       <element name="card">
         <ref name="Name"/>
         <ref name="Email"/>
       </element>
     </define>

     <define name="Name">
       <element name="name">
         <text/>
       </element>
     </define>

     <define name="Email">
       <element name="email">
         <text/>
       </element>
     </define>

   </grammar>
RELAX NG uses the following numerical pattern quantifications that are similar to DTDs and many other expression languages:

<oneOrMore>. Must consist of at least one, and may consist of more than one.

<zeroOrMore>. May consist of one or more, or may be omitted.

<optional>. May consist of one instance, or may be omitted.

In addition, if you want to specify a sequence of patterns at the same level, there are three different elements that you can use: <choice>, <group>, or <interleave>.

<choice>. Indicates that one and only one of multiple elements inside of it must be specified. For example:
  
   <choice>
       <element name='femaleName'>
           <text/>
       </element>
       <element name='maleName'>
           <text/>
       </element>
   </choice>
<group>. Groups together the elements on the inside, such that the entire group can be acted on by an outside qualifier. For example:
  
    <oneOrMore>
        <group>
            <element name='areaCode'>
                <text/>
            </element>
            <element name='phoneNumber'>
                <text/>
            </element>
        </group>
   </oneOrMore>
<interleave>. Allows child elements to appear in any order, as long as they obey the other semantics assigned inside of them.

<list>. The <list> element contains a pattern that the sequence of tokens must match. For example, suppose you want to have a vector element that contains two floating point numbers separated by whitespace. You could use list as follows:
   <element name="vector">
     <list>
       <data type="float"/>
       <data type="float"/>
     </list>
   </element>
There are other parts of the RELAX NG grammar that are interesting, such as merging inline patterns. For more information, see the RELAX NG tutorial.

Revisiting the Birthday Example

The following example demonstrates the use of the Java API for XML Binding (JAXB) with RELAX NG. The source code for the example is provided in the sample code for this tip, ttmay2005-rng.jar. In this case, we've converted the example from the December 2004 JAXB tech tip to use RELAX NG instead of XML Schema.

Here is an the XML file (birthdate.xml) that is used in the example.
<?xml version="1.0"?>
<birthdate>
    <birthdayMonth>January</birthdayMonth>
    <birthdayDay>21</birthdayDay>
    <birthdayYear>1983</birthdayYear>
</birthdate>
Here is the RELAX NG grammar that specifies the rules for the XML file. The grammar is in file birthdate.rng. This file is presented in its raw RELAX NG format first, without any JAXB elements, so that you can see how the XML file above will be validated.
<?xml version="1.0"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
         
  <start>
     <element name="birthdate">
        <element name="birthdayMonth">
            <data type="string"/> 
        </element>            
        <element name="birthdayDay">
            <data type="integer"/> 
        </element>           
        <element name="birthdayYear">
            <data type="integer"/>  
        </element>
     </element>
  </start>
 
</grammar>
This version adds the JAXB bindings to indicate how each of the elements inside of the RELAX NG grammar should bind to a Java object when the "xjc" tool generated the appropriate source code.
<?xml version="1.0"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
         xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
         xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
         jaxb:extensionBindingPrefixes="xjc"
         jaxb:version="1.0">
  
  <jaxb:schemaBindings>
    <jaxb:package name="birthdate"/>
  </jaxb:schemaBindings>
  
  <start>
     <element name="birthdate">
        <jaxb:class name="Birthdate" />           
            <element name="birthdayMonth">
                <jaxb:property name="Month" />
                <data type="string">
                    <jaxb:javaType name="java.lang.String"
                     parseMethod="new" printMethod="toString" />  
                </data>
            </element>            
            <element name="birthdayDay">
                <jaxb:property name="Day" />
                <data type="integer">
                    <jaxb:javaType name="java.lang.Integer"
                     parseMethod="new" printMethod="toString" />  
                </data>
            </element>           
            <element name="birthdayYear">
                <jaxb:property name="Year" />
                <data type="integer">
                    <jaxb:javaType name="java.lang.Integer"
                     parseMethod="new" printMethod="toString" />  
                </data>
            </element>
     </element>
  </start>
 
</grammar>
This version specifies first that all classes defined will be in the "birthdate" package using the <jaxb:package> element inside of <jaxb:schemaBindings>. In addition, <birthdate> will map to a "Birthdate" class; the <birthdayMonth> element will be validated against a RELAX NG string data type, and will map to a java.lang.String read/write property with the name "Month." In the same manner, the <birthdayDay> and <birthdayYear> elements will map to similar constructs using a java.lang.Integer object.

Here is the Java code (in file RELAXNGExample.java) that uses JAXB to marshal data to the XML file from a JAXB-generated instance, and unmarshal data from an XML file to a JAXB-generated instance:
  import java.io.File;
  import javax.xml.bind.JAXBContext;

  public class RELAXNGExample {

    public static void main(String[] args) throws Exception {
        test(args[0]);       
    }
    
    private static void test( String fileName ) throws
       Exception {
        
        
        JAXBContext context = JAXBContext.newInstance("birthdate");
        
        Object o = context.createUnmarshaller().
            unmarshal(new File(fileName)); 
        context.createValidator().validate(o);
        context.createMarshaller().marshal(o,System.out);
    }
  }
To run the example, you first need to compile the RelaxNG grammar using the XJC compiler. You can request that XJC use RELAX NG with the -relaxng option. Run the following XJC command:
   xjc -relaxng birthdate.rng -d gen-src
The options inside of the RelaxNG file will generate source code targeted towards the birthdate package, including a Birthdate interface shown here (without comments):
package birthdate;

public interface Birthdate {

    java.lang.Integer getDay();
    void setDay(java.lang.Integer value);

    java.lang.Integer getYear();
    void setYear(java.lang.Integer value);

    java.lang.String getMonth();
    void setMonth(java.lang.String value);
}
Next, compile the RELAXNGExample class, and the classes just generated in the gen-src directory. Then run the compiled classes. An easy way to do the compile and run is to use the ant build tool. A build file (build.xml) is provided in the sample code for this tip. You can do the build by running ant in the same directory as the build file for the sample. Change your current directory to the relaxng directory below where you installed the sample code. Then enter the following command:
   ant
In response, you should see the following:
   Buildfile: build.xml

   compile:
        [echo] Compiling the schema...
        ...
        [echo] Compiling the java source files...
        ...
   
   run:
        [echo] Running the sample application...
        [java] <?xml version="1.0" encoding="UTF-8" 
        standalone="yes"?>
        [java] <birthdate><birthdayMonth>January</birthdayMonth>
        <birthdayDay>21</birthdayDay><birthdayYear>1983
        </birthdayYear></birthdate>
   
   
   BUILD SUCCESSFUL
Total time: 4 seconds
Additional Resources

For more information about JAXB, see Chapter 2: Using JAXB.

For more information about RELAX NG, see the RELAX NG tutorial.

For more information on the JAXB RI project.

For more information on the JAXB extensions for RELAX NG.

Back to Top

 
TRY THE NEW SEARCH FACILITY


Sun is working on a new search facility for its developer sites. The search facility is currently available as a beta release. Try it out and provide your feedback. You can access the search facility.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=sdn

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 (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).
You can subscribe to these and other Java technology developer newsletters or manage your current newsletter subscriptions on the Sun Developer Network Subscriptions 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

© 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://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.