package com.nortal.jroad.client.service.extractor; import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.soap.AttachmentPart; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import org.apache.commons.lang.StringUtils; import org.apache.xmlbeans.SchemaType; import org.apache.xmlbeans.SchemaTypeLoader; import org.apache.xmlbeans.XmlBeans; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.client.core.WebServiceMessageExtractor; import org.springframework.ws.soap.saaj.SaajSoapMessage; import org.springframework.xml.transform.StringResult; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.nortal.jroad.client.exception.NonTechnicalFaultException; import com.nortal.jroad.client.util.XmlBeansUtil; import com.nortal.jroad.model.XRoadAttachment; import com.nortal.jroad.model.XRoadMessage; import com.nortal.jroad.model.XmlBeansXRoadMessage; import com.nortal.jroad.model.XmlBeansXRoadMetadata; import com.nortal.jroad.util.SOAPUtil; /** * @author Dmitri Danilkin */ @SuppressWarnings("rawtypes") public class StandardXRoadConsumerMessageExtractor implements WebServiceMessageExtractor { private final XmlBeansXRoadMetadata metadata; public StandardXRoadConsumerMessageExtractor(XmlBeansXRoadMetadata metadata) { this.metadata = metadata; } public XRoadMessage<XmlObject> extractData(WebServiceMessage response) throws IOException { Node kehaNode; try { SaajSoapMessage message = (SaajSoapMessage) response; SOAPMessage mes = message.getSaajMessage(); Element body = mes.getSOAPBody(); NodeList kehaNodes = body.getChildNodes(); kehaNode = body.getChildNodes().item(0); if (kehaNode.getTextContent().contains("\n")) { kehaNode = kehaNodes.item(1); } if (kehaNodes.getLength() > 1) { // In case of multiple elements take the first one that matches specified hierarchy for (int i = 0; i < kehaNodes.getLength(); i++) { if (kehaNodes.item(i).getParentNode().getParentNode().equals(body)) { kehaNode = kehaNodes.item(i); break; } } } } catch (SOAPException e) { throw new RuntimeException(e); } checkForNonTechnicalFault(kehaNode); try { XmlOptions options = new XmlOptions(); SchemaTypeLoader loader = XmlBeans.getContextTypeLoader(); QName responseElement = new QName(metadata.getResponseElementNs(), metadata.getResponseElementName()); SchemaType type = loader.findType(responseElement); XmlObject responseObj; if (StringUtils.isBlank(responseElement.getNamespaceURI()) && !StringUtils.equalsIgnoreCase(kehaNode.getNamespaceURI(), responseElement.getNamespaceURI())) { DOMSource src = new DOMSource(kehaNode); StringResult result = new StringResult(); TransformerFactory.newInstance().newTransformer().transform(src, result); DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance(); fac.setNamespaceAware(false); ByteArrayInputStream stream = new ByteArrayInputStream(result.toString().getBytes("UTF-8")); kehaNode = SOAPUtil.getFirstNonTextChild(fac.newDocumentBuilder().parse(stream)); } if (type != null) { options.setDocumentType(type); options.setLoadReplaceDocumentElement(new QName("xml-fragment")); responseObj = XmlObject.Factory.parse(XmlObject.Factory.parse(kehaNode, options).toString(), new XmlOptions().setDocumentType(type)); } else { options.setLoadReplaceDocumentElement(responseElement); responseObj = XmlBeansUtil.getResponseObject(XmlObject.Factory.parse(kehaNode, options)); } Map<String, XRoadAttachment> attachments = new HashMap<String, XRoadAttachment>(); List<XRoadAttachment> undefined = new ArrayList<XRoadAttachment>(); for (Iterator<?> i = SOAPUtil.extractSoapMessage(response).getAttachments(); i.hasNext();) { AttachmentPart part = (AttachmentPart) i.next(); String cid = part.getContentId(); if (cid == null) { undefined.add(new XRoadAttachment(cid, part.getDataHandler())); } else { cid = cid.startsWith("<") && cid.endsWith(">") ? cid.substring(1, cid.length() - 1) : cid; attachments.put(cid, new XRoadAttachment(part.getContentId(), part.getDataHandler())); } } if (!attachments.isEmpty()) { for (XmlObject obj : XmlBeansUtil.getAllObjects(responseObj)) { for (Method method : XmlBeansUtil.getSwaRefSetters(obj)) { String field = XmlBeansUtil.getFieldName(method); String cid = XmlBeansUtil.getCid(obj, field); cid = cid.startsWith("cid:") ? cid.substring(4) : cid; XRoadAttachment attachment = attachments.get(cid); if (attachment != null) { attachments.remove(cid); method.invoke(obj, attachment.getDataHandler()); } } } } undefined.addAll(attachments.values()); return new XmlBeansXRoadMessage<XmlObject>(responseObj, undefined); } catch (Exception e) { throw new RuntimeException(e); } } private void checkForNonTechnicalFault(Node kehaNode) throws NonTechnicalFaultException { String nonTechnicalFaultCode = null; String nonTechnicalFaultString = null; NodeList nodes = kehaNode.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("faultCode".equalsIgnoreCase(node.getLocalName())) { nonTechnicalFaultCode = node.getTextContent(); } else if ("faultString".equalsIgnoreCase(node.getLocalName())) { nonTechnicalFaultString = node.getTextContent(); } } if (nonTechnicalFaultCode != null || nonTechnicalFaultString != null) { throw new NonTechnicalFaultException(nonTechnicalFaultCode, nonTechnicalFaultString); } } }