<repo_name>tenato/webservice-client-api<file_sep>/src/main/java/fr/foop/ws/tools/configurators/CxfClientBuilderConfigurator.java
package fr.foop.ws.tools.configurators;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;

import fr.foop.ws.CxfClientBuilder;

public interface CxfClientBuilderConfigurator {

	public final static Logger LOGGER = LoggerFactory.getLogger(CxfClientBuilderConfigurator.class);
	
	public static abstract class BasicBuilderConfigurator implements
			CxfClientBuilderConfigurator {
		@Override
		public CxfClientBuilder configure(CxfClientBuilder configured,
				Optional<String> propValue) {
			LOGGER.debug("autoconfigure : {} -> {}", this.getClass().getName(), propValue.toString());
			
			if (propValue.isPresent()) {
				return ensurePresentConfigured(configured, propValue.get());
			}
			
			return configured;
		}

		protected abstract CxfClientBuilder ensurePresentConfigured(
				final CxfClientBuilder configured, final String propValue);
	}

	public final static CxfClientBuilderConfigurator NOOP_CONFIGURATOR = new CxfClientBuilderConfigurator() {

		@Override
		public CxfClientBuilder configure(CxfClientBuilder configured,
				Optional<String> propValue) {
			return configured;
		}
	};

	public final static CxfClientBuilderConfigurator ENDPOINT_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withEndpoint(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator INLOGGER_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withInLogger(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator OUTLOGGER_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withOutLogger(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator LOGGER_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withLogger(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator WSSE_USER_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withWsseUser(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator WSSE_PWD_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withWssePwd(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator CONNECTION_TIMEOUT_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withConnectionTimeout(Long.valueOf(propValue));
		}
	};

	public final static CxfClientBuilderConfigurator RECEIVE_TIMEOUT_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withReceiveTimeout(Long.valueOf(propValue));
		}
	};


	public final static CxfClientBuilderConfigurator MOCKED_PORT_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withMockedPort(propValue);
		}
	};

	public final static CxfClientBuilderConfigurator USE_MOCK_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			final boolean useMock = Boolean.valueOf(propValue);
			if(useMock) {
				return configured.enableMocking();
			}
			else {
				return configured.disableMocking();
			}
		}
	};
	
	public final static CxfClientBuilderConfigurator SERVERS_CONFIGURATOR = new BasicBuilderConfigurator() {
		@Override
		protected CxfClientBuilder ensurePresentConfigured(
				CxfClientBuilder configured, String propValue) {
			return configured.withServers(Iterables.toArray(Splitter.on(",")
					.trimResults().omitEmptyStrings().split(propValue),
					String.class));
		}
	};

	public CxfClientBuilder configure(final CxfClientBuilder configured,
			final Optional<String> propValue);
}
<file_sep>/README.md
# WebService Client API

An API to easily built webservice client, based on CXF.

## Quick start Guide

The easiest way is to clone the existing example project. Although you can start from scratch by creating a maven simple jar project.

+ Clone the example project :

`git clone https://github.com/cedricbou/webservice-client-example.git <<your project name here>>`

+ (Optional) Remove the .git folder to "ungit" the project :

`cd <<your project name here>>`
`rm -rf .git`

+ Open the pom.xml file :
    1. Modify the groupId, artifactId, version with yours.
    2. Change description and name to something describing the client you are creating.
    3. Update the `<wsdl>` tag in the cxf plugin with the URL to your WSDL.

+ Clean and generate source

`mvn clean generate-sources`

+ The project will contain compilation error, we need to adapt the Client class :
    1. Open the CRMClient class, rename it to whatever you need, and change the package as well to something you like.
    2. Adapt the CxfClient extended class with generic types corresponding to the Port generated by CXF, and the service manager class generated by CXF :
    `public class CRMClient extends CxfClient<_WebServicePort_, _WebServiceManager_>`
    3. In the `newPort` method, calls the manager method to instanciate your port interface, the manager is passed in parameter.
    4. In the `checkIfPortUp` method, implements a health check. If an exception is thrown the service is considered unhealthy.
    
## Configuration DSL 

### Basic features

