Enterprise Java Technologies Tech Tips Tips, Techniques, and Sample Code Welcome to the Enterprise Java Technologies Tech Tips for January 25, 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: * Introduction to the Java Transaction API * Using the Java XML Digital Signature API 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 Java technology developer, editor, and author. Robert is owner of Nexes Consulting, a Java consulting firm based in Austin, Texas. You can view this issue of the Tech Tips on the Web at http://java.sun.com/developer/EJTechTips/2005/tt0125.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 archives for these tips at http://java.sun.com/developer/EJTechTips/download/ttJan2005jta.jar and http://java.sun.com/developer/EJTechTips/download/ttJan2005xmldsig.jar. 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 - The marketplace for Java technology, applications and services. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INTRODUCTION TO THE JAVA TRANSACTION API A transaction is a series of operations that must be performed atomically. In other words, each operation in the series must succeed for the entire transaction to be successful. If any operation in the transaction does not succeed, the entire transaction fails. At that point, any operations which have succeeded must be "rolled back" so that the end state matches what was in place before the transaction started. For example, let's say you want to transfer $50 from a savings account (account number: 12345-1) to a checking account (account number 12345-2). The steps in this transaction can be stated in "pseudo code" as follows: BOUNDARY: START TRANSACTION A SUBTRACT 50 DOLLARS FROM SAVINGS ACCOUNT 12345-1 ADD 50 DOLLARS TO THE CHECKING ACCOUNT 12345-2 BOUNDARY: END TRANSACTION A To run the transaction, the following code is required: PREPARE (RUN) TRANSACTION A IF TRANSACTION A SUCCEEDED COMMIT TRANSACTION A ELSE ROLLBACK TRANSACTION A Let's assume that there are sufficient funds to subtract $50 from the savings account, so the first part of the transaction succeeds. However, let's also assume that the second part fails. When the computer attempts to add 50 dollars to the checking account, it discovers that the checking account is frozen. Because the second part of the transaction fails, the entire transaction fails. As a result, the first part of the transaction needs to be rolled back: $50 needs to be placed back into the savings account 12345-1. This is essential. Otherwise, each time the computer tries to transfer money from the savings to the checking account, it will lose the money! If the entire transaction succeeds, then the entire transaction is committed, and the results are made permanent. Note that the commit process takes two phases to complete. In the first phase, checks are made to see that the transaction ran without error. If there were no errors, the results are committed in the second phase. If there were errors in the first-phase check, the transaction is rolled back. This common transaction strategy is appropriately called the two-phase commit protocol. Transactions in the J2EE Environment There are typically three participants in a transaction: an application that initiates the request for the transaction, a data store (such as a database) that the transaction runs against, and an API (such as a driver) that communicates between the application and the data store. In the J2EE platform, the API (or driver) is provided by the J2EE-compliant application server. The application program calls the application server to perform the transaction. The Java Transaction API (JTA) is part of the J2EE platform. The API gives you the ability to perform distributed transactions, that is, an application can use the API to perform transactions on more than one data store in the network at the same time. But to do this efficiently, it helps to have another component operating in the application server: a J2EE transaction manager. A transaction manager helps to efficiently schedule and execute the potentially large number of transactions coming in through the application server. Many database vendors provide their own transaction managers. However, a particular DBMS's transaction manager might not work with databases from different vendors. If you want to work with these heterogeneous databases, for example, if you want to update multiple databases from different vendors, you should consider using a JTA transaction with a corresponding J2EE transaction manager. The JTA specification states that "A JTA transaction is controlled by the J2EE transaction manager." Note that the J2EE transaction manager does have one limitation: the J2EE transaction model is flat. Support for nested transactions is not part of J2EE. This means that the J2EE transaction manager cannot start a transaction for an instance until the previous transaction has ended. A J2EE-conforming application server implements a transaction manager using the Java Transaction Service (JTS). The JTA provides the API to call into the lower-level JTS routines. Be sure not to confuse the JTA with the JTS. Learning the JTA There are three separate interfaces that you can use with the JTA to perform transactions, and each uses a unique approach to handling transactions. The interfaces are: o javax.transaction.UserTransaction. This interface allows you to specify the transaction boundaries, bypassing a transaction manager. o javax.transaction.TransactionManager. This interface allows you to delegate the boundaries of the transactions, as well as various transaction operations, to the J2EE transaction manager. o javax.transaction.xa.XAResource. This interface maps to the X/Open CAE Specification (Distributed Transaction Processing: The XA Specification) standard for using third-party XA-compliant transaction managers to perform transactions. Because most J2EE programmers only use the first interface, the remainder of this tip focuses on that interface. EJB Transactions: Container and Bean-Managed Transactions In the J2EE environment, the most logical place to perform transactions is inside of an Enterprise JavaBeans (EJB) technology component (also called an enterprise bean). There are two approaches you can take if you use enterprise beans to perform transactions, The first approach allows the EJB container to manage the transaction boundaries. This puts less of a burden on the programmer. This approach is called container-managed transactions. The second approach allows the programmer more freedom by explicitly defining the boundaries of transactions in the enterprise bean code. This approach is called bean-managed transactions. Container-managed transactions can be used with any type of enterprise bean (session bean, entity bean, or message-driven bean). With container-managed transactions, the EJB container sets the boundaries of the transaction. This is typically done by marking one or more methods in the bean as individual transactions. The container sets the transaction boundary just before the beginning of the method, and sets the end boundary just before the method exits. However, with container-managed transactions, each method can be only one transaction -- multiple transactions are not allowed. When deploying a bean, you specify which of the bean's methods are associated with transactions. You do this by setting the transaction attributes. Transaction attributes control the scope of a transaction when one enterprise bean method calls another enterprise bean method. The JTA specification states that an enterprise bean method can be marked with one of six different transaction attributes in the EJB deployment descriptor. The transaction attribute indicates how the EJB container should treat the method called by the client enterprise bean when transactions are involved. Transaction attributes appear in the EJB deployment descriptor as follows: ... ... BankBean Remote transferMoney java.lang.String java.lang.String java.lang.double Required Here is what the specification says about each of the six transaction attributes: o Required - If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method. Most container-managed transactions use Required. o RequiresNew - If the client is running within a transaction and invokes the enterprise bean's method, the container suspends the client's transaction, starts a new transaction, delegates the call to the method, and finally resumes the client's transaction after the method completes. If the client is not associated with a transaction, the container starts a new transaction before running the method. o Mandatory - If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container throws the TransactionRequiredException. Use the Mandatory attribute if the enterprise bean's method must use the transaction of the client. o NotSupported - If the client is running within a transaction and invokes the enterprise bean's method, the container suspends the client's transaction before invoking the method. After the method has completed, the container resumes the client's transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method. Use the NotSupported attribute for methods that don't need transactions. Because transactions involve overhead, this attribute may improve performance. o Supports - If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method. Because the transactional behavior of the method may vary, you should use the Supports attribute with caution. o Never - If the client is running within a transaction and invokes the enterprise bean's method, the container throws a RemoteException. If the client is not associated with a transaction, the container does not start a new transaction before running the method. There are two ways to roll back a container-managed transaction. If a system exception is thrown, the container automatically rolls back the transaction. You can also roll back a transaction by invoking the setRollbackOnly() method of the EJBContext interface. This instructs the container to roll back the transaction. If an enterprise bean throws an application exception, the rollback is not automatic, but the rollback can be initiated by a call to setRollbackOnly(). Note that you cannot invoke some JTA methods while using container-managed transactions. That's because these methods are reserved for use with bean-managed transactions. These methods are: o Any resource-specific functions that conflict with the transactional semantics, such as the commit(), setAutoCommit(), and rollback() methods of java.sql.Connection o The getUserTransaction() method of javax.ejb.EJBContext o Any method of javax.transaction.UserTransaction In a bean-managed transaction, the code in the session or message-driven bean explicitly marks the boundaries of the transaction. An entity bean cannot have bean-managed transactions, it must use container-managed transactions. When you code a bean-managed transaction for session or message-driven beans, you typically can use either JDBC or JTA transactions. A JDBC transaction is controlled by the transaction manager of the database management system, and not by the J2EE transaction manager. To perform a JDBC transaction, use the commit() and rollback() methods of the java.sql.Connection interface. The beginning of a transaction is generally assumed with the first SQL statement that follows the most recent commit(), rollback(), or connect() statement. For JTA transactions, you can invoke the begin(), commit(), and rollback() methods of the javax.transaction.UserTransaction interface. The begin() and commit() methods mark the transaction boundaries. If the transaction operations fail, an exception handler typically invokes the rollback() method, and throws an EJBException. The following code shows how to use the JTA javax.transaction.UserTransaction interface to perform a bean-managed transaction: UserTransaction ut = context.getUserTransaction(); try { ut.begin(); // Do whatever transaction functionality is necessary ut.commit(); } catch (Exception ex) { try { ut.rollback(); } catch (SystemException syex) { throw new EJBException ("Rollback failed: " + syex.getMessage()); } throw new EJBException ("Transaction failed: " + ex.getMessage()); } The code to perform a JDBC bean-managed transaction is similar. Note, however, that the code turns off the auto-commit on the database connection. This way, the database treats all subsequent operations as a single transaction (until the code calls the commit() method) . try { Connection con = makeDatabaseConnection(); con.setAutoCommit(false); // Do whatever database transaction functionality // is necessary con.commit(); } catch (Exception ex) { try { con.rollback(); } catch (SQLException sqx) { throw new EJBException("Rollback failed: " + sqx.getMessage()); } } finally { releaseDatabaseConnection(); } Here are a few rules stated by the JTA specification: In a stateless session bean with bean-managed transactions, a business method must commit or roll back a transaction before returning. However, a stateful session bean does not have this restriction. In a stateful session bean with a JTA transaction, the association between the bean instance and the transaction is retained across multiple client calls. Even if each business method called by the client opens and closes the database connection, the association is retained until the instance completes the transaction. In a stateful session bean with a JDBC transaction, the JDBC connection retains the association between the bean instance and the transaction across multiple calls. If the connection is closed, the association is not retained. There is one method limitation with JTA bean-managed transactions: do not invoke the getRollbackOnly() and setRollbackOnly() methods of the EJBContext interface (these methods should be used only in container-managed transactions). For bean-managed transactions, invoke the getStatus() and rollback() methods of the UserTransaction interface instead. And, be sure not to invoke any resource-specific functions that conflict with the transactional semantics. For more information about JTA and JTS, see the J2EE Transaction page (http://java.sun.com/j2ee/transactions/index.jsp). Running the Sample Code for the Java Transaction API Tip 1. Download the sample archive for the Java Transaction API tip (http://java.sun.com/developer/EJTechTips/download/ttJan2005jta.jar). 2. Change to the directory where you downloaded the sample archive. Uncompress the JAR file for the sample archive as follows: jar xvf ttJan2005jta.jar The result is a directory called jta with source code, compiled classes, and other supporting files. 3. Start the application server. The J2EE 1.4 SDK contains the Sun Java System Application Server Platform Edition 8. Note that to work properly, the sample code requires Sun Java Application Server 8.1 4Q2004 or later. 4. Start the PointBase database server 5. Change to the jta directory. Edit the Ant script (build.xml) to point to your J2EE home directory. 6. Enter the command: ant create-db on the command line. This creates a database and fills it with an "account" table. If the database stalls when trying to dump the table, shut down and restart PointBase. 7. Enter the command: ant build This creates a directory called ejb and fills it with two JAR files: bank-client.jar and bank-ejb.jar 8. Deploy bank-ejb.jar. You can do this using the Sun Java System Application Server Platform Edition 8 Admin Console, (under Applications->EJB Modules), or by copying the file into the Autodeploy directory link (if you installed the server with that option). 9. Change to the ejb directory, and enter the following command: appclient -client bank-client.jar In response, you should see the following: --OUTPUT FROM APP CLIENT BEGIN-- Using Bean Transaction Management (Database Transaction Manager)... Balance of 12345-01 is: 100.0 Balance of 12345-02 is: 0.0 Now transferring 23.43 from 12345-01 to 12345-02 Balance of 12345-01 is: 76.57 Balance of 12345-02 is: 23.43 Now transferring 23.43 from 12345-01 to fictional account number 12345-10 Balance should be the same as before... Balance of 12345-01 is: 76.57 Balance of 12345-02 is: 23.43 Now Using JTA Container Transaction Management... Now transferring 23.43 from 12345-01 to fictional account number 12345-10 Exception was caught. Balance should again be the same as before... Balance of 12345-01 is: 76.57 Balance of 12345-02 is: 23.43 --OUTPUT FROM APP CLIENT END-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USING THE JAVA XML DIGITAL SIGNATURE API XML digital signatures have been on programmers' wish lists for some time. The good news is that JSR 105 (http://www.jcp.org/en/jsr/detail?id=105) now defines a standard Java technology API for providing XML digital signatures. This API is now part of the Java Web Services Development Pack (Java WSDP) 1.5 (http://java.sun.com/webservices/downloads/webservicespack.html). The Java WSDP 1.5 includes an implementation of the JSR 105 Proposed Final Draft. (Note that this is only the "proposed" final draft. The libraries might change before the final release.) The stated purpose of the Java XML Digital Signature API is to provide a vendor-neutral implementation of the W3C Recommendations for XML-Signature Syntax and Processing. What is a digital signature? Much like its pen and paper counterpart, a digital signature assures to anyone reading data that the author is indeed who he or she claims to be. A digital signature provides what cryptographers call "authentication." It also ensures that the content of the data is exactly the same as what the author signed (that is, nothing has been added or removed). In the world of cryptography, this is known as "integrity." Performing a digital signature involves two steps. In the first step, the data is run through a hashing algorithm. A typical hashing algorithm scans through the data and generates a number of some size -- this is typically called a "digest." If the same data is run through the hashing algorithm again, the same digest should be generated. Good hashing algorithms vary the digest unpredictably if the slightest change is made in the data. This makes it impossible to reverse engineer the original data, given the digest. The second step in producing a digital signature is to encrypt the digest using the private key of the author. If you're not familiar with the terms public key or private key, then you've probably never heard of public key cryptography. The basic concepts of public key cryptography are simple: anything that is encrypted using an individual's private key, can only be decrypted using the same individual's public key. The reverse is also true: anything encrypted using an individual's public key, can only be decrypted using the same individual's private key. The two keys are mathematically linked. After encrypting the digest with the user's private key, the resulting scrambled data is then appended to the original document data. Because public keys can be shared with anyone, and private keys should be known only to the signing author, verifying a digital signature is simple. The steps are: 1. Rehash the document data that was received. 2. Decrypt the encrypted digest with the author's public key that is typically appended to the document. 3. Compare the two digests. If they are equal, the signature is valid. If the two digests are not equal, then either the document has been altered, or the author of the document is not the same as the individual that signed it. However this information does not indicate which of those two faults (or both) have occurred. The Java XML Digital Signature API There are two parts of the JSR 105 API. The first part allows Java developers to create XML digital signatures for their data. The second part allows third-party developers to create provider implementations of the XML Digital Signature API and register them. This tip covers the first part only. It presents a simple example of how to sign an XML document and then verify that signature. Note that the XML signatures generated by JSR 105 can be applied to both XML and binary data. The resulting signature is created in XML. An XML Signature takes one of three forms. Assuming that the XML signature is contained in a element, the only difference between the three forms is where the element is located with respect to the document data. The three forms are: o Detached. A detached signature is over data that is external to the signature element. That is: o Enveloping. An enveloping signature is a signature over data that is inside the signature element. o Enveloped. An enveloped signature is a signature that is contained inside the data that it is signing. Let's assume that the data to be signed is contained in an element. Here is what the XML document looks like before applying a signature: Here's what the XML document looks like after the data is signed with an enveloped signature (note that these examples have been re-formatted and indented for easier reading): A number of elements are added inside of the element by the XML digital signature process. These elements are , element, and . The element contains signature information, as well as references to the data that is to be signed. In actuality, is the element that the signature is calculated over. Here is how this happens: o The data that the references point to is transformed, canonicalized (see below) and digested. o The element containing those references is canonicalized, digested and signed. Here is what a element might look like: uooqbWYa5VCqcJCbuymBKqm17vY= The elements within the element are: o . Describes the algorithm that the signature process used to generate a canonical version of the SignedInfo element. A canonical version of an XML document resolves trivial variances from different XML generators, such as explicit namespace-scoped elements or whitespaces, that would generate different signatures for documents that are otherwise logically equivalent. For more information on why canonicalization is necessary, see the W3C document "Canonical XML Version 1.0" (http://www.w3.org/TR/2001/REC-xml-c14n-20010315). o . Identifies the method used to generate the signature over the element. In this example, the DSA (Digital Signature Algorithm) is used after the SignedInfo digest is calculated with the SHA (Secure Hashing Algorithm) 1. o --One or more elements are listed that scope the data affected by their child elements. In the example, the URI attribute contains an empty string (""), that refers to the root element of the XML document (and so includes the entire document). First a transformation is performed on the data to ensure that the enveloped signature is not included in any subsequent calculations. Next, the data is digested using the digest algorithm listed. Finally, the digest value that was generated for the document by that algorithm is shown. The second element, , is relatively simple. It contains an arbitrarily-large text-encoded number which is the scrambled signature for the document in question. For example: KedJuTob5gtvYx9qM3k3gm7kbLBwVbEQRl26S2tmXjqNND7MRGtoew== Anyone who receives the XML document must be able to validate this signature. So the original document author (the signer) must append his or her public key to the document. (In reality, the public key should be authenticated with a certificate authority, but that's beyond the scope of this tip.) The public key is stored in the third element, . Here is an example of a raw DSA key. The value is in the element (a subelement of ):

