Skip to content

Commit

Permalink
playframework#68 Add Play SOAP server
Browse files Browse the repository at this point in the history
  • Loading branch information
ihostage committed Aug 9, 2019
1 parent 2179a1c commit a8b411c
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.apache.cxf.transport.http_play;

/** Inspired by {@link org.apache.cxf.transport.http.DestinationRegistry} */
public interface PlayDestinationRegistry {

PlayHTTPDestination addDestination(PlayHTTPDestination destination);

// void removeDestination(String path);

PlayHTTPDestination getDestinationForPath(String path);

// PlayHTTPDestination getDestinationForPath(String path, boolean tryDecoding);
//
// PlayHTTPDestination checkRestfulRequest(String address);
//
// Collection<PlayHTTPDestination> getDestinations();
//
// AbstractDestination[] getSortedDestinations();
//
// Set<String> getDestinationsPaths();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.apache.cxf.transport.http_play;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/** Inpired by {@link org.apache.cxf.transport.http.DestinationRegistryImpl} */
public class PlayDestinationRegistryImpl implements PlayDestinationRegistry {

private ConcurrentMap<String, PlayHTTPDestination> destinations = new ConcurrentHashMap<>();
private ConcurrentMap<String, PlayHTTPDestination> decodedDestinations =
new ConcurrentHashMap<>();

public PlayHTTPDestination addDestination(PlayHTTPDestination destination) {
String path = getTrimmedPath(destination.getEndpointInfo().getAddress());
PlayHTTPDestination dest = destinations.computeIfAbsent(path, key -> destination);
try {
String path2 = URLDecoder.decode(path, "UTF-8");
if (!path.equals(path2)) {
decodedDestinations.putIfAbsent(path2, dest);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported Encoding", e);
}
return dest;
}

public PlayHTTPDestination getDestinationForPath(String path) {
String m = getTrimmedPath(path);
PlayHTTPDestination s = destinations.get(m);
return (s != null) ? s : decodedDestinations.get(m);
}

/**
* Remove the transport protocol from the path and make it starts with /
*
* @param path
* @return trimmed path
*/
private String getTrimmedPath(String path) {
if (path == null) {
return "/";
}
final String lh = "http://localhost/";
final String lhs = "https://localhost/";

if (path.startsWith(lh)) {
path = path.substring(lh.length());
} else if (path.startsWith(lhs)) {
path = path.substring(lhs.length());
}
if (!path.contains("://") && !path.startsWith("/")) {
path = "/" + path;
}
return path;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.apache.cxf.transport.http_play;

import org.apache.cxf.Bus;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.AbstractDestination;
import org.apache.cxf.transport.Conduit;

import java.util.logging.Logger;

/** Play HTTP destination */
public class PlayHTTPDestination extends AbstractDestination {

private static final Logger LOG = LogUtils.getL7dLogger(PlayHTTPDestination.class);

public PlayHTTPDestination(Bus b, EndpointInfo ei) {
super(b, getTargetReference(ei, b), ei);
}

@Override
protected Conduit getInbuiltBackChannel(Message inMessage) {
return null;
}

@Override
protected Logger getLogger() {
return LOG;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.apache.cxf.transport.http_play;

import org.apache.cxf.Bus;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.AbstractTransportFactory;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.transport.ConduitInitiator;
import org.apache.cxf.transport.Destination;
import org.apache.cxf.transport.DestinationFactory;
import org.apache.cxf.ws.addressing.EndpointReferenceType;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/** Inspired by {@link org.apache.cxf.transport.http.HTTPTransportFactory} */
public class PlayTransportFactory extends AbstractTransportFactory
implements ConduitInitiator, DestinationFactory {

// public static final List<String> DEFAULT_NAMESPACES =
// Collections.unmodifiableList(
// Arrays.asList(
// "http://cxf.apache.org/transports/http",
// "http://cxf.apache.org/transports/http/configuration",
// "http://schemas.xmlsoap.org/wsdl/http",
// "http://schemas.xmlsoap.org/wsdl/http/"));

public static final List<String> DEFAULT_NAMESPACES =
Collections.unmodifiableList(Arrays.asList("http://cxf.apache.org/transports/play"));

private static final Logger LOG = LogUtils.getL7dLogger(PlayTransportFactory.class);

protected final PlayDestinationRegistry registry;

public PlayTransportFactory() {
super(DEFAULT_NAMESPACES);
this.registry = new PlayDestinationRegistryImpl();
}

@Override
public Conduit getConduit(EndpointInfo targetInfo, Bus bus) throws IOException {
return null;
}

@Override
public Conduit getConduit(EndpointInfo localInfo, EndpointReferenceType target, Bus bus)
throws IOException {
return null;
}

@Override
public Destination getDestination(EndpointInfo endpointInfo, Bus bus) throws IOException {
if (endpointInfo == null) throw new IllegalArgumentException("EndpointInfo cannot be null");
PlayHTTPDestination dest = registry.getDestinationForPath(endpointInfo.getAddress());
if (dest == null) dest = registry.addDestination(createDestination(endpointInfo, bus));
return dest;
}

private PlayHTTPDestination createDestination(EndpointInfo endpointInfo, Bus bus) {
return new PlayHTTPDestination(bus, endpointInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package play.soap.server;

import com.typesafe.config.Config;
import org.apache.cxf.BusFactory;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.slf4j.Logger;
Expand All @@ -31,18 +31,17 @@ public class EndpointPublisher {
public EndpointPublisher(
ApplicationLifecycle lifecycle,
JaxWsServerFactoryBean server,
Bus bus,
Injector injector,
Config config)
throws ClassNotFoundException {
List<? extends Config> configEndpoints = config.getConfigList("jaxws.endpoints");
for (Config endpointConfig : configEndpoints) {
String address = endpointConfig.getString("address");
String implementorClass = endpointConfig.getString("implementor");
Object implementor =
injector.instanceOf(
Thread.currentThread().getContextClassLoader().loadClass(implementorClass));
EndpointImpl endpoint =
new EndpointImpl(BusFactory.getThreadDefaultBus(), implementor, server);
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Object implementor = injector.instanceOf(contextClassLoader.loadClass(implementorClass));
EndpointImpl endpoint = new EndpointImpl(bus, implementor, server);
endpoint.setAddress(address);
endpoints.add(endpoint);
}
Expand Down
29 changes: 28 additions & 1 deletion play-server/src/main/java/play/soap/server/SoapModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,52 @@
package play.soap.server;

import com.typesafe.config.Config;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.jaxws.PlayJaxWsServerFactoryBean;
import org.apache.cxf.jaxws.PlayJaxWsServiceFactoryBean;
import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
import org.apache.cxf.transport.http_play.PlayTransportFactory;
import play.Environment;
import play.inject.Binding;
import play.inject.Module;

import java.util.Arrays;
import java.util.List;
import javax.inject.Provider;
import javax.inject.Singleton;

/** @author Sergey Morgunov {@literal <[email protected]>} */
/** Guice module for Play Soap Server */
public class SoapModule extends Module {

@Singleton
public static class BusProvider implements Provider<Bus> {

private final Bus bus = BusFactory.newInstance().createBus();

// private final Provider<PlayTransportFactory> transportFactoryProvider;
//
// @Inject
// public BusProvider(Provider<PlayTransportFactory> transportFactoryProvider) {
// this.transportFactoryProvider = transportFactoryProvider;
// }

@Override
public Bus get() {
// Bus bus = factory.createBus();
// bus.setExtension(transportFactoryProvider.get(), PlayTransportFactory.class);
return bus;
}
}

@Override
public List<Binding<?>> bindings(Environment environment, Config config) {
return Arrays.asList(
bindClass(JaxWsServiceFactoryBean.class).to(PlayJaxWsServiceFactoryBean.class),
bindClass(JaxWsServerFactoryBean.class).to(PlayJaxWsServerFactoryBean.class),
bindClass(PlayTransportFactory.class).toSelf(),
bindClass(Bus.class).toProvider(BusProvider.class),
bindClass(EndpointPublisher.class).toSelf().eagerly());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.apache.cxf.transport.http_play.PlayTransportFactory::true
19 changes: 19 additions & 0 deletions play-server/src/main/scala/play/soap/server/SoapController.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package play.soap.server

import javax.inject.Inject
import org.apache.cxf.Bus
import org.apache.cxf.bus.extension.ExtensionManager
import org.apache.cxf.transport.http_play.PlayTransportFactory
import play.api.mvc.{AbstractController, ControllerComponents}

class SoapController @Inject()(cc: ControllerComponents, bus: Bus) extends AbstractController(cc) {

val transportFactory: PlayTransportFactory = {
val extensionManager = bus.getExtension(classOf[ExtensionManager])
extensionManager.getExtension(classOf[PlayTransportFactory].getName, classOf[PlayTransportFactory])
}

def echo = Action { request =>
Ok("Got request [" + request + "]")
}
}
17 changes: 17 additions & 0 deletions play-server/src/main/scala/play/soap/server/SoapRouter.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package play.soap.server

import javax.inject.Inject
import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
import play.api.routing.sird._

class SoapRouter @Inject()(controller: SoapController) extends SimpleRouter {
override def routes: Routes = {
case GET(p"/$path*") => {
controller.echo()
}
case POST(p"/*$path*") => {
controller.echo()
}
}
}
12 changes: 12 additions & 0 deletions play-server/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<configuration>

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{"yyyy-MM-dd'T'HH:mm:ss.SSSZ"} %level %logger [%mdc] - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="stdout" />
</root>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.specs2.specification.BeforeAll
import play.api.Configuration
import play.api.inject.bind
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.routing.Router
import play.api.test.WithServer
import play.inject.ApplicationLifecycle
import play.inject.DelegateApplicationLifecycle
Expand All @@ -20,19 +21,19 @@ import play.soap.testservice.client.User

import scala.collection.JavaConverters._

class SoapServerSpec extends Specification with BeforeAll {
class SoapServerSpec extends Specification {

sequential

override def beforeAll(): Unit = {}

"SOAP server" in {

"with Java Futures implementation" in new WithServer(
app = GuiceApplicationBuilder()
.configure(new Configuration(ConfigFactory.parseResources("application.java_server.conf")))
.bindings(bind[ApplicationLifecycle].to[DelegateApplicationLifecycle])
.build()
.overrides(bind[Router].to[SoapRouter])
.build(),
port = 9005
) {
withJavaClient { client =>
testHelloService(client)
Expand Down

0 comments on commit a8b411c

Please sign in to comment.