public class WSClient {

    private WSInvokerPM configuration;
    private Logger logger;
    private String wsdlNamespace;
    private MessageContext outMsgCtx;
    private ServiceClient serviceClient;

    public WSClient(WSInvokerPM configuration, Logger logger) throws ServiceExecutionException {
        this.configuration = configuration;
        this.logger = logger;
        this.wsdlNamespace = ClarkName.getNamespace(configuration.getService());
        initialize();
    }

    private void initialize() throws ServiceExecutionException {
        try {
            URL url = new URL(configuration.getUrlToUse());
            QName serviceName = ClarkName.toQName(configuration.getService());
            String portName = configuration.getPortName();
            serviceClient = new ServiceClient(null, url, serviceName, portName);
            logger.log(Level.FINE, "Created service client");
            outMsgCtx = new MessageContext();
            Options opts = outMsgCtx.getOptions();
            String soapBodyNS = configuration.getSoapBodyNS();
            if (soapBodyNS != null) {
                if (com.fiorano.services.webserviceconsumer.wsdl.WSDLConstants.isSOAP12(soapBodyNS)) {
                    opts.setSoapVersionURI(com.ibm.wsdl.extensions.soap12.SOAP12Constants.NS_URI_SOAP12);
                }
            }
            if (configuration.isAuthenticationRequired()) {
                HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
                authenticator.setUsername(configuration.getUserName());
                authenticator.setPassword(configuration.getPassword());
                authenticator.setPreemptiveAuthentication(true);
                opts.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
            }
            opts.setTo(new EndpointReference(configuration.getEndpointAddress()));
            opts.setAction(configuration.getAction());
            opts.setTimeOutInMilliSeconds(configuration.getTimeout());
            opts.setUseSeparateListener(true);
        } catch (MalformedURLException e) {
            throw new ServiceExecutionException("Failed to initialize web service client", e, ServiceErrorID.SERVICE_LAUNCH_ERROR);
        } catch (AxisFault axisFault) {
            throw new ServiceExecutionException("Failed to initialize web service client", axisFault, ServiceErrorID.SERVICE_LAUNCH_ERROR);
        }
    }

    public String invoke(String payload) throws ServiceExecutionException {
        try {
            OperationClient operationClient = serviceClient.createClient(new QName(wsdlNamespace, configuration.getOperationName()));
            logger.log(Level.FINE, "Created operation client");
            operationClient.addMessageContext(outMsgCtx);
            OMElement payLoadOME = AXIOMUtil.stringToOM(payload);
            SOAPEnvelope envelope = getSoapEnvelope(payLoadOME);
            logger.log(Level.FINE, "Parsed request");

            outMsgCtx.setEnvelope(envelope);
            logger.log(Level.INFO, "Invoking webservice.\n\tEnd point Address: " + configuration.getEndpointAddress()
                    + "\n\tService: " + configuration.getService() + "\n\tOperation: " + configuration.getOperationName());
            operationClient.execute(true);
            logger.log(Level.INFO, "Invoked webservice successfully");
            MessageContext inMsgtCtx = operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
            SOAPEnvelope response = inMsgtCtx.getEnvelope();
            operationClient.reset();
            return getResponseString(response);
        } catch (XMLStreamException e) {
            throw new ServiceExecutionException("Failed to invoke web service", e, ServiceErrorID.REQUEST_EXECUTION_ERROR);
        } catch (AxisFault e) {
            throw new ServiceExecutionException("Failed to invoke web service", e, ServiceErrorID.REQUEST_EXECUTION_ERROR);
        }
    }
