1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.hbql.mapping;
22
23 import org.apache.expreval.client.NullColumnValueException;
24 import org.apache.expreval.client.ResultMissingColumnException;
25 import org.apache.hadoop.hbase.client.Result;
26 import org.apache.hadoop.hbase.hbql.client.HBqlException;
27 import org.apache.hadoop.hbase.hbql.impl.Utils;
28 import org.apache.hadoop.hbase.hbql.io.IO;
29 import org.apache.hadoop.hbase.hbql.parser.ParserSupport;
30 import org.apache.hadoop.hbase.hbql.statement.args.ColumnWidth;
31 import org.apache.hadoop.hbase.hbql.statement.args.DefaultArg;
32 import org.apache.hadoop.hbase.hbql.util.AtomicReferences;
33
34 import java.io.Serializable;
35 import java.lang.reflect.InvocationTargetException;
36 import java.lang.reflect.Method;
37 import java.util.Map;
38 import java.util.NavigableMap;
39 import java.util.concurrent.atomic.AtomicReference;
40
41 public abstract class ColumnAttrib implements Serializable {
42
43 private static final long serialVersionUID = 1L;
44
45 private ColumnDefinition columnDefinition;
46
47 private AtomicReference<byte[]> atomicFamilyQualifiedBytes = AtomicReferences.newAtomicReference();
48 private AtomicReference<byte[]> atomicFamilyBytes = AtomicReferences.newAtomicReference();
49 private AtomicReference<byte[]> atomicColumnBytes = AtomicReferences.newAtomicReference();
50 private transient Method getterMethod = null;
51 private transient Method setterMethod = null;
52 private boolean embedded;
53
54 public ColumnAttrib() {
55 }
56
57 protected ColumnAttrib(final ColumnDefinition columnDefinition) {
58 this.columnDefinition = columnDefinition;
59 this.embedded = this.getFamilyName() != null && this.getFamilyName().equals(ParserSupport.EMBEDDED);
60 }
61
62 private boolean isEmbedded() {
63 return this.embedded;
64 }
65
66 public Object getDefaultValue() throws HBqlException {
67 return (this.hasDefaultArg()) ? this.getDefaultArg().getDefaultValue() : null;
68 }
69
70 public boolean hasDefaultArg() throws HBqlException {
71 return this.getDefaultArg() != null;
72 }
73
74 protected DefaultArg getDefaultArg() {
75 return null;
76 }
77
78 public abstract Object getCurrentValue(final Object obj) throws HBqlException, ResultMissingColumnException, NullColumnValueException;
79
80 public abstract void setCurrentValue(final Object obj,
81 final long timestamp,
82 final Object val) throws HBqlException;
83
84 public abstract Map<Long, Object> getVersionMap(final Object obj) throws HBqlException;
85
86 public abstract void setUnMappedCurrentValue(final Object obj,
87 final String name,
88 final byte[] value) throws HBqlException;
89
90 public abstract void setUnMappedVersionMap(final Object obj,
91 final String name,
92 final NavigableMap<Long, byte[]> timeStampMap) throws HBqlException;
93
94 protected abstract Method getMethod(final String methodName,
95 final Class<?>... params) throws NoSuchMethodException, HBqlException;
96
97 protected abstract Class getComponentType() throws HBqlException;
98
99 public abstract String getNameToUseInExceptions();
100
101 public abstract String getEnclosingClassName();
102
103
104 public void resetDefaultValue() throws HBqlException {
105 if (this.hasDefaultArg())
106 this.getDefaultArg().reset();
107 }
108
109 public void setVersionMap(final Object obj, final NavigableMap<Long, byte[]> timeStampMap) throws HBqlException {
110
111 final Map<Long, Object> mapVal = this.getVersionMap(obj);
112
113 for (final Long timestamp : timeStampMap.keySet()) {
114 final Object val = this.getValueFromBytes(obj, timeStampMap.get(timestamp));
115 mapVal.put(timestamp, val);
116 }
117 }
118
119 public String getFamilyQualifiedName() {
120 if (!this.isEmbedded() && Utils.isValidString(this.getFamilyName()))
121 return this.getFamilyName() + ":" + this.getColumnName();
122 else
123 return this.getColumnName();
124 }
125
126 private AtomicReference<byte[]> getAtomicFamilyQualifiedBytes() {
127 return this.atomicFamilyQualifiedBytes;
128 }
129
130 public byte[] getFamilyQualifiedNameAsBytes() throws HBqlException {
131 if (this.getAtomicFamilyQualifiedBytes().get() == null)
132 synchronized (this) {
133 if (this.getAtomicFamilyQualifiedBytes().get() == null) {
134 final byte[] b = IO.getSerialization().getStringAsBytes(this.getFamilyQualifiedName());
135 this.getAtomicFamilyQualifiedBytes().set(b);
136 }
137 }
138 return this.getAtomicFamilyQualifiedBytes().get();
139 }
140
141 private AtomicReference<byte[]> getAtomicFamilyBytes() {
142 return this.atomicFamilyBytes;
143 }
144
145 public byte[] getFamilyNameAsBytes() throws HBqlException {
146 if (this.getAtomicFamilyBytes().get() == null)
147 synchronized (this) {
148 if (this.getAtomicFamilyBytes().get() == null) {
149 final byte[] b = IO.getSerialization().getStringAsBytes(this.getFamilyName());
150 this.getAtomicFamilyBytes().set(b);
151 }
152 }
153 return this.getAtomicFamilyBytes().get();
154 }
155
156 private AtomicReference<byte[]> getAtomicColumnBytes() {
157 return this.atomicColumnBytes;
158 }
159
160 public byte[] getColumnNameAsBytes() throws HBqlException {
161 if (this.getAtomicColumnBytes().get() == null)
162 synchronized (this) {
163 if (this.getAtomicColumnBytes().get() == null) {
164 final byte[] b = IO.getSerialization().getStringAsBytes(this.getColumnName());
165 this.getAtomicColumnBytes().set(b);
166 }
167 }
168 return this.getAtomicColumnBytes().get();
169 }
170
171 public boolean equals(final Object o) {
172
173 if (!(o instanceof ColumnAttrib))
174 return false;
175
176 final ColumnAttrib var = (ColumnAttrib)o;
177
178 return var.getAliasName().equals(this.getAliasName())
179 && var.getFamilyQualifiedName().equals(this.getFamilyQualifiedName());
180 }
181
182 public int hashCode() {
183 return this.getAliasName().hashCode() + this.getFamilyQualifiedName().hashCode();
184 }
185
186 protected void defineAccessors() throws HBqlException {
187 try {
188 if (Utils.isValidString(this.getGetter())) {
189 this.getterMethod = this.getMethod(this.getGetter());
190
191
192 final Class<?> returnType = this.getGetterMethod().getReturnType();
193
194 if (!(returnType.isArray() && returnType.getComponentType() == Byte.TYPE))
195 throw new HBqlException(this.getEnclosingClassName() + "." + this.getGetter() + "()"
196 + " does not have a return type of byte[]");
197 }
198 }
199 catch (NoSuchMethodException e) {
200 throw new HBqlException("Missing method byte[] " + this.getEnclosingClassName() + "."
201 + this.getGetter() + "()");
202 }
203
204 try {
205 if (Utils.isValidString(this.getSetter())) {
206 this.setterMethod = this.getMethod(this.getSetter(), Class.forName("[B"));
207
208
209 final Class<?>[] args = this.getSetterMethod().getParameterTypes();
210 if (args.length != 1 || !(args[0].isArray() && args[0].getComponentType() == Byte.TYPE))
211 throw new HBqlException(this.getEnclosingClassName() + "." + this.getSetter() + "()"
212 + " does not have single byte[] arg");
213 }
214 }
215 catch (NoSuchMethodException e) {
216 throw new HBqlException("Missing method " + this.getEnclosingClassName()
217 + "." + this.getSetter() + "(byte[] arg)");
218 }
219 catch (ClassNotFoundException e) {
220
221 throw new HBqlException("Missing method " + this.getEnclosingClassName()
222 + "." + this.getSetter() + "(byte[] arg)");
223 }
224 }
225
226 public byte[] invokeGetterMethod(final Object obj) throws HBqlException {
227 try {
228 return (byte[])this.getGetterMethod().invoke(obj);
229 }
230 catch (IllegalAccessException e) {
231 throw new HBqlException("Error getting value of " + this.getNameToUseInExceptions());
232 }
233 catch (InvocationTargetException e) {
234 throw new HBqlException("Error getting value of " + this.getNameToUseInExceptions());
235 }
236 }
237
238 public Object invokeSetterMethod(final Object obj, final byte[] b) throws HBqlException {
239 try {
240
241 return this.getSetterMethod().invoke(obj, b);
242 }
243 catch (IllegalAccessException e) {
244 throw new HBqlException("Error setting value of " + this.getNameToUseInExceptions());
245 }
246 catch (InvocationTargetException e) {
247 throw new HBqlException("Error setting value of " + this.getNameToUseInExceptions());
248 }
249 }
250
251 public byte[] getValueAsBytes(final Object obj) throws HBqlException {
252
253 final byte[] retval;
254
255 if (this.hasGetter()) {
256 retval = this.invokeGetterMethod(obj);
257 }
258 else {
259 final Object value;
260 try {
261 value = this.getCurrentValue(obj);
262 }
263 catch (ResultMissingColumnException e) {
264 return null;
265 }
266 catch (NullColumnValueException e) {
267 return null;
268 }
269
270 if (this.isAnArray()) {
271 retval = IO.getSerialization().getArrayAsBytes(this.getFieldType(), value);
272 }
273 else {
274 this.validateValueWidth(value);
275 retval = IO.getSerialization().getScalarAsBytes(this.getFieldType(), value);
276 }
277 }
278
279 return retval;
280 }
281
282 public void validateValueWidth(final Object value) throws HBqlException {
283
284 final ColumnWidth columnWidth = this.getColumnDefinition().getColumnWidth();
285 if (columnWidth.isWidthSpecified()) {
286 final int width = columnWidth.getWidth();
287 if (width > 0 && value instanceof String) {
288 final String str = (String)value;
289 if (str.length() != width)
290 throw new HBqlException("Invalid length in " + this.getNameToUseInExceptions()
291 + " expecting width " + width + " but found " + str.length()
292 + " with string \"" + str + "\"");
293 }
294 }
295 }
296
297 public Object getValueFromBytes(final Object obj, final byte[] b) throws HBqlException {
298
299 if (this.hasSetter())
300 return this.invokeSetterMethod(obj, b);
301
302 if (this.isAnArray())
303 return IO.getSerialization().getArrayFromBytes(this.getFieldType(), this.getComponentType(), b);
304 else
305 return IO.getSerialization().getScalarFromBytes(this.getFieldType(), b);
306 }
307
308 public Object getValueFromBytes(final Result result) throws HBqlException, ResultMissingColumnException, NullColumnValueException {
309
310 if (this.isAKeyAttrib()) {
311 return IO.getSerialization().getStringFromBytes(result.getRow());
312 }
313 else {
314 if (!result.containsColumn(this.getFamilyNameAsBytes(), this.getColumnNameAsBytes())) {
315
316
317 if (!this.hasDefaultArg())
318 throw new ResultMissingColumnException(this.getFamilyQualifiedName());
319
320 return this.getDefaultValue();
321 }
322
323 final byte[] b = result.getValue(this.getFamilyNameAsBytes(), this.getColumnNameAsBytes());
324
325 if (b == null) {
326 throw new NullColumnValueException(this.getFamilyQualifiedName());
327 }
328 else {
329 if (this.isAnArray())
330 return IO.getSerialization().getArrayFromBytes(this.getFieldType(), this.getComponentType(), b);
331 else
332 return IO.getSerialization().getScalarFromBytes(this.getFieldType(), b);
333 }
334 }
335 }
336
337 public void setCurrentValue(final Object obj, final long timestamp, final byte[] b) throws HBqlException {
338 final Object val = this.getValueFromBytes(obj, b);
339 this.setCurrentValue(obj, timestamp, val);
340 }
341
342 protected String getGetter() {
343 return this.getColumnDefinition().getGetter();
344 }
345
346 protected String getSetter() {
347 return this.getColumnDefinition().getSetter();
348 }
349
350 protected Method getGetterMethod() {
351 return this.getterMethod;
352 }
353
354 protected Method getSetterMethod() {
355 return this.setterMethod;
356 }
357
358 protected boolean hasGetter() {
359 return this.getGetterMethod() != null;
360 }
361
362 protected boolean hasSetter() {
363 return this.getSetterMethod() != null;
364 }
365
366 public boolean isACurrentValue() {
367 return true;
368 }
369
370 public boolean isAVersionValue() {
371 return false;
372 }
373
374 public ColumnDefinition getColumnDefinition() {
375 return this.columnDefinition;
376 }
377
378 public boolean hasAlias() {
379 return Utils.isValidString(this.getColumnDefinition().getAliasName());
380 }
381
382 public String getAliasName() {
383 return (this.hasAlias()) ? this.getColumnDefinition().getAliasName() : this.getFamilyQualifiedName();
384 }
385
386 public boolean isASelectFamilyAttrib() {
387 return false;
388 }
389
390 public boolean isAnArray() {
391 return this.getColumnDefinition().isAnArray();
392 }
393
394 public String getFamilyName() {
395 return this.getColumnDefinition().getFamilyName();
396 }
397
398 public String getColumnName() {
399 return this.getColumnDefinition().getColumnName();
400 }
401
402 public FieldType getFieldType() {
403 return this.getColumnDefinition().getFieldType();
404 }
405
406 public boolean isAKeyAttrib() {
407 return false;
408 }
409 }