1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.thrift; 19 20 import java.nio.ByteBuffer; 21 import java.util.ArrayList; 22 import java.util.HashMap; 23 import java.util.HashSet; 24 import java.util.List; 25 import java.util.Map; 26 import java.util.Set; 27 28 import org.apache.thrift.protocol.TField; 29 import org.apache.thrift.protocol.TProtocol; 30 import org.apache.thrift.protocol.TProtocolException; 31 import org.apache.thrift.protocol.TStruct; 32 import org.apache.thrift.scheme.IScheme; 33 import org.apache.thrift.scheme.SchemeFactory; 34 import org.apache.thrift.scheme.StandardScheme; 35 import org.apache.thrift.scheme.TupleScheme; 36 37 public abstract class TUnion<T extends TUnion<T,F>, F extends TFieldIdEnum> implements TBase<T, F> { 38 39 protected Object value_; 40 protected F setField_; 41 TUnion()42 protected TUnion() { 43 setField_ = null; 44 value_ = null; 45 } 46 47 private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>(); 48 static { schemes.put(StandardScheme.class, new TUnionStandardSchemeFactory())49 schemes.put(StandardScheme.class, new TUnionStandardSchemeFactory()); schemes.put(TupleScheme.class, new TUnionTupleSchemeFactory())50 schemes.put(TupleScheme.class, new TUnionTupleSchemeFactory()); 51 } 52 TUnion(F setField, Object value)53 protected TUnion(F setField, Object value) { 54 setFieldValue(setField, value); 55 } 56 TUnion(TUnion<T, F> other)57 protected TUnion(TUnion<T, F> other) { 58 if (!other.getClass().equals(this.getClass())) { 59 throw new ClassCastException(); 60 } 61 setField_ = other.setField_; 62 value_ = deepCopyObject(other.value_); 63 } 64 deepCopyObject(Object o)65 private static Object deepCopyObject(Object o) { 66 if (o instanceof TBase) { 67 return ((TBase)o).deepCopy(); 68 } else if (o instanceof ByteBuffer) { 69 return TBaseHelper.copyBinary((ByteBuffer)o); 70 } else if (o instanceof List) { 71 return deepCopyList((List)o); 72 } else if (o instanceof Set) { 73 return deepCopySet((Set)o); 74 } else if (o instanceof Map) { 75 return deepCopyMap((Map)o); 76 } else { 77 return o; 78 } 79 } 80 deepCopyMap(Map<Object, Object> map)81 private static Map deepCopyMap(Map<Object, Object> map) { 82 Map copy = new HashMap(map.size()); 83 for (Map.Entry<Object, Object> entry : map.entrySet()) { 84 copy.put(deepCopyObject(entry.getKey()), deepCopyObject(entry.getValue())); 85 } 86 return copy; 87 } 88 deepCopySet(Set set)89 private static Set deepCopySet(Set set) { 90 Set copy = new HashSet(set.size()); 91 for (Object o : set) { 92 copy.add(deepCopyObject(o)); 93 } 94 return copy; 95 } 96 deepCopyList(List list)97 private static List deepCopyList(List list) { 98 List copy = new ArrayList(list.size()); 99 for (Object o : list) { 100 copy.add(deepCopyObject(o)); 101 } 102 return copy; 103 } 104 getSetField()105 public F getSetField() { 106 return setField_; 107 } 108 getFieldValue()109 public Object getFieldValue() { 110 return value_; 111 } 112 getFieldValue(F fieldId)113 public Object getFieldValue(F fieldId) { 114 if (fieldId != setField_) { 115 throw new IllegalArgumentException("Cannot get the value of field " + fieldId + " because union's set field is " + setField_); 116 } 117 118 return getFieldValue(); 119 } 120 getFieldValue(int fieldId)121 public Object getFieldValue(int fieldId) { 122 return getFieldValue(enumForId((short)fieldId)); 123 } 124 isSet()125 public boolean isSet() { 126 return setField_ != null; 127 } 128 isSet(F fieldId)129 public boolean isSet(F fieldId) { 130 return setField_ == fieldId; 131 } 132 isSet(int fieldId)133 public boolean isSet(int fieldId) { 134 return isSet(enumForId((short)fieldId)); 135 } 136 read(TProtocol iprot)137 public void read(TProtocol iprot) throws TException { 138 schemes.get(iprot.getScheme()).getScheme().read(iprot, this); 139 } 140 setFieldValue(F fieldId, Object value)141 public void setFieldValue(F fieldId, Object value) { 142 checkType(fieldId, value); 143 setField_ = fieldId; 144 value_ = value; 145 } 146 setFieldValue(int fieldId, Object value)147 public void setFieldValue(int fieldId, Object value) { 148 setFieldValue(enumForId((short)fieldId), value); 149 } 150 write(TProtocol oprot)151 public void write(TProtocol oprot) throws TException { 152 schemes.get(oprot.getScheme()).getScheme().write(oprot, this); 153 } 154 155 /** 156 * Implementation should be generated so that we can efficiently type check 157 * various values. 158 * @param setField 159 * @param value 160 */ checkType(F setField, Object value)161 protected abstract void checkType(F setField, Object value) throws ClassCastException; 162 163 /** 164 * Implementation should be generated to read the right stuff from the wire 165 * based on the field header. 166 * @param field 167 * @return read Object based on the field header, as specified by the argument. 168 */ standardSchemeReadValue(TProtocol iprot, TField field)169 protected abstract Object standardSchemeReadValue(TProtocol iprot, TField field) throws TException; standardSchemeWriteValue(TProtocol oprot)170 protected abstract void standardSchemeWriteValue(TProtocol oprot) throws TException; 171 tupleSchemeReadValue(TProtocol iprot, short fieldID)172 protected abstract Object tupleSchemeReadValue(TProtocol iprot, short fieldID) throws TException; tupleSchemeWriteValue(TProtocol oprot)173 protected abstract void tupleSchemeWriteValue(TProtocol oprot) throws TException; 174 getStructDesc()175 protected abstract TStruct getStructDesc(); 176 getFieldDesc(F setField)177 protected abstract TField getFieldDesc(F setField); 178 enumForId(short id)179 protected abstract F enumForId(short id); 180 181 @Override toString()182 public String toString() { 183 StringBuilder sb = new StringBuilder(); 184 sb.append("<"); 185 sb.append(this.getClass().getSimpleName()); 186 sb.append(" "); 187 188 if (getSetField() != null) { 189 Object v = getFieldValue(); 190 sb.append(getFieldDesc(getSetField()).name); 191 sb.append(":"); 192 if(v instanceof ByteBuffer) { 193 TBaseHelper.toString((ByteBuffer)v, sb); 194 } else { 195 sb.append(v.toString()); 196 } 197 } 198 sb.append(">"); 199 return sb.toString(); 200 } 201 clear()202 public final void clear() { 203 this.setField_ = null; 204 this.value_ = null; 205 } 206 207 private static class TUnionStandardSchemeFactory implements SchemeFactory { getScheme()208 public TUnionStandardScheme getScheme() { 209 return new TUnionStandardScheme(); 210 } 211 } 212 213 private static class TUnionStandardScheme extends StandardScheme<TUnion> { 214 215 @Override read(TProtocol iprot, TUnion struct)216 public void read(TProtocol iprot, TUnion struct) throws TException { 217 struct.setField_ = null; 218 struct.value_ = null; 219 220 iprot.readStructBegin(); 221 222 TField field = iprot.readFieldBegin(); 223 224 struct.value_ = struct.standardSchemeReadValue(iprot, field); 225 if (struct.value_ != null) { 226 struct.setField_ = struct.enumForId(field.id); 227 } 228 229 iprot.readFieldEnd(); 230 // this is so that we will eat the stop byte. we could put a check here to 231 // make sure that it actually *is* the stop byte, but it's faster to do it 232 // this way. 233 iprot.readFieldBegin(); 234 iprot.readStructEnd(); 235 } 236 237 @Override write(TProtocol oprot, TUnion struct)238 public void write(TProtocol oprot, TUnion struct) throws TException { 239 if (struct.getSetField() == null || struct.getFieldValue() == null) { 240 throw new TProtocolException("Cannot write a TUnion with no set value!"); 241 } 242 oprot.writeStructBegin(struct.getStructDesc()); 243 oprot.writeFieldBegin(struct.getFieldDesc(struct.setField_)); 244 struct.standardSchemeWriteValue(oprot); 245 oprot.writeFieldEnd(); 246 oprot.writeFieldStop(); 247 oprot.writeStructEnd(); 248 } 249 } 250 251 private static class TUnionTupleSchemeFactory implements SchemeFactory { getScheme()252 public TUnionTupleScheme getScheme() { 253 return new TUnionTupleScheme(); 254 } 255 } 256 257 private static class TUnionTupleScheme extends TupleScheme<TUnion> { 258 259 @Override read(TProtocol iprot, TUnion struct)260 public void read(TProtocol iprot, TUnion struct) throws TException { 261 struct.setField_ = null; 262 struct.value_ = null; 263 short fieldID = iprot.readI16(); 264 struct.value_ = struct.tupleSchemeReadValue(iprot, fieldID); 265 if (struct.value_ != null) { 266 struct.setField_ = struct.enumForId(fieldID); 267 } 268 } 269 270 @Override write(TProtocol oprot, TUnion struct)271 public void write(TProtocol oprot, TUnion struct) throws TException { 272 if (struct.getSetField() == null || struct.getFieldValue() == null) { 273 throw new TProtocolException("Cannot write a TUnion with no set value!"); 274 } 275 oprot.writeI16(struct.setField_.getThriftFieldId()); 276 struct.tupleSchemeWriteValue(oprot); 277 } 278 } 279 } 280