- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / main / java / com / google / protobuf / SingleFieldBuilder.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 /**
34  * {@code SingleFieldBuilder} implements a structure that a protocol
35  * message uses to hold a single field of another protocol message. It supports
36  * the classical use case of setting an immutable {@link Message} as the value
37  * of the field and is highly optimized around this.
38  * <br>
39  * It also supports the additional use case of setting a {@link Message.Builder}
40  * as the field and deferring conversion of that {@code Builder}
41  * to an immutable {@code Message}. In this way, it's possible to maintain
42  * a tree of {@code Builder}'s that acts as a fully read/write data
43  * structure.
44  * <br>
45  * Logically, one can think of a tree of builders as converting the entire tree
46  * to messages when build is called on the root or when any method is called
47  * that desires a Message instead of a Builder. In terms of the implementation,
48  * the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
49  * classes cache messages that were created so that messages only need to be
50  * created when some change occured in its builder or a builder for one of its
51  * descendants.
52  *
53  * @param <MType> the type of message for the field
54  * @param <BType> the type of builder for the field
55  * @param <IType> the common interface for the message and the builder
56  *
57  * @author jonp@google.com (Jon Perlow)
58  */
59 public class SingleFieldBuilder
60     <MType extends GeneratedMessage,
61      BType extends GeneratedMessage.Builder,
62      IType extends MessageOrBuilder>
63     implements GeneratedMessage.BuilderParent {
64
65   // Parent to send changes to.
66   private GeneratedMessage.BuilderParent parent;
67
68   // Invariant: one of builder or message fields must be non-null.
69
70   // If set, this is the case where we are backed by a builder. In this case,
71   // message field represents a cached message for the builder (or null if
72   // there is no cached message).
73   private BType builder;
74
75   // If builder is non-null, this represents a cached message from the builder.
76   // If builder is null, this is the authoritative message for the field.
77   private MType message;
78
79   // Indicates that we've built a message and so we are now obligated
80   // to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
81   private boolean isClean;
82
83   public SingleFieldBuilder(
84       MType message,
85       GeneratedMessage.BuilderParent parent,
86       boolean isClean) {
87     if (message == null) {
88       throw new NullPointerException();
89     }
90     this.message = message;
91     this.parent = parent;
92     this.isClean = isClean;
93   }
94
95   public void dispose() {
96     // Null out parent so we stop sending it invalidations.
97     parent = null;
98   }
99
100   /**
101    * Get the message for the field. If the message is currently stored
102    * as a {@code Builder}, it is converted to a {@code Message} by
103    * calling {@link Message.Builder#buildPartial} on it. If no message has
104    * been set, returns the default instance of the message.
105    *
106    * @return the message for the field
107    */
108   @SuppressWarnings("unchecked")
109   public MType getMessage() {
110     if (message == null) {
111       // If message is null, the invariant is that we must be have a builder.
112       message = (MType) builder.buildPartial();
113     }
114     return message;
115   }
116
117   /**
118    * Builds the message and returns it.
119    *
120    * @return the message
121    */
122   public MType build() {
123     // Now that build has been called, we are required to dispatch
124     // invalidations.
125     isClean = true;
126     return getMessage();
127   }
128
129   /**
130    * Gets a builder for the field. If no builder has been created yet, a
131    * builder is created on demand by calling {@link Message#toBuilder}.
132    *
133    * @return The builder for the field
134    */
135   @SuppressWarnings("unchecked")
136   public BType getBuilder() {
137     if (builder == null) {
138       // builder.mergeFrom() on a fresh builder
139       // does not create any sub-objects with independent clean/dirty states,
140       // therefore setting the builder itself to clean without actually calling
141       // build() cannot break any invariants.
142       builder = (BType) message.newBuilderForType(this);
143       builder.mergeFrom(message); // no-op if message is the default message
144       builder.markClean();
145     }
146     return builder;
147   }
148
149   /**
150    * Gets the base class interface for the field. This may either be a builder
151    * or a message. It will return whatever is more efficient.
152    *
153    * @return the message or builder for the field as the base class interface
154    */
155   @SuppressWarnings("unchecked")
156   public IType getMessageOrBuilder() {
157     if (builder != null) {
158       return  (IType) builder;
159     } else {
160       return (IType) message;
161     }
162   }
163
164   /**
165    * Sets a  message for the field replacing any existing value.
166    *
167    * @param message the message to set
168    * @return the builder
169    */
170   public SingleFieldBuilder<MType, BType, IType> setMessage(
171       MType message) {
172     if (message == null) {
173       throw new NullPointerException();
174     }
175     this.message = message;
176     if (builder != null) {
177       builder.dispose();
178       builder = null;
179     }
180     onChanged();
181     return this;
182   }
183
184   /**
185    * Merges the field from another field.
186    *
187    * @param value the value to merge from
188    * @return the builder
189    */
190   public SingleFieldBuilder<MType, BType, IType> mergeFrom(
191       MType value) {
192     if (builder == null && message == message.getDefaultInstanceForType()) {
193       message = value;
194     } else {
195       getBuilder().mergeFrom(value);
196     }
197     onChanged();
198     return this;
199   }
200
201   /**
202    * Clears the value of the field.
203    *
204    * @return the builder
205    */
206   @SuppressWarnings("unchecked")
207   public SingleFieldBuilder<MType, BType, IType> clear() {
208     message = (MType) (message != null ?
209         message.getDefaultInstanceForType() :
210         builder.getDefaultInstanceForType());
211     if (builder != null) {
212       builder.dispose();
213       builder = null;
214     }
215     onChanged();
216     return this;
217   }
218
219   /**
220    * Called when a the builder or one of its nested children has changed
221    * and any parent should be notified of its invalidation.
222    */
223   private void onChanged() {
224     // If builder is null, this is the case where onChanged is being called
225     // from setMessage or clear.
226     if (builder != null) {
227       message = null;
228     }
229     if (isClean && parent != null) {
230       parent.markDirty();
231
232       // Don't keep dispatching invalidations until build is called again.
233       isClean = false;
234     }
235   }
236
237   //@Override (Java 1.6 override semantics, but we must support 1.5)
238   public void markDirty() {
239     onChanged();
240   }
241 }