Listing 6-12.The Signing Tree private static void signTreeNode root, PrivateKey privateKey, XMLSignature sig throws MarshalException, XMLSignatureException { Element envelope = getFirstC
Trang 1CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null),
sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null),Collections.singletonList(ref));
KeyInfoFactory kif = sigFactory.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(keypair.getPublic());
KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(kv));
return sigFactory.newXMLSignature(signedInfo, keyInfo);
}
By now, the hard part is over Listing 6-12 shows how to identify where to insert thesignature and connect back to the previously used body ID The last sig.sign()call iswhat does the signing
Listing 6-12.The Signing Tree
private static void signTree(Node root, PrivateKey privateKey, XMLSignature sig) throws MarshalException, XMLSignatureException {
Element envelope = getFirstChildElement(root);
Element header = getFirstChildElement(envelope);
DOMSignContext sigContext = new DOMSignContext(privateKey, header);
to see if the tree passes
Listing 6-13.Validating the XML Signature
private static boolean validateXMLSignature(
PublicKey publicKey, Node root, XMLSignature sig)throws XMLSignatureException {
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L )
136
Trang 2Element envelope = getFirstChildElement(root);
Element header = getFirstChildElement(envelope);
Element sigElement = getFirstChildElement(header);
DOMValidateContext valContext = new DOMValidateContext(publicKey, sigElement);
valContext.setIdAttributeNS(getNextSiblingElement(header),
"http://schemas.xmlsoap.org/soap/security/2000-12", "id");
return sig.validate(valContext);
}Listing 6-14 shows the complete program in action A couple of DOM tree dumps areshown before and after the tree is signed
Listing 6-14.The Complete XML Signing Example
public class Signing {
public static void main(String[] args) throws Exception {SOAPMessage soapMessage = createSOAPMessage();
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L ) 137
Trang 3SOAPPart soapPart = soapMessage.getSOAPPart();
Source source = soapPart.getContent();
Node root = generateDOM(source);
dumpDocument(root);
KeyPair keypair = generateDSAKeyPair();
XMLSignature sig = generateXMLSignature(keypair);
System.out.println("Signing the message ");
signTree(root, keypair.getPrivate(), sig);
dumpDocument(root);
System.out.println("Validate the signature ");
boolean valid = validateXMLSignature(keypair.getPublic(), root, sig);System.out.println("Signature valid? " + valid);
}private static SOAPMessage createSOAPMessage() throws SOAPException {SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
SOAPHeaderElement headerElement = soapHeader.addHeaderElement(
Trang 4Document doc = db.parse(inSource);
root = (Node) doc.getDocumentElement();
} else {throw new IllegalArgumentException(
"Class type: " + source.getClass().getName());
}
return root;
}private static KeyPair generateDSAKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024, new SecureRandom());
return kpg.generateKeyPair();
}
private static XMLSignature generateXMLSignature(KeyPair keypair) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException,KeyException {
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance();
Reference ref = sigFactory.newReference("#Body", sigFactory.newDigestMethod(DigestMethod.SHA1, null));
SignedInfo signedInfo = sigFactory.newSignedInfo(
sigFactory.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null),
sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null),Collections.singletonList(ref));
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L ) 139
Trang 5KeyInfoFactory kif = sigFactory.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(keypair.getPublic());
KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(kv));
return sigFactory.newXMLSignature(signedInfo, keyInfo);
}private static void signTree(Node root, PrivateKey privateKey, XMLSignature sig) throws MarshalException, XMLSignatureException {
Element envelope = getFirstChildElement(root);
Element header = getFirstChildElement(envelope);
DOMSignContext sigContext = new DOMSignContext(privateKey, header);
PublicKey publicKey, Node root, XMLSignature sig)throws XMLSignatureException {
Element envelope = getFirstChildElement(root);
Element header = getFirstChildElement(envelope);
Element sigElement = getFirstChildElement(header);
DOMValidateContext valContext = new DOMValidateContext(publicKey, sigElement);valContext.setIdAttributeNS(getNextSiblingElement(header),
"http://schemas.xmlsoap.org/soap/security/2000-12", "id");
return sig.validate(valContext);
}private static void dumpDocument(Node root) throws TransformerException {
Console console = System.console();
Trang 6private static Element getFirstChildElement(Node node) {
Node child = node.getFirstChild();
while ((child != null) && (child.getNodeType() != Node.ELEMENT_NODE)) {child = child.getNextSibling();
}return (Element) child;
}public static Element getNextSiblingElement(Node node) {Node sibling = node.getNextSibling();
while ((sibling != null) && (sibling.getNodeType() != Node.ELEMENT_NODE)) {sibling = sibling.getNextSibling();
}return (Element) sibling;
}}
When run, you’ll see both tree dumps, and hopefully a note showing that the tion passed The “before” tree, shown following, is rather small:
valida-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
have a namespace of dsbecause of the earlierputNamespacePrefix()call
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Trang 7<ds:KeyValue>
<ds:DSAKeyValue>
<ds:P>/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXguAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu
K2HXKu/yIgMZndFIAcc=</ds:P>
<ds:Q>l2BQjxUjC8yykrmCouuEC/BYHPU=</ds:Q>
<ds:G>9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKL
Zl6Ae1UlZAFMO/7PSSo=</ds:G>
<ds:Y>pX4PwF5u7xqoIv4wgk/zq7CaNHwLgFXxZncbqHU9vL1oZttOmADKKSsRsnLsHw67Q7KktzN16amo/2YHCGJ4r4iTNTxiOgAlGRg6CD/Em4c5tRcu/Qi8/Ck31BIT2B8EgzcY1SfXc1gqLRYFNwfLUBp
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L )
142
Trang 8The javax.xml.stream Package
Another facet of the new XML-related APIs in Java 6 has to do with JSR 173 and the
Streaming API for XML, or StAX It is like SAX parsing, but works on pulling events from
the parser, instead of the parser throwing events at you It definitely does not follow the
tree model of DOM, but does allow you to pause the parsing and skip ahead if necessary;
and unlike SAX, it does allow writing of XML documents, not just reading
There are two parts to the StAX API: a Cursor API for walking the document frombeginning to end, and an Iterator API for handling events in the order that they appear in
the source document You’ll see how to use both, but first you need an XML document to
read Listing 6-15 shows one that represents a series of points, with x and y coordinates
for each
Listing 6-15.A Simple XML Document
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
file The class basically gets an XMLStreamReaderfrom the XMLInputFactoryand then starts
looping through the stream For each event the system runs across, the cursor stops for
processing You can check the event type against one of the XMLEventinterface constants,
or rely on methods like isStartElement()or isCharacters()of the same interface to test
for event type By working with the integer constants, you can create a switch statement
like the one in Listing 6-16 for handling different element types
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L ) 143
Trang 9Listing 6-16.Cursor API Usage
import java.io.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
public class CursorRead {
public static void main(String args[]) throws Exception {Console console = System.console();
XMLInputFactory xmlif = XMLInputFactory.newInstance();
XMLStreamReader xmlsr = xmlif.createXMLStreamReader(
new FileReader("points.xml"));
int eventType;
while (xmlsr.hasNext()) {eventType = xmlsr.next();
switch (eventType) {case XMLEvent.START_ELEMENT:
The Cursor API and its XMLStreamReaderinterface don’t implement the Iteratorface; however, the events are iterated through in the same way—with hasNext()andnext()methods Be sure to call next()after hasNext()has returned trueto move to thenext element in the stream
inter-Running Listing 6-16 against the XML file in Listing 6-15 produces the followingresults:
Trang 10x 3
y 4point
ciated data for each element you get from the cursor, you instead get an XMLEventback as
you walk through the iteration Each XMLEventthus has its associated data with it, like the
name for the start element or the text data for the characters
Listing 6-17.Iterator API Usage
import java.io.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
public class IteratorRead {
public static void main(String args[]) throws Exception {Console console = System.console();
XMLInputFactory xmlif = XMLInputFactory.newInstance();
XMLEventReader xmler = xmlif.createXMLEventReader(
new FileReader("points.xml"));
XMLEvent event;
while (xmler.hasNext()) {event = xmler.nextEvent();
if (event.isStartElement()) {console.printf("%s", event.asStartElement().getName());
} else if (event.isCharacters()) {console.printf("\t%s", event.asCharacters().getData());
}} }}
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L ) 145
Trang 11The output produced with Listing 6-17 is identical to that of 6-16 While the output isthe same, there are many differences between the two APIs First, the Iterator API allowsyou to peek ahead without actually reading the stream This allows you to check ahead tosee what to do next before committing to reading the element While the Cursor API ismore efficient in memory-constrained environments, the Iterator API supports modifica-tions, and is best when pipelining streams If the Iterator API is sufficient, it is typicallybest to stick with that for desktop and web applications.
For more information on StAX parsing, visit its java.net home at https://sjsxp.dev.java.net The Java Web Services tutorial (http://java.sun.com/webservices/docs/1.6/tutorial/doc) includes a good introduction to the technology, too
Summary
If you’ve been doing Java EE–related development, many of the new XML-related APIs forMustang won’t be new and different for you All they are now is standard with Java SE.The JAXB 2.0 libraries give you Java-to-XML and XML-to-Java data bindings, the XMLDigital Signature API gives you signing of your XML files, and the StAX processing givesyou yet another way to parse your XML files—this time in a streaming fashion with thepossibility to write and not just read the stream
The next chapter takes you to even more familiar APIs for the Java EE developer:those related to web services With the ever-growing popularity of web services, theyaren’t just for enterprise developers anymore Thanks to their inclusion in Java 6, you toocan use them without adding any optional packages to your Java SE environment
C H A P T E R 6 ■ E X T E N S I B L E M A R K U P L A N G U A G E ( X M L )
146
Trang 12Web Services
Who doesn’t use web services these days? Due to the increasing popularity of web
serv-ices, the Java APIs for taking advantage of the functionality are moving from the latest
Java EE release into the Java SE 6 platform In other words, there are no add-on kits for
web services, and both platforms have the same API Mustang adds a handful of different
web services–related APIs to the standard tool chest: Web Services Metadata for the Java
Platform with JSR 181, the Java API for XML-Based Web Services (JAX-WS) 2.0 via JSR 224,
and the SOAP with Attachments API for Java (SAAJ) 1.3 as part of JSR 67
Before continuing with the chapter, it is necessary to point out one very importantpoint: this is not a book about web services I’ve seen 1,000-plus-page books on web serv-
ices that still require you to understand some level of XML, SOAP, or some other Java API
to take full advantage of the described capabilities In this chapter, I’ll do my best to show
examples of using the new APIs in the context of a Java SE program If you need more
information about creating web services, consider getting one of Apress’s other titles or
some of the many online tutorials on the topic You will need to “convert” the online
tutorial to Mustang, but the web services APIs are pretty much the same, just in a new
environment: Java SE, instead of Java EE
The packages associated with the three web services APIs are new to Java SE, so noneed for tables showing the differences between Java 5 and 6 The JAX-WS API is found in
the javax.xml.wspackages, the SAAJ classes are in javax.xml.soap, and the Web Services
Metadata classes are found under javax.jws
The javax.jws Package
JSR 181 and its specification of Web Services Metadata for the Java Platform provide a
mechanism to utilize annotations in classes to design and develop web services For
those unfamiliar with annotations, they were introduced with J2SE 5.0 and have been
expanded somewhat with Java 6 They are described more fully in Chapter 10; but they
essentially allow you to add @tagsto classes, methods, and properties to describe
associ-ated metadata A parser can then locate the tags and act appropriately; though when that
action happens is dependent upon the tag itself
147
C H A P T E R 7
Trang 13The two packages involved here are javax.jwsand javax.jws.soap Both packagesonly define enumerations and annotations There are neither classes nor interfaces here.
By importing the appropriate package for the annotations, you can annotate the classesthat represent web services, and their methods, as shown in Listing 7-1 Be sure toinclude a packagestatement If you don’t, when you run the wsgentool later, you’ll get
an error message, as follows:
modeler error: @javax.jws.Webservice annotated classes that do not belong to apackage must have the @javax.jws.Webservice.targetNamespace element
}}
There are two basic annotations specified here: @WebServiceand @WebMethod The
@WebServiceannotation identifies the HelloServiceclass as a web service If not specifiedotherwise, the @WebServiceannotation assumes the name is that of the class You can alsospecify a namespace, service name, WSDL location, and endpoint interface
But what can you do with the source file? Running the javaccompiler against thesource just spits out a classfile—nothing else special You still need to do that But aftercompiling the class, you also need to run the wsgencommand-line tool (wsgenis short forweb service generator)
The wsgentool generates a handful of source files and then compiles Since the age name of the example here is net.zukowski.revealed, the new classes are generatedinto the net/zukowski/revealed/jaxwsdirectory Listings 7-2 and 7-3 show the source forthe classes generated from running the following command:
pack-> wsgen -cp net.zukowski.revealed.HelloService
C H A P T E R 7 ■ W E B S E R V I C E S
148
Trang 14Listing 7-2.The First Generated Class for the Web Service
@XmlType(name = "helloWorld", namespace = "http://revealed.zukowski.net/")
public class HelloWorld {
@XmlType(name = "helloWorldResponse", namespace = "http://revealed.zukowski.net/")
public class HelloWorldResponse {
@XmlElement(name = "return", namespace = "")private String _return;
Trang 15There is certainly much more you can do with annotations here In fact, the tions found in the javax.jws.soappackage are where you get the SOAP bindings, whichtakes us to the next section.
annota-The javax.xml.ws and javax.xml.soap Packages
The JAX-WS API is very closely associated with JAXB Where JAXB is the Java-to-XMLmapping, and vice versa, JAX-WS is the mapping of Java objects to and from the Web Ser-vices Description Language (WSDL) Together, with the help of the SAAJ, the trio givesyou the API stack for web services
What does all that mean? With the help of last chapter’s JAXB, you can use the SAAJand JAX-WS APIs to generate SOAP messages to connect to web services to get results.You’re not going to deploy web services with Mustang Instead, you’re going to connect topreexisting services to get answers The available APIs are what you get with Java EE 5
SOAP Messages
In the last chapter, you saw an example creating a SOAP message The javax.xml.soappackage provides a MessageFactory, from which you get an instance to create the message.SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();
This generates a SOAP 1.2 message format If you need to create a message for theSOAP 1.1 protocol, you can pass the protocol name to the createMessage()method.SOAPMessage soapMessage =
MessageFactory.newInstance().createMessage(SOAPConstants.SOAP_1_1_PROTOCOL);The SOAP message in turn consists of a series of other objects: SOAPPart,SOAPEnvelope, SOAPBody, and SOAPHeader All of these bits are in XML format To includenon-XML data within the message, you would use one or more AttachmentParttypeobjects These are created from either an Activation Framework DataHandler, or directly
C H A P T E R 7 ■ W E B S E R V I C E S
150
Trang 16from an Objectand mime type Think of e-mail attachments here There is built-in
support in SAAJ 1.3 for mime types of type text/plain, multipart/*, and text/xmlor
application/xml For other mime types, that’s where the DataHandlercomes into play
AttachmentPart attachment = soapMessage.createAttachmentPart();
Continued
C H A P T E R 7 ■ W E B S E R V I C E S 151