package de.kp.wsclient.soap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import de.kp.wsclient.security.SecConstants;
import de.kp.wsclient.security.SecCrypto;
import de.kp.wsclient.security.SecDecryptor;
import de.kp.wsclient.security.SecEncryptor;
import de.kp.wsclient.security.SecSignature;
import de.kp.wsclient.security.SecValidator;
import de.kp.wsclient.util.UUIDGenerator;
import de.kp.wsclient.xml.XMLSerializer;
public class SOAPMessage {
private Document xmlDoc;
private Element header;
private Element body;
private String bodyId = "BE-" + UUIDGenerator.getUUID();
// this constructor is used to build a new SOAP message;
// use case: outgoing SOAP message
//private static String SOAP_NS = SecConstants.URI_SOAP12_ENV;
private static String SOAP_NS = SecConstants.URI_SOAP11_ENV;
public SOAPMessage() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try {
xmlDoc = factory.newDocumentBuilder().newDocument();
// create SOAP envelope
String envelopeName = SecConstants.SOAP_PRE + ":" + SecConstants.ELEM_ENVELOPE;
Element envelope = xmlDoc.createElementNS(SOAP_NS, envelopeName);
xmlDoc.appendChild(envelope);
// create SOAP header
String headerName = SecConstants.SOAP_PRE + ":" + SecConstants.ELEM_HEADER;
header = xmlDoc.createElementNS(SOAP_NS, headerName);
envelope.appendChild(header);
// create SOAP body
String bodyName = SecConstants.SOAP_PRE + ":" + SecConstants.ELEM_BODY;
body = xmlDoc.createElementNS(SOAP_NS, bodyName);
body.setAttribute("id", bodyId);
envelope.appendChild(body);
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
/**
* Constructor SOAPMessage
*
* @param xml
*/
public SOAPMessage(String xml) {
InputStream is = getISFromXML(xml);
if (is != null) setSOAPMessageFromIS(is);
}
/**
* Constructor SOAPMessage
*
* @param is
*/
public SOAPMessage(InputStream is) {
setSOAPMessageFromIS(is);
}
/**
* Constructor SOAPMessage
*
* @param xmlDoc
*/
public SOAPMessage(Document xmlDoc) {
this.xmlDoc = xmlDoc;
this.header = getSOAPElement(xmlDoc, SecConstants.ELEM_HEADER);
this.body = getSOAPElement(xmlDoc, SecConstants.ELEM_BODY);
}
/**
* @param is
*/
private void setSOAPMessageFromIS(InputStream is) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try {
this.xmlDoc = factory.newDocumentBuilder().parse(is);
this.header = getSOAPElement(xmlDoc, SecConstants.ELEM_HEADER);
this.body = getSOAPElement(xmlDoc, SecConstants.ELEM_BODY);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private Element getSOAPElement(Document xmlDoc, String localName) {
NodeList nodes = xmlDoc.getElementsByTagNameNS(SOAP_NS, localName);
if (nodes.getLength() == 0) return null;
return (Element) nodes.item(0);
}
public Document getXMLDoc() {
return this.xmlDoc;
}
// this method adds content to the SOAP body element
public void setContent(Node content) throws Exception {
if (this.body == null) throw new Exception("Invalid SOAP Message detected (missing body).");
this.body.appendChild(content);
}
// returned the first child node of the body node;
// in case of a decrypted xml document, the respective
// node is a document fragment
public Node getContent() throws Exception {
if (this.body == null) throw new Exception("Invalid SOAP Message detected (missing body).");
return this.body.getFirstChild();
}
// this method supports the signing of the SOAP message
public void sign(SecCrypto sigCrypto) throws Exception {
SecSignature signature = new SecSignature(sigCrypto);
this.xmlDoc = signature.sign(this.xmlDoc);
}
// this method supports encryption and signing
// of the SOAP message; note, that encryption
// MUST be invoked BEFORE signing is called
public void encryptAndSign(SecCrypto sigCrypto, SecCrypto encCrypto) throws Exception {
// encrypt
SecEncryptor encryptor = new SecEncryptor(encCrypto);
this.xmlDoc = encryptor.encrypt(this.xmlDoc);
// sign
SecSignature signature = new SecSignature(sigCrypto);
this.xmlDoc = signature.sign(this.xmlDoc);
}
// this method verifies the signature assigned with th SOAP message
public void verify() throws Exception {
SecValidator validator = new SecValidator();
validator.verify(this.xmlDoc);
}
// this method supports verification of a signed
// SOAP message and afterwards decryption of the
// respective content
public void verifyAndDecrypt(SecCrypto crypto) throws Exception {
// verify signature of SOAP message
SecValidator validator = new SecValidator();
this.xmlDoc = validator.verify(this.xmlDoc);
// decrypt content of SOAP message (this is
// actually restricted to the BODY element)
SecDecryptor decryptor = new SecDecryptor(crypto);
this.xmlDoc = decryptor.decrypt(this.xmlDoc);
}
public String toXML() {
return XMLSerializer.serialize(this.xmlDoc);
}
private InputStream getISFromXML(String xml) {
byte[] bytes;
try {
bytes = xml.getBytes("UTF-8");
return new ByteArrayInputStream(bytes);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}