All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jibx.ws.soap.client.SoapClient Maven / Gradle / Ivy

/*
 * Copyright (c) 2007-2009, Sosnoski Software Associates Limited. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 * disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of
 * JiBX nor the names of its contributors may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.jibx.ws.soap.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jibx.runtime.IBindingFactory;
import org.jibx.ws.WsBindingException;
import org.jibx.ws.WsConfigurationException;
import org.jibx.ws.WsException;
import org.jibx.ws.client.Client;
import org.jibx.ws.context.ExchangeContext;
import org.jibx.ws.context.InContext;
import org.jibx.ws.context.OutContext;
import org.jibx.ws.io.MessageOptions;
import org.jibx.ws.io.handler.InHandler;
import org.jibx.ws.io.handler.MarshallingOutHandler;
import org.jibx.ws.io.handler.OutHandler;
import org.jibx.ws.io.handler.UnmarshallingInHandler;
import org.jibx.ws.process.Processor;
import org.jibx.ws.soap.SoapFault;
import org.jibx.ws.soap.SoapFaultException;
import org.jibx.ws.soap.SoapPhase;
import org.jibx.ws.soap.SoapProcessor;
import org.jibx.ws.soap.SoapProtocol;
import org.jibx.ws.transport.DuplexConnection;
import org.jibx.ws.transport.MessageProperties;

/**
 * A client for accessing SOAP web services.
 * 

* Typically, this class will be configured to use JiBX bindings for marshalling the request payload and unmarshalling * the response payload for example using: *

*

* *
 * SoapClient soapClient = new SoapClient("http://mystockws.com", BindingDirectory.getFactory(Ticker.class));
 * response = soapClient.call(request);
 * 
* *
*

* To configure a client with different bindings for Request and Response classes: *

*

* *
 * SoapClient soapClient = new SoapClient(path);
 * soapClient.setOutBodyBindingFactory(BindingDirectory.getFactory(Request.class));
 * soapClient.setInBodyBindingFactory(BindingDirectory.getFactory(Response.class));
 * response = soapClient.call(request);
 * 
* *
*

* If a SOAP Fault occurs, the call method will throw a {@link SoapFaultException}. Any detail elements * of the SOAP fault are skipped unless handlers are configured to read the SOAP fault detail elements, see * {@link #addInFaultDetailsHandler(InHandler)} or {@link #addInFaultDetailsBindingFactory(IBindingFactory)}. *

* By default an encoding of UTF-8 is used, the outbound XML is unformatted and contains an XML declaration of * <?xml version="1.0" encoding="UTF-8"?>. The encoding, XML declaration and formatting of the * outbound message can be overridden by calling {@link #setMessageOptions(MessageOptions)}. * * @author Nigel Charman */ public final class SoapClient extends Client { /** The version of the SOAP protocol. */ private SoapProtocol m_protocol = SoapProtocol.SOAP1_1; /** The processor that implements the SOAP protocol. */ private SoapProcessor m_processor; /** A list of {@link OutHandler}s for writing the SOAP header contents. The handlers will be called sequentially. */ private List m_outHeaderHandlers; /** A list of {@link InHandler}s for reading the SOAP header contents. The handlers will be called sequentially. */ private List m_inHeaderHandlers; /** A list of {@link InHandler}s for reading the SOAP fault contents. The handlers will be called sequentially. */ private List m_inFaultDetailsHandlers; /** The operation name. For SOAP over HTTP the SOAP Action will be set to this value. */ private String m_operationName; /** The optional SOAP encoding style to set in the SOAP message. */ private String m_encodingStyle; /** An optional SOAP fault resolver. */ private SoapFaultResolver m_soapFaultResolver; private InContext m_inCtx; private OutContext m_outCtx; /** * Create a SOAP 1.1 client to connect to a service at the specified location. * * @param location the location of the service * @throws WsConfigurationException on configuration exception, for instance the location is invalid. */ public SoapClient(String location) throws WsConfigurationException { super(location); } /** * Create a SOAP 1.1 client to connect to a service at the specified location. The client will use the * specified JiBX binding factory for marshalling and unmarshalling the SOAP body and unmarshalling any SOAP fault * details. * * @param location the location of the service * @param factory the factory containing bindings for the outbound SOAP body, inbound SOAP body and inbound SOAP * fault details. Bindings are only required for non-empty outbound or inbound SOAP bodies. If SOAP fault details * are received that do not match any of the bindings, the SOAP fault details will be skipped. * @throws WsBindingException if client cannot be created due to an error with the JiBX bindings * @throws WsConfigurationException on configuration exception, for instance the location is invalid. */ public SoapClient(String location, IBindingFactory factory) throws WsBindingException, WsConfigurationException { super(location); setBindingFactory(factory); } /** * Create a SOAP 1.1 client to connect to a service at the specified location. The client will use the * specified JiBX binding factory for marshalling and unmarshalling the SOAP body and unmarshalling any SOAP fault * details. * * @param location the location of the service * @param factory the factory containing bindings for the outbound SOAP body, inbound SOAP body and inbound SOAP * fault details. Bindings are only required for non-empty outbound or inbound SOAP bodies. If SOAP fault details * are received that do not match any of the bindings, the SOAP fault details will be skipped. * @param options output options * @throws WsBindingException if client cannot be created due to an error with the JiBX bindings * @throws WsConfigurationException on configuration exception, for instance the location is invalid. */ public SoapClient(String location, IBindingFactory factory, MessageOptions options) throws WsBindingException, WsConfigurationException { this(location, factory); setMessageOptions(options); } /** * Create a SOAP client to connect to a service at the specified location. The client will use the specified JiBX * binding factory for marshalling and unmarshalling the SOAP body and unmarshalling any SOAP fault details. * @param location the location of the service * @param factory the factory containing bindings for the outbound SOAP body, inbound SOAP body and inbound SOAP * fault details. Bindings are only required for non-empty outbound or inbound SOAP bodies. If SOAP fault details * are received that do not match any of the bindings, the SOAP fault details will be skipped. * @param options output options * @param protocol the version of the SOAP protocol for the client to use * * @throws WsBindingException if client cannot be created due to an error with the JiBX bindings * @throws WsConfigurationException on configuration exception, for instance the location is invalid. */ public SoapClient(String location, IBindingFactory factory, MessageOptions options, SoapProtocol protocol) throws WsBindingException, WsConfigurationException { this(location, factory, options); setProtocol(protocol); } /** * Set SOAP protocol version. See {@link SoapProtocol} for supported protocols. * * @param protocol the version of SOAP protocol */ public void setProtocol(SoapProtocol protocol) { m_protocol = protocol; setModified(true); } /** * Sets a single JiBX binding factory to be used for for marshalling and unmarshalling the SOAP body and * unmarshalling any SOAP fault details. This binding factory should include bindings for any elements that are to * be contained in the outbound or inbound SOAP body (if any) and in custom SOAP fault details (if any). *

* For finer grain control of the different elements use {@link #setOutBodyBindingFactory(IBindingFactory)}, * {@link #setInBodyBindingFactory(IBindingFactory)} and {@link #addInFaultDetailsBindingFactory(IBindingFactory)}. * * @param factory the binding factory to use for outbound and/or inbound SOAP bodies, and/or SOAP fault details * @throws WsBindingException if marshaller cannot be created due to an error with the JiBX bindings */ public void setBindingFactory(IBindingFactory factory) throws WsBindingException { setOutBodyBindingFactory(factory); setInBodyBindingFactory(factory); addInFaultDetailsBindingFactory(factory); setModified(true); } /** * Sets the name of the operation to be called. For SOAP over HTTP the SOAP Action will be set to this value. This * is not normally required for document/literal services since the element type of the marshalled request object is * expected to identify the actual operation to be performed. The operation name should only be set if you have a * specific need to set the SOAPAction header. * * @param operationName the operation name */ public void setOperationName(String operationName) { m_operationName = operationName; } /** * Sets the optional SOAP encodingStyle * attribute on the SOAP envelope. If this method is not called, or the encodingStyle parameter is set to * null, then no encodingStyle attribute is added. * * @param encodingStyle value to set in encodingStyle attribute */ public void setSoapEncodingStyle(String encodingStyle) { m_encodingStyle = encodingStyle; } /** * Sets the outbound header handlers. Replaces existing header handlers, if any. * * @param outHeaderHandlers the list of {@link OutHandler} * @throws WsConfigurationException if the list contains objects of type other than {@link OutHandler}s. */ public void setOutHeaderHandlers(List outHeaderHandlers) throws WsConfigurationException { for (Iterator iter = outHeaderHandlers.iterator(); iter.hasNext();) { if (!(iter.next() instanceof OutHandler)) { throw new WsConfigurationException( "The list passed to setOutHeaderHandlers must only contain objects of type OutHandler"); } } m_outHeaderHandlers = outHeaderHandlers; setModified(true); } /** * Adds the specified header handler to the outbound processing. Header handlers are called sequentially in the * order that they have been added. * * @param headerHandler the handler that will write the header */ public void addOutHeaderHandler(OutHandler headerHandler) { if (m_outHeaderHandlers == null) { m_outHeaderHandlers = new ArrayList(); } m_outHeaderHandlers.add(headerHandler); setModified(true); } /** * Adds the specified object as a header to the outbound message. For this to work, there must be exactly one JiBX * binding compiled for the class of the object. An appropriate handler is created that will marshal the * specified object. * * @param obj the object to include in the header * @throws WsException if binding cannot be found, or other error */ public void addOutHeader(Object obj) throws WsException { addOutHeaderHandler(new MarshallingOutHandler(obj)); } /** * Removes all outbound header handlers. */ public void removeOutHeaderHandlers() { m_outHeaderHandlers = null; setModified(true); } /** * Sets the inbound header handlers. Replaces existing header handlers, if any. * * @param inHeaderHandlers the list of {@link InHandler} * @throws WsConfigurationException if the list contains objects of type other than {@link InHandler}s. */ public void setInHeaderHandlers(List inHeaderHandlers) throws WsConfigurationException { for (Iterator iter = inHeaderHandlers.iterator(); iter.hasNext();) { if (!(iter.next() instanceof InHandler)) { throw new WsConfigurationException( "The list passed to setInHeaderHandlers must only contain objects of type InHandler"); } } m_inHeaderHandlers = inHeaderHandlers; setModified(true); } /** * Adds the specified header handler to the inbound processing. For each SOAP header, the header handlers are * invoked sequentially in the order that they have been added, until a handler returns true from the * {@link InHandler#invoke(InContext, org.jibx.runtime.IXMLReader)} method, when the processing of that header is * deemed to be complete, and processing carries on with the next header. * * @param headerHandler the handler that will write the header */ public void addInHeaderHandler(InHandler headerHandler) { if (m_inHeaderHandlers == null) { m_inHeaderHandlers = new ArrayList(); } m_inHeaderHandlers.add(headerHandler); setModified(true); } /** * Removes all inbound header handlers. */ public void removeInHeaderHandlers() { m_inHeaderHandlers = null; setModified(true); } /** * Adds a JiBX binding factory for the inbound SOAP fault details. Only required if SOAP fault details are to be * read. Handlers will be called sequentially. The first handler that can read a particular fault detail will set * the details on the {@link SoapFault} and all other handlers will be skipped. * * * @param factory the JiBX binding factory to use for reading the inbound SOAP body * @throws WsBindingException if unmarshaller cannot be created due to an error with the JiBX bindings */ public void addInFaultDetailsBindingFactory(IBindingFactory factory) throws WsBindingException { addInFaultDetailsHandler(new UnmarshallingInHandler(factory)); } /** * Adds a handler to use for reading the SOAP fault details. Only required if SOAP fault details are to be read. * Handlers will be called sequentially. The first handler that can read a particular fault detail will set the * details on the {@link SoapFault} and all other handlers will be skipped. * * @param inFaultDetailsHandler the handler to use for reading the SOAP fault details */ public void addInFaultDetailsHandler(InHandler inFaultDetailsHandler) { if (m_inFaultDetailsHandlers == null) { m_inFaultDetailsHandlers = new ArrayList(); } m_inFaultDetailsHandlers.add(inFaultDetailsHandler); setModified(true); } /** * Removes all inbound fault details handlers. */ public void removeInFaultDetailsHandlers() { m_inFaultDetailsHandlers = null; setModified(true); } /** * Removes all header handlers and inbound fault details handlers. */ public void removeAllHandlers() { removeOutHeaderHandlers(); removeInHeaderHandlers(); removeInFaultDetailsHandlers(); } /** * Sets the SOAP fault resolver. If set to a non null value, this resolver will be called in place of the default * default soap fault handling, when a SOAP fault occurs. * * @param soapFaultResolver the resolver */ public void setSoapFaultResolver(SoapFaultResolver soapFaultResolver) { this.m_soapFaultResolver = soapFaultResolver; } /** * Call the service with specified operation name. * * @param request object to be marshalled to XML as body of request (may be null, for an empty * request body) * * @return response object unmarshalled from body of response (may be null, for an empty response * body) * * @throws IOException on error in communicating with service * @throws WsException on error in SOAP request processing, or a WsConfigurationException if either: *

    *
  • the service location has not been set before invoking this method, or
  • *
  • request is non null and a binding factory or handler has not been set for the outbound SOAP * body, or
  • *
  • the SOAP response contains a non-empty SOAP body and a binding factory or handler has not been set for the * inbound SOAP body.
  • *
* @throws SoapFaultException if the service returns a SOAP fault, and a custom {@link SoapFaultResolver} has not * been set. */ public Object call(Object request) throws IOException, WsException { if (getBodyWriter() == null && request != null) { throw new WsConfigurationException( "Binding factory or handler must be defined for the outbound SOAP body"); } Processor processor = getProcessor(); m_outCtx.setBody(request); MessageProperties msgProps = m_protocol.buildMessageProperties(m_operationName, getMessageOptions()); DuplexConnection duplex = getChannel().getDuplex(msgProps, getMessageOptions().getXmlOptions()); processor.invoke(duplex.getOutbound(), duplex.getInbound()); Object body = m_inCtx.getBody(); if (body instanceof SoapFault) { return handleFault((SoapFault) body); } return m_inCtx.getBody(); } private Object handleFault(SoapFault fault) { if (m_soapFaultResolver != null) { return m_soapFaultResolver.handleFault(fault); } throw new SoapFaultException(fault); } /** * Returns a SOAP processor configured according to the current options set on the client. If no options have * changed since the last call to this method, the current processor will be returned. * * @return SoapProcessor * @throws WsException */ private Processor getProcessor() throws WsException { if (m_processor != null) { m_processor.reset(); } if (m_processor == null || isModified()) { m_outCtx = new OutContext(); if (m_outHeaderHandlers != null) { for (Iterator iter = m_outHeaderHandlers.iterator(); iter.hasNext();) { OutHandler handler = (OutHandler) iter.next(); m_outCtx.addHandler(SoapPhase.HEADER, handler); } } if (getBodyWriter() != null) { m_outCtx.setBodyWriter(getBodyWriter()); } m_inCtx = new InContext(); if (m_inHeaderHandlers != null) { for (Iterator iter = m_inHeaderHandlers.iterator(); iter.hasNext();) { InHandler handler = (InHandler) iter.next(); m_inCtx.addHandler(SoapPhase.HEADER, handler); } } if (getBodyReader() != null) { m_inCtx.setBodyReader(getBodyReader()); } if (m_inFaultDetailsHandlers != null) { for (Iterator iter = m_inFaultDetailsHandlers.iterator(); iter.hasNext();) { InHandler handler = (InHandler) iter.next(); m_inCtx.addHandler(SoapPhase.BODY_FAULT, handler); } } m_processor = (SoapProcessor) m_protocol.createProcessor(ExchangeContext.createOutInExchange(m_outCtx, m_inCtx)); m_processor.setSoapEncodingStyle(m_encodingStyle); setModified(false); } return m_processor; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy