MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DomainFieldHandlerImpl.java
1 /*
2  Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 package com.mysql.clusterj.core.metadata;
19 
20 import com.mysql.clusterj.core.spi.ValueHandler;
21 import com.mysql.clusterj.ClusterJDatastoreException;
22 import com.mysql.clusterj.ClusterJUserException;
23 import com.mysql.clusterj.ColumnType;
24 
25 import com.mysql.clusterj.annotation.Column;
26 import com.mysql.clusterj.annotation.Lob;
27 import com.mysql.clusterj.annotation.NotPersistent;
28 import com.mysql.clusterj.annotation.NullValue;
29 import com.mysql.clusterj.annotation.Persistent;
30 
31 import com.mysql.clusterj.core.store.Operation;
32 import com.mysql.clusterj.core.store.Table;
33 
34 import java.lang.annotation.Annotation;
35 
36 import java.lang.reflect.Method;
37 
38 import java.math.BigDecimal;
39 import java.math.BigInteger;
40 
50 
52  NullValue nullValue = NullValue.NONE;
53 
55  Method getMethod;
56 
58  protected Method setMethod;
59 
62 
64  protected com.mysql.clusterj.annotation.Index indexAnnotation = null;
65 
67  protected Persistent persistentAnnotation = null;
68 
70  protected Column columnAnnotation = null;
71 
74 
76  protected Lob lobAnnotation;
77 
83 
84  public int compareTo(Object other) {
85  return compareTo((DomainFieldHandlerImpl)other);
86  }
87 
98  public DomainFieldHandlerImpl(DomainTypeHandlerImpl<?> domainTypeHandler, Table table,
99  int fieldNumber, String name, Class<?> type,
100  Method getMethod, Method setMethod) {
101  if (logger.isDebugEnabled()) logger.debug("new DomainFieldHandlerImpl: fieldNumber: " + fieldNumber + "; name:" + name + "; getMethod: " + getMethod + "; setMethod: " + setMethod);
102  this.domainTypeHandler = domainTypeHandler;
103  this.fieldNumber = fieldNumber;
104  this.name = name;
105  this.type = type;
106  this.setMethod = setMethod;
107  this.getMethod = getMethod;
108 
109  Annotation[] annotations = setMethod.getAnnotations();
110  if (annotations != null && annotations.length != 0) {
111  for (Annotation a: annotations) {
112  error(local.message("ERR_Annotate_Set_Method",
113  name, a.annotationType().getName()));
114  }
115  }
116  notPersistentAnnotation = getMethod.getAnnotation(NotPersistent.class);
117  if (isPersistent()) {
118  // process column annotation first and check the class annotation
119  // for primary key
120  // Initialize default column name; may be overridden with annotation
121  this.columnName = name.toLowerCase();
122  this.columnNames = new String[]{name};
123  columnAnnotation = getMethod.getAnnotation(Column.class);
124  if (columnAnnotation != null) {
125  if (columnAnnotation.name() != null) {
127  this.columnNames = new String[]{columnName};
128  }
129  if (logger.isDebugEnabled())
130  logger.debug("Column name annotation for " + name + " is "
131  + columnName);
133  if (logger.isDebugEnabled())
134  logger.debug("Column allowsNull annotation for " + name
135  + " is " + columnAllowsNull);
137  // if user has not specified column defaultValue, set it to null,
138  // which makes it easier for later processing
139  if (columnDefaultValue.equals("")) {
140  columnDefaultValue = null;
141  }
142  if (logger.isDebugEnabled())
143  logger.debug("Column defaultValue annotation for " + name
144  + " is " + columnDefaultValue);
145  }
146  storeColumn = table.getColumn(columnName);
147  if (storeColumn == null) {
148  throw new ClusterJUserException(local.message("ERR_No_Column",
149  name, table.getName(), columnName));
150  }
151  initializeColumnMetadata(storeColumn);
152  if (logger.isDebugEnabled())
153  logger.debug("Column type for " + name + " is "
154  + storeColumnType.toString() + "; charset name is "
155  + charsetName);
156  domainTypeHandler.registerPrimaryKeyColumn(this, columnName);
157  lobAnnotation = getMethod.getAnnotation(Lob.class);
158  }
159  if (primaryKey) {
160  if (type.equals(int.class)) {
161  objectOperationHandlerDelegate = objectOperationHandlerKeyInt;
162  } else if (type.equals(long.class)) {
163  objectOperationHandlerDelegate = objectOperationHandlerKeyLong;
164  } else if (type.equals(String.class)) {
165  objectOperationHandlerDelegate = objectOperationHandlerKeyString;
166  } else if (type.equals(byte[].class)) {
167  objectOperationHandlerDelegate = objectOperationHandlerKeyBytes;
168  } else {
169  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
170  error(
171  local.message("ERR_Primary_Field_Type", domainTypeHandler.getName(), name, printableName(type)));
172  }
173  } else if (lobAnnotation != null) {
174  // large object support for byte[]
175  if (type.equals(byte[].class)) {
176  objectOperationHandlerDelegate = objectOperationHandlerBytesLob;
177  } else if (type.equals(String.class)) {
178  objectOperationHandlerDelegate = objectOperationHandlerStringLob;
179  } else {
180  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
181  error(
182  local.message("ERR_Unsupported_Field_Type", printableName(type), name));
183  }
184  } else if (!isPersistent()) {
185  // NotPersistent field
186  if (type.equals(byte.class)) {
187  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentByte;
188  } else if (type.equals(double.class)) {
189  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentDouble;
190  } else if (type.equals(float.class)) {
191  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentFloat;
192  } else if (type.equals(int.class)) {
193  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentInt;
194  } else if (type.equals(long.class)) {
195  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentLong;
196  } else if (type.equals(short.class)) {
197  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentShort;
198  } else {
199  objectOperationHandlerDelegate = objectOperationHandlerNotPersistentObject;
200  }
201  } else {
202  // not a pk field; use xxxValue to set values
203  if (type.equals(byte[].class)) {
204  objectOperationHandlerDelegate = objectOperationHandlerBytes;
205  } else if (type.equals(java.util.Date.class)) {
206  objectOperationHandlerDelegate = objectOperationHandlerJavaUtilDate;
207  } else if (type.equals(BigDecimal.class)) {
208  objectOperationHandlerDelegate = objectOperationHandlerDecimal;
209  } else if (type.equals(BigInteger.class)) {
210  objectOperationHandlerDelegate = objectOperationHandlerBigInteger;
211  } else if (type.equals(double.class)) {
212  objectOperationHandlerDelegate = objectOperationHandlerDouble;
213  } else if (type.equals(float.class)) {
214  objectOperationHandlerDelegate = objectOperationHandlerFloat;
215  } else if (type.equals(int.class)) {
216  objectOperationHandlerDelegate = objectOperationHandlerInt;
217  } else if (type.equals(Integer.class)) {
218  objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
219  } else if (type.equals(Long.class)) {
220  objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
221  } else if (type.equals(Short.class)) {
222  if (ColumnType.Year.equals(storeColumnType)) {
223  objectOperationHandlerDelegate = objectOperationHandlerObjectShortYear;
224  } else {
225  objectOperationHandlerDelegate = objectOperationHandlerObjectShort;
226  }
227  } else if (type.equals(Float.class)) {
228  objectOperationHandlerDelegate = objectOperationHandlerObjectFloat;
229  } else if (type.equals(Double.class)) {
230  objectOperationHandlerDelegate = objectOperationHandlerObjectDouble;
231  } else if (type.equals(long.class)) {
232  objectOperationHandlerDelegate = objectOperationHandlerLong;
233  } else if (type.equals(short.class)) {
234  if (ColumnType.Year.equals(storeColumnType)) {
235  objectOperationHandlerDelegate = objectOperationHandlerShortYear;
236  } else {
237  objectOperationHandlerDelegate = objectOperationHandlerShort;
238  }
239  } else if (type.equals(String.class)) {
240  objectOperationHandlerDelegate = objectOperationHandlerString;
241  } else if (type.equals(Byte.class)) {
242  objectOperationHandlerDelegate = objectOperationHandlerObjectByte;
243  } else if (type.equals(byte.class)) {
244  objectOperationHandlerDelegate = objectOperationHandlerByte;
245  } else if (type.equals(boolean.class)) {
246  objectOperationHandlerDelegate = objectOperationHandlerBoolean;
247  } else if (type.equals(Boolean.class)) {
248  objectOperationHandlerDelegate = objectOperationHandlerObjectBoolean;
249  } else if (type.equals(java.sql.Date.class)) {
250  objectOperationHandlerDelegate = objectOperationHandlerJavaSqlDate;
251  } else if (type.equals(java.sql.Time.class)) {
252  objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTime;
253  } else if (type.equals(java.sql.Timestamp.class)) {
254  objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTimestamp;
255  } else {
256  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
257  error(
258  local.message("ERR_Unsupported_Field_Type", type.getName()));
259  }
260  }
261  // Handle indexes. One index can be annotated on this field.
262  // Other indexes including the column mapped to this field
263  // are annotated on the class.
264  // TODO: indexes are ignored since they are handled by reading the column metadata
265  indexAnnotation = getMethod.getAnnotation(
266  com.mysql.clusterj.annotation.Index.class);
267  String indexName = null;
268  if (indexAnnotation != null) {
269  indexName = indexAnnotation.name();
270  if (indexAnnotation.columns().length != 0) {
271  throw new ClusterJUserException(
272  local.message("ERR_Index_Annotation_Columns", domainTypeHandler.getName(), name));
273  }
274  }
275  registerIndices(domainTypeHandler);
276 
277  persistentAnnotation = getMethod.getAnnotation(Persistent.class);
278  if (persistentAnnotation != null) {
279  nullValue = persistentAnnotation.nullValue();
280  logger.debug("Persistent nullValue annotation for " + name + " is " + nullValue);
281  }
282  // convert the string default value to type-specific value
284  logger.debug("Default null value for " + name + " is " + defaultValue);
285 
286  // set up the null value handler based on the annotation
287  switch (nullValue) {
288  case DEFAULT:
289  // value is null and user has specified a default value
290  nullValueDelegate = nullValueDEFAULT;
291  break;
292  case EXCEPTION:
293  // value is null and user wants a ClusterJ exception
294  nullValueDelegate = nullValueEXCEPTION;
295  break;
296  case NONE:
297  // value is null and no special handling
298  nullValueDelegate = nullValueNONE;
299  break;
300  }
301  reportErrors();
302  }
303 
312  DomainTypeHandlerImpl<?> domainTypeHandler, Table table, int i,
313  com.mysql.clusterj.core.store.Column storeColumn) {
314  if (logger.isDebugEnabled()) logger.debug("new dynamic DomainFieldHandlerImpl: " +
315  "fieldNumber: " + fieldNumber + "; name:" + name);
316  this.domainTypeHandler = domainTypeHandler;
317  this.fieldNumber = i;
318  this.storeColumn = storeColumn;
319  initializeColumnMetadata(storeColumn);
320  this.name = this.columnName;
321  this.columnNames = new String[]{columnName};
322  if (primaryKey) {
323  domainTypeHandler.registerPrimaryKeyColumn(this, columnName);
324  switch (this.storeColumnType) {
325  case Int:
326  case Unsigned:
327  this.objectOperationHandlerDelegate = objectOperationHandlerKeyInt;
328  this.type = Integer.class;
329  break;
330  case Char:
331  case Varchar:
332  this.objectOperationHandlerDelegate = objectOperationHandlerKeyString;
333  this.type = String.class;
334  break;
335  case Bigint:
336  case Bigunsigned:
337  this.objectOperationHandlerDelegate = objectOperationHandlerKeyLong;
338  this.type = Long.class;
339  break;
340  case Binary:
341  case Varbinary:
342  case Longvarbinary:
343  this.objectOperationHandlerDelegate = objectOperationHandlerKeyBytes;
344  this.type = byte[].class;
345  break;
346  default:
347  error(local.message("ERR_Primary_Column_Type", domainTypeHandler.getName(), name, this.storeColumnType));
348  }
349  } else {
350  switch (this.storeColumnType) {
351  case Bigint:
352  case Bigunsigned:
353  this.objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
354  this.type = Long.class;
355  break;
356  case Binary:
357  this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
358  this.type = byte[].class;
359  break;
360  case Bit:
361  this.objectOperationHandlerDelegate = objectOperationHandlerObjectLong;
362  this.type = Long.class;
363  break;
364  case Blob:
365  this.objectOperationHandlerDelegate = objectOperationHandlerBytesLob;
366  this.type = byte[].class;
367  break;
368  case Char:
369  this.objectOperationHandlerDelegate = objectOperationHandlerString;
370  this.type = String.class;
371  break;
372  case Date:
373  this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlDate;
374  this.type = java.sql.Date.class;
375  break;
376  case Datetime:
377  this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTimestamp;
378  this.type = java.sql.Timestamp.class;
379  break;
380  case Decimal:
381  case Decimalunsigned:
382  this.objectOperationHandlerDelegate = objectOperationHandlerDecimal;
383  this.type = BigDecimal.class;
384  break;
385  case Double:
386  this.objectOperationHandlerDelegate = objectOperationHandlerObjectDouble;
387  this.type = Double.class;
388  break;
389  case Float:
390  this.objectOperationHandlerDelegate = objectOperationHandlerObjectFloat;
391  this.type = Float.class;
392  break;
393  case Int:
394  this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
395  this.type = Integer.class;
396  break;
397  case Longvarbinary:
398  this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
399  this.type = byte[].class;
400  break;
401  case Longvarchar:
402  this.objectOperationHandlerDelegate = objectOperationHandlerString;
403  this.type = String.class;
404  break;
405  case Mediumint:
406  case Mediumunsigned:
407  this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
408  this.type = Integer.class;
409  break;
410  case Olddecimal:
411  error(local.message("ERR_Unsupported_Field_Type", "Olddecimal", name));
412  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
413  break;
414  case Olddecimalunsigned:
415  error(local.message("ERR_Unsupported_Field_Type", "Olddecimalunsigned", name));
416  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
417  break;
418  case Smallint:
419  case Smallunsigned:
420  this.objectOperationHandlerDelegate = objectOperationHandlerObjectShort;
421  this.type = Short.class;
422  break;
423  case Text:
424  this.objectOperationHandlerDelegate = objectOperationHandlerStringLob;
425  this.type = String.class;
426  break;
427  case Time:
428  this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTime;
429  this.type = java.sql.Time.class;
430  break;
431  case Timestamp:
432  this.objectOperationHandlerDelegate = objectOperationHandlerJavaSqlTimestamp;
433  this.type = java.sql.Timestamp.class;
434  break;
435  case Tinyint:
436  case Tinyunsigned:
437  this.objectOperationHandlerDelegate = objectOperationHandlerObjectByte;
438  this.type = Byte.class;
439  break;
440  case Undefined:
441  error(local.message("ERR_Unsupported_Field_Type", "Undefined"));
442  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
443  break;
444  case Unsigned:
445  this.objectOperationHandlerDelegate = objectOperationHandlerObjectInteger;
446  this.type = Integer.class;
447  break;
448  case Varbinary:
449  this.objectOperationHandlerDelegate = objectOperationHandlerBytes;
450  this.type = byte[].class;
451  break;
452  case Varchar:
453  this.objectOperationHandlerDelegate = objectOperationHandlerString;
454  this.type = String.class;
455  break;
456  case Year:
457  this.objectOperationHandlerDelegate = objectOperationHandlerObjectShortYear;
458  this.type = Short.class;
459  break;
460  default:
461  error(local.message("ERR_Unsupported_Field_Type", this.storeColumnType));
462  objectOperationHandlerDelegate = objectOperationHandlerUnsupportedType;
463  }
464  }
465  nullValueDelegate = nullValueNONE;
466  registerIndices(domainTypeHandler);
467  reportErrors();
468  }
469 
470  public boolean isPersistent() {
471  return notPersistentAnnotation == null;
472  }
473 
474  protected void registerIndices(DomainTypeHandlerImpl<?> domainTypeHandler) {
475  this.indices = domainTypeHandler.registerIndices(this, columnName);
476  this.indexNames = domainTypeHandler.getIndexNames(indices);
477  if (logger.isDebugEnabled()) logger.debug("Index names for " + name + " are " + indexNames);
478  if (logger.isDebugEnabled()) logger.debug("Indices for " + name + " are " + printIndices());
479  }
480 
481  @Override
482  public void operationSetValue(ValueHandler handler, Operation op) {
483  // handle NullValue here
484  boolean isNull = handler.isNull(fieldNumber);
485  if (logger.isDetailEnabled()) logger.detail("Column: " + columnName + " field: " + name + " isNull: " + isNull + " type: " + type + " delegate " + objectOperationHandlerDelegate.handler());
486  try {
487  if (isNull) {
488  // value is null; let delegate see what to do
489  if (nullValueDelegate.operationSetValue(this, op)) {
490  return;
491  }
492  }
493  objectOperationHandlerDelegate.operationSetValue(this, handler, op);
494  } catch (ClusterJDatastoreException ex) {
495  throw new ClusterJDatastoreException(local.message("ERR_Value_Delegate", name, columnName, objectOperationHandlerDelegate.handler(), "setValue"), ex);
496  }
497  }
498 
499  protected interface NullObjectOperationHandler {
510  }
511 
512  static NullObjectOperationHandler nullValueDEFAULT = new NullObjectOperationHandler() {
513  public boolean operationSetValue(DomainFieldHandlerImpl fmd, Operation op) {
514  // set the default value and then return
515  fmd.operationSetValue(fmd, fmd.defaultValue, op);
516  return true;
517  };
518  };
519 
520  static NullObjectOperationHandler nullValueEXCEPTION = new NullObjectOperationHandler() {
521  public boolean operationSetValue(DomainFieldHandlerImpl fmd, Operation op) {
522  // always throw an exception
523  throw new ClusterJUserException(
524  local.message("ERR_Null_Value_Exception",
525  fmd.domainTypeHandler.getName(), fmd.name));
526  };
527  };
528 
529  static NullObjectOperationHandler nullValueNONE = new NullObjectOperationHandler() {
530  public boolean operationSetValue(DomainFieldHandlerImpl fmd, Operation op) {
531  // don't do anything here but do the standard processing
532  return false;
533  };
534  };
535 
536 }