/** * 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.camel.component.cxf.feature; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import org.apache.camel.component.cxf.interceptors.ConfigureDocLitWrapperInterceptor; import org.apache.camel.component.cxf.interceptors.SetSoapVersionInterceptor; import org.apache.cxf.Bus; import org.apache.cxf.binding.Binding; import org.apache.cxf.binding.soap.SoapBinding; import org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxws.interceptors.HolderInInterceptor; import org.apache.cxf.jaxws.interceptors.HolderOutInterceptor; import org.apache.cxf.service.model.BindingMessageInfo; import org.apache.cxf.service.model.BindingOperationInfo; import org.apache.cxf.service.model.MessageInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This feature just setting up the CXF endpoint interceptor for handling the * Message in PAYLOAD data format */ public class PayLoadDataFormatFeature extends AbstractDataFormatFeature { private static final Logger LOG = LoggerFactory.getLogger(PayLoadDataFormatFeature.class); private static final boolean DEFAULT_ALLOW_STREAMING; static { String s = System.getProperty("org.apache.camel.component.cxf.streaming"); DEFAULT_ALLOW_STREAMING = s == null || Boolean.parseBoolean(s); } boolean allowStreaming = DEFAULT_ALLOW_STREAMING; public PayLoadDataFormatFeature() { } public PayLoadDataFormatFeature(Boolean streaming) { if (streaming != null) { allowStreaming = streaming; } } @Override public void initialize(Client client, Bus bus) { client.getEndpoint().put("org.apache.cxf.binding.soap.addNamespaceContext", "true"); removeFaultInInterceptorFromClient(client); // Need to remove some interceptors that are incompatible // We don't support JAX-WS Holders for PAYLOAD (not needed anyway) // and thus we need to remove those interceptors to prevent Holder // object from being created and stuck into the contents list // instead of Source objects removeInterceptor(client.getEndpoint().getInInterceptors(), HolderInInterceptor.class); removeInterceptor(client.getEndpoint().getOutInterceptors(), HolderOutInterceptor.class); // The SoapHeaderInterceptor maps various headers onto method parameters. // At this point, we expect all the headers to remain as headers, not // part of the body, so we remove that one. removeInterceptor(client.getEndpoint().getBinding().getInInterceptors(), SoapHeaderInterceptor.class); client.getEndpoint().getBinding().getInInterceptors().add(new ConfigureDocLitWrapperInterceptor(true)); resetPartTypes(client.getEndpoint().getBinding()); LOG.info("Initialized CXF Client: {} in Payload mode with allow streaming: {}", client, allowStreaming); } @Override public void initialize(Server server, Bus bus) { server.getEndpoint().put("org.apache.cxf.binding.soap.addNamespaceContext", "true"); server.getEndpoint().getBinding().getInInterceptors().add(new ConfigureDocLitWrapperInterceptor(true)); if (server.getEndpoint().getBinding() instanceof SoapBinding) { server.getEndpoint().getBinding().getOutInterceptors().add(new SetSoapVersionInterceptor()); } // Need to remove some interceptors that are incompatible // See above. removeInterceptor(server.getEndpoint().getInInterceptors(), HolderInInterceptor.class); removeInterceptor(server.getEndpoint().getOutInterceptors(), HolderOutInterceptor.class); removeInterceptor(server.getEndpoint().getBinding().getInInterceptors(), SoapHeaderInterceptor.class); resetPartTypes(server.getEndpoint().getBinding()); LOG.info("Initialized CXF Server: {} in Payload mode with allow streaming: {}", server, allowStreaming); } @Override protected Logger getLogger() { return LOG; } private void resetPartTypes(Binding bop2) { // The HypbridSourceDatabinding, based on JAXB, will possibly set // JAXB types into the parts. Since we need the Source objects, // we'll reset the types to either Source (for streaming), or null // (for non-streaming, defaults to DOMSource. for (BindingOperationInfo bop : bop2.getBindingInfo().getOperations()) { resetPartTypes(bop); } } private void resetPartTypes(BindingOperationInfo bop) { if (bop.isUnwrapped()) { bop = bop.getWrappedOperation(); } if (bop.isUnwrappedCapable()) { resetPartTypeClass(bop.getWrappedOperation().getOperationInfo().getInput()); resetPartTypeClass(bop.getWrappedOperation().getOperationInfo().getOutput()); resetPartTypeClass(bop.getWrappedOperation().getInput()); resetPartTypeClass(bop.getWrappedOperation().getOutput()); } else { resetPartTypeClass(bop.getOperationInfo().getInput()); resetPartTypeClass(bop.getOperationInfo().getOutput()); resetPartTypeClass(bop.getInput()); resetPartTypeClass(bop.getOutput()); } } protected void resetPartTypeClass(BindingMessageInfo bmi) { if (bmi != null) { int size = bmi.getMessageParts().size(); for (int x = 0; x < size; x++) { //last part can be streamed, others need DOM parsing if (x < (size - 1)) { bmi.getMessageParts().get(x).setTypeClass(allowStreaming ? DOMSource.class : null); } else { bmi.getMessageParts().get(x).setTypeClass(allowStreaming ? Source.class : null); } } } } protected void resetPartTypeClass(MessageInfo msgInfo) { if (msgInfo != null) { int size = msgInfo.getMessageParts().size(); for (int x = 0; x < size; x++) { //last part can be streamed, others need DOM parsing if (x < (size - 1)) { msgInfo.getMessageParts().get(x).setTypeClass(allowStreaming ? DOMSource.class : null); } else { msgInfo.getMessageParts().get(x).setTypeClass(allowStreaming ? Source.class : null); } } } } }