- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / main / java / com / google / protobuf / LazyField.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 java.io.IOException;
34 import java.util.Iterator;
35 import java.util.Map.Entry;
36
37 /**
38  * LazyField encapsulates the logic of lazily parsing message fields. It stores
39  * the message in a ByteString initially and then parse it on-demand.
40  *
41  * LazyField is thread-compatible e.g. concurrent read are safe, however,
42  * synchronizations are needed under read/write situations.
43  *
44  * Now LazyField is only used to lazily load MessageSet.
45  * TODO(xiangl): Use LazyField to lazily load all messages.
46  *
47  * @author xiangl@google.com (Xiang Li)
48  */
49 class LazyField {
50
51   final private MessageLite defaultInstance;
52   final private ExtensionRegistryLite extensionRegistry;
53
54   // Mutable because it is initialized lazily.
55   private ByteString bytes;
56   private volatile MessageLite value;
57   private volatile boolean isDirty = false;
58
59   public LazyField(MessageLite defaultInstance,
60       ExtensionRegistryLite extensionRegistry, ByteString bytes) {
61     this.defaultInstance = defaultInstance;
62     this.extensionRegistry = extensionRegistry;
63     this.bytes = bytes;
64   }
65
66   public MessageLite getValue() {
67     ensureInitialized();
68     return value;
69   }
70
71   /**
72    * LazyField is not thread-safe for write access. Synchronizations are needed
73    * under read/write situations.
74    */
75   public MessageLite setValue(MessageLite value) {
76     MessageLite originalValue = this.value;
77     this.value = value;
78     bytes = null;
79     isDirty = true;
80     return originalValue;
81   }
82
83   /**
84    * Due to the optional field can be duplicated at the end of serialized
85    * bytes, which will make the serialized size changed after LazyField
86    * parsed. Be careful when using this method.
87    */
88   public int getSerializedSize() {
89     if (isDirty) {
90       return value.getSerializedSize();
91     }
92     return bytes.size();
93   }
94
95   public ByteString toByteString() {
96     if (!isDirty) {
97       return bytes;
98     }
99     synchronized (this) {
100       if (!isDirty) {
101         return bytes;
102       }
103       bytes = value.toByteString();
104       isDirty = false;
105       return bytes;
106     }
107   }
108
109   @Override
110   public int hashCode() {
111     ensureInitialized();
112     return value.hashCode();
113   }
114
115   @Override
116   public boolean equals(Object obj) {
117     ensureInitialized();
118     return value.equals(obj);
119   }
120
121   @Override
122   public String toString() {
123     ensureInitialized();
124     return value.toString();
125   }
126
127   private void ensureInitialized() {
128     if (value != null) {
129       return;
130     }
131     synchronized (this) {
132       if (value != null) {
133         return;
134       }
135       try {
136         if (bytes != null) {
137           value = defaultInstance.getParserForType()
138               .parseFrom(bytes, extensionRegistry);
139         }
140       } catch (IOException e) {
141         // TODO(xiangl): Refactory the API to support the exception thrown from
142         // lazily load messages.
143       }
144     }
145   }
146
147   // ====================================================
148
149   /**
150    * LazyEntry and LazyIterator are used to encapsulate the LazyField, when
151    * users iterate all fields from FieldSet.
152    */
153   static class LazyEntry<K> implements Entry<K, Object> {
154     private Entry<K, LazyField> entry;
155
156     private LazyEntry(Entry<K, LazyField> entry) {
157       this.entry = entry;
158     }
159
160     public K getKey() {
161       return entry.getKey();
162     }
163
164     public Object getValue() {
165       LazyField field = entry.getValue();
166       if (field == null) {
167         return null;
168       }
169       return field.getValue();
170     }
171
172     public LazyField getField() {
173       return entry.getValue();
174     }
175
176     public Object setValue(Object value) {
177       if (!(value instanceof MessageLite)) {
178         throw new IllegalArgumentException(
179             "LazyField now only used for MessageSet, "
180             + "and the value of MessageSet must be an instance of MessageLite");
181       }
182       return entry.getValue().setValue((MessageLite) value);
183     }
184   }
185
186   static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
187     private Iterator<Entry<K, Object>> iterator;
188
189     public LazyIterator(Iterator<Entry<K, Object>> iterator) {
190       this.iterator = iterator;
191     }
192
193     public boolean hasNext() {
194       return iterator.hasNext();
195     }
196
197     @SuppressWarnings("unchecked")
198     public Entry<K, Object> next() {
199       Entry<K, ?> entry = iterator.next();
200       if (entry.getValue() instanceof LazyField) {
201         return new LazyEntry<K>((Entry<K, LazyField>) entry);
202       }
203       return (Entry<K, Object>) entry;
204     }
205
206     public void remove() {
207       iterator.remove();
208     }
209   }
210 }