```java
builder()
	.withWsseCredentials(username, password) // Configure username and password using the WSSE standard, as PasswordText.
	.withConnectionTimeout(1000) // Set the timeout in millis on socket connection
	.withReceiveTimeout(3000) // Set the timeout in millis to wait for data.
	.withEndpoint("http://....") // Define the endpoint to use.
	.withInLogger(logger) // The SLF4J logger to use for payload sent to the server, the level is INFO.
	.withOutLogger(logger) // The SLF4J logger to use for payload received from the server, the level is INFO.
	.withLogger(logger) // Shortcut for withInLogger(logger).withOutLogger(logger)
```

### Endpoint and servers

During service instanciation, the API endpoint failover. For an endpoint,
you can defined several target servers address.

When instanciating the service, for each server, it will attempt to configure a client. It uses the `checkIfPortUp` method to check if the server is available. If everything is fine, it will use this port, otherwise, it would try the next server. If nothing works, it returns `null`.

For this to work, you need to write your endpoint with the special `{{server}}` tag :

```java
builder()
    .withEndpoint("http://{{server}}/mywebservice")
```

Then you'll configure the server list to use :

```java
builder()
    .withEndpoint("http://{{server}}/mywebservice")
    .withServers("localhost:8080", "10.10.10.10:6541");
```

### Loading from properties

```java
Properties props = new Properties();
props.load(...);

builder()
    .withProperties("com.myprops", props)
    .withServers("localhost:8080", "10.10.10.10:6541");
```

## The Client class

To build the client, use the `build` method : 

```java
final CRMClient client = CRMClient.builder()
	.withReceiveTimeout(2000)
	.withLogger("com.myservice.Trames")
	.build(CRMClient.class); // The port is instanciated at this stage.

final CRMServicePT port = client.service(); // Return the port instanciated above.

// Now you can call the web services.
port.getAll();
port.create(new CustomerType(...));
```

You need to pass the Client class. This is used to automatically cast to the right type in the return.



    



<file_sep>/src/main/java/fr/foop/ws/tools/WebServicePortConfigurer.java
package fr.foop.ws.tools;

import java.util.HashMap;
import java.util.Map;

import javax.xml.ws.BindingProvider;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.slf4j.Logger;

public class WebServicePortConfigurer<Port> {

	private final Client client;
	private final HTTPConduit http;
	private final BindingProvider provider;
	private final Endpoint cxfEndpoint;

	public WebServicePortConfigurer(final Port port) {
		this.client = ClientProxy.getClient(port);
		this.http = (HTTPConduit) client.getConduit();
		this.provider = (BindingProvider) port;
		this.cxfEndpoint = client.getEndpoint();
	}

	public void configureEndpoint(final String endpoint, final String server) {
		final String concreteEndpoint = endpoint.replaceFirst(
				"\\{\\{server\\}\\}", server);

		provider.getRequestContext().put(
				BindingProvider.ENDPOINT_ADDRESS_PROPERTY, concreteEndpoint);
	}

	public void configureWsse(final String wsseUser, final String wssePwd) {
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION,
				WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, wsseUser);
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_REF,
				new ClientPasswordCallback(wsseUser, wssePwd));

		WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
		cxfEndpoint.getOutInterceptors().add(wssOut);
	}

	public void configureInLogger(final Logger logger) {
		cxfEndpoint.getInInterceptors().add(new LoggingInInterceptor() {

			@Override
			protected void log(java.util.logging.Logger arg0, String arg1) {
				logger.info(arg1);
			}
		});
	}

	public void configureOutLogger(final Logger logger) {
		cxfEndpoint.getOutInterceptors().add(new LoggingOutInterceptor() {

			@Override
			protected void log(java.util.logging.Logger arg0, String arg1) {
				logger.info(arg1);
			}
		});
	}
	
	public void configureTimeouts(final long connectionTimeout, final long receiveTimeout) {
		final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
		httpClientPolicy.setConnectionTimeout(connectionTimeout);
		httpClientPolicy.setAllowChunking(false);
		httpClientPolicy.setReceiveTimeout(receiveTimeout);
		http.setClient(httpClientPolicy);		
	}

}
<file_sep>/src/main/java/fr/foop/ws/CxfClient.java
package fr.foop.ws;

