下面列出了com.google.protobuf.Descriptors.DescriptorValidationException#com.google.protobuf.Descriptors.FileDescriptor 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private ServerReflectionResponse createServerReflectionResponse(
ServerReflectionRequest request, FileDescriptor fd) {
FileDescriptorResponse.Builder fdRBuilder = FileDescriptorResponse.newBuilder();
Set<String> seenFiles = new HashSet<String>();
Queue<FileDescriptor> frontier = new ArrayDeque<FileDescriptor>();
seenFiles.add(fd.getName());
frontier.add(fd);
while (!frontier.isEmpty()) {
FileDescriptor nextFd = frontier.remove();
fdRBuilder.addFileDescriptorProto(nextFd.toProto().toByteString());
for (FileDescriptor dependencyFd : nextFd.getDependencies()) {
if (!seenFiles.contains(dependencyFd.getName())) {
seenFiles.add(dependencyFd.getName());
frontier.add(dependencyFd);
}
}
}
return ServerReflectionResponse.newBuilder()
.setValidHost(request.getHost())
.setOriginalRequest(request)
.setFileDescriptorResponse(fdRBuilder)
.build();
}
private void processService(ServiceDescriptor service, FileDescriptor fd) {
String serviceName = service.getFullName();
checkState(
!fileDescriptorsBySymbol.containsKey(serviceName),
"Service already defined: %s",
serviceName);
fileDescriptorsBySymbol.put(serviceName, fd);
for (MethodDescriptor method : service.getMethods()) {
String methodName = method.getFullName();
checkState(
!fileDescriptorsBySymbol.containsKey(methodName),
"Method already defined: %s",
methodName);
fileDescriptorsBySymbol.put(methodName, fd);
}
}
/**
* Creates a resolver which searches the supplied {@link FileDescriptorSet}.
*/
public static ServiceResolver fromFileDescriptorSet(FileDescriptorSet descriptorSet) {
ImmutableMap<String, FileDescriptorProto> descriptorProtoIndex =
computeDescriptorProtoIndex(descriptorSet);
Map<String, FileDescriptor> descriptorCache = new HashMap<>();
ImmutableList.Builder<FileDescriptor> result = ImmutableList.builder();
for (FileDescriptorProto descriptorProto : descriptorSet.getFileList()) {
try {
result.add(descriptorFromProto(descriptorProto, descriptorProtoIndex, descriptorCache));
} catch (DescriptorValidationException e) {
logger.warn("Skipped descriptor " + descriptorProto.getName() + " due to error", e);
}
}
return new ServiceResolver(result.build());
}
/** Creates a resolver which searches the supplied {@link FileDescriptorSet}. */
public static ServiceResolver fromFileDescriptorSet(FileDescriptorSet descriptorSet) {
ImmutableMap<String, FileDescriptorProto> descriptorProtoIndex =
computeDescriptorProtoIndex(descriptorSet);
Map<String, FileDescriptor> descriptorCache = new HashMap<>();
ImmutableList.Builder<FileDescriptor> result = ImmutableList.builder();
for (FileDescriptorProto descriptorProto : descriptorSet.getFileList()) {
try {
result.add(descriptorFromProto(descriptorProto, descriptorProtoIndex, descriptorCache));
} catch (DescriptorValidationException e) {
logger.warn("Skipped descriptor " + descriptorProto.getName() + " due to error", e);
continue;
}
}
return new ServiceResolver(result.build());
}
private void processService(ServiceDescriptor service, FileDescriptor fd) {
String serviceName = service.getFullName();
checkState(
!fileDescriptorsBySymbol.containsKey(serviceName),
"Service already defined: %s",
serviceName);
fileDescriptorsBySymbol.put(serviceName, fd);
for (MethodDescriptor method : service.getMethods()) {
String methodName = method.getFullName();
checkState(
!fileDescriptorsBySymbol.containsKey(methodName),
"Method already defined: %s",
methodName);
fileDescriptorsBySymbol.put(methodName, fd);
}
}
/**
* Recursively constructs file descriptors for all dependencies of the supplied proto and returns
* a {@link FileDescriptor} for the supplied proto itself. For maximal efficiency, reuse the
* descriptorCache argument across calls.
*/
private static FileDescriptor descriptorFromProto(
FileDescriptorProto descriptorProto,
ImmutableMap<String, FileDescriptorProto> descriptorProtoIndex,
Map<String, FileDescriptor> descriptorCache) throws DescriptorValidationException {
// First, check the cache.
String descritorName = descriptorProto.getName();
if (descriptorCache.containsKey(descritorName)) {
return descriptorCache.get(descritorName);
}
// Then, fetch all the required dependencies recursively.
ImmutableList.Builder<FileDescriptor> dependencies = ImmutableList.builder();
for (String dependencyName : descriptorProto.getDependencyList()) {
if (!descriptorProtoIndex.containsKey(dependencyName)) {
throw new IllegalArgumentException("Could not find dependency: " + dependencyName);
}
FileDescriptorProto dependencyProto = descriptorProtoIndex.get(dependencyName);
dependencies.add(descriptorFromProto(dependencyProto, descriptorProtoIndex, descriptorCache));
}
// Finally, construct the actual descriptor.
FileDescriptor[] empty = new FileDescriptor[0];
return FileDescriptor.buildFrom(descriptorProto, dependencies.build().toArray(empty));
}
@Test
public void swapUnionFields() {
FileDescriptor updatedDescriptor = mutateFile(fileBuilder ->
fileBuilder.getMessageTypeBuilderList().forEach(message -> {
if (message.getName().equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME)) {
message.getFieldBuilderList().forEach(field -> {
if (field.getNumber() == 1) {
field.setNumber(2);
} else {
field.setNumber(1);
}
});
}
})
);
// The two record types do not have the same form, so swapping them should fail.
// However, the exact way they fail isn't super important.
RecordMetaData metaData1 = RecordMetaData.build(TestRecords1Proto.getDescriptor());
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedDescriptor);
assertInvalid("", metaData1, metaData2);
}
public void testInvalidPublicDependency() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("foo.proto") .build();
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("boo.proto")
.addDependency("foo.proto")
.addPublicDependency(1) // Error, should be 0.
.build();
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
new FileDescriptor[0]);
try {
Descriptors.FileDescriptor.buildFrom(barProto,
new FileDescriptor[] {fooFile});
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
assertTrue(
e.getMessage().indexOf("Invalid public dependency index.") != -1);
}
}
@Test
public void swapRecordTypes() {
FileDescriptor updatedFile = mutateFile(fileBuilder -> {
// Update the field of the union descriptor.
fileBuilder.getMessageTypeBuilderList().forEach(messageType -> {
if (messageType.getName().equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME)) {
messageType.getFieldBuilderList().forEach(field -> {
if (field.getName().equals("_MyOtherRecord")) {
field.setTypeName("MySimpleRecord");
}
if (field.getName().equals("_MySimpleRecord")) {
field.setTypeName("MyOtherRecord");
}
});
}
});
});
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecords1Proto.getDescriptor());
metaDataBuilder.addIndex("MyOtherRecord", "num_value_3_indexed");
RecordMetaData metaData1 = metaDataBuilder.getRecordMetaData();
// Swap is noticed as the two records are not of compatible forms
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedFile);
assertInvalid("", metaData1, metaData2);
}
@Test
public void dropField() {
FileDescriptor updatedFile = mutateFile(fileBuilder ->
fileBuilder.getMessageTypeBuilderList().forEach(message -> {
if (message.getName().equals("MySimpleRecord")) {
int fieldNumValue2Index = 0;
while (!message.getField(fieldNumValue2Index).getName().equals("num_value_2")) {
fieldNumValue2Index++;
}
message.removeField(fieldNumValue2Index);
}
})
);
assertInvalid("field removed from message descriptor", TestRecords1Proto.getDescriptor(), updatedFile);
RecordMetaData metaData1 = RecordMetaData.build(TestRecords1Proto.getDescriptor());
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedFile);
assertInvalid("field removed from message descriptor", metaData1, metaData2);
}
@Test
public void renameField() {
FileDescriptor updatedFile = mutateField("MySimpleRecord", "num_value_2",
field -> field.setName("num_value_too"));
assertInvalid("field renamed", TestRecords1Proto.getDescriptor(), updatedFile);
RecordMetaData metaData1 = RecordMetaData.build(TestRecords1Proto.getDescriptor());
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedFile);
assertInvalid("field renamed", metaData1, metaData2);
// This updates both the field name and its indexes which means that this is actually okay.
updatedFile = mutateField("MySimpleRecord", "str_value_indexed",
field -> field.setName("str_value_still_indexed"));
RecordMetaData metaData3 = replaceRecordsDescriptor(metaData1, updatedFile, protoBuilder ->
protoBuilder.getIndexesBuilderList().forEach(index -> {
if (index.getName().equals("MySimpleRecord$str_value_indexed")) {
index.setRootExpression(Key.Expressions.field("str_value_still_indexed").toKeyExpression());
}
})
);
assertInvalid("field renamed", metaData1, metaData3);
}
private ServerReflectionResponse createServerReflectionResponse(
ServerReflectionRequest request, FileDescriptor fd) {
FileDescriptorResponse.Builder fdRBuilder = FileDescriptorResponse.newBuilder();
Set<String> seenFiles = new HashSet<>();
Queue<FileDescriptor> frontier = new ArrayDeque<>();
seenFiles.add(fd.getName());
frontier.add(fd);
while (!frontier.isEmpty()) {
FileDescriptor nextFd = frontier.remove();
fdRBuilder.addFileDescriptorProto(nextFd.toProto().toByteString());
for (FileDescriptor dependencyFd : nextFd.getDependencies()) {
if (!seenFiles.contains(dependencyFd.getName())) {
seenFiles.add(dependencyFd.getName());
frontier.add(dependencyFd);
}
}
}
return ServerReflectionResponse.newBuilder()
.setValidHost(request.getHost())
.setOriginalRequest(request)
.setFileDescriptorResponse(fdRBuilder)
.build();
}
@Test
public void nestedTypeChangesName() {
FileDescriptor updatedFile = mutateFile(TestRecordsWithHeaderProto.getDescriptor(), fileBuilder ->
fileBuilder.getMessageTypeBuilderList().forEach(message -> {
if (message.getName().equals("HeaderRecord")) {
message.setName("Header");
} else if (message.getName().equals("MyRecord")) {
message.getFieldBuilderList().forEach(field -> {
if (field.getName().equals("header")) {
field.setTypeName("." + fileBuilder.getPackage() + ".Header");
}
});
}
})
);
assertThat(updatedFile.getMessageTypes().stream().map(Descriptor::getName).collect(Collectors.toList()), containsInAnyOrder("MyRecord", RecordMetaDataBuilder.DEFAULT_UNION_NAME, "Header"));
validator.validateUnion(TestRecordsWithHeaderProto.RecordTypeUnion.getDescriptor(), updatedFile.findMessageTypeByName(RecordMetaDataBuilder.DEFAULT_UNION_NAME));
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecordsWithHeaderProto.getDescriptor());
metaDataBuilder.getRecordType("MyRecord").setPrimaryKey(Key.Expressions.field("header").nest(Key.Expressions.concatenateFields("path", "rec_no")));
RecordMetaData metaData1 = metaDataBuilder.getRecordMetaData();
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedFile);
validator.validate(metaData1, metaData2);
}
@Test
public void dropType() {
FileDescriptor updatedFile = mutateFile(fileBuilder ->
fileBuilder.getMessageTypeBuilderList().forEach(message -> {
if (message.getName().equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME)) {
message.removeField(1);
}
})
);
assertInvalid("record type removed from union", TestRecords1Proto.getDescriptor(), updatedFile);
RecordMetaData metaData1 = RecordMetaData.build(TestRecords1Proto.getDescriptor());
MetaDataException e = assertThrows(MetaDataException.class, () -> replaceRecordsDescriptor(metaData1, updatedFile));
assertThat(e.getMessage(), containsString("Unknown record type MyOtherRecord"));
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, updatedFile, protoBuilder -> {
protoBuilder.removeRecordTypes(1);
final List<RecordMetaDataProto.Index> indexes = protoBuilder.getIndexesList().stream()
.filter(index -> !index.getRecordTypeList().contains("MyOtherRecord"))
.collect(Collectors.toList());
protoBuilder.clearIndexes().addAllIndexes(indexes);
});
assertInvalid("record type removed from union", metaData1, metaData2);
}
/**
* Creates a resolver which searches the supplied {@link FileDescriptorSet}.
*/
public static ServiceResolver fromFileDescriptorSet(FileDescriptorSet descriptorSet) {
ImmutableMap<String, FileDescriptorProto> descriptorProtoIndex =
computeDescriptorProtoIndex(descriptorSet);
Map<String, FileDescriptor> descriptorCache = new HashMap<>();
ImmutableList.Builder<FileDescriptor> result = ImmutableList.builder();
for (FileDescriptorProto descriptorProto : descriptorSet.getFileList()) {
try {
result.add(descriptorFromProto(descriptorProto, descriptorProtoIndex, descriptorCache));
} catch (DescriptorValidationException e) {
logger.warn("Skipped descriptor " + descriptorProto.getName() + " due to error", e);
}
}
return new ServiceResolver(result.build());
}
/**
* Recursively constructs file descriptors for all dependencies of the supplied proto and returns
* a {@link FileDescriptor} for the supplied proto itself. For maximal efficiency, reuse the
* descriptorCache argument across calls.
*/
private static FileDescriptor descriptorFromProto(
FileDescriptorProto descriptorProto,
ImmutableMap<String, FileDescriptorProto> descriptorProtoIndex,
Map<String, FileDescriptor> descriptorCache) throws DescriptorValidationException {
// First, check the cache.
String descriptorName = descriptorProto.getName();
if (descriptorCache.containsKey(descriptorName)) {
return descriptorCache.get(descriptorName);
}
// Then, fetch all the required dependencies recursively.
ImmutableList.Builder<FileDescriptor> dependencies = ImmutableList.builder();
for (String dependencyName : descriptorProto.getDependencyList()) {
if (!descriptorProtoIndex.containsKey(dependencyName)) {
throw new IllegalArgumentException("Could not find dependency: " + dependencyName);
}
FileDescriptorProto dependencyProto = descriptorProtoIndex.get(dependencyName);
dependencies.add(descriptorFromProto(dependencyProto, descriptorProtoIndex, descriptorCache));
}
// Finally, construct the actual descriptor.
FileDescriptor[] empty = new FileDescriptor[0];
return FileDescriptor.buildFrom(descriptorProto, dependencies.build().toArray(empty));
}
void loadProtos(RpcApp app, String proto) {
if (isEmpty(proto)) {
log.info("no dynamic proto resource need to load");
return;
}
if (!proto.endsWith("/")) proto = proto + "/";
try {
InputStream basein = RpcMetas.class.getResourceAsStream("descriptor.proto.pb");
FileDescriptorSet baseSet = FileDescriptorSet.parseFrom(basein);
basein.close();
FileDescriptor base = FileDescriptor.buildFrom(baseSet.getFile(0), new FileDescriptor[]{});
List<String> files = getProtoFiles(proto);
for (String file : files) {
loadProtoFile(app, base, proto + file);
}
} catch (Exception e) {
log.error("load dynamic proto resource failed", e);
}
}
public GqlInputConverter build() {
HashBiMap<String, Descriptor> mapping = HashBiMap.create();
HashBiMap<String, EnumDescriptor> enumMapping = HashBiMap.create(getEnumMap(enumDescriptors));
LinkedList<Descriptor> loop = new LinkedList<>(descriptors);
Set<FileDescriptor> fileDescriptorSet = ProtoRegistry.extractDependencies(fileDescriptors);
for (FileDescriptor fileDescriptor : fileDescriptorSet) {
loop.addAll(fileDescriptor.getMessageTypes());
enumMapping.putAll(getEnumMap(fileDescriptor.getEnumTypes()));
}
while (!loop.isEmpty()) {
Descriptor descriptor = loop.pop();
if (!mapping.containsKey(descriptor.getFullName())) {
mapping.put(getReferenceName(descriptor), descriptor);
loop.addAll(descriptor.getNestedTypes());
enumMapping.putAll(getEnumMap(descriptor.getEnumTypes()));
}
}
return new GqlInputConverter(
ImmutableBiMap.copyOf(mapping), ImmutableBiMap.copyOf(enumMapping));
}
private FileDescriptor asFileDescriptor(Class<?> clazz) {
try {
Method method = clazz.getMethod("getDescriptor");
return (FileDescriptor) method.invoke(null);
} catch (Exception e) {
return null;
}
}
public void testPublicDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("bar.proto")
.addMessageType(DescriptorProto.newBuilder().setName("Bar"))
.build();
FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
.setName("forward.proto")
.addDependency("bar.proto")
.addPublicDependency(0)
.build();
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addDependency("forward.proto")
.addMessageType(DescriptorProto.newBuilder()
.setName("Foo")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar")
.setName("bar")
.setNumber(1)))
.build();
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
barProto, new FileDescriptor[0]);
FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
forwardProto, new FileDescriptor[]{barFile});
Descriptors.FileDescriptor.buildFrom(
fooProto, new FileDescriptor[] {forwardFile});
}
private void getFileByExtension(ServerReflectionRequest request) {
ExtensionRequest extensionRequest = request.getFileContainingExtension();
String type = extensionRequest.getContainingType();
int extension = extensionRequest.getExtensionNumber();
FileDescriptor fd =
serverReflectionIndex.getFileDescriptorByExtensionAndNumber(type, extension);
if (fd != null) {
serverCallStreamObserver.onNext(createServerReflectionResponse(request, fd));
} else {
sendErrorResponse(request, Status.Code.NOT_FOUND, "Extension not found.");
}
}
/**
* Used in proto1 generated code only.
*
* After enabling bridge, we can define proto2 extensions (the extended type
* is a proto2 mutable message) in a proto1 .proto file. For these extensions
* we should generate proto2 GeneratedExtensions.
*/
public static <ContainingType extends Message, Type>
GeneratedExtension<ContainingType, Type>
newFileScopedGeneratedExtension(
final Class singularType, final Message defaultInstance,
final String descriptorOuterClass, final String extensionName) {
// For extensions scoped within a file, we load the descriptor outer
// class and rely on it to get the FileDescriptor which then can be
// used to obtain the extension's FieldDescriptor.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
protected FieldDescriptor loadDescriptor() {
try {
Class clazz =
singularType.getClassLoader().loadClass(descriptorOuterClass);
FileDescriptor file =
(FileDescriptor) clazz.getField("descriptor").get(null);
return file.findExtensionByName(extensionName);
} catch (Exception e) {
throw new RuntimeException(
"Cannot load descriptors: " + descriptorOuterClass +
" is not a valid descriptor class name", e);
}
}
},
singularType,
defaultInstance,
Extension.ExtensionType.MUTABLE);
}
@Nullable
private FileDescriptor getFileDescriptorBySymbol(String symbol) {
FileDescriptor fd = immutableServicesIndex.getFileDescriptorBySymbol(symbol);
if (fd == null) {
fd = mutableServicesIndex.getFileDescriptorBySymbol(symbol);
}
return fd;
}
@Nullable
private FileDescriptor getFileDescriptorByExtensionAndNumber(String type, int extension) {
FileDescriptor fd =
immutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension);
if (fd == null) {
fd = mutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension);
}
return fd;
}
FileDescriptorIndex(List<ServerServiceDefinition> services) {
Queue<FileDescriptor> fileDescriptorsToProcess = new ArrayDeque<FileDescriptor>();
Set<String> seenFiles = new HashSet<String>();
for (ServerServiceDefinition service : services) {
io.grpc.ServiceDescriptor serviceDescriptor = service.getServiceDescriptor();
if (serviceDescriptor.getSchemaDescriptor() instanceof ProtoFileDescriptorSupplier) {
FileDescriptor fileDescriptor =
((ProtoFileDescriptorSupplier) serviceDescriptor.getSchemaDescriptor())
.getFileDescriptor();
String serviceName = serviceDescriptor.getName();
checkState(
!serviceNames.contains(serviceName), "Service already defined: %s", serviceName);
serviceFileDescriptors.add(fileDescriptor);
serviceNames.add(serviceName);
if (!seenFiles.contains(fileDescriptor.getName())) {
seenFiles.add(fileDescriptor.getName());
fileDescriptorsToProcess.add(fileDescriptor);
}
}
}
while (!fileDescriptorsToProcess.isEmpty()) {
FileDescriptor currentFd = fileDescriptorsToProcess.remove();
processFileDescriptor(currentFd);
for (FileDescriptor dependencyFd : currentFd.getDependencies()) {
if (!seenFiles.contains(dependencyFd.getName())) {
seenFiles.add(dependencyFd.getName());
fileDescriptorsToProcess.add(dependencyFd);
}
}
}
}
protected ProtobufRowDataConverter converter(Group g) throws Exception {
AISToProtobuf a2p = new AISToProtobuf(ProtobufRowFormat.Type.GROUP_MESSAGE);
a2p.addGroup(g);
FileDescriptorSet set = a2p.build();
if (false) {
new ProtobufDecompiler((Appendable)System.out).decompile(set);
}
FileDescriptor gdesc = FileDescriptor.buildFrom(set.getFile(0),
ProtobufStorageDescriptionHelper.DEPENDENCIES);
return ProtobufRowDataConverter.forGroup(g, gdesc);
}
@Nullable
private FileDescriptor getFileDescriptorByExtensionAndNumber(String type, int number) {
if (fileDescriptorsByExtensionAndNumber.containsKey(type)) {
return fileDescriptorsByExtensionAndNumber.get(type).get(number);
}
return null;
}
private void processFileDescriptor(FileDescriptor fd) {
String fdName = fd.getName();
checkState(!fileDescriptorsByName.containsKey(fdName), "File name already used: %s", fdName);
fileDescriptorsByName.put(fdName, fd);
for (ServiceDescriptor service : fd.getServices()) {
processService(service, fd);
}
for (Descriptor type : fd.getMessageTypes()) {
processType(type, fd);
}
for (FieldDescriptor extension : fd.getExtensions()) {
processExtension(extension, fd);
}
}
@Nullable
private FileDescriptor getFileDescriptorByExtensionAndNumber(String type, int extension) {
FileDescriptor fd =
immutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension);
if (fd == null) {
fd = mutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension);
}
return fd;
}
private void processExtension(FieldDescriptor extension, FileDescriptor fd) {
String extensionName = extension.getContainingType().getFullName();
int extensionNumber = extension.getNumber();
if (!fileDescriptorsByExtensionAndNumber.containsKey(extensionName)) {
fileDescriptorsByExtensionAndNumber.put(
extensionName, new HashMap<Integer, FileDescriptor>());
}
checkState(
!fileDescriptorsByExtensionAndNumber.get(extensionName).containsKey(extensionNumber),
"Extension name and number already defined: %s, %s",
extensionName,
extensionNumber);
fileDescriptorsByExtensionAndNumber.get(extensionName).put(extensionNumber, fd);
}