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()); } }