/* * Copyright 2014 The gRPC Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.grpc; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** Definition of a service to be exposed via a Server. */ public final class ServerServiceDefinition { /** Convenience that constructs a {@link ServiceDescriptor} simultaneously. */ public static Builder builder(String serviceName) { return new Builder(serviceName); } public static Builder builder(ServiceDescriptor serviceDescriptor) { return new Builder(serviceDescriptor); } private final ServiceDescriptor serviceDescriptor; private final Map> methods; private ServerServiceDefinition( ServiceDescriptor serviceDescriptor, Map> methods) { this.serviceDescriptor = checkNotNull(serviceDescriptor, "serviceDescriptor"); this.methods = Collections.unmodifiableMap(new HashMap<>(methods)); } /** * The descriptor for the service. */ public ServiceDescriptor getServiceDescriptor() { return serviceDescriptor; } /** * Gets all the methods of service. */ public Collection> getMethods() { return methods.values(); } /** * Look up a method by its fully qualified name. * * @param methodName the fully qualified name without leading slash. E.g., "com.foo.Foo/Bar" */ @Internal public ServerMethodDefinition getMethod(String methodName) { return methods.get(methodName); } /** * Builder for constructing Service instances. */ public static final class Builder { private final String serviceName; private final ServiceDescriptor serviceDescriptor; private final Map> methods = new HashMap<>(); private Builder(String serviceName) { this.serviceName = checkNotNull(serviceName, "serviceName"); this.serviceDescriptor = null; } private Builder(ServiceDescriptor serviceDescriptor) { this.serviceDescriptor = checkNotNull(serviceDescriptor, "serviceDescriptor"); this.serviceName = serviceDescriptor.getName(); } /** * Add a method to be supported by the service. * * @param method the {@link MethodDescriptor} of this method. * @param handler handler for incoming calls */ public Builder addMethod( MethodDescriptor method, ServerCallHandler handler) { return addMethod(ServerMethodDefinition.create( checkNotNull(method, "method must not be null"), checkNotNull(handler, "handler must not be null"))); } /** Add a method to be supported by the service. */ public Builder addMethod(ServerMethodDefinition def) { MethodDescriptor method = def.getMethodDescriptor(); checkArgument( serviceName.equals(method.getServiceName()), "Method name should be prefixed with service name and separated with '/'. " + "Expected service name: '%s'. Actual fully qualifed method name: '%s'.", serviceName, method.getFullMethodName()); String name = method.getFullMethodName(); checkState(!methods.containsKey(name), "Method by same name already registered: %s", name); methods.put(name, def); return this; } /** * Construct new ServerServiceDefinition. */ public ServerServiceDefinition build() { ServiceDescriptor serviceDescriptor = this.serviceDescriptor; if (serviceDescriptor == null) { List> methodDescriptors = new ArrayList<>(methods.size()); for (ServerMethodDefinition serverMethod : methods.values()) { methodDescriptors.add(serverMethod.getMethodDescriptor()); } serviceDescriptor = new ServiceDescriptor(serviceName, methodDescriptors); } Map> tmpMethods = new HashMap<>(methods); for (MethodDescriptor descriptorMethod : serviceDescriptor.getMethods()) { ServerMethodDefinition removed = tmpMethods.remove( descriptorMethod.getFullMethodName()); if (removed == null) { throw new IllegalStateException( "No method bound for descriptor entry " + descriptorMethod.getFullMethodName()); } if (removed.getMethodDescriptor() != descriptorMethod) { throw new IllegalStateException( "Bound method for " + descriptorMethod.getFullMethodName() + " not same instance as method in service descriptor"); } } if (tmpMethods.size() > 0) { throw new IllegalStateException( "No entry in descriptor matching bound method " + tmpMethods.values().iterator().next().getMethodDescriptor().getFullMethodName()); } return new ServerServiceDefinition(serviceDescriptor, methods); } } }