package com.github.skjolber.mockito.soap;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.spi.Provider;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.EndpointException;
import org.apache.cxf.endpoint.ServerImpl;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
import org.apache.cxf.service.ServiceImpl;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.ChainInitiationObserver;
import org.apache.cxf.transport.Destination;
import org.apache.cxf.transport.DestinationFactory;
import org.apache.cxf.transport.DestinationFactoryManager;
/**
* Fork of {@link SoapEndpointRule} that set endpoint.setBindingUri(SOAPBinding.SOAP12HTTP_BINDING)
* into {@link EndpointImpl}.
*
* @author tlenz
*
*/
public class Soap12EndpointRule extends SoapServerRule {
private static final int PORT_RANGE_START = 1024 + 1;
private static final int PORT_RANGE_END = PortManager.PORT_RANGE_MAX;
public static Soap12EndpointRule newInstance() {
return new Soap12EndpointRule();
}
private final Map endpoints = new HashMap<>();
private PortManager portManager;
public Soap12EndpointRule() {
this(PORT_RANGE_START, PORT_RANGE_END);
}
public Soap12EndpointRule(String... portNames) {
this(PORT_RANGE_START, PORT_RANGE_END, portNames);
}
public Soap12EndpointRule(int portRangeStart, int portRangeEnd, String... portNames) {
portManager = new PortManager(portRangeStart, portRangeEnd) {
@Override
public Destination reserve(int port) throws Exception {
return createDestination(port);
}
@Override
public void release(Destination destination) {
destination.shutdown();
}
};
portManager.add(portNames);
}
/**
* Returns the port number that was reserved for the given name.
*
* @param portName port name
* @return a valid port number if the port has been reserved, -1 otherwise
*/
public int getPort(String portName) {
return portManager.getPort(portName);
}
/**
* Returns all port names and respective port numbers.
*
* @return a map of port name and port value (a valid port number if the port
* has been reserved, or -1 otherwise)
*/
public Map getPorts() {
return portManager.getPorts();
}
/**
* Attempt to reserve a port by starting a server.
*
* @param port port to reserve
* @return destination if successful
* @throws IOException
* @throws EndpointException
*/
private Destination createDestination(int port) throws IOException, EndpointException {
final JaxWsServiceFactoryBean jaxWsServiceFactoryBean = new JaxWsServiceFactoryBean();
final JaxWsServerFactoryBean serverFactoryBean = new JaxWsServerFactoryBean(jaxWsServiceFactoryBean);
final Bus bus = serverFactoryBean.getBus();
final String address = "http://localhost:" + port;
serverFactoryBean.setAddress(address);
final DestinationFactory destinationFactory = bus.getExtension(DestinationFactoryManager.class)
.getDestinationFactoryForUri(address);
final EndpointInfo ei = new EndpointInfo(null, Integer.toString(port));
ei.setAddress(address);
final Destination destination = destinationFactory.getDestination(ei, bus);
final ServiceImpl serviceImpl = new ServiceImpl();
final org.apache.cxf.endpoint.Endpoint endpoint = new org.apache.cxf.endpoint.EndpointImpl(bus,
serviceImpl, ei);
destination.setMessageObserver(new ChainInitiationObserver(endpoint, bus));
return destination;
}
@Override
public void proxy(T target, Class port, String address, String wsdlLocation,
List schemaLocations, Map properties) {
assertValidParams(target, port, address);
if (endpoints.containsKey(address)) {
throw new IllegalArgumentException("Endpoint " + address + " already exists");
}
final T serviceInterface = SoapServiceProxy.newInstance(target);
final EndpointImpl endpoint = (EndpointImpl) Provider.provider().createEndpoint(null, serviceInterface);
endpoint.setBindingUri(SOAPBinding.SOAP12HTTP_BINDING);
if (wsdlLocation != null) {
endpoint.setWsdlLocation(wsdlLocation);
}
if (schemaLocations != null) {
endpoint.setSchemaLocations(schemaLocations);
}
endpoint.setProperties(processProperties(properties, wsdlLocation, schemaLocations));
final Destination destination = portManager.getData(parsePort(address));
if (destination != null) {
final ServerImpl server = endpoint.getServer();
server.setDestination(destination);
}
endpoint.publish(address);
endpoints.put(address, endpoint);
}
@Override
protected void before() {
// reserve all ports
portManager.start();
}
@Override
protected void after() {
destroy();
}
/**
* Stop and remove endpoints, keeping port reservations.
*/
public void clear() {
endpoints.values().forEach(EndpointImpl::stop);
endpoints.clear();
}
@Override
public void destroy() {
endpoints.values().forEach(endpoint -> {
endpoint.stop();
endpoint.getBus().shutdown(true);
});
endpoints.clear();
portManager.stop();
}
@Override
public void stop() {
endpoints.values().forEach(endpoint -> endpoint.getServer().stop());
}
@Override
public void start() {
// republish
endpoints.values().forEach(endpoint -> endpoint.getServer().start());
}
}