From 34aede347ab941db86cdc85dc40cc1c1eecf56ab Mon Sep 17 00:00:00 2001 From: ejona Date: Mon, 18 Aug 2014 14:30:24 -0700 Subject: [PATCH] Move inner classes out of Server. This is only a move with appropriate code changes to use the new class names. The only functional change was changing the visibility of MethodDefinition's constructor to package-private so ServiceDefinition could construct it. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=73569974 --- .../google/net/stubby/HandlerRegistry.java | 14 +- .../net/stubby/MutableHandlerRegistry.java | 6 +- .../stubby/MutableHandlerRegistryImpl.java | 16 +- .../java/com/google/net/stubby/Server.java | 275 +----------------- .../com/google/net/stubby/ServerCall.java | 116 ++++++++ .../google/net/stubby/ServerCallHandler.java | 25 ++ .../google/net/stubby/ServerInterceptor.java | 25 ++ .../google/net/stubby/ServerInterceptors.java | 66 +++-- .../net/stubby/ServerMethodDefinition.java | 39 +++ .../net/stubby/ServerServiceDefinition.java | 79 +++++ .../MutableHandlerRegistryImplTest.java | 27 +- .../net/stubby/ServerInterceptorsTest.java | 105 +++---- 12 files changed, 404 insertions(+), 389 deletions(-) create mode 100644 core/src/main/java/com/google/net/stubby/ServerCall.java create mode 100644 core/src/main/java/com/google/net/stubby/ServerCallHandler.java create mode 100644 core/src/main/java/com/google/net/stubby/ServerInterceptor.java create mode 100644 core/src/main/java/com/google/net/stubby/ServerMethodDefinition.java create mode 100644 core/src/main/java/com/google/net/stubby/ServerServiceDefinition.java diff --git a/core/src/main/java/com/google/net/stubby/HandlerRegistry.java b/core/src/main/java/com/google/net/stubby/HandlerRegistry.java index 33ad884c6d..1a0db15949 100644 --- a/core/src/main/java/com/google/net/stubby/HandlerRegistry.java +++ b/core/src/main/java/com/google/net/stubby/HandlerRegistry.java @@ -1,7 +1,7 @@ package com.google.net.stubby; -import com.google.net.stubby.Server.MethodDefinition; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerMethodDefinition; +import com.google.net.stubby.ServerServiceDefinition; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -15,19 +15,19 @@ public abstract class HandlerRegistry { /** A method definition and its parent's service definition. */ public static final class Method { - private final ServiceDefinition serviceDef; - private final MethodDefinition methodDef; + private final ServerServiceDefinition serviceDef; + private final ServerMethodDefinition methodDef; - public Method(ServiceDefinition serviceDef, MethodDefinition methodDef) { + public Method(ServerServiceDefinition serviceDef, ServerMethodDefinition methodDef) { this.serviceDef = serviceDef; this.methodDef = methodDef; } - public ServiceDefinition getServiceDefinition() { + public ServerServiceDefinition getServiceDefinition() { return serviceDef; } - public MethodDefinition getMethodDefinition() { + public ServerMethodDefinition getMethodDefinition() { return methodDef; } } diff --git a/core/src/main/java/com/google/net/stubby/MutableHandlerRegistry.java b/core/src/main/java/com/google/net/stubby/MutableHandlerRegistry.java index 855777a084..05ac532f91 100644 --- a/core/src/main/java/com/google/net/stubby/MutableHandlerRegistry.java +++ b/core/src/main/java/com/google/net/stubby/MutableHandlerRegistry.java @@ -1,6 +1,6 @@ package com.google.net.stubby; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerServiceDefinition; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -12,9 +12,9 @@ public abstract class MutableHandlerRegistry extends HandlerRegistry { * Returns {@code null}, or previous service if {@code service} replaced an existing service. */ @Nullable - public abstract ServiceDefinition addService(ServiceDefinition service); + public abstract ServerServiceDefinition addService(ServerServiceDefinition service); /** Returns {@code false} if {@code service} was not registered. */ @Nullable - public abstract boolean removeService(ServiceDefinition service); + public abstract boolean removeService(ServerServiceDefinition service); } diff --git a/core/src/main/java/com/google/net/stubby/MutableHandlerRegistryImpl.java b/core/src/main/java/com/google/net/stubby/MutableHandlerRegistryImpl.java index f6d686e83a..8cd2c7254f 100644 --- a/core/src/main/java/com/google/net/stubby/MutableHandlerRegistryImpl.java +++ b/core/src/main/java/com/google/net/stubby/MutableHandlerRegistryImpl.java @@ -1,7 +1,7 @@ package com.google.net.stubby; -import com.google.net.stubby.Server.MethodDefinition; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerMethodDefinition; +import com.google.net.stubby.ServerServiceDefinition; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -13,17 +13,17 @@ import javax.annotation.concurrent.ThreadSafe; /** Mutable registry implementation of services and their methods for dispatching incoming calls. */ @ThreadSafe public final class MutableHandlerRegistryImpl extends MutableHandlerRegistry { - private final ConcurrentMap services - = new ConcurrentHashMap(); + private final ConcurrentMap services + = new ConcurrentHashMap(); @Override @Nullable - public ServiceDefinition addService(ServiceDefinition service) { + public ServerServiceDefinition addService(ServerServiceDefinition service) { return services.put(service.getName(), service); } @Override - public boolean removeService(ServiceDefinition service) { + public boolean removeService(ServerServiceDefinition service) { return services.remove(service.getName(), service); } @@ -39,11 +39,11 @@ public final class MutableHandlerRegistryImpl extends MutableHandlerRegistry { if (index == -1) { return null; } - ServiceDefinition service = services.get(methodName.substring(0, index)); + ServerServiceDefinition service = services.get(methodName.substring(0, index)); if (service == null) { return null; } - MethodDefinition method = service.getMethod(methodName.substring(index + 1)); + ServerMethodDefinition method = service.getMethod(methodName.substring(index + 1)); if (method == null) { return null; } diff --git a/core/src/main/java/com/google/net/stubby/Server.java b/core/src/main/java/com/google/net/stubby/Server.java index 1ace9fb0e3..9a6f90cf18 100644 --- a/core/src/main/java/com/google/net/stubby/Server.java +++ b/core/src/main/java/com/google/net/stubby/Server.java @@ -1,16 +1,7 @@ package com.google.net.stubby; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.Service; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; /** @@ -18,268 +9,4 @@ import javax.annotation.concurrent.ThreadSafe; * not expected to be implemented by application code or interceptors. */ @ThreadSafe -public interface Server extends Service { - /** Definition of a service to be exposed via a Server. */ - final class ServiceDefinition { - public static ServiceDefinition.Builder builder(String serviceName) { - return new ServiceDefinition.Builder(serviceName); - } - - private final String name; - private final ImmutableList methods; - private final ImmutableMap methodLookup; - - private ServiceDefinition(String name, ImmutableList methods, - Map methodLookup) { - this.name = name; - this.methods = methods; - this.methodLookup = ImmutableMap.copyOf(methodLookup); - } - - /** Simple name of the service. It is not an absolute path. */ - public String getName() { - return name; - } - - public ImmutableList getMethods() { - return methods; - } - - public MethodDefinition getMethod(String name) { - return methodLookup.get(name); - } - - /** Builder for constructing Service instances. */ - public static final class Builder { - private final String serviceName; - private final ImmutableList.Builder methods = ImmutableList.builder(); - private final Map methodLookup - = new HashMap(); - - private Builder(String serviceName) { - this.serviceName = serviceName; - } - - /** - * Add a method to be supported by the service. - * - * @param name simple name of the method, without the service prefix - * @param requestMarshaller marshaller for deserializing incoming requests - * @param responseMarshaller marshaller for serializing outgoing responses - * @param handler handler for incoming calls - */ - public Builder addMethod(String name, Marshaller requestMarshaller, - Marshaller responseMarshaller, CallHandler handler) { - Preconditions.checkNotNull(name, "name must not be null"); - if (methodLookup.containsKey(name)) { - throw new IllegalStateException("Method by same name already registered"); - } - MethodDefinition def = new MethodDefinition(name, - Preconditions.checkNotNull(requestMarshaller, "requestMarshaller must not be null"), - Preconditions.checkNotNull(responseMarshaller, "responseMarshaller must not be null"), - Preconditions.checkNotNull(handler, "handler must not be null")); - methodLookup.put(name, def); - methods.add(def); - return this; - } - - /** Construct new ServiceDefinition. */ - public ServiceDefinition build() { - return new ServiceDefinition(serviceName, methods.build(), methodLookup); - } - } - } - - /** Definition of a method supported by a service. */ - final class MethodDefinition { - private final String name; - private final Marshaller requestMarshaller; - private final Marshaller responseMarshaller; - private final CallHandler handler; - - // MethodDefinition has no form of public construction. It is only created within the context of - // a ServiceDefinition.Builder. - private MethodDefinition(String name, Marshaller requestMarshaller, - Marshaller responseMarshaller, CallHandler handler) { - this.name = name; - this.requestMarshaller = requestMarshaller; - this.responseMarshaller = responseMarshaller; - this.handler = handler; - } - - /** The simple name of the method. It is not an absolute path. */ - public String getName() { - return name; - } - - /** Marshaller for deserializing incoming requests. */ - public Marshaller getRequestMarshaller() { - return requestMarshaller; - } - - /** Marshaller for serializing outgoing responses. */ - public Marshaller getResponseMarshaller() { - return responseMarshaller; - } - - /** Handler for incoming calls. */ - public CallHandler getCallHandler() { - return handler; - } - } - - /** - * Interface for intercepting incoming RPCs before the handler receives them. - */ - @ThreadSafe - interface Interceptor { - /** - * Intercept a new call. General semantics of {@link Server.CallHandler#startCall} apply. {@code - * next} may only be called once. Returned listener must not be {@code null}. - * - *

If the implementation throws an exception, {@code call} will be closed with an error. - * Implementations must not throw an exception if they started processing that may use {@code - * call} on another thread. - * - * @param method metadata concerning the call - * @param call object for responding - * @param next next processor in the interceptor chain - * @return listener for processing incoming messages for {@code call} - */ - Server.Call.Listener interceptCall(MethodDescriptor method, - Server.Call call, CallHandler next); - } - - /** - * Interface to begin processing incoming RPCs. Advanced applications and generated code implement - * this interface to implement service methods. - */ - @ThreadSafe - interface CallHandler { - /** - * Produce a non-{@code null} listener for the incoming call. Implementations are free to call - * methods on {@code call} before this method has returned. - * - *

If the implementation throws an exception, {@code call} will be closed with an error. - * Implementations must not throw an exception if they started processing that may use {@code - * call} on another thread. - * - * @param method metadata concerning the call - * @param call object for responding - * @return listener for processing incoming messages for {@code call} - */ - Server.Call.Listener startCall(MethodDescriptor method, - Server.Call call); - } - - /** - * Low-level method for communicating with a remote client during a single RPC. Unlike normal - * RPCs, calls may stream any number of requests and responses, although a single request and - * single response is most common. This API is generally intended for use generated handlers, but - * advanced applications may have need for it. - * - *

Any contexts must be sent before any payloads, which must be sent before closing. - * - *

No generic method for determining message receipt or providing acknowlegement is provided. - * Applications are expected to utilize normal payload messages for such signals, as a response - * natually acknowledges its request. - * - *

Methods are guaranteed to be non-blocking. Implementations are not required to be - * thread-safe. - */ - abstract class Call { - /** - * Callbacks for consuming incoming RPC messages. - * - *

Any contexts are guaranteed to arrive before any payloads, which are guaranteed before - * half close, which is guaranteed before completion. - * - *

Implementations are free to block for extended periods of time. Implementations are not - * required to be thread-safe. - */ - // TODO(user): We need to decide what to do in the case of server closing with non-cancellation - // before client half closes. It may be that we treat such a case as an error. If we permit such - // a case then we either get to generate a half close or purposefully omit it. - public abstract static class Listener { - /** - * A request context has been received. Any context messages will precede payload messages. - * - *

The {@code value} {@link InputStream} will be closed when the returned future completes. - * If no future is returned, the value will be closed immediately after returning from this - * method. - */ - @Nullable - public abstract ListenableFuture onContext(String name, InputStream value); - - /** - * A request payload has been receiveed. For streaming calls, there may be zero payload - * messages. - */ - @Nullable - public abstract ListenableFuture onPayload(T payload); - - /** - * The client completed all message sending. However, the call may still be cancelled. - */ - public abstract void onHalfClose(); - - /** - * The call was cancelled and the server is encouraged to abort processing to save resources, - * since the client will not process any further messages. Cancellations can be caused by - * timeouts, explicit cancel by client, network errors, and similar. - * - *

There will be no further callbacks for the call. - */ - public abstract void onCancel(); - - /** - * The call is considered complete and {@link #onCancel} is guaranteed not to be called. - * However, the client is not guaranteed to have received all messages. - * - *

There will be no further callbacks for the call. - */ - public abstract void onCompleted(); - } - - /** - * Close the call with the provided status. No further sending or receiving will occur. If - * {@code status} is not equal to {@link Status#OK}, then the call is said to have failed. - * - *

If {@code status} is not {@link Status#CANCELLED} and no errors or cancellations are known - * to have occured, then a {@link Listener#onCompleted} notification should be expected. - * Otherwise {@link Listener#onCancel} has been or will be called. - * - * @throws IllegalStateException if call is already {@code close}d - */ - public abstract void close(Status status); - - /** - * Send a context message. Context messages are intended for side-channel information like - * statistics and authentication. - * - * @param name key identifier of context - * @param value context value bytes - * @throws IllegalStateException if call is {@link #close}d, or after {@link #sendPayload} - */ - public abstract void sendContext(String name, InputStream value); - - /** - * Send a payload message. Payload messages are the primary form of communication associated - * with RPCs. Multiple payload messages may exist for streaming calls. - * - * @param payload message - * @throws IllegalStateException if call is {@link #close}d - */ - public abstract void sendPayload(ResponseT payload); - - /** - * Returns {@code true} when the call is cancelled and the server is encouraged to abort - * processing to save resources, since the client will not be processing any further methods. - * Cancellations can be caused by timeouts, explicit cancel by client, network errors, and - * similar. - * - *

This method may safely be called concurrently from multiple threads. - */ - public abstract boolean isCancelled(); - } -} +public interface Server extends Service {} diff --git a/core/src/main/java/com/google/net/stubby/ServerCall.java b/core/src/main/java/com/google/net/stubby/ServerCall.java new file mode 100644 index 0000000000..bc7950cf94 --- /dev/null +++ b/core/src/main/java/com/google/net/stubby/ServerCall.java @@ -0,0 +1,116 @@ +package com.google.net.stubby; + +import com.google.common.util.concurrent.ListenableFuture; + +import java.io.InputStream; +import javax.annotation.Nullable; + +/** + * Low-level method for communicating with a remote client during a single RPC. Unlike normal RPCs, + * calls may stream any number of requests and responses, although a single request and single + * response is most common. This API is generally intended for use generated handlers, but advanced + * applications may have need for it. + * + *

Any contexts must be sent before any payloads, which must be sent before closing. + * + *

No generic method for determining message receipt or providing acknowlegement is provided. + * Applications are expected to utilize normal payload messages for such signals, as a response + * natually acknowledges its request. + * + *

Methods are guaranteed to be non-blocking. Implementations are not required to be thread-safe. + */ +public abstract class ServerCall { + /** + * Callbacks for consuming incoming RPC messages. + * + *

Any contexts are guaranteed to arrive before any payloads, which are guaranteed before half + * close, which is guaranteed before completion. + * + *

Implementations are free to block for extended periods of time. Implementations are not + * required to be thread-safe. + */ + // TODO(user): We need to decide what to do in the case of server closing with non-cancellation + // before client half closes. It may be that we treat such a case as an error. If we permit such + // a case then we either get to generate a half close or purposefully omit it. + public abstract static class Listener { + /** + * A request context has been received. Any context messages will precede payload messages. + * + *

The {@code value} {@link InputStream} will be closed when the returned future completes. + * If no future is returned, the value will be closed immediately after returning from this + * method. + */ + @Nullable + public abstract ListenableFuture onContext(String name, InputStream value); + + /** + * A request payload has been receiveed. For streaming calls, there may be zero payload + * messages. + */ + @Nullable + public abstract ListenableFuture onPayload(T payload); + + /** + * The client completed all message sending. However, the call may still be cancelled. + */ + public abstract void onHalfClose(); + + /** + * The call was cancelled and the server is encouraged to abort processing to save resources, + * since the client will not process any further messages. Cancellations can be caused by + * timeouts, explicit cancel by client, network errors, and similar. + * + *

There will be no further callbacks for the call. + */ + public abstract void onCancel(); + + /** + * The call is considered complete and {@link #onCancel} is guaranteed not to be called. + * However, the client is not guaranteed to have received all messages. + * + *

There will be no further callbacks for the call. + */ + public abstract void onCompleted(); + } + + /** + * Close the call with the provided status. No further sending or receiving will occur. If {@code + * status} is not equal to {@link Status#OK}, then the call is said to have failed. + * + *

If {@code status} is not {@link Status#CANCELLED} and no errors or cancellations are known + * to have occured, then a {@link Listener#onCompleted} notification should be expected. + * Otherwise {@link Listener#onCancel} has been or will be called. + * + * @throws IllegalStateException if call is already {@code close}d + */ + public abstract void close(Status status); + + /** + * Send a context message. Context messages are intended for side-channel information like + * statistics and authentication. + * + * @param name key identifier of context + * @param value context value bytes + * @throws IllegalStateException if call is {@link #close}d, or after {@link #sendPayload} + */ + public abstract void sendContext(String name, InputStream value); + + /** + * Send a payload message. Payload messages are the primary form of communication associated with + * RPCs. Multiple payload messages may exist for streaming calls. + * + * @param payload message + * @throws IllegalStateException if call is {@link #close}d + */ + public abstract void sendPayload(ResponseT payload); + + /** + * Returns {@code true} when the call is cancelled and the server is encouraged to abort + * processing to save resources, since the client will not be processing any further methods. + * Cancellations can be caused by timeouts, explicit cancel by client, network errors, and + * similar. + * + *

This method may safely be called concurrently from multiple threads. + */ + public abstract boolean isCancelled(); +} diff --git a/core/src/main/java/com/google/net/stubby/ServerCallHandler.java b/core/src/main/java/com/google/net/stubby/ServerCallHandler.java new file mode 100644 index 0000000000..9f97c7b586 --- /dev/null +++ b/core/src/main/java/com/google/net/stubby/ServerCallHandler.java @@ -0,0 +1,25 @@ +package com.google.net.stubby; + +import javax.annotation.concurrent.ThreadSafe; + +/** + * Interface to begin processing incoming RPCs. Advanced applications and generated code implement + * this interface to implement service methods. + */ +@ThreadSafe +public interface ServerCallHandler { + /** + * Produce a non-{@code null} listener for the incoming call. Implementations are free to call + * methods on {@code call} before this method has returned. + * + *

If the implementation throws an exception, {@code call} will be closed with an error. + * Implementations must not throw an exception if they started processing that may use {@code + * call} on another thread. + * + * @param method metadata concerning the call + * @param call object for responding + * @return listener for processing incoming messages for {@code call} + */ + ServerCall.Listener startCall(MethodDescriptor method, + ServerCall call); +} diff --git a/core/src/main/java/com/google/net/stubby/ServerInterceptor.java b/core/src/main/java/com/google/net/stubby/ServerInterceptor.java new file mode 100644 index 0000000000..28be42861a --- /dev/null +++ b/core/src/main/java/com/google/net/stubby/ServerInterceptor.java @@ -0,0 +1,25 @@ +package com.google.net.stubby; + +import javax.annotation.concurrent.ThreadSafe; + +/** + * Interface for intercepting incoming RPCs before the handler receives them. + */ +@ThreadSafe +public interface ServerInterceptor { + /** + * Intercept a new call. General semantics of {@link ServerCallHandler#startCall} apply. {@code + * next} may only be called once. Returned listener must not be {@code null}. + * + *

If the implementation throws an exception, {@code call} will be closed with an error. + * Implementations must not throw an exception if they started processing that may use {@code + * call} on another thread. + * + * @param method metadata concerning the call + * @param call object for responding + * @param next next processor in the interceptor chain + * @return listener for processing incoming messages for {@code call} + */ + ServerCall.Listener interceptCall(MethodDescriptor method, + ServerCall call, ServerCallHandler next); +} diff --git a/core/src/main/java/com/google/net/stubby/ServerInterceptors.java b/core/src/main/java/com/google/net/stubby/ServerInterceptors.java index 1b823281a3..79f1f13365 100644 --- a/core/src/main/java/com/google/net/stubby/ServerInterceptors.java +++ b/core/src/main/java/com/google/net/stubby/ServerInterceptors.java @@ -2,87 +2,89 @@ package com.google.net.stubby; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.net.stubby.Server.CallHandler; -import com.google.net.stubby.Server.Interceptor; -import com.google.net.stubby.Server.MethodDefinition; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerMethodDefinition; +import com.google.net.stubby.ServerCallHandler; +import com.google.net.stubby.ServerInterceptor; +import com.google.net.stubby.ServerServiceDefinition; import java.util.List; import java.util.Iterator; -/** Utility class for {@link Server.Interceptor}s. */ +/** Utility class for {@link ServerInterceptor}s. */ public class ServerInterceptors { // Prevent instantiation private ServerInterceptors() {} /** - * Create a new {@code ServiceDefinition} whose {@link Server.CallHandler}s will call {@code - * interceptors} before calling the pre-existing {@code CallHandler}. + * Create a new {@code ServerServiceDefinition} whose {@link ServerCallHandler}s will call {@code + * interceptors} before calling the pre-existing {@code ServerCallHandler}. */ - public static ServiceDefinition intercept(ServiceDefinition serviceDef, - List interceptors) { + public static ServerServiceDefinition intercept(ServerServiceDefinition serviceDef, + List interceptors) { Preconditions.checkNotNull(serviceDef); - List immutableInterceptors = ImmutableList.copyOf(interceptors); + List immutableInterceptors = ImmutableList.copyOf(interceptors); if (immutableInterceptors.isEmpty()) { return serviceDef; } - ServiceDefinition.Builder serviceDefBuilder = ServiceDefinition.builder(serviceDef.getName()); - for (MethodDefinition method : serviceDef.getMethods()) { + ServerServiceDefinition.Builder serviceDefBuilder + = ServerServiceDefinition.builder(serviceDef.getName()); + for (ServerMethodDefinition method : serviceDef.getMethods()) { wrapAndAddMethod(serviceDefBuilder, method, immutableInterceptors); } return serviceDefBuilder.build(); } - private static void wrapAndAddMethod(ServiceDefinition.Builder serviceDefBuilder, - MethodDefinition method, List interceptors) { - CallHandler callHandler - = InterceptCallHandler.create(interceptors, method.getCallHandler()); + private static void wrapAndAddMethod( + ServerServiceDefinition.Builder serviceDefBuilder, ServerMethodDefinition method, + List interceptors) { + ServerCallHandler callHandler + = InterceptCallHandler.create(interceptors, method.getServerCallHandler()); serviceDefBuilder.addMethod(method.getName(), method.getRequestMarshaller(), method.getResponseMarshaller(), callHandler); } - private static class InterceptCallHandler implements CallHandler { + private static class InterceptCallHandler implements ServerCallHandler { public static InterceptCallHandler create( - List interceptors, CallHandler callHandler) { + List interceptors, ServerCallHandler callHandler) { return new InterceptCallHandler(interceptors, callHandler); } - private final List interceptors; - private final CallHandler callHandler; + private final List interceptors; + private final ServerCallHandler callHandler; - private InterceptCallHandler(List interceptors, - CallHandler callHandler) { + private InterceptCallHandler(List interceptors, + ServerCallHandler callHandler) { this.interceptors = interceptors; this.callHandler = callHandler; } @Override - public Server.Call.Listener startCall(MethodDescriptor method, - Server.Call call) { + public ServerCall.Listener startCall(MethodDescriptor method, + ServerCall call) { return ProcessInterceptorsCallHandler.create(interceptors.iterator(), callHandler) .startCall(method, call); } } private static class ProcessInterceptorsCallHandler - implements CallHandler { + implements ServerCallHandler { public static ProcessInterceptorsCallHandler create( - Iterator interceptors, CallHandler callHandler) { + Iterator interceptors, ServerCallHandler callHandler) { return new ProcessInterceptorsCallHandler(interceptors, callHandler); } - private Iterator interceptors; - private final CallHandler callHandler; + private Iterator interceptors; + private final ServerCallHandler callHandler; - private ProcessInterceptorsCallHandler(Iterator interceptors, - CallHandler callHandler) { + private ProcessInterceptorsCallHandler(Iterator interceptors, + ServerCallHandler callHandler) { this.interceptors = interceptors; this.callHandler = callHandler; } @Override - public Server.Call.Listener startCall(MethodDescriptor method, - Server.Call call) { + public ServerCall.Listener startCall(MethodDescriptor method, + ServerCall call) { if (interceptors != null && interceptors.hasNext()) { return interceptors.next().interceptCall(method, call, this); } else { diff --git a/core/src/main/java/com/google/net/stubby/ServerMethodDefinition.java b/core/src/main/java/com/google/net/stubby/ServerMethodDefinition.java new file mode 100644 index 0000000000..416accb835 --- /dev/null +++ b/core/src/main/java/com/google/net/stubby/ServerMethodDefinition.java @@ -0,0 +1,39 @@ +package com.google.net.stubby; + +/** Definition of a method supported by a service. */ +public final class ServerMethodDefinition { + private final String name; + private final Marshaller requestMarshaller; + private final Marshaller responseMarshaller; + private final ServerCallHandler handler; + + // ServerMethodDefinition has no form of public construction. It is only created within the + // context of a ServerServiceDefinition.Builder. + ServerMethodDefinition(String name, Marshaller requestMarshaller, + Marshaller responseMarshaller, ServerCallHandler handler) { + this.name = name; + this.requestMarshaller = requestMarshaller; + this.responseMarshaller = responseMarshaller; + this.handler = handler; + } + + /** The simple name of the method. It is not an absolute path. */ + public String getName() { + return name; + } + + /** Marshaller for deserializing incoming requests. */ + public Marshaller getRequestMarshaller() { + return requestMarshaller; + } + + /** Marshaller for serializing outgoing responses. */ + public Marshaller getResponseMarshaller() { + return responseMarshaller; + } + + /** Handler for incoming calls. */ + public ServerCallHandler getServerCallHandler() { + return handler; + } +} diff --git a/core/src/main/java/com/google/net/stubby/ServerServiceDefinition.java b/core/src/main/java/com/google/net/stubby/ServerServiceDefinition.java new file mode 100644 index 0000000000..2fa2eaa831 --- /dev/null +++ b/core/src/main/java/com/google/net/stubby/ServerServiceDefinition.java @@ -0,0 +1,79 @@ +package com.google.net.stubby; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import java.util.HashMap; +import java.util.Map; + +/** Definition of a service to be exposed via a Server. */ +public final class ServerServiceDefinition { + public static Builder builder(String serviceName) { + return new Builder(serviceName); + } + + private final String name; + private final ImmutableList methods; + private final ImmutableMap methodLookup; + + private ServerServiceDefinition(String name, ImmutableList methods, + Map methodLookup) { + this.name = name; + this.methods = methods; + this.methodLookup = ImmutableMap.copyOf(methodLookup); + } + + /** Simple name of the service. It is not an absolute path. */ + public String getName() { + return name; + } + + public ImmutableList getMethods() { + return methods; + } + + public ServerMethodDefinition getMethod(String name) { + return methodLookup.get(name); + } + + /** Builder for constructing Service instances. */ + public static final class Builder { + private final String serviceName; + private final ImmutableList.Builder methods = ImmutableList.builder(); + private final Map methodLookup + = new HashMap(); + + private Builder(String serviceName) { + this.serviceName = serviceName; + } + + /** + * Add a method to be supported by the service. + * + * @param name simple name of the method, without the service prefix + * @param requestMarshaller marshaller for deserializing incoming requests + * @param responseMarshaller marshaller for serializing outgoing responses + * @param handler handler for incoming calls + */ + public Builder addMethod(String name, Marshaller requestMarshaller, + Marshaller responseMarshaller, ServerCallHandler handler) { + Preconditions.checkNotNull(name, "name must not be null"); + if (methodLookup.containsKey(name)) { + throw new IllegalStateException("Method by same name already registered"); + } + ServerMethodDefinition def = new ServerMethodDefinition(name, + Preconditions.checkNotNull(requestMarshaller, "requestMarshaller must not be null"), + Preconditions.checkNotNull(responseMarshaller, "responseMarshaller must not be null"), + Preconditions.checkNotNull(handler, "handler must not be null")); + methodLookup.put(name, def); + methods.add(def); + return this; + } + + /** Construct new ServerServiceDefinition. */ + public ServerServiceDefinition build() { + return new ServerServiceDefinition(serviceName, methods.build(), methodLookup); + } + } +} diff --git a/core/src/test/java/com/google/net/stubby/MutableHandlerRegistryImplTest.java b/core/src/test/java/com/google/net/stubby/MutableHandlerRegistryImplTest.java index ff42f7c20b..86b03d29f5 100644 --- a/core/src/test/java/com/google/net/stubby/MutableHandlerRegistryImplTest.java +++ b/core/src/test/java/com/google/net/stubby/MutableHandlerRegistryImplTest.java @@ -7,9 +7,9 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; -import com.google.net.stubby.Server.CallHandler; -import com.google.net.stubby.Server.MethodDefinition; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerMethodDefinition; +import com.google.net.stubby.ServerCallHandler; +import com.google.net.stubby.ServerServiceDefinition; import com.google.net.stubby.HandlerRegistry.Method; import org.junit.After; @@ -24,15 +24,16 @@ public class MutableHandlerRegistryImplTest { private MutableHandlerRegistry registry = new MutableHandlerRegistryImpl(); private Marshaller requestMarshaller = mock(Marshaller.class); private Marshaller responseMarshaller = mock(Marshaller.class); - private CallHandler handler = mock(CallHandler.class); - private ServiceDefinition basicServiceDefinition = ServiceDefinition.builder("basic") + private ServerCallHandler handler = mock(ServerCallHandler.class); + private ServerServiceDefinition basicServiceDefinition = ServerServiceDefinition.builder("basic") .addMethod("flow", requestMarshaller, responseMarshaller, handler).build(); - private MethodDefinition flowMethodDefinition = basicServiceDefinition.getMethods().get(0); - private ServiceDefinition multiServiceDefinition = ServiceDefinition.builder("multi") + private ServerMethodDefinition flowMethodDefinition = basicServiceDefinition.getMethods().get(0); + private ServerServiceDefinition multiServiceDefinition = ServerServiceDefinition.builder("multi") .addMethod("couple", requestMarshaller, responseMarshaller, handler) .addMethod("few", requestMarshaller, responseMarshaller, handler).build(); - private MethodDefinition coupleMethodDefinition = multiServiceDefinition.getMethod("couple"); - private MethodDefinition fewMethodDefinition = multiServiceDefinition.getMethod("few"); + private ServerMethodDefinition coupleMethodDefinition + = multiServiceDefinition.getMethod("couple"); + private ServerMethodDefinition fewMethodDefinition = multiServiceDefinition.getMethod("few"); @After public void makeSureMocksUnused() { @@ -90,9 +91,9 @@ public class MutableHandlerRegistryImplTest { public void replaceAndLookup() { assertNull(registry.addService(basicServiceDefinition)); assertNotNull(registry.lookupMethod("/basic.flow")); - ServiceDefinition replaceServiceDefinition = ServiceDefinition.builder("basic") + ServerServiceDefinition replaceServiceDefinition = ServerServiceDefinition.builder("basic") .addMethod("another", requestMarshaller, responseMarshaller, handler).build(); - MethodDefinition anotherMethodDefinition = replaceServiceDefinition.getMethods().get(0); + ServerMethodDefinition anotherMethodDefinition = replaceServiceDefinition.getMethods().get(0); assertSame(basicServiceDefinition, registry.addService(replaceServiceDefinition)); assertNull(registry.lookupMethod("/basic.flow")); @@ -122,7 +123,7 @@ public class MutableHandlerRegistryImplTest { @Test public void removeMissingNameConflictFails() { assertNull(registry.addService(basicServiceDefinition)); - assertFalse(registry.removeService(ServiceDefinition.builder("basic").build())); + assertFalse(registry.removeService(ServerServiceDefinition.builder("basic").build())); } @Test @@ -142,6 +143,6 @@ public class MutableHandlerRegistryImplTest { public void addReturnsPrevious() { assertNull(registry.addService(basicServiceDefinition)); assertSame(basicServiceDefinition, - registry.addService(ServiceDefinition.builder("basic").build())); + registry.addService(ServerServiceDefinition.builder("basic").build())); } } diff --git a/core/src/test/java/com/google/net/stubby/ServerInterceptorsTest.java b/core/src/test/java/com/google/net/stubby/ServerInterceptorsTest.java index bc356d3cb7..a64e4d6490 100644 --- a/core/src/test/java/com/google/net/stubby/ServerInterceptorsTest.java +++ b/core/src/test/java/com/google/net/stubby/ServerInterceptorsTest.java @@ -9,11 +9,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; -import com.google.net.stubby.Server.Interceptor; -import com.google.net.stubby.Server.Call; -import com.google.net.stubby.Server.CallHandler; -import com.google.net.stubby.Server.MethodDefinition; -import com.google.net.stubby.Server.ServiceDefinition; +import com.google.net.stubby.ServerInterceptor; +import com.google.net.stubby.ServerCall; +import com.google.net.stubby.ServerCallHandler; +import com.google.net.stubby.ServerServiceDefinition; import org.junit.After; import org.junit.Before; @@ -31,17 +30,18 @@ import java.util.List; public class ServerInterceptorsTest { private Marshaller requestMarshaller = mock(Marshaller.class); private Marshaller responseMarshaller = mock(Marshaller.class); - private CallHandler handler = mock(CallHandler.class); - private Call.Listener listener = mock(Call.Listener.class); + private ServerCallHandler handler = mock(ServerCallHandler.class); + private ServerCall.Listener listener = mock(ServerCall.Listener.class); private MethodDescriptor methodDescriptor = mock(MethodDescriptor.class); - private Call call = mock(Call.class); - private ServiceDefinition serviceDefinition = ServiceDefinition.builder("basic") + private ServerCall call = mock(ServerCall.class); + private ServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder("basic") .addMethod("flow", requestMarshaller, responseMarshaller, handler).build(); @Before public void setUp() { Mockito.when(handler.startCall( - Mockito.>any(), Mockito.>any())) + Mockito.>any(), + Mockito.>any())) .thenReturn(listener); } @@ -55,7 +55,7 @@ public class ServerInterceptorsTest { @Test(expected = NullPointerException.class) public void npeForNullServiceDefinition() { - ServerInterceptors.intercept(null, Arrays.asList()); + ServerInterceptors.intercept(null, Arrays.asList()); } @Test(expected = NullPointerException.class) @@ -65,28 +65,28 @@ public class ServerInterceptorsTest { @Test(expected = NullPointerException.class) public void npeForNullInterceptor() { - ServerInterceptors.intercept(serviceDefinition, Arrays.asList((Interceptor) null)); + ServerInterceptors.intercept(serviceDefinition, Arrays.asList((ServerInterceptor) null)); } @Test public void noop() { assertSame(serviceDefinition, - ServerInterceptors.intercept(serviceDefinition, Arrays.asList())); + ServerInterceptors.intercept(serviceDefinition, Arrays.asList())); } @Test public void multipleInvocationsOfHandler() { - Interceptor interceptor = Mockito.spy(new NoopInterceptor()); - ServiceDefinition intercepted + ServerInterceptor interceptor = Mockito.spy(new NoopInterceptor()); + ServerServiceDefinition intercepted = ServerInterceptors.intercept(serviceDefinition, Arrays.asList(interceptor)); assertSame(listener, - intercepted.getMethods().get(0).getCallHandler().startCall(methodDescriptor, call)); + intercepted.getMethods().get(0).getServerCallHandler().startCall(methodDescriptor, call)); verify(interceptor).interceptCall(same(methodDescriptor), same(call), anyCallHandler()); verify(handler).startCall(methodDescriptor, call); verifyNoMoreInteractions(interceptor, handler); assertSame(listener, - intercepted.getMethods().get(0).getCallHandler().startCall(methodDescriptor, call)); + intercepted.getMethods().get(0).getServerCallHandler().startCall(methodDescriptor, call)); verify(interceptor, times(2)) .interceptCall(same(methodDescriptor), same(call), anyCallHandler()); verify(handler, times(2)).startCall(methodDescriptor, call); @@ -95,18 +95,18 @@ public class ServerInterceptorsTest { @Test public void correctHandlerCalled() { - CallHandler handler2 = Mockito.mock(CallHandler.class); - serviceDefinition = ServiceDefinition.builder("basic") + ServerCallHandler handler2 = Mockito.mock(ServerCallHandler.class); + serviceDefinition = ServerServiceDefinition.builder("basic") .addMethod("flow", requestMarshaller, responseMarshaller, handler) .addMethod("flow2", requestMarshaller, responseMarshaller, handler2).build(); - ServiceDefinition intercepted = ServerInterceptors.intercept( - serviceDefinition, Arrays.asList(new NoopInterceptor())); - intercepted.getMethod("flow").getCallHandler().startCall(methodDescriptor, call); + ServerServiceDefinition intercepted = ServerInterceptors.intercept( + serviceDefinition, Arrays.asList(new NoopInterceptor())); + intercepted.getMethod("flow").getServerCallHandler().startCall(methodDescriptor, call); verify(handler).startCall(methodDescriptor, call); verifyNoMoreInteractions(handler); verifyZeroInteractions(handler2); - intercepted.getMethod("flow2").getCallHandler().startCall(methodDescriptor, call); + intercepted.getMethod("flow2").getServerCallHandler().startCall(methodDescriptor, call); verify(handler2).startCall(methodDescriptor, call); verifyNoMoreInteractions(handler); verifyNoMoreInteractions(handler2); @@ -115,72 +115,73 @@ public class ServerInterceptorsTest { @Test public void ordered() { final List order = new ArrayList(); - handler = new CallHandler() { + handler = new ServerCallHandler() { @Override - public Call.Listener startCall(MethodDescriptor method, - Call call) { + public ServerCall.Listener startCall(MethodDescriptor method, + ServerCall call) { order.add("handler"); return listener; } }; - Interceptor interceptor1 = new Interceptor() { + ServerInterceptor interceptor1 = new ServerInterceptor() { @Override - public Call.Listener interceptCall( - MethodDescriptor method, Call call, - CallHandler next) { + public ServerCall.Listener interceptCall( + MethodDescriptor method, ServerCall call, + ServerCallHandler next) { order.add("i1"); return next.startCall(method, call); } }; - Interceptor interceptor2 = new Interceptor() { + ServerInterceptor interceptor2 = new ServerInterceptor() { @Override - public Call.Listener interceptCall( - MethodDescriptor method, Call call, - CallHandler next) { + public ServerCall.Listener interceptCall( + MethodDescriptor method, ServerCall call, + ServerCallHandler next) { order.add("i2"); return next.startCall(method, call); } }; - ServiceDefinition serviceDefinition = ServiceDefinition.builder("basic") + ServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder("basic") .addMethod("flow", requestMarshaller, responseMarshaller, handler).build(); - ServiceDefinition intercepted = ServerInterceptors.intercept( + ServerServiceDefinition intercepted = ServerInterceptors.intercept( serviceDefinition, Arrays.asList(interceptor1, interceptor2)); assertSame(listener, - intercepted.getMethods().get(0).getCallHandler().startCall(methodDescriptor, call)); + intercepted.getMethods().get(0).getServerCallHandler().startCall(methodDescriptor, call)); assertEquals(Arrays.asList("i1", "i2", "handler"), order); } @Test public void argumentsPassed() { final MethodDescriptor method2 = mock(MethodDescriptor.class); - final Call call2 = mock(Call.class); - final Call.Listener listener2 = mock(Call.Listener.class); - Interceptor interceptor = new Interceptor() { + final ServerCall call2 = mock(ServerCall.class); + final ServerCall.Listener listener2 = mock(ServerCall.Listener.class); + ServerInterceptor interceptor = new ServerInterceptor() { @Override - public Call.Listener interceptCall( - MethodDescriptor method, Call call, - CallHandler next) { + public ServerCall.Listener interceptCall( + MethodDescriptor method, ServerCall call, + ServerCallHandler next) { assertSame(method, methodDescriptor); assertSame(call, ServerInterceptorsTest.this.call); - assertSame(listener, next.startCall((MethodDescriptor) method2, (Call) call2)); - return (Call.Listener) listener2; + assertSame(listener, next.startCall((MethodDescriptor) method2, (ServerCall) call2)); + return (ServerCall.Listener) listener2; } }; - ServiceDefinition intercepted = ServerInterceptors.intercept( + ServerServiceDefinition intercepted = ServerInterceptors.intercept( serviceDefinition, Arrays.asList(interceptor)); assertSame(listener2, - intercepted.getMethods().get(0).getCallHandler().startCall(methodDescriptor, call)); + intercepted.getMethods().get(0).getServerCallHandler().startCall(methodDescriptor, call)); verify(handler).startCall(method2, call2); } - private CallHandler anyCallHandler() { - return Mockito.>any(); + private ServerCallHandler anyCallHandler() { + return Mockito.>any(); } - private static class NoopInterceptor implements Interceptor { + private static class NoopInterceptor implements ServerInterceptor { @Override - public Call.Listener interceptCall(MethodDescriptor method, - Call call, CallHandler next) { + public ServerCall.Listener interceptCall( + MethodDescriptor method, ServerCall call, + ServerCallHandler next) { return next.startCall(method, call); } }