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<>(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<>(methods.size()); 111 for (MethodDescriptor<?, ?> method : methods) { 112 checkNotNull(method, "method"); 113 String methodServiceName = method.getServiceName(); 114 checkArgument(serviceName.equals(methodServiceName), 115 "service names %s != %s", methodServiceName, serviceName); 116 checkArgument(allNames.add(method.getFullMethodName()), 117 "duplicate name %s", method.getFullMethodName()); 118 } 119 } 120 121 /** 122 * Creates a new builder for a {@link ServiceDescriptor}. 123 * 124 * @since 1.1.0 125 */ newBuilder(String name)126 public static Builder newBuilder(String name) { 127 return new Builder(name); 128 } 129 130 /** 131 * A builder for a {@link ServiceDescriptor}. 132 * 133 * @since 1.1.0 134 */ 135 public static final class Builder { Builder(String name)136 private Builder(String name) { 137 setName(name); 138 } 139 140 private String name; 141 private List<MethodDescriptor<?, ?>> methods = new ArrayList<>(); 142 private Object schemaDescriptor; 143 144 /** 145 * Sets the name. This should be non-{@code null}. 146 * 147 * @param name The name of the service. 148 * @return this builder. 149 * @since 1.1.0 150 */ 151 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2666") setName(String name)152 public Builder setName(String name) { 153 this.name = checkNotNull(name, "name"); 154 return this; 155 } 156 157 /** 158 * Adds a method to this service. This should be non-{@code null}. 159 * 160 * @param method the method to add to the descriptor. 161 * @return this builder. 162 * @since 1.1.0 163 */ addMethod(MethodDescriptor<?, ?> method)164 public Builder addMethod(MethodDescriptor<?, ?> method) { 165 methods.add(checkNotNull(method, "method")); 166 return this; 167 } 168 169 /** 170 * Currently not exposed. Bulk adds methods to this builder. 171 * 172 * @param methods the methods to add. 173 * @return this builder. 174 */ addAllMethods(Collection<MethodDescriptor<?, ?>> methods)175 private Builder addAllMethods(Collection<MethodDescriptor<?, ?>> methods) { 176 this.methods.addAll(methods); 177 return this; 178 } 179 180 /** 181 * Sets the schema descriptor for this builder. A schema descriptor is an object that is not 182 * used by gRPC core but includes information related to the service. The type of the object 183 * is specific to the consumer, so both the code calling this and the code calling 184 * {@link ServiceDescriptor#getSchemaDescriptor()} must coordinate. For example, protobuf 185 * generated code sets this value, in order to be consumed by the server reflection service. 186 * 187 * @param schemaDescriptor an object that describes the service structure. Should be immutable. 188 * @return this builder. 189 * @since 1.1.0 190 */ setSchemaDescriptor(@ullable Object schemaDescriptor)191 public Builder setSchemaDescriptor(@Nullable Object schemaDescriptor) { 192 this.schemaDescriptor = schemaDescriptor; 193 return this; 194 } 195 196 /** 197 * Constructs a new {@link ServiceDescriptor}. {@link #setName} should have been called with a 198 * non-{@code null} value before calling this. 199 * 200 * @return a new ServiceDescriptor 201 * @since 1.1.0 202 */ build()203 public ServiceDescriptor build() { 204 return new ServiceDescriptor(this); 205 } 206 } 207 208 @Override toString()209 public String toString() { 210 return MoreObjects.toStringHelper(this) 211 .add("name", name) 212 .add("schemaDescriptor", schemaDescriptor) 213 .add("methods", methods) 214 .omitNullValues() 215 .toString(); 216 } 217 }