1 /* 2 * Copyright 2016 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 22 import com.google.common.base.MoreObjects; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Collection; 26 import java.util.Collections; 27 import java.util.HashSet; 28 import java.util.List; 29 import java.util.Set; 30 import javax.annotation.Nullable; 31 32 /** 33 * Descriptor for a service. 34 * 35 * @since 1.0.0 36 */ 37 public final class ServiceDescriptor { 38 39 private final String name; 40 private final Collection<MethodDescriptor<?, ?>> methods; 41 private final Object schemaDescriptor; 42 43 /** 44 * Constructs a new Service Descriptor. Users are encouraged to use {@link #newBuilder} 45 * instead. 46 * 47 * @param name The name of the service 48 * @param methods The methods that are part of the service 49 * @since 1.0.0 50 */ ServiceDescriptor(String name, MethodDescriptor<?, ?>... methods)51 public ServiceDescriptor(String name, MethodDescriptor<?, ?>... methods) { 52 this(name, Arrays.asList(methods)); 53 } 54 55 /** 56 * Constructs a new Service Descriptor. Users are encouraged to use {@link #newBuilder} 57 * instead. 58 * 59 * @param name The name of the service 60 * @param methods The methods that are part of the service 61 * @since 1.0.0 62 */ ServiceDescriptor(String name, Collection<MethodDescriptor<?, ?>> methods)63 public ServiceDescriptor(String name, Collection<MethodDescriptor<?, ?>> methods) { 64 this(newBuilder(name).addAllMethods(checkNotNull(methods, "methods"))); 65 } 66 ServiceDescriptor(Builder b)67 private ServiceDescriptor(Builder b) { 68 this.name = b.name; 69 validateMethodNames(name, b.methods); 70 this.methods = Collections.unmodifiableList(new ArrayList<MethodDescriptor<?, ?>>(b.methods)); 71 this.schemaDescriptor = b.schemaDescriptor; 72 } 73 74 /** 75 * Simple name of the service. It is not an absolute path. 76 * 77 * @since 1.0.0 78 */ getName()79 public String getName() { 80 return name; 81 } 82 83 /** 84 * A collection of {@link MethodDescriptor} instances describing the methods exposed by the 85 * service. 86 * 87 * @since 1.0.0 88 */ getMethods()89 public Collection<MethodDescriptor<?, ?>> getMethods() { 90 return methods; 91 } 92 93 /** 94 * Returns the schema descriptor for this service. A schema descriptor is an object that is not 95 * used by gRPC core but includes information related to the service. The type of the object 96 * is specific to the consumer, so both the code setting the schema descriptor and the code 97 * calling {@link #getSchemaDescriptor()} must coordinate. For example, protobuf generated code 98 * sets this value, in order to be consumed by the server reflection service. See also: 99 * {@code io.grpc.protobuf.ProtoFileDescriptorSupplier}. 100 * 101 * @since 1.1.0 102 */ 103 @Nullable 104 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222") getSchemaDescriptor()105 public Object getSchemaDescriptor() { 106 return schemaDescriptor; 107 } 108 validateMethodNames(String serviceName, Collection<MethodDescriptor<?, ?>> methods)109 static void validateMethodNames(String serviceName, Collection<MethodDescriptor<?, ?>> methods) { 110 Set<String> allNames = new HashSet<String>(methods.size()); 111 for (MethodDescriptor<?, ?> method : methods) { 112 checkNotNull(method, "method"); 113 String methodServiceName = 114 MethodDescriptor.extractFullServiceName(method.getFullMethodName()); 115 checkArgument(serviceName.equals(methodServiceName), 116 "service names %s != %s", methodServiceName, serviceName); 117 checkArgument(allNames.add(method.getFullMethodName()), 118 "duplicate name %s", method.getFullMethodName()); 119 } 120 } 121 122 /** 123 * Creates a new builder for a {@link ServiceDescriptor}. 124 * 125 * @since 1.1.0 126 */ newBuilder(String name)127 public static Builder newBuilder(String name) { 128 return new Builder(name); 129 } 130 131 /** 132 * A builder for a {@link ServiceDescriptor}. 133 * 134 * @since 1.1.0 135 */ 136 public static final class Builder { Builder(String name)137 private Builder(String name) { 138 setName(name); 139 } 140 141 private String name; 142 private List<MethodDescriptor<?, ?>> methods = new ArrayList<MethodDescriptor<?, ?>>(); 143 private Object schemaDescriptor; 144 145 /** 146 * Sets the name. This should be non-{@code null}. 147 * 148 * @param name The name of the service. 149 * @return this builder. 150 * @since 1.1.0 151 */ 152 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2666") setName(String name)153 public Builder setName(String name) { 154 this.name = checkNotNull(name, "name"); 155 return this; 156 } 157 158 /** 159 * Adds a method to this service. This should be non-{@code null}. 160 * 161 * @param method the method to add to the descriptor. 162 * @return this builder. 163 * @since 1.1.0 164 */ addMethod(MethodDescriptor<?, ?> method)165 public Builder addMethod(MethodDescriptor<?, ?> method) { 166 methods.add(checkNotNull(method, "method")); 167 return this; 168 } 169 170 /** 171 * Currently not exposed. Bulk adds methods to this builder. 172 * 173 * @param methods the methods to add. 174 * @return this builder. 175 */ addAllMethods(Collection<MethodDescriptor<?, ?>> methods)176 private Builder addAllMethods(Collection<MethodDescriptor<?, ?>> methods) { 177 this.methods.addAll(methods); 178 return this; 179 } 180 181 /** 182 * Sets the schema descriptor for this builder. A schema descriptor is an object that is not 183 * used by gRPC core but includes information related to the service. The type of the object 184 * is specific to the consumer, so both the code calling this and the code calling 185 * {@link ServiceDescriptor#getSchemaDescriptor()} must coordinate. For example, protobuf 186 * generated code sets this value, in order to be consumed by the server reflection service. 187 * 188 * @param schemaDescriptor an object that describes the service structure. Should be immutable. 189 * @return this builder. 190 * @since 1.1.0 191 */ setSchemaDescriptor(@ullable Object schemaDescriptor)192 public Builder setSchemaDescriptor(@Nullable Object schemaDescriptor) { 193 this.schemaDescriptor = schemaDescriptor; 194 return this; 195 } 196 197 /** 198 * Constructs a new {@link ServiceDescriptor}. {@link #setName} should have been called with a 199 * non-{@code null} value before calling this. 200 * 201 * @return a new ServiceDescriptor 202 * @since 1.1.0 203 */ build()204 public ServiceDescriptor build() { 205 return new ServiceDescriptor(this); 206 } 207 } 208 209 @Override toString()210 public String toString() { 211 return MoreObjects.toStringHelper(this) 212 .add("name", name) 213 .add("schemaDescriptor", schemaDescriptor) 214 .add("methods", methods) 215 .omitNullValues() 216 .toString(); 217 } 218 }