import java.lang.reflect.InvocationTargetException;
import java.net.URL;

import org.apache.cxf.frontend.ClientProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.foop.ws.tools.WebServicePortConfigurer;

public abstract class CxfClient<Port, ServiceManager> {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(CxfClient.class);

	private final CxfClientBuilder config;
	private final Port port;
	private final Class<ServiceManager> smClazz;
	private final String endpoint;

	protected CxfClient(final CxfClientBuilder config,
			final Class<ServiceManager> smClazz) {
		this.config = config;
		this.smClazz = smClazz;
		this.endpoint = detectEndpoint();
		this.port = enableMockIfRequired();
	}

	@SuppressWarnings("unchecked")
	private Port enableMockIfRequired() {
		if(config.useMock && config.mockedPort.isPresent()) {
			return (Port)config.mockedPort.get();
		}
		else {
			return electPort();
		}
	}
	
	public CxfClientBuilder config() {
		return config;
	}

	public abstract void checkIfPortUp(final Port port) throws Exception;

	public abstract Port newPort(final ServiceManager serviceManager);

	private String detectEndpoint() {
		if (config.endpoint.isPresent()) {
			return config.endpoint.get();
		} else {
			return ClientProxy.getClient(newPort(newDefaultServiceManager()))
					.getEndpoint().getEndpointInfo().getAddress();
		}
	}

	private ServiceManager newNoEndpointServiceManager() {
		try {
			return smClazz.getConstructor(URL.class).newInstance((URL) null);
		} catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException
				| NoSuchMethodException | SecurityException e) {
			throw new RuntimeException(
					"failed to instanciate new service manager", e);
		}
	}

	private ServiceManager newDefaultServiceManager() {
		try {
			return smClazz.newInstance();
		} catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | SecurityException e) {
			throw new RuntimeException(
					"failed to instanciate new service manager", e);
		}
	}


	/**
	 * Instanciate a configured web service port the provided server.
	 * @param server
	 * @return
	 */
	private Port instanciateForServer(final String server) {
		final Port port = newPort(newNoEndpointServiceManager());
		final WebServicePortConfigurer<Port> configurer = new WebServicePortConfigurer<Port>(port);
		
		configurer.configureEndpoint(endpoint, server);
		
		if(config.inLogger.isPresent()) {
			configurer.configureInLogger(config.inLogger.get());
		}

		if(config.outLogger.isPresent()) {
			configurer.configureOutLogger(config.outLogger.get());
		}
		
		if(config.wsseUser.isPresent() && config.wssePwd.isPresent()) {
			configurer.configureWsse(config.wsseUser.get(), config.wssePwd.get());
		}
		
		configurer.configureTimeouts(config.connectionTimeout, config.receiveTimeout);

		return port;
	}

	/**
	 * Try to find a working Web Service Port for the given server list.
	 * @return
	 */
	private Port electPort() {
		if (config.servers.size() == 0) {
			return instanciateForServer("");
		} else {
			int i = 0;
			while (i < config.servers.size()) {
				final Port port = instanciateForServer(config.servers.get(i++));

				try {
					checkIfPortUp(port);
					return port;
				} catch (Exception e) {
					LOGGER.warn(
							"Failed to instanciate Service [{}] : {}",
							config.endpoint + " <-- "
									+ config.servers.get(i - 1), e.getMessage());
					LOGGER.debug("Failed to instanciate Service", e);
				}
			}
		}

		return null;
	}

	public Port service() {
		return port;
	}
	
}
<file_sep>/src/main/java/fr/foop/ws/CxfClientBuilder.java
package fr.foop.ws;

import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import fr.foop.ws.tools.configurators.CxfClientBuilderConfigurator;
import fr.foop.ws.tools.configurators.PropertyMeta;

public class CxfClientBuilder {

	public final Optional<String> endpoint;

	public final Optional<String> wsseUser;

	public final Optional<String> wssePwd;

	public final long connectionTimeout;

	public final long receiveTimeout;

	public final ImmutableList<String> servers;