/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxe Eu0ImbzRMqzVDZkVG9xD7nN1kuFw==

li7dzDacuo67Jg7mtqEm2TRuOMU= Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/ XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA== qV38IqrWJG0V/ mZQvRVi1OHw9Zj84nDC4jO8P0axi1gb6d+475yhMjSc/ BrIVC58W3ydbkK+Ri4OKbaRZlYeRA==
Using the XML Digital Signature API Here is an example that can be used to generate an XML digital signature (the example is adapted from the examples provided for the API with Java WSDP 1.5): String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList( fac.newTransform(Transform.ENVELOPED, null)), null, null); SignedInfo si = fac.newSignedInfo (fac.newCanonicalizationMethod (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, null), fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null), Collections.singletonList(ref)); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(512); KeyPair kp = kpg.generateKeyPair(); KeyInfoFactory kif = fac.getKeyInfoFactory(); KeyValue kv = kif.newKeyValue(kp.getPublic()); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv)); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder(). parse(new FileInputStream("myfile")); DOMSignContext dsc = new DOMSignContext (kp.getPrivate(), doc.getDocumentElement()); XMLSignature signature = fac.newXMLSignature(si, ki); signature.sign(dsc); TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform( new DOMSource(doc), new StreamResult( new FileOutputStream("mySignedFile")); The following lines of code create the XML signature factory, which is used to sign the document: String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); The code then creates Reference and SignedInfo objects. These map directly to their respective elements in the XML signature. Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList( fac.newTransform(Transform.ENVELOPED, null)), null, null); SignedInfo si = fac.newSignedInfo (fac.newCanonicalizationMethod (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, null), fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null), Collections.singletonList(ref)); Next, the JCA classes are used to generate a 512-bit DSA key, and create a KeyInfo object that includes the public key. The KeyInfo object also maps to the element in the signature. KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(512); KeyPair kp = kpg.generateKeyPair(); KeyInfoFactory kif = fac.getKeyInfoFactory(); KeyValue kv = kif.newKeyValue(kp.getPublic()); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv)); Finally, the code uses the JAXP DocumentBuilderFactory to create a document from the filename given, create an XML signature object, and use the TransformerFactory to write the signature to an OutputStream. The result is sent to the file mySignedFile. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder(). parse(new FileInputStream("myfile")); DOMSignContext dsc = new DOMSignContext (kp.getPrivate(), doc.getDocumentElement()); XMLSignature signature = fac.newXMLSignature(si, ki); signature.sign(dsc); TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform( new DOMSource(doc), new StreamResult( new FileOutputStream("mySignedFile")); Validating the Signature Here is the source code needed to validate the signature: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("mySignedFile")); NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); } String providerName = System.getProperty( "jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); DOMValidateContext valContext = new DOMValidateContext (new KeyValueKeySelector(), nl.item(0)); XMLSignature signature = fac.unmarshalXMLSignature(valContext); boolean coreValidity = signature.validate(valContext); if (coreValidity == false) { System.err.println("Signature failed"); } else { System.out.println("Signature passed"); } } The first section of code uses the JAXP DocumentBuilderFactory to create a namespace-aware Document object from the file mySignedFile: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("mySignedFile")); Next, it programmatically extracts the element (and all its children) from the XML: NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); } Then it creates an XMLSignatureFactory and DOMValidateContext object for use in unmarshalling the XML signature: String providerName = System.getProperty( "jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); DOMValidateContext valContext = new DOMValidateContext (new KeyValueKeySelector(), nl.item(0)); After an appropriate XMLSignature object is obtained, the program calls the validate() method using the appropriate context to determine whether the signature is valid: XMLSignature signature = fac.unmarshalXMLSignature(valContext); boolean coreValidity = signature.validate(valContext); if (coreValidity == false) { System.err.println("Signature failed"); } else { System.out.println("Signature passed"); } } For more information about the Digital Signature API, see "Chapter 4: Java XML Digital Signature API" in the Java Web Services Tutorial (http://java.sun.com/webservices/docs/1.5/tutorial/doc/index.html). Running the Sample Code for the Java XML Digital Signature API Tip 1. Download the sample archive for the Java XML Digital Signature API tip (http://java.sun.com/developer/EJTechTips/download/ttJan2005xmldsig.jar). 2. Download and install Java WSDP 1.5 from the "Java Web Services Developer Pack Downloads" page (http://java.sun.com/webservices/downloads/webservicespack.html). 3. Set your executable PATH to include the Ant application, which is located in the apache-ant/bin directory of Java WSDP 1.5. For example, if you installed Java WSDP 1.5 in C:\jwsdp-1.5 in the Windows environment, enter the commands: set JWSDP_HOME=C:\jwsdp-1.5 set ANT_HOME=%JWSDP_HOME%\apache-ant set PATH=%ANT_HOME%\bin;%PATH% 4. Change to the directory where you downloaded the sample archive. Uncompress the JAR file for the sample archive as follows: jar xvf ttJan2005xmldsig.jar 5. Change to the xmldsig base directory. Edit the Ant script (build.xml) to point to the base directory of your Java WSDP 1.5 installation. 6. Run the build.xml Ant script by entering: ant on the command line. In response, you should see the following: Buildfile: build.xml compile: run: [java] Generating DSA Key Pair... [java] Signing XML Document... [java] Signed XML Output Save to File: envelopedSignature.xml [java] Retrieving Signed XML File At: envelopedSignature.xml [java] Searching for Element... [java] Verifying Signature... [java] Signature Is Valid BUILD SUCCESSFUL - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Additional Resources NetBeans IDE 4.0 is the first, free open source IDE to support J2SE 5.0. NetBeans IDE 4.0 has the Tomcat server built in, provides integrated profiling (JFluid), and a project system based on Ant to meet all your development needs. You can download NetBeans IDE 4.0 from the NetBeans IDE downloads page (http://www.netbeans.org/downloads/). . . . . . . . . . . . . . . . . . . . . . . . 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 January 25, 2004 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.