import com.ibm.dom.util.XPathCanonicalizer;
import com.ibm.xml.sax.StandardErrorHandler;
import java.io.File;
import org.xml.sax.InputSource;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ibm.xml.dsig.KeyInfo;
import com.ibm.xml.dsig.SignatureContext;
import com.ibm.xml.dsig.util.AdHocIDResolver;
import com.ibm.xml.dsig.util.DOMParserNS;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.NodeList;

public class XMLDSigSampleWithKeyName{
    private static String keyStorePath = "tourOperatorDSAKey";
    private static String alias = "myTourOperatorKey";
    private static String storePass = new String("myKeyStorePass");
    private static String keyPass = new String("myKeyPass");
    private static String signatureTemplateFile = "SignatureTemplate.xml";
    private static String inputFile = "input.xml";
    private static String outputFile = "XMLDSigWithKeyNameOutput.xml";

    public static void main ( String argv[] ) throws Exception{

    /*********Step1*********/
        DocumentBuilder builder = DOMParserNS.createBuilder();
        builder.setErrorHandler(new StandardErrorHandler());
        Document inputDoc = builder.parse(inputFile);

    /*********Step2*********/
        Element elementToBeSigned = null;
        NodeList nodes = inputDoc.getDocumentElement().getChildNodes();

        for ( int i = 0; i < nodes.getLength(); i++ ){
            if ( nodes.item(i).getNodeType() == Node.ELEMENT_NODE ){
                elementToBeSigned = (Element) nodes.item(i);
                break;
            }// end of if
        }// end of for

    /*********Step3*********/
        String elementToBeSignedId = elementToBeSigned.getAttribute( "Id" );

    /*********Step4*********/
        Document templateDoc = builder.parse(signatureTemplateFile);
        Element templateElement =  
                    (Element) inputDoc.importNode( templateDoc.getDocumentElement(), true );
        inputDoc.getDocumentElement().appendChild (templateElement);

    /*********Step5*********/
        Element reference = (Element) templateElement.
                              getElementsByTagName("Reference").item(0);
        reference.setAttribute( "URI", "#" + elementToBeSignedId );

    /*********Step6*********/
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(
                     new FileInputStream(keyStorePath),
                     storePass.toCharArray() );
        X509Certificate cert = 
                            (X509Certificate)keystore.getCertificate(alias);
        Key key = keystore.getKey(alias, keyPass.toCharArray());
        if (key == null) {
            throw new RuntimeException("Could not get a private key: "+alias);
        }

    /*********Step7*********/

    /*********Step8*********/
        KeyInfo keyInfo = new KeyInfo();
        String keyNames[] = {alias};
        keyInfo.setKeyNames(keyNames);

    /*********Step9*********/
        keyInfo.insertTo(templateElement);

    /*********Step10*********/
        SignatureContext sigContext = new SignatureContext();

    /*********Step11*********/
        sigContext.setIDResolver(new AdHocIDResolver(inputDoc));

    /*********Step12*********/
        sigContext.sign(templateElement, key);

    /*********Step13*********/
        OutputStream os = new FileOutputStream(outputFile);
        printDocument(inputDoc, os);
        os.close();
    }//end of main

    public static void printDocument(Document doc, OutputStream out)
                    throws IOException {
        Writer wr = new OutputStreamWriter(out, "UTF-8");
        XPathCanonicalizer.serializeAll(doc, true, wr);
        wr.flush();
    }// end of printDocument method
}// end of class