	public final Optional<Logger> inLogger;

	public final Optional<Logger> outLogger;
	
	public final Optional<Object> mockedPort;
	
	public final boolean useMock;

	private final static String[] propNames = new String[] { "endpoint",
			"wsseUser", "wssePwd", "connectionTimeout", "receiveTimeout",
			"inLogger", "outLogger", "logger", "mockedPort", "useMock", "servers" };
	
	private final static ImmutableMap<String, PropertyMeta> propMetas = ImmutableMap
			.<String, PropertyMeta> builder()
			.put("endpoint",
					new PropertyMeta(
							"The web service endpoint, can contain the variable {{server}}, in this case it would be replaced by one of the server defined in servers.",
							CxfClientBuilderConfigurator.ENDPOINT_CONFIGURATOR))
			.put("wsseUser",
					new PropertyMeta(
							"The user to pass as WSSE user credential", CxfClientBuilderConfigurator.WSSE_USER_CONFIGURATOR))
			.put("wssePwd",
					new PropertyMeta(
							"The password to pass as the WSSE password credential (only PasswordText supported for now)",
							CxfClientBuilderConfigurator.WSSE_PWD_CONFIGURATOR))
			.put("connectionTimeout",
					new PropertyMeta(
							"the time in millis before timeout during connection",
							CxfClientBuilderConfigurator.CONNECTION_TIMEOUT_CONFIGURATOR))
			.put("receiveTimeout",
					new PropertyMeta(
							"The time in millis to wait before timeout while not receiving data",
							CxfClientBuilderConfigurator.RECEIVE_TIMEOUT_CONFIGURATOR))
			.put("inLogger",
					new PropertyMeta(
							"The logger name to use for client request sent to the server (seen from server side)",
							CxfClientBuilderConfigurator.INLOGGER_CONFIGURATOR))
			.put("outLogger",
					new PropertyMeta(
							"The logger name to log server response sent to the client (seen from server side)",
							CxfClientBuilderConfigurator.OUTLOGGER_CONFIGURATOR))
			.put("logger",
					new PropertyMeta(
							"The logger name to use for both in/out logger. It will override in/out logger settings",
							CxfClientBuilderConfigurator.LOGGER_CONFIGURATOR))
			.put("mockedPort",
					new PropertyMeta(
							"The mocked object to use as port, it must implements the CXF generated port interface",
							CxfClientBuilderConfigurator.MOCKED_PORT_CONFIGURATOR))
			.put("useMock",
					new PropertyMeta(
							"A flag to enable or disable the use of the mocked port object",
							CxfClientBuilderConfigurator.USE_MOCK_CONFIGURATOR))
			.put("servers",
					new PropertyMeta(
							"Comma separated list of server to use in the endpoint, they will be tried turn by turn at service initialisation",
							CxfClientBuilderConfigurator.SERVERS_CONFIGURATOR))
			.build();

	public CxfClientBuilder() {
		this(Optional.<String> absent(), Optional.<String> absent(), Optional
				.<String> absent(), 1000, 3000, Optional.<Logger> absent(),
				Optional.<Logger> absent(), Optional.<Object> absent(), false, ImmutableList.<String> of());
	}

	public CxfClientBuilder(final String endPoint, final String... servers) {
		this(Optional.of(endPoint), Optional.<String> absent(), Optional
				.<String> absent(), 1000, 3000, Optional.<Logger> absent(),
				Optional.<Logger> absent(),  Optional.<Object> absent(), false, ImmutableList.copyOf(servers));
	}

	public CxfClientBuilder(final Optional<String> endpoint,
			final Optional<String> username, final Optional<String> password,
			final long connectionTimeout, final long receiveTimeout,
			final Optional<Logger> inLogger, final Optional<Logger> outLogger,
			final Optional<Object> mockedPort,
			final boolean useMock,
			final ImmutableList<String> servers) {
		this.endpoint = endpoint;
		this.wsseUser = username;
		this.wssePwd = <PASSWORD>;
		this.connectionTimeout = connectionTimeout;
		this.receiveTimeout = receiveTimeout;
		this.outLogger = outLogger;
		this.inLogger = inLogger;
		this.mockedPort = mockedPort;
		this.useMock = useMock;
		this.servers = ImmutableList.<String> copyOf(servers);
	}

