1 /* 2 * Copyright 2014 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.base.Preconditions.checkState; 22 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.Collections; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 30 /** Definition of a service to be exposed via a Server. */ 31 public final class ServerServiceDefinition { 32 /** Convenience that constructs a {@link ServiceDescriptor} simultaneously. */ builder(String serviceName)33 public static Builder builder(String serviceName) { 34 return new Builder(serviceName); 35 } 36 builder(ServiceDescriptor serviceDescriptor)37 public static Builder builder(ServiceDescriptor serviceDescriptor) { 38 return new Builder(serviceDescriptor); 39 } 40 41 private final ServiceDescriptor serviceDescriptor; 42 private final Map<String, ServerMethodDefinition<?, ?>> methods; 43 ServerServiceDefinition( ServiceDescriptor serviceDescriptor, Map<String, ServerMethodDefinition<?, ?>> methods)44 private ServerServiceDefinition( 45 ServiceDescriptor serviceDescriptor, Map<String, ServerMethodDefinition<?, ?>> methods) { 46 this.serviceDescriptor = checkNotNull(serviceDescriptor, "serviceDescriptor"); 47 this.methods = Collections.unmodifiableMap(new HashMap<>(methods)); 48 } 49 50 /** 51 * The descriptor for the service. 52 */ getServiceDescriptor()53 public ServiceDescriptor getServiceDescriptor() { 54 return serviceDescriptor; 55 } 56 57 /** 58 * Gets all the methods of service. 59 */ getMethods()60 public Collection<ServerMethodDefinition<?, ?>> getMethods() { 61 return methods.values(); 62 } 63 64 /** 65 * Look up a method by its fully qualified name. 66 * 67 * @param methodName the fully qualified name without leading slash. E.g., "com.foo.Foo/Bar" 68 */ 69 @Internal getMethod(String methodName)70 public ServerMethodDefinition<?, ?> getMethod(String methodName) { 71 return methods.get(methodName); 72 } 73 74 /** 75 * Builder for constructing Service instances. 76 */ 77 public static final class Builder { 78 private final String serviceName; 79 private final ServiceDescriptor serviceDescriptor; 80 private final Map<String, ServerMethodDefinition<?, ?>> methods = new HashMap<>(); 81 Builder(String serviceName)82 private Builder(String serviceName) { 83 this.serviceName = checkNotNull(serviceName, "serviceName"); 84 this.serviceDescriptor = null; 85 } 86 Builder(ServiceDescriptor serviceDescriptor)87 private Builder(ServiceDescriptor serviceDescriptor) { 88 this.serviceDescriptor = checkNotNull(serviceDescriptor, "serviceDescriptor"); 89 this.serviceName = serviceDescriptor.getName(); 90 } 91 92 /** 93 * Add a method to be supported by the service. 94 * 95 * @param method the {@link MethodDescriptor} of this method. 96 * @param handler handler for incoming calls 97 */ addMethod( MethodDescriptor<ReqT, RespT> method, ServerCallHandler<ReqT, RespT> handler)98 public <ReqT, RespT> Builder addMethod( 99 MethodDescriptor<ReqT, RespT> method, ServerCallHandler<ReqT, RespT> handler) { 100 return addMethod(ServerMethodDefinition.create( 101 checkNotNull(method, "method must not be null"), 102 checkNotNull(handler, "handler must not be null"))); 103 } 104 105 /** Add a method to be supported by the service. */ addMethod(ServerMethodDefinition<ReqT, RespT> def)106 public <ReqT, RespT> Builder addMethod(ServerMethodDefinition<ReqT, RespT> def) { 107 MethodDescriptor<ReqT, RespT> method = def.getMethodDescriptor(); 108 checkArgument( 109 serviceName.equals(method.getServiceName()), 110 "Method name should be prefixed with service name and separated with '/'. " 111 + "Expected service name: '%s'. Actual fully qualifed method name: '%s'.", 112 serviceName, method.getFullMethodName()); 113 String name = method.getFullMethodName(); 114 checkState(!methods.containsKey(name), "Method by same name already registered: %s", name); 115 methods.put(name, def); 116 return this; 117 } 118 119 /** 120 * Construct new ServerServiceDefinition. 121 */ build()122 public ServerServiceDefinition build() { 123 ServiceDescriptor serviceDescriptor = this.serviceDescriptor; 124 if (serviceDescriptor == null) { 125 List<MethodDescriptor<?, ?>> methodDescriptors 126 = new ArrayList<>(methods.size()); 127 for (ServerMethodDefinition<?, ?> serverMethod : methods.values()) { 128 methodDescriptors.add(serverMethod.getMethodDescriptor()); 129 } 130 serviceDescriptor = new ServiceDescriptor(serviceName, methodDescriptors); 131 } 132 Map<String, ServerMethodDefinition<?, ?>> tmpMethods = new HashMap<>(methods); 133 for (MethodDescriptor<?, ?> descriptorMethod : serviceDescriptor.getMethods()) { 134 ServerMethodDefinition<?, ?> removed = tmpMethods.remove( 135 descriptorMethod.getFullMethodName()); 136 if (removed == null) { 137 throw new IllegalStateException( 138 "No method bound for descriptor entry " + descriptorMethod.getFullMethodName()); 139 } 140 if (removed.getMethodDescriptor() != descriptorMethod) { 141 throw new IllegalStateException( 142 "Bound method for " + descriptorMethod.getFullMethodName() 143 + " not same instance as method in service descriptor"); 144 } 145 } 146 if (tmpMethods.size() > 0) { 147 throw new IllegalStateException( 148 "No entry in descriptor matching bound method " 149 + tmpMethods.values().iterator().next().getMethodDescriptor().getFullMethodName()); 150 } 151 return new ServerServiceDefinition(serviceDescriptor, methods); 152 } 153 } 154 } 155