/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package de.christofreichardt.jaxws.securitypriceservice;

import de.christofreichardt.diagnosis.AbstractTracer;
import de.christofreichardt.diagnosis.Traceable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.crypto.Data;
import javax.xml.crypto.OctetStreamData;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.URIReference;
import javax.xml.crypto.URIReferenceException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.dom.DOMURIReference;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author Christof Reichardt
 */
abstract public class AbstractSoapBodyDereferencer implements URIDereferencer, Traceable {
  public final static String SOAPBODY_URI = "#xpointer(/S:Envelope/S:Body)";

  @Override
  public Data dereference(URIReference uriReference, XMLCryptoContext context) throws URIReferenceException {
    AbstractTracer tracer = getCurrentTracer();
    tracer.entry("Data", this, "dereference(URIReference uriReference, XMLCryptoContext context)");
    
    try {
      if (SOAPBODY_URI.equals(uriReference.getURI())) {
        if (!(uriReference instanceof DOMURIReference))
          throw new IllegalArgumentException("Need a DOMURIReference.");
        
        DOMURIReference domURIReference = (DOMURIReference) uriReference;
        Node here = domURIReference.getHere();
        Element documentElement = here.getOwnerDocument().getDocumentElement();
        NodeList elements = documentElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/soap/envelope/", "Body");
        
        if (elements.getLength() == 0)
          throw new URIReferenceException("No SOAP body found.");
        else if (elements.getLength() > 1)
          throw new URIReferenceException("Multiple SOAP bodies found.");
        
        Element soapBodyElement = (Element) elements.item(0);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        getXmlSerializer().serialize(soapBodyElement, outputStream);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());

        return new OctetStreamData(inputStream);
      }
      else
        throw new URIReferenceException("'" + SOAPBODY_URI + "' as URI expected.");
    }
    finally {
      tracer.wayout();
    }
  }

  abstract AbstractXMLSerializer getXmlSerializer();
}