	public CxfClientBuilder withEndpoint(final String endpoint) {
		return new CxfClientBuilder(Optional.of(endpoint), wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withReceiveTimeout(final long receiveTimeout) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withConnectionTimeout(final long connectionTimeout) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withWsseUser(final String username) {
		return new CxfClientBuilder(endpoint, Optional.fromNullable(username),
				wssePwd, connectionTimeout, receiveTimeout, inLogger,
				outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withWssePwd(final String password) {
		return new CxfClientBuilder(endpoint, wsseUser,
				Optional.fromNullable(password), connectionTimeout,
				receiveTimeout, inLogger, outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withWsseCredentials(final String username,
			final String password) {
		return this.withWsseUser(username).withWssePwd(password);
	}

	public CxfClientBuilder withInLogger(final Logger logger) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout,
				Optional.fromNullable(logger), outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withInLogger(final String loggerName) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, Optional.of(LoggerFactory
						.getLogger(loggerName)), outLogger, mockedPort, useMock, servers);
	}

	public CxfClientBuilder withOutLogger(final Logger logger) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger,
				Optional.fromNullable(logger), mockedPort, useMock, servers);
	}

	public CxfClientBuilder withOutLogger(final String loggerName) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger,
				Optional.of(LoggerFactory.getLogger(loggerName)), mockedPort, useMock, servers);
	}

	public CxfClientBuilder withLogger(final Logger logger) {
		return this.withInLogger(logger).withOutLogger(logger);
	}

	public CxfClientBuilder withLogger(final String loggerName) {
		return this.withInLogger(loggerName).withOutLogger(loggerName);
	}

	public CxfClientBuilder withInOutLogger(final Logger logger) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout,
				Optional.fromNullable(logger), Optional.fromNullable(logger),
				mockedPort, useMock, servers);
	}

	public CxfClientBuilder withServers(final String... servers) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, useMock,
				ImmutableList.copyOf(servers));
	}

	public CxfClientBuilder withProperties(final String rootKey,
			final Properties props) {
		CxfClientBuilder configured = this;

		final boolean rootKeyEndsWithDot = rootKey.endsWith(".");
		
		for (final String property : propNames) {
			final String rootedProperty = Joiner.on(rootKeyEndsWithDot?"":".").join(rootKey, property);
			configured = Optional
					.fromNullable(propMetas.get(property).configurator)
					.or(CxfClientBuilderConfigurator.NOOP_CONFIGURATOR)
					.configure(configured,
							Optional.fromNullable((String) props.get(rootedProperty)));
		}

		return configured;
	}
	
	public <Port> CxfClientBuilder withMockedPort(final Port port) {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, Optional.<Object>of((Object)port), useMock,
				servers);
	}
	
	public <Port> CxfClientBuilder withMockedPort(final Class<Port> portClass) {
		try {
			return withMockedPort(portClass.newInstance());
		} catch (InstantiationException | IllegalAccessException e) {
			throw new RuntimeException("unable to instianciate mocked port class : " + portClass.getName(), e);
		}
	}
	
	public CxfClientBuilder enableMocking() {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, true,
				servers);
	}

	public CxfClientBuilder disableMocking() {
		return new CxfClientBuilder(endpoint, wsseUser, wssePwd,
				connectionTimeout, receiveTimeout, inLogger, outLogger, mockedPort, false,
				servers);
	}

	public CxfClientBuilder withMockedPort(final String portClassName) {
		try {
			return withMockedPort(Class.forName(portClassName));
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("unable to find class for named mocked port : " + portClassName, e);
		}
	}

	public <Port, Client extends CxfClient<Port, ?>> Client build(
			Class<Client> clazz) {
		try {
			return clazz.getConstructor(CxfClientBuilder.class).newInstance(
					this);
		} catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException
				| NoSuchMethodException | SecurityException e) {
			throw new IllegalArgumentException(
					"failed to build CxfClient with class : "
							+ clazz.toString(), e);
		}
	}

}