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
31package com.google.protobuf;
32
33import com.google.protobuf.Descriptors.Descriptor;
34import com.google.protobuf.Descriptors.FieldDescriptor;
35
36import java.io.InputStream;
37import java.io.IOException;
38import java.util.ArrayList;
39import java.util.List;
40import java.util.Map;
41
42/**
43 * A partial implementation of the {@link Message} interface which implements
44 * as many methods of that interface as possible in terms of other methods.
45 *
46 * @author kenton@google.com Kenton Varda
47 */
48public abstract class AbstractMessage extends AbstractMessageLite
49                                      implements Message {
50  @SuppressWarnings("unchecked")
51  public boolean isInitialized() {
52    // Check that all required fields are present.
53    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
54      if (field.isRequired()) {
55        if (!hasField(field)) {
56          return false;
57        }
58      }
59    }
60
61    // Check that embedded messages are initialized.
62    for (final Map.Entry<FieldDescriptor, Object> entry :
63        getAllFields().entrySet()) {
64      final FieldDescriptor field = entry.getKey();
65      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
66        if (field.isRepeated()) {
67          for (final Message element : (List<Message>) entry.getValue()) {
68            if (!element.isInitialized()) {
69              return false;
70            }
71          }
72        } else {
73          if (!((Message) entry.getValue()).isInitialized()) {
74            return false;
75          }
76        }
77      }
78    }
79
80    return true;
81  }
82
83  @Override
84  public final String toString() {
85    return TextFormat.printToString(this);
86  }
87
88  public void writeTo(final CodedOutputStream output) throws IOException {
89    final boolean isMessageSet =
90        getDescriptorForType().getOptions().getMessageSetWireFormat();
91
92    for (final Map.Entry<FieldDescriptor, Object> entry :
93        getAllFields().entrySet()) {
94      final FieldDescriptor field = entry.getKey();
95      final Object value = entry.getValue();
96      if (isMessageSet && field.isExtension() &&
97          field.getType() == FieldDescriptor.Type.MESSAGE &&
98          !field.isRepeated()) {
99        output.writeMessageSetExtension(field.getNumber(), (Message) value);
100      } else {
101        FieldSet.writeField(field, value, output);
102      }
103    }
104
105    final UnknownFieldSet unknownFields = getUnknownFields();
106    if (isMessageSet) {
107      unknownFields.writeAsMessageSetTo(output);
108    } else {
109      unknownFields.writeTo(output);
110    }
111  }
112
113  private int memoizedSize = -1;
114
115  public int getSerializedSize() {
116    int size = memoizedSize;
117    if (size != -1) {
118      return size;
119    }
120
121    size = 0;
122    final boolean isMessageSet =
123        getDescriptorForType().getOptions().getMessageSetWireFormat();
124
125    for (final Map.Entry<FieldDescriptor, Object> entry :
126        getAllFields().entrySet()) {
127      final FieldDescriptor field = entry.getKey();
128      final Object value = entry.getValue();
129      if (isMessageSet && field.isExtension() &&
130          field.getType() == FieldDescriptor.Type.MESSAGE &&
131          !field.isRepeated()) {
132        size += CodedOutputStream.computeMessageSetExtensionSize(
133            field.getNumber(), (Message) value);
134      } else {
135        size += FieldSet.computeFieldSize(field, value);
136      }
137    }
138
139    final UnknownFieldSet unknownFields = getUnknownFields();
140    if (isMessageSet) {
141      size += unknownFields.getSerializedSizeAsMessageSet();
142    } else {
143      size += unknownFields.getSerializedSize();
144    }
145
146    memoizedSize = size;
147    return size;
148  }
149
150  @Override
151  public boolean equals(final Object other) {
152    if (other == this) {
153      return true;
154    }
155    if (!(other instanceof Message)) {
156      return false;
157    }
158    final Message otherMessage = (Message) other;
159    if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
160      return false;
161    }
162    return getAllFields().equals(otherMessage.getAllFields()) &&
163        getUnknownFields().equals(otherMessage.getUnknownFields());
164  }
165
166  @Override
167  public int hashCode() {
168    int hash = 41;
169    hash = (19 * hash) + getDescriptorForType().hashCode();
170    hash = (53 * hash) + getAllFields().hashCode();
171    hash = (29 * hash) + getUnknownFields().hashCode();
172    return hash;
173  }
174
175  // =================================================================
176
177  /**
178   * A partial implementation of the {@link Message.Builder} interface which
179   * implements as many methods of that interface as possible in terms of
180   * other methods.
181   */
182  @SuppressWarnings("unchecked")
183  public static abstract class Builder<BuilderType extends Builder>
184      extends AbstractMessageLite.Builder<BuilderType>
185      implements Message.Builder {
186    // The compiler produces an error if this is not declared explicitly.
187    @Override
188    public abstract BuilderType clone();
189
190    public BuilderType clear() {
191      for (final Map.Entry<FieldDescriptor, Object> entry :
192           getAllFields().entrySet()) {
193        clearField(entry.getKey());
194      }
195      return (BuilderType) this;
196    }
197
198    public BuilderType mergeFrom(final Message other) {
199      if (other.getDescriptorForType() != getDescriptorForType()) {
200        throw new IllegalArgumentException(
201          "mergeFrom(Message) can only merge messages of the same type.");
202      }
203
204      // Note:  We don't attempt to verify that other's fields have valid
205      //   types.  Doing so would be a losing battle.  We'd have to verify
206      //   all sub-messages as well, and we'd have to make copies of all of
207      //   them to insure that they don't change after verification (since
208      //   the Message interface itself cannot enforce immutability of
209      //   implementations).
210      // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
211      //   which allows people to make secure deep copies of messages.
212
213      for (final Map.Entry<FieldDescriptor, Object> entry :
214           other.getAllFields().entrySet()) {
215        final FieldDescriptor field = entry.getKey();
216        if (field.isRepeated()) {
217          for (final Object element : (List)entry.getValue()) {
218            addRepeatedField(field, element);
219          }
220        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
221          final Message existingValue = (Message)getField(field);
222          if (existingValue == existingValue.getDefaultInstanceForType()) {
223            setField(field, entry.getValue());
224          } else {
225            setField(field,
226              existingValue.newBuilderForType()
227                .mergeFrom(existingValue)
228                .mergeFrom((Message)entry.getValue())
229                .build());
230          }
231        } else {
232          setField(field, entry.getValue());
233        }
234      }
235
236      mergeUnknownFields(other.getUnknownFields());
237
238      return (BuilderType) this;
239    }
240
241    @Override
242    public BuilderType mergeFrom(final CodedInputStream input)
243                                 throws IOException {
244      return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
245    }
246
247    @Override
248    public BuilderType mergeFrom(
249        final CodedInputStream input,
250        final ExtensionRegistryLite extensionRegistry)
251        throws IOException {
252      final UnknownFieldSet.Builder unknownFields =
253        UnknownFieldSet.newBuilder(getUnknownFields());
254      while (true) {
255        final int tag = input.readTag();
256        if (tag == 0) {
257          break;
258        }
259
260        if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
261                            this, tag)) {
262          // end group tag
263          break;
264        }
265      }
266      setUnknownFields(unknownFields.build());
267      return (BuilderType) this;
268    }
269
270    /**
271     * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
272     * ExtensionRegistryLite, Message.Builder)}, but parses a single field.
273     * Package-private because it is used by GeneratedMessage.ExtendableMessage.
274     * @param tag The tag, which should have already been read.
275     * @return {@code true} unless the tag is an end-group tag.
276     */
277    @SuppressWarnings("unchecked")
278    static boolean mergeFieldFrom(
279        final CodedInputStream input,
280        final UnknownFieldSet.Builder unknownFields,
281        final ExtensionRegistryLite extensionRegistry,
282        final Message.Builder builder,
283        final int tag) throws IOException {
284      final Descriptor type = builder.getDescriptorForType();
285
286      if (type.getOptions().getMessageSetWireFormat() &&
287          tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
288        mergeMessageSetExtensionFromCodedStream(
289          input, unknownFields, extensionRegistry, builder);
290        return true;
291      }
292
293      final int wireType = WireFormat.getTagWireType(tag);
294      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
295
296      final FieldDescriptor field;
297      Message defaultInstance = null;
298
299      if (type.isExtensionNumber(fieldNumber)) {
300        // extensionRegistry may be either ExtensionRegistry or
301        // ExtensionRegistryLite.  Since the type we are parsing is a full
302        // message, only a full ExtensionRegistry could possibly contain
303        // extensions of it.  Otherwise we will treat the registry as if it
304        // were empty.
305        if (extensionRegistry instanceof ExtensionRegistry) {
306          final ExtensionRegistry.ExtensionInfo extension =
307            ((ExtensionRegistry) extensionRegistry)
308              .findExtensionByNumber(type, fieldNumber);
309          if (extension == null) {
310            field = null;
311          } else {
312            field = extension.descriptor;
313            defaultInstance = extension.defaultInstance;
314            if (defaultInstance == null &&
315                field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
316              throw new IllegalStateException(
317                  "Message-typed extension lacked default instance: " +
318                  field.getFullName());
319            }
320          }
321        } else {
322          field = null;
323        }
324      } else {
325        field = type.findFieldByNumber(fieldNumber);
326      }
327
328      boolean unknown = false;
329      boolean packed = false;
330      if (field == null) {
331        unknown = true;  // Unknown field.
332      } else if (wireType == FieldSet.getWireFormatForFieldType(
333                   field.getLiteType(),
334                   false  /* isPacked */)) {
335        packed = false;
336      } else if (field.isPackable() &&
337                 wireType == FieldSet.getWireFormatForFieldType(
338                   field.getLiteType(),
339                   true  /* isPacked */)) {
340        packed = true;
341      } else {
342        unknown = true;  // Unknown wire type.
343      }
344
345      if (unknown) {  // Unknown field or wrong wire type.  Skip.
346        return unknownFields.mergeFieldFrom(tag, input);
347      }
348
349      if (packed) {
350        final int length = input.readRawVarint32();
351        final int limit = input.pushLimit(length);
352        if (field.getLiteType() == WireFormat.FieldType.ENUM) {
353          while (input.getBytesUntilLimit() > 0) {
354            final int rawValue = input.readEnum();
355            final Object value = field.getEnumType().findValueByNumber(rawValue);
356            if (value == null) {
357              // If the number isn't recognized as a valid value for this
358              // enum, drop it (don't even add it to unknownFields).
359              return true;
360            }
361            builder.addRepeatedField(field, value);
362          }
363        } else {
364          while (input.getBytesUntilLimit() > 0) {
365            final Object value =
366              FieldSet.readPrimitiveField(input, field.getLiteType());
367            builder.addRepeatedField(field, value);
368          }
369        }
370        input.popLimit(limit);
371      } else {
372        final Object value;
373        switch (field.getType()) {
374          case GROUP: {
375            final Message.Builder subBuilder;
376            if (defaultInstance != null) {
377              subBuilder = defaultInstance.newBuilderForType();
378            } else {
379              subBuilder = builder.newBuilderForField(field);
380            }
381            if (!field.isRepeated()) {
382              subBuilder.mergeFrom((Message) builder.getField(field));
383            }
384            input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
385            value = subBuilder.build();
386            break;
387          }
388          case MESSAGE: {
389            final Message.Builder subBuilder;
390            if (defaultInstance != null) {
391              subBuilder = defaultInstance.newBuilderForType();
392            } else {
393              subBuilder = builder.newBuilderForField(field);
394            }
395            if (!field.isRepeated()) {
396              subBuilder.mergeFrom((Message) builder.getField(field));
397            }
398            input.readMessage(subBuilder, extensionRegistry);
399            value = subBuilder.build();
400            break;
401          }
402          case ENUM:
403            final int rawValue = input.readEnum();
404            value = field.getEnumType().findValueByNumber(rawValue);
405            // If the number isn't recognized as a valid value for this enum,
406            // drop it.
407            if (value == null) {
408              unknownFields.mergeVarintField(fieldNumber, rawValue);
409              return true;
410            }
411            break;
412          default:
413            value = FieldSet.readPrimitiveField(input, field.getLiteType());
414            break;
415        }
416
417        if (field.isRepeated()) {
418          builder.addRepeatedField(field, value);
419        } else {
420          builder.setField(field, value);
421        }
422      }
423
424      return true;
425    }
426
427    /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
428    private static void mergeMessageSetExtensionFromCodedStream(
429        final CodedInputStream input,
430        final UnknownFieldSet.Builder unknownFields,
431        final ExtensionRegistryLite extensionRegistry,
432        final Message.Builder builder) throws IOException {
433      final Descriptor type = builder.getDescriptorForType();
434
435      // The wire format for MessageSet is:
436      //   message MessageSet {
437      //     repeated group Item = 1 {
438      //       required int32 typeId = 2;
439      //       required bytes message = 3;
440      //     }
441      //   }
442      // "typeId" is the extension's field number.  The extension can only be
443      // a message type, where "message" contains the encoded bytes of that
444      // message.
445      //
446      // In practice, we will probably never see a MessageSet item in which
447      // the message appears before the type ID, or where either field does not
448      // appear exactly once.  However, in theory such cases are valid, so we
449      // should be prepared to accept them.
450
451      int typeId = 0;
452      ByteString rawBytes = null;  // If we encounter "message" before "typeId"
453      Message.Builder subBuilder = null;
454      FieldDescriptor field = null;
455
456      while (true) {
457        final int tag = input.readTag();
458        if (tag == 0) {
459          break;
460        }
461
462        if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
463          typeId = input.readUInt32();
464          // Zero is not a valid type ID.
465          if (typeId != 0) {
466            final ExtensionRegistry.ExtensionInfo extension;
467
468            // extensionRegistry may be either ExtensionRegistry or
469            // ExtensionRegistryLite.  Since the type we are parsing is a full
470            // message, only a full ExtensionRegistry could possibly contain
471            // extensions of it.  Otherwise we will treat the registry as if it
472            // were empty.
473            if (extensionRegistry instanceof ExtensionRegistry) {
474              extension = ((ExtensionRegistry) extensionRegistry)
475                  .findExtensionByNumber(type, typeId);
476            } else {
477              extension = null;
478            }
479
480            if (extension != null) {
481              field = extension.descriptor;
482              subBuilder = extension.defaultInstance.newBuilderForType();
483              final Message originalMessage = (Message)builder.getField(field);
484              if (originalMessage != null) {
485                subBuilder.mergeFrom(originalMessage);
486              }
487              if (rawBytes != null) {
488                // We already encountered the message.  Parse it now.
489                subBuilder.mergeFrom(
490                  CodedInputStream.newInstance(rawBytes.newInput()));
491                rawBytes = null;
492              }
493            } else {
494              // Unknown extension number.  If we already saw data, put it
495              // in rawBytes.
496              if (rawBytes != null) {
497                unknownFields.mergeField(typeId,
498                  UnknownFieldSet.Field.newBuilder()
499                    .addLengthDelimited(rawBytes)
500                    .build());
501                rawBytes = null;
502              }
503            }
504          }
505        } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
506          if (typeId == 0) {
507            // We haven't seen a type ID yet, so we have to store the raw bytes
508            // for now.
509            rawBytes = input.readBytes();
510          } else if (subBuilder == null) {
511            // We don't know how to parse this.  Ignore it.
512            unknownFields.mergeField(typeId,
513              UnknownFieldSet.Field.newBuilder()
514                .addLengthDelimited(input.readBytes())
515                .build());
516          } else {
517            // We already know the type, so we can parse directly from the input
518            // with no copying.  Hooray!
519            input.readMessage(subBuilder, extensionRegistry);
520          }
521        } else {
522          // Unknown tag.  Skip it.
523          if (!input.skipField(tag)) {
524            break;  // end of group
525          }
526        }
527      }
528
529      input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
530
531      if (subBuilder != null) {
532        builder.setField(field, subBuilder.build());
533      }
534    }
535
536    public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
537      setUnknownFields(
538        UnknownFieldSet.newBuilder(getUnknownFields())
539                       .mergeFrom(unknownFields)
540                       .build());
541      return (BuilderType) this;
542    }
543
544    /**
545     * Construct an UninitializedMessageException reporting missing fields in
546     * the given message.
547     */
548    protected static UninitializedMessageException
549        newUninitializedMessageException(Message message) {
550      return new UninitializedMessageException(findMissingFields(message));
551    }
552
553    /**
554     * Populates {@code this.missingFields} with the full "path" of each
555     * missing required field in the given message.
556     */
557    private static List<String> findMissingFields(final Message message) {
558      final List<String> results = new ArrayList<String>();
559      findMissingFields(message, "", results);
560      return results;
561    }
562
563    /** Recursive helper implementing {@link #findMissingFields(Message)}. */
564    private static void findMissingFields(final Message message,
565                                          final String prefix,
566                                          final List<String> results) {
567      for (final FieldDescriptor field :
568          message.getDescriptorForType().getFields()) {
569        if (field.isRequired() && !message.hasField(field)) {
570          results.add(prefix + field.getName());
571        }
572      }
573
574      for (final Map.Entry<FieldDescriptor, Object> entry :
575           message.getAllFields().entrySet()) {
576        final FieldDescriptor field = entry.getKey();
577        final Object value = entry.getValue();
578
579        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
580          if (field.isRepeated()) {
581            int i = 0;
582            for (final Object element : (List) value) {
583              findMissingFields((Message) element,
584                                subMessagePrefix(prefix, field, i++),
585                                results);
586            }
587          } else {
588            if (message.hasField(field)) {
589              findMissingFields((Message) value,
590                                subMessagePrefix(prefix, field, -1),
591                                results);
592            }
593          }
594        }
595      }
596    }
597
598    private static String subMessagePrefix(final String prefix,
599                                           final FieldDescriptor field,
600                                           final int index) {
601      final StringBuilder result = new StringBuilder(prefix);
602      if (field.isExtension()) {
603        result.append('(')
604              .append(field.getFullName())
605              .append(')');
606      } else {
607        result.append(field.getName());
608      }
609      if (index != -1) {
610        result.append('[')
611              .append(index)
612              .append(']');
613      }
614      result.append('.');
615      return result.toString();
616    }
617
618    // ===============================================================
619    // The following definitions seem to be required in order to make javac
620    // not produce weird errors like:
621    //
622    // java/com/google/protobuf/DynamicMessage.java:203: types
623    //   com.google.protobuf.AbstractMessage.Builder<
624    //     com.google.protobuf.DynamicMessage.Builder> and
625    //   com.google.protobuf.AbstractMessage.Builder<
626    //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
627    //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
628    //   return types.
629    //
630    // Strangely, these lines are only needed if javac is invoked separately
631    // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
632    // invoked on both simultaneously, it works.  (Or maybe the important
633    // point is whether or not DynamicMessage.java is compiled together with
634    // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
635    // bug.
636
637    @Override
638    public BuilderType mergeFrom(final ByteString data)
639        throws InvalidProtocolBufferException {
640      return super.mergeFrom(data);
641    }
642
643    @Override
644    public BuilderType mergeFrom(
645        final ByteString data,
646        final ExtensionRegistryLite extensionRegistry)
647        throws InvalidProtocolBufferException {
648      return super.mergeFrom(data, extensionRegistry);
649    }
650
651    @Override
652    public BuilderType mergeFrom(final byte[] data)
653        throws InvalidProtocolBufferException {
654      return super.mergeFrom(data);
655    }
656
657    @Override
658    public BuilderType mergeFrom(
659        final byte[] data, final int off, final int len)
660        throws InvalidProtocolBufferException {
661      return super.mergeFrom(data, off, len);
662    }
663
664    @Override
665    public BuilderType mergeFrom(
666        final byte[] data,
667        final ExtensionRegistryLite extensionRegistry)
668        throws InvalidProtocolBufferException {
669      return super.mergeFrom(data, extensionRegistry);
670    }
671
672    @Override
673    public BuilderType mergeFrom(
674        final byte[] data, final int off, final int len,
675        final ExtensionRegistryLite extensionRegistry)
676        throws InvalidProtocolBufferException {
677      return super.mergeFrom(data, off, len, extensionRegistry);
678    }
679
680    @Override
681    public BuilderType mergeFrom(final InputStream input)
682        throws IOException {
683      return super.mergeFrom(input);
684    }
685
686    @Override
687    public BuilderType mergeFrom(
688        final InputStream input,
689        final ExtensionRegistryLite extensionRegistry)
690        throws IOException {
691      return super.mergeFrom(input, extensionRegistry);
692    }
693
694    @Override
695    public boolean mergeDelimitedFrom(final InputStream input)
696        throws IOException {
697      return super.mergeDelimitedFrom(input);
698    }
699
700    @Override
701    public boolean mergeDelimitedFrom(
702        final InputStream input,
703        final ExtensionRegistryLite extensionRegistry)
704        throws IOException {
705      return super.mergeDelimitedFrom(input, extensionRegistry);
706    }
707
708  }
709}
710