/** * 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.interceptor; import java.io.IOException; import java.util.List; import java.util.logging.Logger; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.apache.cxf.annotations.SchemaValidation.SchemaValidationType; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.SoapVersion; import org.apache.cxf.binding.soap.model.SoapHeaderInfo; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.headers.Header; import org.apache.cxf.helpers.ServiceUtils; import org.apache.cxf.interceptor.AbstractInDatabindingInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.message.Exchange; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageContentsList; import org.apache.cxf.phase.Phase; import org.apache.cxf.service.Service; import org.apache.cxf.service.model.BindingMessageInfo; import org.apache.cxf.service.model.BindingOperationInfo; import org.apache.cxf.service.model.MessagePartInfo; import org.apache.cxf.service.model.ServiceModelUtil; import org.apache.cxf.staxutils.W3CDOMStreamReader; import org.apache.cxf.ws.addressing.EndpointReferenceUtils; import org.apache.cxf.wsdl.interceptors.BareInInterceptor; import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor; /** * Perform databinding of the SOAP headers. */ public class SoapHeaderInterceptor extends AbstractInDatabindingInterceptor { private static final Logger LOG = LogUtils.getL7dLogger(SoapHeaderInterceptor.class); public SoapHeaderInterceptor() { super(Phase.UNMARSHAL); addAfter(BareInInterceptor.class.getName()); addAfter(RPCInInterceptor.class.getName()); addAfter(DocLiteralInInterceptor.class.getName()); } public void handleMessage(Message m) throws Fault { SoapMessage message = (SoapMessage) m; SoapVersion soapVersion = message.getVersion(); Exchange exchange = message.getExchange(); MessageContentsList parameters = MessageContentsList.getContentsList(message); if (null == parameters) { parameters = new MessageContentsList(); } BindingOperationInfo bop = exchange.getBindingOperationInfo(); if (null == bop) { return; } if (bop.isUnwrapped()) { bop = bop.getWrappedOperation(); } boolean client = isRequestor(message); BindingMessageInfo bmi = client ? bop.getOutput() : bop.getInput(); if (bmi == null) { // one way operation. return; } List<SoapHeaderInfo> headers = bmi.getExtensors(SoapHeaderInfo.class); if (headers == null || headers.size() == 0) { return; } boolean supportsNode = this.supportsDataReader(message, Node.class); Service service = ServiceModelUtil.getService(message.getExchange()); for (SoapHeaderInfo header : headers) { MessagePartInfo mpi = header.getPart(); try { if (ServiceUtils.isSchemaValidationEnabled(SchemaValidationType.IN, message)) { Schema schema = EndpointReferenceUtils.getSchema(service.getServiceInfos().get(0), message .getExchange().getBus()); validateHeader(message, mpi, schema); } } catch (Fault f) { if (!isRequestor(message)) { f.setFaultCode(Fault.FAULT_CODE_CLIENT); } throw f; } if (mpi.getTypeClass() != null) { Header param = findHeader(message, mpi); Object object = null; if (param != null) { message.getHeaders().remove(param); if (param.getDataBinding() == null) { Node source = (Node)param.getObject(); if (source instanceof Element) { //need to remove these attributes as they //would cause validation failures Element el = (Element)source; el.removeAttributeNS(soapVersion.getNamespace(), soapVersion.getAttrNameMustUnderstand()); el.removeAttributeNS(soapVersion.getNamespace(), soapVersion.getAttrNameRole()); } if (supportsNode) { object = getNodeDataReader(message).read(mpi, source); } else { W3CDOMStreamReader reader = new W3CDOMStreamReader((Element)source); try { reader.nextTag(); //advance into the first tag } catch (XMLStreamException e) { //ignore } object = getDataReader(message, XMLStreamReader.class).read(mpi, reader); } } else { object = param.getObject(); } } parameters.put(mpi, object); } } if (!parameters.isEmpty()) { message.setContent(List.class, parameters); } } private void validateHeader(final SoapMessage message, MessagePartInfo mpi, Schema schema) { Header param = findHeader(message, mpi); if (param != null && param.getDataBinding() == null) { Node source = (Node)param.getObject(); if (!(source instanceof Element)) { return; } if (schema != null) { final Element el = (Element)source; DOMSource ds = new DOMSource(el); try { Validator v = schema.newValidator(); ErrorHandler errorHandler = new ErrorHandler() { public void warning(SAXParseException exception) throws SAXException { } public void error(SAXParseException exception) throws SAXException { String msg = exception.getMessage(); if (msg.contains(el.getLocalName()) && (msg.contains(":" + message.getVersion().getAttrNameRole()) || msg.contains(":" + message.getVersion().getAttrNameMustUnderstand()))) { return; } throw exception; } public void fatalError(SAXParseException exception) throws SAXException { throw exception; } }; v.setErrorHandler(errorHandler); v.validate(ds); } catch (SAXException e) { throw new Fault("COULD_NOT_VALIDATE_SOAP_HEADER_CAUSED_BY", LOG, e, e.getClass() .getCanonicalName(), e.getMessage()); } catch (IOException e) { throw new Fault("COULD_NOT_VALIDATE_SOAP_HEADER_CAUSED_BY", LOG, e, e.getClass() .getCanonicalName(), e.getMessage()); } } } } private Header findHeader(SoapMessage message, MessagePartInfo mpi) { return message.getHeader(mpi.getConcreteName()); } }