/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.binding.soap.saaj; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import javax.xml.namespace.QName; import javax.xml.soap.AttachmentPart; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.Namespace; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.dom.DOMSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.apache.cxf.Bus; import org.apache.cxf.attachment.AttachmentDataSource; import org.apache.cxf.binding.soap.Soap11; import org.apache.cxf.binding.soap.Soap12; import org.apache.cxf.binding.soap.SoapFault; import org.apache.cxf.binding.soap.SoapHeader; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor; import org.apache.cxf.common.i18n.BundleUtils; import org.apache.cxf.common.injection.NoJSR250Annotations; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.databinding.DataBinding; import org.apache.cxf.headers.Header; import org.apache.cxf.headers.HeaderManager; import org.apache.cxf.headers.HeaderProcessor; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Attachment; import org.apache.cxf.message.Message; import org.apache.cxf.phase.Phase; import org.apache.cxf.phase.PhaseInterceptor; import org.apache.cxf.staxutils.StaxUtils; import org.apache.cxf.staxutils.W3CDOMStreamWriter; /** * Builds a SAAJ tree from the Document fragment inside the message which contains * the SOAP headers and from the XMLStreamReader. */ @NoJSR250Annotations public class SAAJInInterceptor extends AbstractSoapInterceptor { public static final SAAJInInterceptor INSTANCE = new SAAJInInterceptor(); private static final ResourceBundle BUNDLE = BundleUtils.getBundle(SAAJInInterceptor.class); private static final String BODY_FILLED_IN = SAAJInInterceptor.class.getName() + ".BODY_DONE"; private SAAJPreInInterceptor preInterceptor = SAAJPreInInterceptor.INSTANCE; private List<PhaseInterceptor<? extends Message>> extras = new ArrayList<PhaseInterceptor<? extends Message>>(1); public SAAJInInterceptor() { super(Phase.PRE_PROTOCOL); extras.add(preInterceptor); } public SAAJInInterceptor(String phase) { super(phase); } public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() { return extras; } /** * This class sets up the Document in the Message so that the ReadHeadersInterceptor * can read directly into the SAAJ document instead of creating a new DOM * that we would need to copy into the SAAJ later. */ public static class SAAJPreInInterceptor extends AbstractSoapInterceptor { public static final SAAJPreInInterceptor INSTANCE = new SAAJPreInInterceptor(); private MessageFactory factory11; private MessageFactory factory12; public SAAJPreInInterceptor() { super(Phase.READ); addBefore(ReadHeadersInterceptor.class.getName()); } public void handleMessage(SoapMessage message) throws Fault { if (isGET(message)) { return; } if (isRequestor(message) && message.getExchange().getInMessage() == null) { //already processed return; } try { XMLStreamReader xmlReader = message.getContent(XMLStreamReader.class); if (xmlReader == null) { return; } if (xmlReader.nextTag() == XMLStreamConstants.START_ELEMENT) { ReadHeadersInterceptor.readVersion(xmlReader, message); } MessageFactory factory = getFactory(message); SOAPMessage soapMessage = factory.createMessage(); message.setContent(SOAPMessage.class, soapMessage); SOAPPart part = soapMessage.getSOAPPart(); message.setContent(Node.class, part); message.put(W3CDOMStreamWriter.class, new SAAJStreamWriter(part)); message.put(BODY_FILLED_IN, Boolean.FALSE); } catch (RuntimeException ex) { throw ex; } catch (Exception e) { throw new SoapFault("XML_STREAM_EXC", BUNDLE, e, message.getVersion().getSender()); } } public synchronized MessageFactory getFactory(SoapMessage message) throws SOAPException { if (message.getVersion() instanceof Soap11) { if (factory11 == null) { factory11 = SAAJFactoryResolver.createMessageFactory(message.getVersion()); } return factory11; } if (message.getVersion() instanceof Soap12) { if (factory12 == null) { factory12 = SAAJFactoryResolver.createMessageFactory(message.getVersion()); } return factory12; } return SAAJFactoryResolver.createMessageFactory(null); } } @SuppressWarnings("unchecked") public void handleMessage(SoapMessage message) throws Fault { if (isGET(message)) { return; } Boolean bodySet = (Boolean)message.get(BODY_FILLED_IN); if (Boolean.TRUE.equals(bodySet)) { return; } message.put(BODY_FILLED_IN, Boolean.TRUE); try { SOAPMessage soapMessage = message.getContent(SOAPMessage.class); if (soapMessage == null) { MessageFactory factory = preInterceptor.getFactory(message); soapMessage = factory.createMessage(); message.setContent(SOAPMessage.class, soapMessage); } XMLStreamReader xmlReader = message.getContent(XMLStreamReader.class); if (xmlReader == null) { return; } final SOAPPart part = soapMessage.getSOAPPart(); Document node = (Document) message.getContent(Node.class); if (node != part && node != null) { StaxUtils.copy(node, new SAAJStreamWriter(part)); } else { SOAPEnvelope env = soapMessage.getSOAPPart().getEnvelope(); if (node == null) { adjustPrefixes(env, (String)message.get(ReadHeadersInterceptor.ENVELOPE_PREFIX), (String)message.get(ReadHeadersInterceptor.BODY_PREFIX)); } List<XMLEvent> events = (List<XMLEvent>)message.get(ReadHeadersInterceptor.ENVELOPE_EVENTS); applyEvents(events, env); SOAPBody body = soapMessage.getSOAPBody(); events = (List<XMLEvent>)message.get(ReadHeadersInterceptor.BODY_EVENTS); applyEvents(events, body); } message.setContent(Node.class, soapMessage.getSOAPPart()); Collection<Attachment> atts = message.getAttachments(); if (atts != null) { for (Attachment a : atts) { if (a.getDataHandler().getDataSource() instanceof AttachmentDataSource) { try { ((AttachmentDataSource)a.getDataHandler().getDataSource()).cache(message); } catch (IOException e) { throw new Fault(e); } } AttachmentPart ap = soapMessage.createAttachmentPart(a.getDataHandler()); Iterator<String> i = a.getHeaderNames(); while (i != null && i.hasNext()) { String h = i.next(); String val = a.getHeader(h); ap.addMimeHeader(h, val); } if (StringUtils.isEmpty(ap.getContentId())) { ap.setContentId(a.getId()); } soapMessage.addAttachmentPart(ap); } } //replace header element if necessary if (message.hasHeaders()) { replaceHeaders(soapMessage, message); } if (soapMessage.getSOAPPart().getEnvelope().getHeader() == null) { soapMessage.getSOAPPart().getEnvelope().addHeader(); } //If we have an xmlReader that already is counting the attributes and such //then we don't want to rely on the system level defaults in StaxUtils.copy //CXF-6173 boolean secureReader = StaxUtils.isSecureReader(xmlReader, message); StaxUtils.copy(xmlReader, new SAAJStreamWriter(soapMessage.getSOAPPart(), soapMessage.getSOAPPart().getEnvelope().getBody()), true, !secureReader); DOMSource bodySource = new DOMSource(soapMessage.getSOAPPart().getEnvelope().getBody()); xmlReader = StaxUtils.createXMLStreamReader(bodySource); xmlReader.nextTag(); xmlReader.nextTag(); // move past body tag message.setContent(XMLStreamReader.class, xmlReader); } catch (SOAPException soape) { throw new SoapFault(new org.apache.cxf.common.i18n.Message( "SOAPHANDLERINTERCEPTOR_EXCEPTION", BUNDLE), soape, message.getVersion().getSender()); } catch (XMLStreamException e) { throw new SoapFault(new org.apache.cxf.common.i18n.Message( "SOAPHANDLERINTERCEPTOR_EXCEPTION", BUNDLE), e, message .getVersion().getSender()); } } private static void adjustPrefixes(SOAPEnvelope env, String envPrefix, String bodyPrefix) throws SOAPException { SAAJUtils.adjustPrefix(env, envPrefix); SAAJUtils.adjustPrefix(env.getBody(), bodyPrefix); SAAJUtils.adjustPrefix(env.getHeader(), envPrefix); } private static void applyEvents(List<XMLEvent> events, SOAPElement el) throws SOAPException { if (events != null) { for (XMLEvent ev : events) { if (ev.isNamespace()) { el.addNamespaceDeclaration(((Namespace)ev).getPrefix(), ((Namespace)ev).getNamespaceURI()); } else if (ev.isAttribute()) { el.addAttribute(((Attribute)ev).getName(), ((Attribute)ev).getValue()); } } } } public static void replaceHeaders(SOAPMessage soapMessage, SoapMessage message) throws SOAPException { SOAPHeader header = SAAJUtils.getHeader(soapMessage); if (header == null) { return; } Element elem = DOMUtils.getFirstElement(header); elem = (Element)DOMUtils.getDomElement(elem); while (elem != null) { Bus b = message.getExchange() == null ? null : message.getExchange().getBus(); HeaderProcessor p = null; if (b != null && b.getExtension(HeaderManager.class) != null) { p = b.getExtension(HeaderManager.class).getHeaderProcessor(elem.getNamespaceURI()); } Object obj; DataBinding dataBinding = null; if (p == null || p.getDataBinding() == null) { obj = elem; } else { dataBinding = p.getDataBinding(); obj = p.getDataBinding().createReader(Node.class).read(elem); } //TODO - add the interceptors SoapHeader shead = new SoapHeader(new QName(elem.getNamespaceURI(), elem.getLocalName()), obj, dataBinding); shead.setDirection(SoapHeader.Direction.DIRECTION_IN); String mu = elem.getAttributeNS(message.getVersion().getNamespace(), message.getVersion().getAttrNameMustUnderstand()); String act = elem.getAttributeNS(message.getVersion().getNamespace(), message.getVersion().getAttrNameRole()); shead.setActor(act); shead.setMustUnderstand(Boolean.valueOf(mu) || "1".equals(mu)); Header oldHdr = message.getHeader( new QName(elem.getNamespaceURI(), elem.getLocalName())); if (oldHdr != null) { message.getHeaders().remove(oldHdr); } message.getHeaders().add(shead); elem = DOMUtils.getNextElement(elem); } } }