| 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/ |
![]() |
||||||
|
||||||
| 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:
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:
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:
antThe 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:
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:
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 stubsThe 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 compileThe 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.javaPackage 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 jarThe 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.jarAlternatively, you can use the following command to run the client which handles the classpath additions for you: ant runIn 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:
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-srcThe 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:
antIn 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. |
||
|
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:
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. |