1 #region Copyright notice and license 2 // Copyright 2015 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 #endregion 16 17 using System.Collections.Generic; 18 using Grpc.Core.Utils; 19 using Google.Protobuf.Reflection; 20 21 namespace Grpc.Reflection 22 { 23 /// <summary>Registry of protobuf symbols</summary> 24 public class SymbolRegistry 25 { 26 private readonly Dictionary<string, FileDescriptor> filesByName; 27 private readonly Dictionary<string, FileDescriptor> filesBySymbol; 28 SymbolRegistry(Dictionary<string, FileDescriptor> filesByName, Dictionary<string, FileDescriptor> filesBySymbol)29 private SymbolRegistry(Dictionary<string, FileDescriptor> filesByName, Dictionary<string, FileDescriptor> filesBySymbol) 30 { 31 this.filesByName = new Dictionary<string, FileDescriptor>(filesByName); 32 this.filesBySymbol = new Dictionary<string, FileDescriptor>(filesBySymbol); 33 } 34 35 /// <summary> 36 /// Creates a symbol registry from the specified set of file descriptors. 37 /// </summary> 38 /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param> 39 /// <returns>A symbol registry for the given files.</returns> FromFiles(IEnumerable<FileDescriptor> fileDescriptors)40 public static SymbolRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors) 41 { 42 GrpcPreconditions.CheckNotNull(fileDescriptors); 43 var builder = new Builder(); 44 foreach (var file in fileDescriptors) 45 { 46 builder.AddFile(file); 47 } 48 return builder.Build(); 49 } 50 51 /// <summary> 52 /// Gets file descriptor for given file name (including package path). Returns <c>null</c> if not found. 53 /// </summary> FileByName(string filename)54 public FileDescriptor FileByName(string filename) 55 { 56 FileDescriptor file; 57 filesByName.TryGetValue(filename, out file); 58 return file; 59 } 60 61 /// <summary> 62 /// Gets file descriptor that contains definition of given symbol full name (including package path). Returns <c>null</c> if not found. 63 /// </summary> FileContainingSymbol(string symbol)64 public FileDescriptor FileContainingSymbol(string symbol) 65 { 66 FileDescriptor file; 67 filesBySymbol.TryGetValue(symbol, out file); 68 return file; 69 } 70 71 /// <summary> 72 /// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls. 73 /// </summary> 74 private class Builder 75 { 76 private readonly Dictionary<string, FileDescriptor> filesByName; 77 private readonly Dictionary<string, FileDescriptor> filesBySymbol; 78 79 Builder()80 internal Builder() 81 { 82 filesByName = new Dictionary<string, FileDescriptor>(); 83 filesBySymbol = new Dictionary<string, FileDescriptor>(); 84 } 85 AddFile(FileDescriptor fileDescriptor)86 internal void AddFile(FileDescriptor fileDescriptor) 87 { 88 if (filesByName.ContainsKey(fileDescriptor.Name)) 89 { 90 return; 91 } 92 filesByName.Add(fileDescriptor.Name, fileDescriptor); 93 94 foreach (var dependency in fileDescriptor.Dependencies) 95 { 96 AddFile(dependency); 97 } 98 foreach (var enumeration in fileDescriptor.EnumTypes) 99 { 100 AddEnum(enumeration); 101 } 102 foreach (var message in fileDescriptor.MessageTypes) 103 { 104 AddMessage(message); 105 } 106 foreach (var service in fileDescriptor.Services) 107 { 108 AddService(service); 109 } 110 } 111 AddEnum(EnumDescriptor enumDescriptor)112 private void AddEnum(EnumDescriptor enumDescriptor) 113 { 114 filesBySymbol[enumDescriptor.FullName] = enumDescriptor.File; 115 } 116 AddMessage(MessageDescriptor messageDescriptor)117 private void AddMessage(MessageDescriptor messageDescriptor) 118 { 119 foreach (var nestedEnum in messageDescriptor.EnumTypes) 120 { 121 AddEnum(nestedEnum); 122 } 123 foreach (var nestedType in messageDescriptor.NestedTypes) 124 { 125 AddMessage(nestedType); 126 } 127 filesBySymbol[messageDescriptor.FullName] = messageDescriptor.File; 128 } 129 AddService(ServiceDescriptor serviceDescriptor)130 private void AddService(ServiceDescriptor serviceDescriptor) 131 { 132 foreach (var method in serviceDescriptor.Methods) 133 { 134 filesBySymbol[method.FullName] = method.File; 135 } 136 filesBySymbol[serviceDescriptor.FullName] = serviceDescriptor.File; 137 } 138 Build()139 internal SymbolRegistry Build() 140 { 141 return new SymbolRegistry(filesByName, filesBySymbol); 142 } 143 } 144 } 145 } 146