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.hadoop.hbase.client.Result;
24 import org.apache.hadoop.hbase.hbql.client.Column;
25 import org.apache.hadoop.hbase.hbql.client.ColumnVersionMap;
26 import org.apache.hadoop.hbase.hbql.client.HBqlException;
27 import org.apache.hadoop.hbase.hbql.client.Mapping;
28 import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
29 import org.apache.hadoop.hbase.hbql.statement.select.SelectElement;
30 import org.apache.hadoop.hbase.hbql.util.Maps;
31
32 import java.lang.reflect.Field;
33 import java.util.List;
34 import java.util.Map;
35
36 public class AnnotationResultAccessor extends ResultAccessor {
37
38
39 private final Class<?> clazz;
40 private final Map<String, CurrentValueAnnotationAttrib> columnMap = Maps.newHashMap();
41 private final Map<String, VersionAnnotationAttrib> columnVersionMap = Maps.newHashMap();
42
43 private AnnotationResultAccessor(final TableMapping tableMapping, final Class clazz) throws HBqlException {
44
45 super(new MappingContext(tableMapping));
46
47 this.getMappingContext().setResultAccessor(this);
48
49 this.clazz = clazz;
50
51
52 try {
53 this.getClazz().getConstructor();
54 }
55 catch (NoSuchMethodException e) {
56 throw new HBqlException("Class " + this + " is missing a null constructor");
57 }
58
59 for (final Field field : clazz.getDeclaredFields()) {
60 if (field.getAnnotation(Column.class) != null)
61 this.processColumnAnnotation(field);
62
63 if (field.getAnnotation(ColumnVersionMap.class) != null)
64 this.processColumnVersionAnnotation(field);
65 }
66
67 if (!this.getColumnMap().containsKey(this.getKeyAttrib().getFamilyQualifiedName()))
68 throw new HBqlException(this.getClazz().getName() + " must contain a mapping to key attribute "
69 + this.getKeyAttrib().getFamilyQualifiedName());
70 }
71
72 public static boolean isAnnotatedObject(final Class<?> clazz) {
73 return clazz.getAnnotation(org.apache.hadoop.hbase.hbql.client.Mapping.class) != null;
74 }
75
76 public static AnnotationResultAccessor newAnnotationMapping(final HConnectionImpl conn,
77 final Class<?> clazz) throws HBqlException {
78
79 final Mapping mappingAnnotation = clazz.getAnnotation(Mapping.class);
80
81 if (mappingAnnotation == null)
82 throw new HBqlException("Class " + clazz.getName() + " is missing @Mapping annotation");
83
84 if (mappingAnnotation.name() == null || mappingAnnotation.name().length() == 0)
85 throw new HBqlException("@Mapping annotation for class " + clazz.getName() + " is missing a name");
86
87 final TableMapping tableMapping = conn.getMapping(mappingAnnotation.name());
88 return new AnnotationResultAccessor(tableMapping, clazz);
89 }
90
91 private void processColumnAnnotation(final Field field) throws HBqlException {
92
93 final Column columnAnno = field.getAnnotation(Column.class);
94 final String attribName = columnAnno.name().length() == 0 ? field.getName() : columnAnno.name();
95 final HRecordAttrib columnAttrib = (HRecordAttrib)this.getMapping().getAttribByVariableName(attribName);
96
97 if (columnAttrib == null)
98 throw new HBqlException("Unknown attribute " + this.getMapping() + "." + attribName
99 + " in " + this.getClazz().getName());
100
101 if (this.getColumnMap().containsKey(columnAttrib.getFamilyQualifiedName()))
102 throw new HBqlException("Cannot map multiple instance variables in " + this.getClazz().getName()
103 + " to " + columnAttrib.getFamilyQualifiedName());
104
105 final CurrentValueAnnotationAttrib attrib = new CurrentValueAnnotationAttrib(field, columnAttrib);
106 this.getColumnMap().put(columnAttrib.getFamilyQualifiedName(), attrib);
107 }
108
109 private void processColumnVersionAnnotation(final Field field) throws HBqlException {
110
111 final ColumnVersionMap versionAnno = field.getAnnotation(ColumnVersionMap.class);
112 final String attribName = versionAnno.name().length() == 0 ? field.getName() : versionAnno.name();
113 final ColumnAttrib columnAttrib = this.getMapping().getAttribByVariableName(attribName);
114
115 this.getColumnVersionMap().put(columnAttrib.getFamilyQualifiedName(),
116 new VersionAnnotationAttrib(columnAttrib.getFamilyName(),
117 columnAttrib.getColumnName(),
118 field,
119 columnAttrib.getFieldType(),
120 columnAttrib.getGetter(),
121 columnAttrib.getSetter()));
122 }
123
124 public ColumnAttrib getKeyAttrib() throws HBqlException {
125 final String name = this.getMapping().getKeyAttrib().getFamilyQualifiedName();
126 return this.getAttrib(name);
127 }
128
129 public ColumnAttrib getColumnAttribByQualifiedName(final String familyName,
130 final String columnName) throws HBqlException {
131 final ColumnAttrib attrib = this.getTableMapping().getAttribFromFamilyQualifiedName(familyName
132 + ":" + columnName);
133 return this.getColumnAttribByName(attrib.getFamilyQualifiedName());
134 }
135
136 public ColumnAttrib getColumnAttribByName(final String name) throws HBqlException {
137 final String valname = this.getMapping().getAttribByVariableName(name).getFamilyQualifiedName();
138 return this.getAttrib(valname);
139 }
140
141 private Class<?> getClazz() {
142 return this.clazz;
143 }
144
145 private Map<String, CurrentValueAnnotationAttrib> getColumnMap() {
146 return this.columnMap;
147 }
148
149 private Map<String, VersionAnnotationAttrib> getColumnVersionMap() {
150 return this.columnVersionMap;
151 }
152
153 public CurrentValueAnnotationAttrib getAttrib(final String name) {
154 return this.getColumnMap().get(name);
155 }
156
157 public VersionAnnotationAttrib getVersionAttrib(final String name) {
158 return this.getColumnVersionMap().get(name);
159 }
160
161 private Object newInstance() throws IllegalAccessException, InstantiationException {
162 return this.getClazz().newInstance();
163 }
164
165 public Object newObject(final HConnectionImpl conn,
166 final MappingContext mappingContext,
167 final List<SelectElement> selectElementList,
168 final int maxVersions,
169 final Result result) throws HBqlException {
170 try {
171
172 final Object newobj = this.createNewObject();
173 this.assignSelectValues(conn, newobj, selectElementList, maxVersions, result);
174 return newobj;
175 }
176 catch (Exception e) {
177 e.printStackTrace();
178 throw new HBqlException("Error in newObject() " + e.getMessage());
179 }
180 }
181
182 private void assignSelectValues(final HConnectionImpl conn,
183 final Object newobj,
184 final List<SelectElement> selectElementList,
185 final int maxVersions,
186 final Result result) throws HBqlException {
187
188
189 final ColumnAttrib keyAttrib = this.getKeyAttrib();
190 this.getAttrib(keyAttrib.getFamilyQualifiedName()).setCurrentValue(newobj, 0, result.getRow());
191
192
193 for (final SelectElement selectElement : selectElementList)
194 selectElement.assignSelectValue(conn, newobj, maxVersions, result);
195 }
196
197 private Object createNewObject() throws HBqlException {
198
199
200 final Object newobj;
201 try {
202 newobj = this.newInstance();
203 }
204 catch (Exception e) {
205 e.printStackTrace();
206 throw new HBqlException("Cannot create new instance of " + this.getClazz().getName());
207 }
208
209 return newobj;
210 }
211 }