Enterprise Java Technologies Tech Tips
Tips, Techniques, and Sample Code
Welcome to the Enterprise Java Technologies Tech Tips for
May 24, 2005. 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:
* 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.
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/EJTechTips/2005/tt0524.html.
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 Using RelaxNG With
JAXB tip at
http://java.sun.com/developer/EJTechTips/download/ttapr2005relaxng.zip.
You can download the sample archive for the Creating a Simple
Web Service Using JAX-RPC tip at
http://java.sun.com/developer/EJTechTips/download/ttmay2005.zip.
Any use of this code and/or information below is subject to the
license terms at
http://developers.sun.com/dispatcher.jsp?uid=6910008.
For more Java technology content, visit these sites:
java.sun.com - The latest Java platform releases, tutorials, and
newsletters.
java.net - A web forum for collaborating and building 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"
(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXRPC.html#wp72279)
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.zip. 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:
o It extends the java.rmi.Remote interface.
o It must not have constant declarations, such as
public final static.
o The methods must throw the java.rmi.RemoteException or one of
its subclasses. (The methods can also throw service-specific
exceptions.)
o Method parameters and return types must be supported JAX-RPC
types. (For a list of the JAX-RPC types, see
http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXRPC4.html#wp130550.)
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
ttMay2005/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:
This configuration file tells wscompile to create a WSDL file
named MyHelloService.wsdl. The file also provides with the
following information and instructions:
o The service name is MyHelloService.
o The SEI is helloservice.HelloIF.
o Put the service classes in the helloservice package.
o 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:
o Creates a temporary directory to assemble the WAR contents.
o Creates two subdirectories in the temporary directory: WEB-INF
and build.
o Creates two subdirectories in the WEB-INF directory: classes
and wsdl.
o Copies HelloIF.class and HelloImpl.class to the
WEB-INF/classes directory.
o Copies MyHelloService.wsdl to the WEB-INF/wsdl directory.
o Copies the mapping.xml file to the build directory.
o 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:
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
(http://java.sun.com/webservices/downloads/webservicespack.html)
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"
(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JAXRPC.html#wp72279)
in the J2EE 1.4 Tutorial.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
USING RELAX NG WITH JAXB
The JAXB libraries in the Java Web Services Developer Pack (Java
WSDP) 1.5 include functionality for RELAX NG
(http://www.relaxng.org/). 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:
]>
Here is an equivalent RELAX NG grammar:
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:
The Hitchhiker's Guide to the Galaxy
Douglas Adams
Arthur Dent
Ford Prefect
Ford Prefect
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:
This states that:
o The grammar must consist of an element named book.
o The element must have an ISBN attribute associated with
it, such as .
o In the book element, there must by a and an
element.
o There must be plain text inside ISBN attribute as well as
inside the and elements.
o There can be zero or more elements.
o Each element has a element, an optional
element, a element, and a
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 element specifies where the RELAX NG grammar
should begin. There can be one or more elements, where
each element has a name attribute. These defined
elements can be referenced with a [ element that specifies
the same name. So, for example:
]
RELAX NG uses the following numerical pattern quantifications
that are similar to DTDs and many other expression languages:
. Must consist of at least one, and may consist of
more than one.
. May consist of one or more, or may be omitted.
. 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: , , or .
. Indicates that one and only one of multiple elements
inside of it must be specified. For example:
. Groups together the elements on the inside, such that
the entire group can be acted on by an outside qualifier. For
example:
. Allows child elements to appear in any order, as
long as they obey the other semantics assigned inside of them.
. The 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:
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
(http://www.oasis-open.org/committees/relax-ng/tutorial.html).
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
(http://java.sun.com/developer/EJTechTips/2004/tt1221.html#1)
to use RELAX NG instead of XML Schema.
Here is an the XML file (birthdate.xml) that is used in the example.
January
21
1983
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.
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.
This version specifies first that all classes defined will
be in the "birthdate" package using the
element inside of . In addition,
will map to a "Birthdate" class; the
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 and
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 (http://ant.apache.org/). 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]
[java] January
211983
BUILD SUCCESSFUL
Total time: 4 seconds
Additional Resources
For more information about JAXB, see "Chapter 2: Using JAXB"
(http://java.sun.com/webservices/docs/1.5/tutorial/doc/JAXBUsing.html#wp78319).
For more information about RELAX NG, see the RELAX NG tutorial
(http://www.oasis-open.org/committees/relax-ng/tutorial.html).
For more information on the JAXB RI project, see this page
(http://jaxb.dev.java.net/).
For more information on the JAXB extensions for RELAX NG, see
this page
(http://java.sun.com/webservices/docs/1.5/jaxb/relaxng.html).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 at
http://onesearch.sun.com/search/onesearch/index.jsp?col=developer-all&qt=java
. . . . . . . . . . . . . . . . . . . . . . .
Please read our Terms of Use and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://developers.sun.com/dispatcher.jsp?uid=6910008
PRIVACY STATEMENT:
Sun respects your online time and privacy (http://sun.com/privacy).
You have received this based on your e-mail preferences. If you
would prefer not to receive this information, please follow the
steps at the bottom of this message to unsubscribe.
* FEEDBACK
Comments? Send your feedback on the Enterprise Java Technologies
Tech Tips to:
http://developers.sun.com/contact/feedback.jsp?category=sdn
* SUBSCRIBE/UNSUBSCRIBE
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 Sun Developer Network - Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
choose the newsletters you want to subscribe to and click
"Submit".
- To unsubscribe, go to the Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
uncheck the appropriate checkbox, and click "Submit".
- To use our one-click unsubscribe facility, see the link at
the end of this email:
- ARCHIVES
You'll find the Enterprise Java Technologies Tech Tips archives at:
http://java.sun.com/developer/EJTechTips/index.html
- COPYRIGHT
Copyright 2005 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/developer/copyright.html
Enterprise Java Technologies Tech Tips
May 24, 2005
Trademark Information: http://www.sun.com/suntrademarks/
Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks
or registered trademarks of Sun Microsystems, Inc. in the
United States and other countries.