- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / main / java / com / google / protobuf / Descriptors.java
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 package com.google.protobuf;
32
33 import com.google.protobuf.DescriptorProtos.*;
34
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.io.UnsupportedEncodingException;
43
44 /**
45  * Contains a collection of classes which describe protocol message types.
46  *
47  * Every message type has a {@link Descriptor}, which lists all
48  * its fields and other information about a type.  You can get a message
49  * type's descriptor by calling {@code MessageType.getDescriptor()}, or
50  * (given a message object of the type) {@code message.getDescriptorForType()}.
51  * Furthermore, each message is associated with a {@link FileDescriptor} for
52  * a relevant {@code .proto} file. You can obtain it by calling
53  * {@code Descriptor.getFile()}. A {@link FileDescriptor} contains descriptors
54  * for all the messages defined in that file, and file descriptors for all the
55  * imported {@code .proto} files.
56  *
57  * Descriptors are built from DescriptorProtos, as defined in
58  * {@code google/protobuf/descriptor.proto}.
59  *
60  * @author kenton@google.com Kenton Varda
61  */
62 public final class Descriptors {
63   /**
64    * Describes a {@code .proto} file, including everything defined within.
65    * That includes, in particular, descriptors for all the messages and
66    * file descriptors for all other imported {@code .proto} files
67    * (dependencies).
68    */
69   public static final class FileDescriptor {
70     /** Convert the descriptor to its protocol message representation. */
71     public FileDescriptorProto toProto() { return proto; }
72
73     /** Get the file name. */
74     public String getName() { return proto.getName(); }
75
76     /**
77      * Get the proto package name.  This is the package name given by the
78      * {@code package} statement in the {@code .proto} file, which differs
79      * from the Java package.
80      */
81     public String getPackage() { return proto.getPackage(); }
82
83     /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
84     public FileOptions getOptions() { return proto.getOptions(); }
85
86     /** Get a list of top-level message types declared in this file. */
87     public List<Descriptor> getMessageTypes() {
88       return Collections.unmodifiableList(Arrays.asList(messageTypes));
89     }
90
91     /** Get a list of top-level enum types declared in this file. */
92     public List<EnumDescriptor> getEnumTypes() {
93       return Collections.unmodifiableList(Arrays.asList(enumTypes));
94     }
95
96     /** Get a list of top-level services declared in this file. */
97     public List<ServiceDescriptor> getServices() {
98       return Collections.unmodifiableList(Arrays.asList(services));
99     }
100
101     /** Get a list of top-level extensions declared in this file. */
102     public List<FieldDescriptor> getExtensions() {
103       return Collections.unmodifiableList(Arrays.asList(extensions));
104     }
105
106     /** Get a list of this file's dependencies (imports). */
107     public List<FileDescriptor> getDependencies() {
108       return Collections.unmodifiableList(Arrays.asList(dependencies));
109     }
110
111     /** Get a list of this file's public dependencies (public imports). */
112     public List<FileDescriptor> getPublicDependencies() {
113       return Collections.unmodifiableList(Arrays.asList(publicDependencies));
114     }
115
116     /**
117      * Find a message type in the file by name.  Does not find nested types.
118      *
119      * @param name The unqualified type name to look for.
120      * @return The message type's descriptor, or {@code null} if not found.
121      */
122     public Descriptor findMessageTypeByName(String name) {
123       // Don't allow looking up nested types.  This will make optimization
124       // easier later.
125       if (name.indexOf('.') != -1) {
126         return null;
127       }
128       if (getPackage().length() > 0) {
129         name = getPackage() + '.' + name;
130       }
131       final GenericDescriptor result = pool.findSymbol(name);
132       if (result != null && result instanceof Descriptor &&
133           result.getFile() == this) {
134         return (Descriptor)result;
135       } else {
136         return null;
137       }
138     }
139
140     /**
141      * Find an enum type in the file by name.  Does not find nested types.
142      *
143      * @param name The unqualified type name to look for.
144      * @return The enum type's descriptor, or {@code null} if not found.
145      */
146     public EnumDescriptor findEnumTypeByName(String name) {
147       // Don't allow looking up nested types.  This will make optimization
148       // easier later.
149       if (name.indexOf('.') != -1) {
150         return null;
151       }
152       if (getPackage().length() > 0) {
153         name = getPackage() + '.' + name;
154       }
155       final GenericDescriptor result = pool.findSymbol(name);
156       if (result != null && result instanceof EnumDescriptor &&
157           result.getFile() == this) {
158         return (EnumDescriptor)result;
159       } else {
160         return null;
161       }
162     }
163
164     /**
165      * Find a service type in the file by name.
166      *
167      * @param name The unqualified type name to look for.
168      * @return The service type's descriptor, or {@code null} if not found.
169      */
170     public ServiceDescriptor findServiceByName(String name) {
171       // Don't allow looking up nested types.  This will make optimization
172       // easier later.
173       if (name.indexOf('.') != -1) {
174         return null;
175       }
176       if (getPackage().length() > 0) {
177         name = getPackage() + '.' + name;
178       }
179       final GenericDescriptor result = pool.findSymbol(name);
180       if (result != null && result instanceof ServiceDescriptor &&
181           result.getFile() == this) {
182         return (ServiceDescriptor)result;
183       } else {
184         return null;
185       }
186     }
187
188     /**
189      * Find an extension in the file by name.  Does not find extensions nested
190      * inside message types.
191      *
192      * @param name The unqualified extension name to look for.
193      * @return The extension's descriptor, or {@code null} if not found.
194      */
195     public FieldDescriptor findExtensionByName(String name) {
196       if (name.indexOf('.') != -1) {
197         return null;
198       }
199       if (getPackage().length() > 0) {
200         name = getPackage() + '.' + name;
201       }
202       final GenericDescriptor result = pool.findSymbol(name);
203       if (result != null && result instanceof FieldDescriptor &&
204           result.getFile() == this) {
205         return (FieldDescriptor)result;
206       } else {
207         return null;
208       }
209     }
210
211     /**
212      * Construct a {@code FileDescriptor}.
213      *
214      * @param proto The protocol message form of the FileDescriptor.
215      * @param dependencies {@code FileDescriptor}s corresponding to all of
216      *                     the file's dependencies, in the exact order listed
217      *                     in {@code proto}.
218      * @throws DescriptorValidationException {@code proto} is not a valid
219      *           descriptor.  This can occur for a number of reasons, e.g.
220      *           because a field has an undefined type or because two messages
221      *           were defined with the same name.
222      */
223     public static FileDescriptor buildFrom(final FileDescriptorProto proto,
224                                            final FileDescriptor[] dependencies)
225                                     throws DescriptorValidationException {
226       // Building descriptors involves two steps:  translating and linking.
227       // In the translation step (implemented by FileDescriptor's
228       // constructor), we build an object tree mirroring the
229       // FileDescriptorProto's tree and put all of the descriptors into the
230       // DescriptorPool's lookup tables.  In the linking step, we look up all
231       // type references in the DescriptorPool, so that, for example, a
232       // FieldDescriptor for an embedded message contains a pointer directly
233       // to the Descriptor for that message's type.  We also detect undefined
234       // types in the linking step.
235       final DescriptorPool pool = new DescriptorPool(dependencies);
236       final FileDescriptor result =
237           new FileDescriptor(proto, dependencies, pool);
238
239       if (dependencies.length != proto.getDependencyCount()) {
240         throw new DescriptorValidationException(result,
241           "Dependencies passed to FileDescriptor.buildFrom() don't match " +
242           "those listed in the FileDescriptorProto.");
243       }
244       for (int i = 0; i < proto.getDependencyCount(); i++) {
245         if (!dependencies[i].getName().equals(proto.getDependency(i))) {
246           throw new DescriptorValidationException(result,
247             "Dependencies passed to FileDescriptor.buildFrom() don't match " +
248             "those listed in the FileDescriptorProto.");
249         }
250       }
251
252       result.crossLink();
253       return result;
254     }
255
256     /**
257      * This method is to be called by generated code only.  It is equivalent
258      * to {@code buildFrom} except that the {@code FileDescriptorProto} is
259      * encoded in protocol buffer wire format.
260      */
261     public static void internalBuildGeneratedFileFrom(
262         final String[] descriptorDataParts,
263         final FileDescriptor[] dependencies,
264         final InternalDescriptorAssigner descriptorAssigner) {
265       // Hack:  We can't embed a raw byte array inside generated Java code
266       //   (at least, not efficiently), but we can embed Strings.  So, the
267       //   protocol compiler embeds the FileDescriptorProto as a giant
268       //   string literal which is passed to this function to construct the
269       //   file's FileDescriptor.  The string literal contains only 8-bit
270       //   characters, each one representing a byte of the FileDescriptorProto's
271       //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
272       //   should get the original bytes that we want.
273
274       // descriptorData may contain multiple strings in order to get around the
275       // Java 64k string literal limit.
276       StringBuilder descriptorData = new StringBuilder();
277       for (String part : descriptorDataParts) {
278         descriptorData.append(part);
279       }
280
281       final byte[] descriptorBytes;
282       try {
283         descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
284       } catch (UnsupportedEncodingException e) {
285         throw new RuntimeException(
286           "Standard encoding ISO-8859-1 not supported by JVM.", e);
287       }
288
289       FileDescriptorProto proto;
290       try {
291         proto = FileDescriptorProto.parseFrom(descriptorBytes);
292       } catch (InvalidProtocolBufferException e) {
293         throw new IllegalArgumentException(
294           "Failed to parse protocol buffer descriptor for generated code.", e);
295       }
296
297       final FileDescriptor result;
298       try {
299         result = buildFrom(proto, dependencies);
300       } catch (DescriptorValidationException e) {
301         throw new IllegalArgumentException(
302           "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
303       }
304
305       final ExtensionRegistry registry =
306           descriptorAssigner.assignDescriptors(result);
307
308       if (registry != null) {
309         // We must re-parse the proto using the registry.
310         try {
311           proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
312         } catch (InvalidProtocolBufferException e) {
313           throw new IllegalArgumentException(
314             "Failed to parse protocol buffer descriptor for generated code.",
315             e);
316         }
317
318         result.setProto(proto);
319       }
320     }
321
322     /**
323      * This class should be used by generated code only.  When calling
324      * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
325      * provides a callback implementing this interface.  The callback is called
326      * after the FileDescriptor has been constructed, in order to assign all
327      * the global variables defined in the generated code which point at parts
328      * of the FileDescriptor.  The callback returns an ExtensionRegistry which
329      * contains any extensions which might be used in the descriptor -- that
330      * is, extensions of the various "Options" messages defined in
331      * descriptor.proto.  The callback may also return null to indicate that
332      * no extensions are used in the descriptor.
333      */
334     public interface InternalDescriptorAssigner {
335       ExtensionRegistry assignDescriptors(FileDescriptor root);
336     }
337
338     private FileDescriptorProto proto;
339     private final Descriptor[] messageTypes;
340     private final EnumDescriptor[] enumTypes;
341     private final ServiceDescriptor[] services;
342     private final FieldDescriptor[] extensions;
343     private final FileDescriptor[] dependencies;
344     private final FileDescriptor[] publicDependencies;
345     private final DescriptorPool pool;
346
347     private FileDescriptor(final FileDescriptorProto proto,
348                            final FileDescriptor[] dependencies,
349                            final DescriptorPool pool)
350                     throws DescriptorValidationException {
351       this.pool = pool;
352       this.proto = proto;
353       this.dependencies = dependencies.clone();
354       this.publicDependencies =
355           new FileDescriptor[proto.getPublicDependencyCount()];
356       for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
357         int index = proto.getPublicDependency(i);
358         if (index < 0 || index >= this.dependencies.length) {
359           throw new DescriptorValidationException(this,
360               "Invalid public dependency index.");
361         }
362         this.publicDependencies[i] =
363             this.dependencies[proto.getPublicDependency(i)];
364       }
365
366       pool.addPackage(getPackage(), this);
367
368       messageTypes = new Descriptor[proto.getMessageTypeCount()];
369       for (int i = 0; i < proto.getMessageTypeCount(); i++) {
370         messageTypes[i] =
371           new Descriptor(proto.getMessageType(i), this, null, i);
372       }
373
374       enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
375       for (int i = 0; i < proto.getEnumTypeCount(); i++) {
376         enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
377       }
378
379       services = new ServiceDescriptor[proto.getServiceCount()];
380       for (int i = 0; i < proto.getServiceCount(); i++) {
381         services[i] = new ServiceDescriptor(proto.getService(i), this, i);
382       }
383
384       extensions = new FieldDescriptor[proto.getExtensionCount()];
385       for (int i = 0; i < proto.getExtensionCount(); i++) {
386         extensions[i] = new FieldDescriptor(
387           proto.getExtension(i), this, null, i, true);
388       }
389     }
390
391     /** Look up and cross-link all field types, etc. */
392     private void crossLink() throws DescriptorValidationException {
393       for (final Descriptor messageType : messageTypes) {
394         messageType.crossLink();
395       }
396
397       for (final ServiceDescriptor service : services) {
398         service.crossLink();
399       }
400
401       for (final FieldDescriptor extension : extensions) {
402         extension.crossLink();
403       }
404     }
405
406     /**
407      * Replace our {@link FileDescriptorProto} with the given one, which is
408      * identical except that it might contain extensions that weren't present
409      * in the original.  This method is needed for bootstrapping when a file
410      * defines custom options.  The options may be defined in the file itself,
411      * so we can't actually parse them until we've constructed the descriptors,
412      * but to construct the descriptors we have to have parsed the descriptor
413      * protos.  So, we have to parse the descriptor protos a second time after
414      * constructing the descriptors.
415      */
416     private void setProto(final FileDescriptorProto proto) {
417       this.proto = proto;
418
419       for (int i = 0; i < messageTypes.length; i++) {
420         messageTypes[i].setProto(proto.getMessageType(i));
421       }
422
423       for (int i = 0; i < enumTypes.length; i++) {
424         enumTypes[i].setProto(proto.getEnumType(i));
425       }
426
427       for (int i = 0; i < services.length; i++) {
428         services[i].setProto(proto.getService(i));
429       }
430
431       for (int i = 0; i < extensions.length; i++) {
432         extensions[i].setProto(proto.getExtension(i));
433       }
434     }
435   }
436
437   // =================================================================
438
439   /** Describes a message type. */
440   public static final class Descriptor implements GenericDescriptor {
441     /**
442      * Get the index of this descriptor within its parent.  In other words,
443      * given a {@link FileDescriptor} {@code file}, the following is true:
444      * <pre>
445      *   for all i in [0, file.getMessageTypeCount()):
446      *     file.getMessageType(i).getIndex() == i
447      * </pre>
448      * Similarly, for a {@link Descriptor} {@code messageType}:
449      * <pre>
450      *   for all i in [0, messageType.getNestedTypeCount()):
451      *     messageType.getNestedType(i).getIndex() == i
452      * </pre>
453      */
454     public int getIndex() { return index; }
455
456     /** Convert the descriptor to its protocol message representation. */
457     public DescriptorProto toProto() { return proto; }
458
459     /** Get the type's unqualified name. */
460     public String getName() { return proto.getName(); }
461
462     /**
463      * Get the type's fully-qualified name, within the proto language's
464      * namespace.  This differs from the Java name.  For example, given this
465      * {@code .proto}:
466      * <pre>
467      *   package foo.bar;
468      *   option java_package = "com.example.protos"
469      *   message Baz {}
470      * </pre>
471      * {@code Baz}'s full name is "foo.bar.Baz".
472      */
473     public String getFullName() { return fullName; }
474
475     /** Get the {@link FileDescriptor} containing this descriptor. */
476     public FileDescriptor getFile() { return file; }
477
478     /** If this is a nested type, get the outer descriptor, otherwise null. */
479     public Descriptor getContainingType() { return containingType; }
480
481     /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
482     public MessageOptions getOptions() { return proto.getOptions(); }
483
484     /** Get a list of this message type's fields. */
485     public List<FieldDescriptor> getFields() {
486       return Collections.unmodifiableList(Arrays.asList(fields));
487     }
488
489     /** Get a list of this message type's extensions. */
490     public List<FieldDescriptor> getExtensions() {
491       return Collections.unmodifiableList(Arrays.asList(extensions));
492     }
493
494     /** Get a list of message types nested within this one. */
495     public List<Descriptor> getNestedTypes() {
496       return Collections.unmodifiableList(Arrays.asList(nestedTypes));
497     }
498
499     /** Get a list of enum types nested within this one. */
500     public List<EnumDescriptor> getEnumTypes() {
501       return Collections.unmodifiableList(Arrays.asList(enumTypes));
502     }
503
504     /** Determines if the given field number is an extension. */
505     public boolean isExtensionNumber(final int number) {
506       for (final DescriptorProto.ExtensionRange range :
507           proto.getExtensionRangeList()) {
508         if (range.getStart() <= number && number < range.getEnd()) {
509           return true;
510         }
511       }
512       return false;
513     }
514
515     /**
516      * Finds a field by name.
517      * @param name The unqualified name of the field (e.g. "foo").
518      * @return The field's descriptor, or {@code null} if not found.
519      */
520     public FieldDescriptor findFieldByName(final String name) {
521       final GenericDescriptor result =
522           file.pool.findSymbol(fullName + '.' + name);
523       if (result != null && result instanceof FieldDescriptor) {
524         return (FieldDescriptor)result;
525       } else {
526         return null;
527       }
528     }
529
530     /**
531      * Finds a field by field number.
532      * @param number The field number within this message type.
533      * @return The field's descriptor, or {@code null} if not found.
534      */
535     public FieldDescriptor findFieldByNumber(final int number) {
536       return file.pool.fieldsByNumber.get(
537         new DescriptorPool.DescriptorIntPair(this, number));
538     }
539
540     /**
541      * Finds a nested message type by name.
542      * @param name The unqualified name of the nested type (e.g. "Foo").
543      * @return The types's descriptor, or {@code null} if not found.
544      */
545     public Descriptor findNestedTypeByName(final String name) {
546       final GenericDescriptor result =
547           file.pool.findSymbol(fullName + '.' + name);
548       if (result != null && result instanceof Descriptor) {
549         return (Descriptor)result;
550       } else {
551         return null;
552       }
553     }
554
555     /**
556      * Finds a nested enum type by name.
557      * @param name The unqualified name of the nested type (e.g. "Foo").
558      * @return The types's descriptor, or {@code null} if not found.
559      */
560     public EnumDescriptor findEnumTypeByName(final String name) {
561       final GenericDescriptor result =
562           file.pool.findSymbol(fullName + '.' + name);
563       if (result != null && result instanceof EnumDescriptor) {
564         return (EnumDescriptor)result;
565       } else {
566         return null;
567       }
568     }
569
570     private final int index;
571     private DescriptorProto proto;
572     private final String fullName;
573     private final FileDescriptor file;
574     private final Descriptor containingType;
575     private final Descriptor[] nestedTypes;
576     private final EnumDescriptor[] enumTypes;
577     private final FieldDescriptor[] fields;
578     private final FieldDescriptor[] extensions;
579
580     private Descriptor(final DescriptorProto proto,
581                        final FileDescriptor file,
582                        final Descriptor parent,
583                        final int index)
584                 throws DescriptorValidationException {
585       this.index = index;
586       this.proto = proto;
587       fullName = computeFullName(file, parent, proto.getName());
588       this.file = file;
589       containingType = parent;
590
591       nestedTypes = new Descriptor[proto.getNestedTypeCount()];
592       for (int i = 0; i < proto.getNestedTypeCount(); i++) {
593         nestedTypes[i] = new Descriptor(
594           proto.getNestedType(i), file, this, i);
595       }
596
597       enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
598       for (int i = 0; i < proto.getEnumTypeCount(); i++) {
599         enumTypes[i] = new EnumDescriptor(
600           proto.getEnumType(i), file, this, i);
601       }
602
603       fields = new FieldDescriptor[proto.getFieldCount()];
604       for (int i = 0; i < proto.getFieldCount(); i++) {
605         fields[i] = new FieldDescriptor(
606           proto.getField(i), file, this, i, false);
607       }
608
609       extensions = new FieldDescriptor[proto.getExtensionCount()];
610       for (int i = 0; i < proto.getExtensionCount(); i++) {
611         extensions[i] = new FieldDescriptor(
612           proto.getExtension(i), file, this, i, true);
613       }
614
615       file.pool.addSymbol(this);
616     }
617
618     /** Look up and cross-link all field types, etc. */
619     private void crossLink() throws DescriptorValidationException {
620       for (final Descriptor nestedType : nestedTypes) {
621         nestedType.crossLink();
622       }
623
624       for (final FieldDescriptor field : fields) {
625         field.crossLink();
626       }
627
628       for (final FieldDescriptor extension : extensions) {
629         extension.crossLink();
630       }
631     }
632
633     /** See {@link FileDescriptor#setProto}. */
634     private void setProto(final DescriptorProto proto) {
635       this.proto = proto;
636
637       for (int i = 0; i < nestedTypes.length; i++) {
638         nestedTypes[i].setProto(proto.getNestedType(i));
639       }
640
641       for (int i = 0; i < enumTypes.length; i++) {
642         enumTypes[i].setProto(proto.getEnumType(i));
643       }
644
645       for (int i = 0; i < fields.length; i++) {
646         fields[i].setProto(proto.getField(i));
647       }
648
649       for (int i = 0; i < extensions.length; i++) {
650         extensions[i].setProto(proto.getExtension(i));
651       }
652     }
653   }
654
655   // =================================================================
656
657   /** Describes a field of a message type. */
658   public static final class FieldDescriptor
659       implements GenericDescriptor, Comparable<FieldDescriptor>,
660                  FieldSet.FieldDescriptorLite<FieldDescriptor> {
661     /**
662      * Get the index of this descriptor within its parent.
663      * @see Descriptors.Descriptor#getIndex()
664      */
665     public int getIndex() { return index; }
666
667     /** Convert the descriptor to its protocol message representation. */
668     public FieldDescriptorProto toProto() { return proto; }
669
670     /** Get the field's unqualified name. */
671     public String getName() { return proto.getName(); }
672
673     /** Get the field's number. */
674     public int getNumber() { return proto.getNumber(); }
675
676     /**
677      * Get the field's fully-qualified name.
678      * @see Descriptors.Descriptor#getFullName()
679      */
680     public String getFullName() { return fullName; }
681
682     /**
683      * Get the field's java type.  This is just for convenience.  Every
684      * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
685      */
686     public JavaType getJavaType() { return type.getJavaType(); }
687
688     /** For internal use only. */
689     public WireFormat.JavaType getLiteJavaType() {
690       return getLiteType().getJavaType();
691     }
692
693     /** Get the {@code FileDescriptor} containing this descriptor. */
694     public FileDescriptor getFile() { return file; }
695
696     /** Get the field's declared type. */
697     public Type getType() { return type; }
698
699     /** For internal use only. */
700     public WireFormat.FieldType getLiteType() {
701       return table[type.ordinal()];
702     }
703     // I'm pretty sure values() constructs a new array every time, since there
704     // is nothing stopping the caller from mutating the array.  Therefore we
705     // make a static copy here.
706     private static final WireFormat.FieldType[] table =
707         WireFormat.FieldType.values();
708
709     /** Is this field declared required? */
710     public boolean isRequired() {
711       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
712     }
713
714     /** Is this field declared optional? */
715     public boolean isOptional() {
716       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
717     }
718
719     /** Is this field declared repeated? */
720     public boolean isRepeated() {
721       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
722     }
723
724     /** Does this field have the {@code [packed = true]} option? */
725     public boolean isPacked() {
726       return getOptions().getPacked();
727     }
728
729     /** Can this field be packed? i.e. is it a repeated primitive field? */
730     public boolean isPackable() {
731       return isRepeated() && getLiteType().isPackable();
732     }
733
734     /** Returns true if the field had an explicitly-defined default value. */
735     public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
736
737     /**
738      * Returns the field's default value.  Valid for all types except for
739      * messages and groups.  For all other types, the object returned is of
740      * the same class that would returned by Message.getField(this).
741      */
742     public Object getDefaultValue() {
743       if (getJavaType() == JavaType.MESSAGE) {
744         throw new UnsupportedOperationException(
745           "FieldDescriptor.getDefaultValue() called on an embedded message " +
746           "field.");
747       }
748       return defaultValue;
749     }
750
751     /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
752     public FieldOptions getOptions() { return proto.getOptions(); }
753
754     /** Is this field an extension? */
755     public boolean isExtension() { return proto.hasExtendee(); }
756
757     /**
758      * Get the field's containing type. For extensions, this is the type being
759      * extended, not the location where the extension was defined.  See
760      * {@link #getExtensionScope()}.
761      */
762     public Descriptor getContainingType() { return containingType; }
763
764     /**
765      * For extensions defined nested within message types, gets the outer
766      * type.  Not valid for non-extension fields.  For example, consider
767      * this {@code .proto} file:
768      * <pre>
769      *   message Foo {
770      *     extensions 1000 to max;
771      *   }
772      *   extend Foo {
773      *     optional int32 baz = 1234;
774      *   }
775      *   message Bar {
776      *     extend Foo {
777      *       optional int32 qux = 4321;
778      *     }
779      *   }
780      * </pre>
781      * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
782      * However, {@code baz}'s extension scope is {@code null} while
783      * {@code qux}'s extension scope is {@code Bar}.
784      */
785     public Descriptor getExtensionScope() {
786       if (!isExtension()) {
787         throw new UnsupportedOperationException(
788           "This field is not an extension.");
789       }
790       return extensionScope;
791     }
792
793     /** For embedded message and group fields, gets the field's type. */
794     public Descriptor getMessageType() {
795       if (getJavaType() != JavaType.MESSAGE) {
796         throw new UnsupportedOperationException(
797           "This field is not of message type.");
798       }
799       return messageType;
800     }
801
802     /** For enum fields, gets the field's type. */
803     public EnumDescriptor getEnumType() {
804       if (getJavaType() != JavaType.ENUM) {
805         throw new UnsupportedOperationException(
806           "This field is not of enum type.");
807       }
808       return enumType;
809     }
810
811     /**
812      * Compare with another {@code FieldDescriptor}.  This orders fields in
813      * "canonical" order, which simply means ascending order by field number.
814      * {@code other} must be a field of the same type -- i.e.
815      * {@code getContainingType()} must return the same {@code Descriptor} for
816      * both fields.
817      *
818      * @return negative, zero, or positive if {@code this} is less than,
819      *         equal to, or greater than {@code other}, respectively.
820      */
821     public int compareTo(final FieldDescriptor other) {
822       if (other.containingType != containingType) {
823         throw new IllegalArgumentException(
824           "FieldDescriptors can only be compared to other FieldDescriptors " +
825           "for fields of the same message type.");
826       }
827       return getNumber() - other.getNumber();
828     }
829
830     private final int index;
831
832     private FieldDescriptorProto proto;
833     private final String fullName;
834     private final FileDescriptor file;
835     private final Descriptor extensionScope;
836
837     // Possibly initialized during cross-linking.
838     private Type type;
839     private Descriptor containingType;
840     private Descriptor messageType;
841     private EnumDescriptor enumType;
842     private Object defaultValue;
843
844     public enum Type {
845       DOUBLE  (JavaType.DOUBLE     ),
846       FLOAT   (JavaType.FLOAT      ),
847       INT64   (JavaType.LONG       ),
848       UINT64  (JavaType.LONG       ),
849       INT32   (JavaType.INT        ),
850       FIXED64 (JavaType.LONG       ),
851       FIXED32 (JavaType.INT        ),
852       BOOL    (JavaType.BOOLEAN    ),
853       STRING  (JavaType.STRING     ),
854       GROUP   (JavaType.MESSAGE    ),
855       MESSAGE (JavaType.MESSAGE    ),
856       BYTES   (JavaType.BYTE_STRING),
857       UINT32  (JavaType.INT        ),
858       ENUM    (JavaType.ENUM       ),
859       SFIXED32(JavaType.INT        ),
860       SFIXED64(JavaType.LONG       ),
861       SINT32  (JavaType.INT        ),
862       SINT64  (JavaType.LONG       );
863
864       Type(final JavaType javaType) {
865         this.javaType = javaType;
866       }
867
868       private JavaType javaType;
869
870       public FieldDescriptorProto.Type toProto() {
871         return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
872       }
873       public JavaType getJavaType() { return javaType; }
874
875       public static Type valueOf(final FieldDescriptorProto.Type type) {
876         return values()[type.getNumber() - 1];
877       }
878     }
879
880     static {
881       // Refuse to init if someone added a new declared type.
882       if (Type.values().length != FieldDescriptorProto.Type.values().length) {
883         throw new RuntimeException(
884           "descriptor.proto has a new declared type but Desrciptors.java " +
885           "wasn't updated.");
886       }
887     }
888
889     public enum JavaType {
890       INT(0),
891       LONG(0L),
892       FLOAT(0F),
893       DOUBLE(0D),
894       BOOLEAN(false),
895       STRING(""),
896       BYTE_STRING(ByteString.EMPTY),
897       ENUM(null),
898       MESSAGE(null);
899
900       JavaType(final Object defaultDefault) {
901         this.defaultDefault = defaultDefault;
902       }
903
904       /**
905        * The default default value for fields of this type, if it's a primitive
906        * type.  This is meant for use inside this file only, hence is private.
907        */
908       private final Object defaultDefault;
909     }
910
911     private FieldDescriptor(final FieldDescriptorProto proto,
912                             final FileDescriptor file,
913                             final Descriptor parent,
914                             final int index,
915                             final boolean isExtension)
916                      throws DescriptorValidationException {
917       this.index = index;
918       this.proto = proto;
919       fullName = computeFullName(file, parent, proto.getName());
920       this.file = file;
921
922       if (proto.hasType()) {
923         type = Type.valueOf(proto.getType());
924       }
925
926       if (getNumber() <= 0) {
927         throw new DescriptorValidationException(this,
928           "Field numbers must be positive integers.");
929       }
930
931       // Only repeated primitive fields may be packed.
932       if (proto.getOptions().getPacked() && !isPackable()) {
933         throw new DescriptorValidationException(this,
934           "[packed = true] can only be specified for repeated primitive " +
935           "fields.");
936       }
937
938       if (isExtension) {
939         if (!proto.hasExtendee()) {
940           throw new DescriptorValidationException(this,
941             "FieldDescriptorProto.extendee not set for extension field.");
942         }
943         containingType = null;  // Will be filled in when cross-linking
944         if (parent != null) {
945           extensionScope = parent;
946         } else {
947           extensionScope = null;
948         }
949       } else {
950         if (proto.hasExtendee()) {
951           throw new DescriptorValidationException(this,
952             "FieldDescriptorProto.extendee set for non-extension field.");
953         }
954         containingType = parent;
955         extensionScope = null;
956       }
957
958       file.pool.addSymbol(this);
959     }
960
961     /** Look up and cross-link all field types, etc. */
962     private void crossLink() throws DescriptorValidationException {
963       if (proto.hasExtendee()) {
964         final GenericDescriptor extendee =
965           file.pool.lookupSymbol(proto.getExtendee(), this,
966               DescriptorPool.SearchFilter.TYPES_ONLY);
967         if (!(extendee instanceof Descriptor)) {
968           throw new DescriptorValidationException(this,
969               '\"' + proto.getExtendee() + "\" is not a message type.");
970         }
971         containingType = (Descriptor)extendee;
972
973         if (!getContainingType().isExtensionNumber(getNumber())) {
974           throw new DescriptorValidationException(this,
975               '\"' + getContainingType().getFullName() +
976               "\" does not declare " + getNumber() +
977               " as an extension number.");
978         }
979       }
980
981       if (proto.hasTypeName()) {
982         final GenericDescriptor typeDescriptor =
983           file.pool.lookupSymbol(proto.getTypeName(), this,
984               DescriptorPool.SearchFilter.TYPES_ONLY);
985
986         if (!proto.hasType()) {
987           // Choose field type based on symbol.
988           if (typeDescriptor instanceof Descriptor) {
989             type = Type.MESSAGE;
990           } else if (typeDescriptor instanceof EnumDescriptor) {
991             type = Type.ENUM;
992           } else {
993             throw new DescriptorValidationException(this,
994                 '\"' + proto.getTypeName() + "\" is not a type.");
995           }
996         }
997
998         if (getJavaType() == JavaType.MESSAGE) {
999           if (!(typeDescriptor instanceof Descriptor)) {
1000             throw new DescriptorValidationException(this,
1001                 '\"' + proto.getTypeName() + "\" is not a message type.");
1002           }
1003           messageType = (Descriptor)typeDescriptor;
1004
1005           if (proto.hasDefaultValue()) {
1006             throw new DescriptorValidationException(this,
1007               "Messages can't have default values.");
1008           }
1009         } else if (getJavaType() == JavaType.ENUM) {
1010           if (!(typeDescriptor instanceof EnumDescriptor)) {
1011             throw new DescriptorValidationException(this,
1012                 '\"' + proto.getTypeName() + "\" is not an enum type.");
1013           }
1014           enumType = (EnumDescriptor)typeDescriptor;
1015         } else {
1016           throw new DescriptorValidationException(this,
1017             "Field with primitive type has type_name.");
1018         }
1019       } else {
1020         if (getJavaType() == JavaType.MESSAGE ||
1021             getJavaType() == JavaType.ENUM) {
1022           throw new DescriptorValidationException(this,
1023             "Field with message or enum type missing type_name.");
1024         }
1025       }
1026
1027       // We don't attempt to parse the default value until here because for
1028       // enums we need the enum type's descriptor.
1029       if (proto.hasDefaultValue()) {
1030         if (isRepeated()) {
1031           throw new DescriptorValidationException(this,
1032             "Repeated fields cannot have default values.");
1033         }
1034
1035         try {
1036           switch (getType()) {
1037             case INT32:
1038             case SINT32:
1039             case SFIXED32:
1040               defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
1041               break;
1042             case UINT32:
1043             case FIXED32:
1044               defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
1045               break;
1046             case INT64:
1047             case SINT64:
1048             case SFIXED64:
1049               defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
1050               break;
1051             case UINT64:
1052             case FIXED64:
1053               defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
1054               break;
1055             case FLOAT:
1056               if (proto.getDefaultValue().equals("inf")) {
1057                 defaultValue = Float.POSITIVE_INFINITY;
1058               } else if (proto.getDefaultValue().equals("-inf")) {
1059                 defaultValue = Float.NEGATIVE_INFINITY;
1060               } else if (proto.getDefaultValue().equals("nan")) {
1061                 defaultValue = Float.NaN;
1062               } else {
1063                 defaultValue = Float.valueOf(proto.getDefaultValue());
1064               }
1065               break;
1066             case DOUBLE:
1067               if (proto.getDefaultValue().equals("inf")) {
1068                 defaultValue = Double.POSITIVE_INFINITY;
1069               } else if (proto.getDefaultValue().equals("-inf")) {
1070                 defaultValue = Double.NEGATIVE_INFINITY;
1071               } else if (proto.getDefaultValue().equals("nan")) {
1072                 defaultValue = Double.NaN;
1073               } else {
1074                 defaultValue = Double.valueOf(proto.getDefaultValue());
1075               }
1076               break;
1077             case BOOL:
1078               defaultValue = Boolean.valueOf(proto.getDefaultValue());
1079               break;
1080             case STRING:
1081               defaultValue = proto.getDefaultValue();
1082               break;
1083             case BYTES:
1084               try {
1085                 defaultValue =
1086                   TextFormat.unescapeBytes(proto.getDefaultValue());
1087               } catch (TextFormat.InvalidEscapeSequenceException e) {
1088                 throw new DescriptorValidationException(this,
1089                   "Couldn't parse default value: " + e.getMessage(), e);
1090               }
1091               break;
1092             case ENUM:
1093               defaultValue = enumType.findValueByName(proto.getDefaultValue());
1094               if (defaultValue == null) {
1095                 throw new DescriptorValidationException(this,
1096                   "Unknown enum default value: \"" +
1097                   proto.getDefaultValue() + '\"');
1098               }
1099               break;
1100             case MESSAGE:
1101             case GROUP:
1102               throw new DescriptorValidationException(this,
1103                 "Message type had default value.");
1104           }
1105         } catch (NumberFormatException e) {
1106           throw new DescriptorValidationException(this, 
1107               "Could not parse default value: \"" + 
1108               proto.getDefaultValue() + '\"', e);
1109         }
1110       } else {
1111         // Determine the default default for this field.
1112         if (isRepeated()) {
1113           defaultValue = Collections.emptyList();
1114         } else {
1115           switch (getJavaType()) {
1116             case ENUM:
1117               // We guarantee elsewhere that an enum type always has at least
1118               // one possible value.
1119               defaultValue = enumType.getValues().get(0);
1120               break;
1121             case MESSAGE:
1122               defaultValue = null;
1123               break;
1124             default:
1125               defaultValue = getJavaType().defaultDefault;
1126               break;
1127           }
1128         }
1129       }
1130
1131       if (!isExtension()) {
1132         file.pool.addFieldByNumber(this);
1133       }
1134
1135       if (containingType != null &&
1136           containingType.getOptions().getMessageSetWireFormat()) {
1137         if (isExtension()) {
1138           if (!isOptional() || getType() != Type.MESSAGE) {
1139             throw new DescriptorValidationException(this,
1140               "Extensions of MessageSets must be optional messages.");
1141           }
1142         } else {
1143           throw new DescriptorValidationException(this,
1144             "MessageSets cannot have fields, only extensions.");
1145         }
1146       }
1147     }
1148
1149     /** See {@link FileDescriptor#setProto}. */
1150     private void setProto(final FieldDescriptorProto proto) {
1151       this.proto = proto;
1152     }
1153
1154     /**
1155      * For internal use only.  This is to satisfy the FieldDescriptorLite
1156      * interface.
1157      */
1158     public MessageLite.Builder internalMergeFrom(
1159         MessageLite.Builder to, MessageLite from) {
1160       // FieldDescriptors are only used with non-lite messages so we can just
1161       // down-cast and call mergeFrom directly.
1162       return ((Message.Builder) to).mergeFrom((Message) from);
1163     }
1164   }
1165
1166   // =================================================================
1167
1168   /** Describes an enum type. */
1169   public static final class EnumDescriptor
1170       implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
1171     /**
1172      * Get the index of this descriptor within its parent.
1173      * @see Descriptors.Descriptor#getIndex()
1174      */
1175     public int getIndex() { return index; }
1176
1177     /** Convert the descriptor to its protocol message representation. */
1178     public EnumDescriptorProto toProto() { return proto; }
1179
1180     /** Get the type's unqualified name. */
1181     public String getName() { return proto.getName(); }
1182
1183     /**
1184      * Get the type's fully-qualified name.
1185      * @see Descriptors.Descriptor#getFullName()
1186      */
1187     public String getFullName() { return fullName; }
1188
1189     /** Get the {@link FileDescriptor} containing this descriptor. */
1190     public FileDescriptor getFile() { return file; }
1191
1192     /** If this is a nested type, get the outer descriptor, otherwise null. */
1193     public Descriptor getContainingType() { return containingType; }
1194
1195     /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
1196     public EnumOptions getOptions() { return proto.getOptions(); }
1197
1198     /** Get a list of defined values for this enum. */
1199     public List<EnumValueDescriptor> getValues() {
1200       return Collections.unmodifiableList(Arrays.asList(values));
1201     }
1202
1203     /**
1204      * Find an enum value by name.
1205      * @param name The unqualified name of the value (e.g. "FOO").
1206      * @return the value's descriptor, or {@code null} if not found.
1207      */
1208     public EnumValueDescriptor findValueByName(final String name) {
1209       final GenericDescriptor result =
1210           file.pool.findSymbol(fullName + '.' + name);
1211       if (result != null && result instanceof EnumValueDescriptor) {
1212         return (EnumValueDescriptor)result;
1213       } else {
1214         return null;
1215       }
1216     }
1217
1218     /**
1219      * Find an enum value by number.  If multiple enum values have the same
1220      * number, this returns the first defined value with that number.
1221      * @param number The value's number.
1222      * @return the value's descriptor, or {@code null} if not found.
1223      */
1224     public EnumValueDescriptor findValueByNumber(final int number) {
1225       return file.pool.enumValuesByNumber.get(
1226         new DescriptorPool.DescriptorIntPair(this, number));
1227     }
1228
1229     private final int index;
1230     private EnumDescriptorProto proto;
1231     private final String fullName;
1232     private final FileDescriptor file;
1233     private final Descriptor containingType;
1234     private EnumValueDescriptor[] values;
1235
1236     private EnumDescriptor(final EnumDescriptorProto proto,
1237                            final FileDescriptor file,
1238                            final Descriptor parent,
1239                            final int index)
1240                     throws DescriptorValidationException {
1241       this.index = index;
1242       this.proto = proto;
1243       fullName = computeFullName(file, parent, proto.getName());
1244       this.file = file;
1245       containingType = parent;
1246
1247       if (proto.getValueCount() == 0) {
1248         // We cannot allow enums with no values because this would mean there
1249         // would be no valid default value for fields of this type.
1250         throw new DescriptorValidationException(this,
1251           "Enums must contain at least one value.");
1252       }
1253
1254       values = new EnumValueDescriptor[proto.getValueCount()];
1255       for (int i = 0; i < proto.getValueCount(); i++) {
1256         values[i] = new EnumValueDescriptor(
1257           proto.getValue(i), file, this, i);
1258       }
1259
1260       file.pool.addSymbol(this);
1261     }
1262
1263     /** See {@link FileDescriptor#setProto}. */
1264     private void setProto(final EnumDescriptorProto proto) {
1265       this.proto = proto;
1266
1267       for (int i = 0; i < values.length; i++) {
1268         values[i].setProto(proto.getValue(i));
1269       }
1270     }
1271   }
1272
1273   // =================================================================
1274
1275   /**
1276    * Describes one value within an enum type.  Note that multiple defined
1277    * values may have the same number.  In generated Java code, all values
1278    * with the same number after the first become aliases of the first.
1279    * However, they still have independent EnumValueDescriptors.
1280    */
1281   public static final class EnumValueDescriptor
1282       implements GenericDescriptor, Internal.EnumLite {
1283     /**
1284      * Get the index of this descriptor within its parent.
1285      * @see Descriptors.Descriptor#getIndex()
1286      */
1287     public int getIndex() { return index; }
1288
1289     /** Convert the descriptor to its protocol message representation. */
1290     public EnumValueDescriptorProto toProto() { return proto; }
1291
1292     /** Get the value's unqualified name. */
1293     public String getName() { return proto.getName(); }
1294
1295     /** Get the value's number. */
1296     public int getNumber() { return proto.getNumber(); }
1297
1298     /**
1299      * Get the value's fully-qualified name.
1300      * @see Descriptors.Descriptor#getFullName()
1301      */
1302     public String getFullName() { return fullName; }
1303
1304     /** Get the {@link FileDescriptor} containing this descriptor. */
1305     public FileDescriptor getFile() { return file; }
1306
1307     /** Get the value's enum type. */
1308     public EnumDescriptor getType() { return type; }
1309
1310     /**
1311      * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
1312      */
1313     public EnumValueOptions getOptions() { return proto.getOptions(); }
1314
1315     private final int index;
1316     private EnumValueDescriptorProto proto;
1317     private final String fullName;
1318     private final FileDescriptor file;
1319     private final EnumDescriptor type;
1320
1321     private EnumValueDescriptor(final EnumValueDescriptorProto proto,
1322                                 final FileDescriptor file,
1323                                 final EnumDescriptor parent,
1324                                 final int index)
1325                          throws DescriptorValidationException {
1326       this.index = index;
1327       this.proto = proto;
1328       this.file = file;
1329       type = parent;
1330
1331       fullName = parent.getFullName() + '.' + proto.getName();
1332
1333       file.pool.addSymbol(this);
1334       file.pool.addEnumValueByNumber(this);
1335     }
1336
1337     /** See {@link FileDescriptor#setProto}. */
1338     private void setProto(final EnumValueDescriptorProto proto) {
1339       this.proto = proto;
1340     }
1341   }
1342
1343   // =================================================================
1344
1345   /** Describes a service type. */
1346   public static final class ServiceDescriptor implements GenericDescriptor {
1347     /**
1348      * Get the index of this descriptor within its parent.
1349      * * @see Descriptors.Descriptor#getIndex()
1350      */
1351     public int getIndex() { return index; }
1352
1353     /** Convert the descriptor to its protocol message representation. */
1354     public ServiceDescriptorProto toProto() { return proto; }
1355
1356     /** Get the type's unqualified name. */
1357     public String getName() { return proto.getName(); }
1358
1359     /**
1360      * Get the type's fully-qualified name.
1361      * @see Descriptors.Descriptor#getFullName()
1362      */
1363     public String getFullName() { return fullName; }
1364
1365     /** Get the {@link FileDescriptor} containing this descriptor. */
1366     public FileDescriptor getFile() { return file; }
1367
1368     /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
1369     public ServiceOptions getOptions() { return proto.getOptions(); }
1370
1371     /** Get a list of methods for this service. */
1372     public List<MethodDescriptor> getMethods() {
1373       return Collections.unmodifiableList(Arrays.asList(methods));
1374     }
1375
1376     /**
1377      * Find a method by name.
1378      * @param name The unqualified name of the method (e.g. "Foo").
1379      * @return the method's descriptor, or {@code null} if not found.
1380      */
1381     public MethodDescriptor findMethodByName(final String name) {
1382       final GenericDescriptor result =
1383           file.pool.findSymbol(fullName + '.' + name);
1384       if (result != null && result instanceof MethodDescriptor) {
1385         return (MethodDescriptor)result;
1386       } else {
1387         return null;
1388       }
1389     }
1390
1391     private final int index;
1392     private ServiceDescriptorProto proto;
1393     private final String fullName;
1394     private final FileDescriptor file;
1395     private MethodDescriptor[] methods;
1396
1397     private ServiceDescriptor(final ServiceDescriptorProto proto,
1398                               final FileDescriptor file,
1399                               final int index)
1400                        throws DescriptorValidationException {
1401       this.index = index;
1402       this.proto = proto;
1403       fullName = computeFullName(file, null, proto.getName());
1404       this.file = file;
1405
1406       methods = new MethodDescriptor[proto.getMethodCount()];
1407       for (int i = 0; i < proto.getMethodCount(); i++) {
1408         methods[i] = new MethodDescriptor(
1409           proto.getMethod(i), file, this, i);
1410       }
1411
1412       file.pool.addSymbol(this);
1413     }
1414
1415     private void crossLink() throws DescriptorValidationException {
1416       for (final MethodDescriptor method : methods) {
1417         method.crossLink();
1418       }
1419     }
1420
1421     /** See {@link FileDescriptor#setProto}. */
1422     private void setProto(final ServiceDescriptorProto proto) {
1423       this.proto = proto;
1424
1425       for (int i = 0; i < methods.length; i++) {
1426         methods[i].setProto(proto.getMethod(i));
1427       }
1428     }
1429   }
1430
1431   // =================================================================
1432
1433   /**
1434    * Describes one method within a service type.
1435    */
1436   public static final class MethodDescriptor implements GenericDescriptor {
1437     /**
1438      * Get the index of this descriptor within its parent.
1439      * * @see Descriptors.Descriptor#getIndex()
1440      */
1441     public int getIndex() { return index; }
1442
1443     /** Convert the descriptor to its protocol message representation. */
1444     public MethodDescriptorProto toProto() { return proto; }
1445
1446     /** Get the method's unqualified name. */
1447     public String getName() { return proto.getName(); }
1448
1449     /**
1450      * Get the method's fully-qualified name.
1451      * @see Descriptors.Descriptor#getFullName()
1452      */
1453     public String getFullName() { return fullName; }
1454
1455     /** Get the {@link FileDescriptor} containing this descriptor. */
1456     public FileDescriptor getFile() { return file; }
1457
1458     /** Get the method's service type. */
1459     public ServiceDescriptor getService() { return service; }
1460
1461     /** Get the method's input type. */
1462     public Descriptor getInputType() { return inputType; }
1463
1464     /** Get the method's output type. */
1465     public Descriptor getOutputType() { return outputType; }
1466
1467     /**
1468      * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
1469      */
1470     public MethodOptions getOptions() { return proto.getOptions(); }
1471
1472     private final int index;
1473     private MethodDescriptorProto proto;
1474     private final String fullName;
1475     private final FileDescriptor file;
1476     private final ServiceDescriptor service;
1477
1478     // Initialized during cross-linking.
1479     private Descriptor inputType;
1480     private Descriptor outputType;
1481
1482     private MethodDescriptor(final MethodDescriptorProto proto,
1483                              final FileDescriptor file,
1484                              final ServiceDescriptor parent,
1485                              final int index)
1486                       throws DescriptorValidationException {
1487       this.index = index;
1488       this.proto = proto;
1489       this.file = file;
1490       service = parent;
1491
1492       fullName = parent.getFullName() + '.' + proto.getName();
1493
1494       file.pool.addSymbol(this);
1495     }
1496
1497     private void crossLink() throws DescriptorValidationException {
1498       final GenericDescriptor input =
1499         file.pool.lookupSymbol(proto.getInputType(), this,
1500             DescriptorPool.SearchFilter.TYPES_ONLY);
1501       if (!(input instanceof Descriptor)) {
1502         throw new DescriptorValidationException(this,
1503             '\"' + proto.getInputType() + "\" is not a message type.");
1504       }
1505       inputType = (Descriptor)input;
1506
1507       final GenericDescriptor output =
1508         file.pool.lookupSymbol(proto.getOutputType(), this,
1509             DescriptorPool.SearchFilter.TYPES_ONLY);
1510       if (!(output instanceof Descriptor)) {
1511         throw new DescriptorValidationException(this,
1512             '\"' + proto.getOutputType() + "\" is not a message type.");
1513       }
1514       outputType = (Descriptor)output;
1515     }
1516
1517     /** See {@link FileDescriptor#setProto}. */
1518     private void setProto(final MethodDescriptorProto proto) {
1519       this.proto = proto;
1520     }
1521   }
1522
1523   // =================================================================
1524
1525   private static String computeFullName(final FileDescriptor file,
1526                                         final Descriptor parent,
1527                                         final String name) {
1528     if (parent != null) {
1529       return parent.getFullName() + '.' + name;
1530     } else if (file.getPackage().length() > 0) {
1531       return file.getPackage() + '.' + name;
1532     } else {
1533       return name;
1534     }
1535   }
1536
1537   // =================================================================
1538
1539   /**
1540    * All descriptors except {@code FileDescriptor} implement this to make
1541    * {@code DescriptorPool}'s life easier.
1542    */
1543   private interface GenericDescriptor {
1544     Message toProto();
1545     String getName();
1546     String getFullName();
1547     FileDescriptor getFile();
1548   }
1549
1550   /**
1551    * Thrown when building descriptors fails because the source DescriptorProtos
1552    * are not valid.
1553    */
1554   public static class DescriptorValidationException extends Exception {
1555     private static final long serialVersionUID = 5750205775490483148L;
1556
1557     /** Gets the full name of the descriptor where the error occurred. */
1558     public String getProblemSymbolName() { return name; }
1559
1560     /**
1561      * Gets the protocol message representation of the invalid descriptor.
1562      */
1563     public Message getProblemProto() { return proto; }
1564
1565     /**
1566      * Gets a human-readable description of the error.
1567      */
1568     public String getDescription() { return description; }
1569
1570     private final String name;
1571     private final Message proto;
1572     private final String description;
1573
1574     private DescriptorValidationException(
1575         final GenericDescriptor problemDescriptor,
1576         final String description) {
1577       super(problemDescriptor.getFullName() + ": " + description);
1578
1579       // Note that problemDescriptor may be partially uninitialized, so we
1580       // don't want to expose it directly to the user.  So, we only provide
1581       // the name and the original proto.
1582       name = problemDescriptor.getFullName();
1583       proto = problemDescriptor.toProto();
1584       this.description = description;
1585     }
1586
1587     private DescriptorValidationException(
1588         final GenericDescriptor problemDescriptor,
1589         final String description,
1590         final Throwable cause) {
1591       this(problemDescriptor, description);
1592       initCause(cause);
1593     }
1594
1595     private DescriptorValidationException(
1596         final FileDescriptor problemDescriptor,
1597         final String description) {
1598       super(problemDescriptor.getName() + ": " + description);
1599
1600       // Note that problemDescriptor may be partially uninitialized, so we
1601       // don't want to expose it directly to the user.  So, we only provide
1602       // the name and the original proto.
1603       name = problemDescriptor.getName();
1604       proto = problemDescriptor.toProto();
1605       this.description = description;
1606     }
1607   }
1608
1609   // =================================================================
1610
1611   /**
1612    * A private helper class which contains lookup tables containing all the
1613    * descriptors defined in a particular file.
1614    */
1615   private static final class DescriptorPool {
1616     
1617     /** Defines what subclass of descriptors to search in the descriptor pool. 
1618      */
1619     enum SearchFilter {
1620       TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
1621     }
1622     
1623     DescriptorPool(final FileDescriptor[] dependencies) {
1624       this.dependencies = new HashSet<FileDescriptor>();
1625
1626       for (int i = 0; i < dependencies.length; i++) {
1627         this.dependencies.add(dependencies[i]);
1628         importPublicDependencies(dependencies[i]);
1629       }
1630
1631       for (final FileDescriptor dependency : this.dependencies) {
1632         try {
1633           addPackage(dependency.getPackage(), dependency);
1634         } catch (DescriptorValidationException e) {
1635           // Can't happen, because addPackage() only fails when the name
1636           // conflicts with a non-package, but we have not yet added any
1637           // non-packages at this point.
1638           assert false;
1639         }
1640       }
1641     }
1642
1643     /** Find and put public dependencies of the file into dependencies set.*/
1644     private void importPublicDependencies(final FileDescriptor file) {
1645       for (FileDescriptor dependency : file.getPublicDependencies()) {
1646         if (dependencies.add(dependency)) {
1647           importPublicDependencies(dependency);
1648         }
1649       }
1650     }
1651
1652     private final Set<FileDescriptor> dependencies;
1653
1654     private final Map<String, GenericDescriptor> descriptorsByName =
1655       new HashMap<String, GenericDescriptor>();
1656     private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
1657       new HashMap<DescriptorIntPair, FieldDescriptor>();
1658     private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
1659         = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
1660
1661     /** Find a generic descriptor by fully-qualified name. */
1662     GenericDescriptor findSymbol(final String fullName) {
1663       return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
1664     }
1665     
1666     /** Find a descriptor by fully-qualified name and given option to only 
1667      * search valid field type descriptors. 
1668      */
1669     GenericDescriptor findSymbol(final String fullName,
1670                                  final SearchFilter filter) {
1671       GenericDescriptor result = descriptorsByName.get(fullName);
1672       if (result != null) {
1673         if ((filter==SearchFilter.ALL_SYMBOLS) ||
1674             ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
1675             ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
1676           return result;
1677         }
1678       }
1679
1680       for (final FileDescriptor dependency : dependencies) {
1681         result = dependency.pool.descriptorsByName.get(fullName);
1682         if (result != null) {
1683           if ((filter==SearchFilter.ALL_SYMBOLS) ||
1684               ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
1685               ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
1686             return result;
1687           }
1688         }
1689       }
1690
1691       return null;
1692     }
1693
1694     /** Checks if the descriptor is a valid type for a message field. */
1695     boolean isType(GenericDescriptor descriptor) {
1696       return (descriptor instanceof Descriptor) || 
1697         (descriptor instanceof EnumDescriptor);
1698     }
1699     
1700     /** Checks if the descriptor is a valid namespace type. */
1701     boolean isAggregate(GenericDescriptor descriptor) {
1702       return (descriptor instanceof Descriptor) || 
1703         (descriptor instanceof EnumDescriptor) || 
1704         (descriptor instanceof PackageDescriptor) || 
1705         (descriptor instanceof ServiceDescriptor);
1706     }
1707        
1708     /**
1709      * Look up a type descriptor by name, relative to some other descriptor.
1710      * The name may be fully-qualified (with a leading '.'),
1711      * partially-qualified, or unqualified.  C++-like name lookup semantics
1712      * are used to search for the matching descriptor.
1713      */
1714     GenericDescriptor lookupSymbol(final String name,
1715                                    final GenericDescriptor relativeTo,
1716                                    final DescriptorPool.SearchFilter filter)
1717                             throws DescriptorValidationException {
1718       // TODO(kenton):  This could be optimized in a number of ways.
1719
1720       GenericDescriptor result;
1721       if (name.startsWith(".")) {
1722         // Fully-qualified name.
1723         result = findSymbol(name.substring(1), filter);
1724       } else {
1725         // If "name" is a compound identifier, we want to search for the
1726         // first component of it, then search within it for the rest.
1727         // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
1728         // defined in multiple parent scopes, we only want to find "Bar.baz" in
1729         // the innermost one.  E.g., the following should produce an error:
1730         //   message Bar { message Baz {} }
1731         //   message Foo {
1732         //     message Bar {
1733         //     }
1734         //     optional Bar.Baz baz = 1;
1735         //   }
1736         // So, we look for just "Foo" first, then look for "Bar.baz" within it
1737         // if found.
1738         final int firstPartLength = name.indexOf('.');
1739         final String firstPart;
1740         if (firstPartLength == -1) {
1741           firstPart = name;
1742         } else {
1743           firstPart = name.substring(0, firstPartLength);
1744         }
1745
1746         // We will search each parent scope of "relativeTo" looking for the
1747         // symbol.
1748         final StringBuilder scopeToTry =
1749             new StringBuilder(relativeTo.getFullName());
1750
1751         while (true) {
1752           // Chop off the last component of the scope.
1753           final int dotpos = scopeToTry.lastIndexOf(".");
1754           if (dotpos == -1) {
1755             result = findSymbol(name, filter);
1756             break;
1757           } else {
1758             scopeToTry.setLength(dotpos + 1);
1759
1760             // Append firstPart and try to find
1761             scopeToTry.append(firstPart);
1762             result = findSymbol(scopeToTry.toString(), 
1763                 DescriptorPool.SearchFilter.AGGREGATES_ONLY);
1764
1765             if (result != null) {
1766               if (firstPartLength != -1) {
1767                 // We only found the first part of the symbol.  Now look for
1768                 // the whole thing.  If this fails, we *don't* want to keep
1769                 // searching parent scopes.
1770                 scopeToTry.setLength(dotpos + 1);
1771                 scopeToTry.append(name);
1772                 result = findSymbol(scopeToTry.toString(), filter);
1773               }
1774               break;
1775             }
1776
1777             // Not found.  Remove the name so we can try again.
1778             scopeToTry.setLength(dotpos);
1779           }
1780         }
1781       }
1782
1783       if (result == null) {
1784         throw new DescriptorValidationException(relativeTo,
1785             '\"' + name + "\" is not defined.");
1786       } else {
1787         return result;
1788       }
1789     }
1790
1791     /**
1792      * Adds a symbol to the symbol table.  If a symbol with the same name
1793      * already exists, throws an error.
1794      */
1795     void addSymbol(final GenericDescriptor descriptor)
1796             throws DescriptorValidationException {
1797       validateSymbolName(descriptor);
1798
1799       final String fullName = descriptor.getFullName();
1800       final int dotpos = fullName.lastIndexOf('.');
1801
1802       final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
1803       if (old != null) {
1804         descriptorsByName.put(fullName, old);
1805
1806         if (descriptor.getFile() == old.getFile()) {
1807           if (dotpos == -1) {
1808             throw new DescriptorValidationException(descriptor,
1809                 '\"' + fullName + "\" is already defined.");
1810           } else {
1811             throw new DescriptorValidationException(descriptor,
1812                 '\"' + fullName.substring(dotpos + 1) +
1813               "\" is already defined in \"" +
1814               fullName.substring(0, dotpos) + "\".");
1815           }
1816         } else {
1817           throw new DescriptorValidationException(descriptor,
1818               '\"' + fullName + "\" is already defined in file \"" +
1819             old.getFile().getName() + "\".");
1820         }
1821       }
1822     }
1823
1824     /**
1825      * Represents a package in the symbol table.  We use PackageDescriptors
1826      * just as placeholders so that someone cannot define, say, a message type
1827      * that has the same name as an existing package.
1828      */
1829     private static final class PackageDescriptor implements GenericDescriptor {
1830       public Message toProto()        { return file.toProto(); }
1831       public String getName()         { return name;           }
1832       public String getFullName()     { return fullName;       }
1833       public FileDescriptor getFile() { return file;           }
1834
1835       PackageDescriptor(final String name, final String fullName,
1836                         final FileDescriptor file) {
1837         this.file = file;
1838         this.fullName = fullName;
1839         this.name = name;
1840       }
1841
1842       private final String name;
1843       private final String fullName;
1844       private final FileDescriptor file;
1845     }
1846
1847     /**
1848      * Adds a package to the symbol tables.  If a package by the same name
1849      * already exists, that is fine, but if some other kind of symbol exists
1850      * under the same name, an exception is thrown.  If the package has
1851      * multiple components, this also adds the parent package(s).
1852      */
1853     void addPackage(final String fullName, final FileDescriptor file)
1854              throws DescriptorValidationException {
1855       final int dotpos = fullName.lastIndexOf('.');
1856       final String name;
1857       if (dotpos == -1) {
1858         name = fullName;
1859       } else {
1860         addPackage(fullName.substring(0, dotpos), file);
1861         name = fullName.substring(dotpos + 1);
1862       }
1863
1864       final GenericDescriptor old =
1865         descriptorsByName.put(fullName,
1866           new PackageDescriptor(name, fullName, file));
1867       if (old != null) {
1868         descriptorsByName.put(fullName, old);
1869         if (!(old instanceof PackageDescriptor)) {
1870           throw new DescriptorValidationException(file,
1871               '\"' + name + "\" is already defined (as something other than a "
1872               + "package) in file \"" + old.getFile().getName() + "\".");
1873         }
1874       }
1875     }
1876
1877     /** A (GenericDescriptor, int) pair, used as a map key. */
1878     private static final class DescriptorIntPair {
1879       private final GenericDescriptor descriptor;
1880       private final int number;
1881
1882       DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
1883         this.descriptor = descriptor;
1884         this.number = number;
1885       }
1886
1887       @Override
1888       public int hashCode() {
1889         return descriptor.hashCode() * ((1 << 16) - 1) + number;
1890       }
1891       @Override
1892       public boolean equals(final Object obj) {
1893         if (!(obj instanceof DescriptorIntPair)) {
1894           return false;
1895         }
1896         final DescriptorIntPair other = (DescriptorIntPair)obj;
1897         return descriptor == other.descriptor && number == other.number;
1898       }
1899     }
1900
1901     /**
1902      * Adds a field to the fieldsByNumber table.  Throws an exception if a
1903      * field with the same containing type and number already exists.
1904      */
1905     void addFieldByNumber(final FieldDescriptor field)
1906                    throws DescriptorValidationException {
1907       final DescriptorIntPair key =
1908         new DescriptorIntPair(field.getContainingType(), field.getNumber());
1909       final FieldDescriptor old = fieldsByNumber.put(key, field);
1910       if (old != null) {
1911         fieldsByNumber.put(key, old);
1912         throw new DescriptorValidationException(field,
1913           "Field number " + field.getNumber() +
1914           "has already been used in \"" +
1915           field.getContainingType().getFullName() +
1916           "\" by field \"" + old.getName() + "\".");
1917       }
1918     }
1919
1920     /**
1921      * Adds an enum value to the enumValuesByNumber table.  If an enum value
1922      * with the same type and number already exists, does nothing.  (This is
1923      * allowed; the first value define with the number takes precedence.)
1924      */
1925     void addEnumValueByNumber(final EnumValueDescriptor value) {
1926       final DescriptorIntPair key =
1927         new DescriptorIntPair(value.getType(), value.getNumber());
1928       final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
1929       if (old != null) {
1930         enumValuesByNumber.put(key, old);
1931         // Not an error:  Multiple enum values may have the same number, but
1932         // we only want the first one in the map.
1933       }
1934     }
1935
1936     /**
1937      * Verifies that the descriptor's name is valid (i.e. it contains only
1938      * letters, digits, and underscores, and does not start with a digit).
1939      */
1940     static void validateSymbolName(final GenericDescriptor descriptor)
1941                                    throws DescriptorValidationException {
1942       final String name = descriptor.getName();
1943       if (name.length() == 0) {
1944         throw new DescriptorValidationException(descriptor, "Missing name.");
1945       } else {
1946         boolean valid = true;
1947         for (int i = 0; i < name.length(); i++) {
1948           final char c = name.charAt(i);
1949           // Non-ASCII characters are not valid in protobuf identifiers, even
1950           // if they are letters or digits.
1951           if (c >= 128) {
1952             valid = false;
1953           }
1954           // First character must be letter or _.  Subsequent characters may
1955           // be letters, numbers, or digits.
1956           if (Character.isLetter(c) || c == '_' ||
1957               (Character.isDigit(c) && i > 0)) {
1958             // Valid
1959           } else {
1960             valid = false;
1961           }
1962         }
1963         if (!valid) {
1964           throw new DescriptorValidationException(descriptor,
1965               '\"' + name + "\" is not a valid identifier.");
1966         }
1967       }
1968     }
1969   }
1970 }