1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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 35 /** 36 * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores 37 * the message in a ByteString initially and then parse it on-demand. 38 * 39 * LazyField is thread-compatible e.g. concurrent read are safe, however, 40 * synchronizations are needed under read/write situations. 41 * 42 * This class is internal implementation detail, so you don't need to use it directly. 43 * 44 * @author xiangl@google.com (Xiang Li) 45 */ 46 public class LazyFieldLite { 47 private ByteString bytes; 48 private ExtensionRegistryLite extensionRegistry; 49 private volatile boolean isDirty = false; 50 51 protected volatile MessageLite value; 52 LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes)53 public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) { 54 this.extensionRegistry = extensionRegistry; 55 this.bytes = bytes; 56 } 57 LazyFieldLite()58 public LazyFieldLite() { 59 } 60 fromValue(MessageLite value)61 public static LazyFieldLite fromValue(MessageLite value) { 62 LazyFieldLite lf = new LazyFieldLite(); 63 lf.setValue(value); 64 return lf; 65 } 66 containsDefaultInstance()67 public boolean containsDefaultInstance() { 68 return value == null && bytes == null; 69 } 70 clear()71 public void clear() { 72 bytes = null; 73 value = null; 74 extensionRegistry = null; 75 isDirty = true; 76 } 77 78 /** 79 * Returns message instance. At first time, serialized data is parsed by 80 * {@code defaultInstance.getParserForType()}. 81 * 82 * @param defaultInstance its message's default instance. It's also used to get parser for the 83 * message type. 84 */ getValue(MessageLite defaultInstance)85 public MessageLite getValue(MessageLite defaultInstance) { 86 ensureInitialized(defaultInstance); 87 return value; 88 } 89 90 /** 91 * LazyField is not thread-safe for write access. Synchronizations are needed 92 * under read/write situations. 93 */ setValue(MessageLite value)94 public MessageLite setValue(MessageLite value) { 95 MessageLite originalValue = this.value; 96 this.value = value; 97 bytes = null; 98 isDirty = true; 99 return originalValue; 100 } 101 merge(LazyFieldLite value)102 public void merge(LazyFieldLite value) { 103 if (value.containsDefaultInstance()) { 104 return; 105 } 106 107 if (bytes == null) { 108 this.bytes = value.bytes; 109 } else { 110 this.bytes.concat(value.toByteString()); 111 } 112 isDirty = false; 113 } 114 setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry)115 public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) { 116 this.bytes = bytes; 117 this.extensionRegistry = extensionRegistry; 118 isDirty = false; 119 } 120 getExtensionRegistry()121 public ExtensionRegistryLite getExtensionRegistry() { 122 return extensionRegistry; 123 } 124 125 /** 126 * Due to the optional field can be duplicated at the end of serialized 127 * bytes, which will make the serialized size changed after LazyField 128 * parsed. Be careful when using this method. 129 */ getSerializedSize()130 public int getSerializedSize() { 131 if (isDirty) { 132 return value.getSerializedSize(); 133 } 134 return bytes.size(); 135 } 136 toByteString()137 public ByteString toByteString() { 138 if (!isDirty) { 139 return bytes; 140 } 141 synchronized (this) { 142 if (!isDirty) { 143 return bytes; 144 } 145 if (value == null) { 146 bytes = ByteString.EMPTY; 147 } else { 148 bytes = value.toByteString(); 149 } 150 isDirty = false; 151 return bytes; 152 } 153 } 154 ensureInitialized(MessageLite defaultInstance)155 protected void ensureInitialized(MessageLite defaultInstance) { 156 if (value != null) { 157 return; 158 } 159 synchronized (this) { 160 if (value != null) { 161 return; 162 } 163 try { 164 if (bytes != null) { 165 value = defaultInstance.getParserForType() 166 .parseFrom(bytes, extensionRegistry); 167 } else { 168 value = defaultInstance; 169 } 170 } catch (IOException e) { 171 // TODO(xiangl): Refactory the API to support the exception thrown from 172 // lazily load messages. 173 } 174 } 175 } 176 } 177