18 package com.mysql.clusterj.openjpa;
20 import java.lang.reflect.Modifier;
21 import java.sql.SQLException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.BitSet;
25 import java.util.HashSet;
26 import java.util.List;
29 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
30 import org.apache.openjpa.jdbc.meta.ClassMapping;
31 import org.apache.openjpa.jdbc.meta.FieldMapping;
32 import org.apache.openjpa.kernel.OpenJPAStateManager;
33 import org.apache.openjpa.kernel.PCState;
35 import com.mysql.clusterj.ClusterJFatalInternalException;
36 import com.mysql.clusterj.core.CacheManager;
37 import com.mysql.clusterj.core.metadata.IndexHandlerImpl;
38 import com.mysql.clusterj.core.metadata.KeyValueHandlerImpl;
39 import com.mysql.clusterj.core.query.CandidateIndexImpl;
40 import com.mysql.clusterj.core.spi.DomainFieldHandler;
41 import com.mysql.clusterj.core.spi.DomainTypeHandler;
42 import com.mysql.clusterj.core.spi.ValueHandler;
43 import com.mysql.clusterj.core.store.Dictionary;
44 import com.mysql.clusterj.core.store.Operation;
45 import com.mysql.clusterj.core.store.PartitionKey;
46 import com.mysql.clusterj.core.store.ResultData;
47 import com.mysql.clusterj.core.store.Table;
48 import com.mysql.clusterj.core.util.I18NHelper;
49 import com.mysql.clusterj.core.util.Logger;
50 import com.mysql.clusterj.core.util.LoggerFactoryService;
55 public class NdbOpenJPADomainTypeHandlerImpl<T>
implements DomainTypeHandler<T> {
64 private Class<T> describedType;
65 private Class<?> oidClass;
66 private Table storeTable;
68 private List<NdbOpenJPADomainFieldHandlerImpl> primaryKeyFields =
69 new ArrayList<NdbOpenJPADomainFieldHandlerImpl>();
70 private int[] primaryKeyFieldNumbers;
71 private List<NdbOpenJPADomainFieldHandlerImpl> fields =
72 new ArrayList<NdbOpenJPADomainFieldHandlerImpl>();
73 private ClassMapping classMapping;
79 private Set<com.mysql.clusterj.core.store.Column> allStoreColumns =
80 new HashSet<com.mysql.clusterj.core.store.Column>();
83 private List<IndexHandlerImpl> indexHandlerImpls =
new ArrayList<IndexHandlerImpl>();
85 private String[] partitionKeyColumnNames;
87 private int numberOfPartitionKeyColumns;
95 private Set<NdbOpenJPADomainTypeHandlerImpl<?>> dependencies =
96 new HashSet<NdbOpenJPADomainTypeHandlerImpl<?>>();
98 private Status status = Status.IN_PROCESS;
101 private List<String> reasons =
new ArrayList<String>();
103 @SuppressWarnings(
"unchecked")
104 NdbOpenJPADomainTypeHandlerImpl(
105 Dictionary dictionary, ClassMapping classMapping,
108 this.dictionary = dictionary;
109 this.domainTypeHandlerFactory = domainTypeHandlerFactory;
110 this.classMapping = classMapping;
111 classMapping.resolve(0xffffffff);
112 oidClass = classMapping.getObjectIdType();
113 this.describedType = (Class<T>)classMapping.getDescribedType();
114 if (classMapping.getPCSuperclass() != null) {
116 message = local.message(
"ERR_Subclass", this.describedType);
117 setUnsupported(message);
119 if (classMapping.getPCSubclasses() != null && classMapping.getPCSubclasses().length > 0) {
121 message = local.message(
"ERR_Superclass", this.describedType);
122 setUnsupported(message);
124 int modifiers = describedType.getClass().getModifiers();
125 if (Modifier.isAbstract(modifiers)) {
127 message = local.message(
"ERR_Abstract_Class", describedType.getClass().getName());
128 setUnsupported(message);
130 this.typeName = describedType.getName();
131 org.apache.openjpa.jdbc.schema.Table
table = classMapping.getTable();
133 this.tableName =
table.getFullName();
134 this.storeTable = dictionary.getTable(tableName);
135 if (storeTable == null) {
137 message = local.message(
"ERR_No_Table", describedType.getClass().getName(), tableName);
138 logger.info(message);
139 setUnsupported(message);
141 if (logger.isTraceEnabled()) {
142 logger.trace(
"initialize for class: " + typeName
143 +
" mapped to table: " + storeTable.getName());
147 partitionKeyColumnNames = storeTable.getPartitionKeyColumnNames();
148 numberOfPartitionKeyColumns = partitionKeyColumnNames.length;
150 if (logger.isDetailEnabled()) {
151 logger.detail(
"partition key columns for class: "+ typeName
152 +
" partition key columns: " + numberOfPartitionKeyColumns
153 +
" names: " + Arrays.toString(partitionKeyColumnNames));
158 message = local.message(
"ERR_No_Mapped_Table", describedType.getClass().getName());
159 logger.info(message);
160 setUnsupported(message);
163 List<FieldMapping> allFieldMappings =
new ArrayList<FieldMapping>();
164 allFieldMappings.addAll(Arrays.asList(classMapping.getFieldMappings()));
165 FieldMapping versionFieldMapping = classMapping.getVersionFieldMapping();
166 if (versionFieldMapping != null) {
167 allFieldMappings.add(versionFieldMapping);
169 for (FieldMapping fm: allFieldMappings) {
170 if (logger.isDetailEnabled()) logger.detail(
"field name: " + fm.getName() +
" of type: " + fm.getTypeCode());
172 dictionary,
this, domainTypeHandlerFactory, fm);
174 if (!fmd.isSupported()) {
175 setUnsupported(fmd.getReason());
178 for (com.mysql.clusterj.core.store.Column column: fmd.getStoreColumns()) {
179 allStoreColumns.add(column);
182 primaryKeyFields.add(fmd);
186 primaryKeyFieldNumbers =
new int[primaryKeyFields.size()];
189 primaryKeyFieldNumbers[i++] = fmd.getFieldNumber();
193 for (
int j = 0; j < numberOfPartitionKeyColumns; ++j) {
194 if (partitionKeyFieldHandlers[j] == null) {
196 reasons.add(
"Unmapped partition key " + partitionKeyColumnNames[j]);
212 for (
int j = 0; j < partitionKeyColumnNames.length; ++j) {
213 if (partitionKeyColumnNames[j].equals(columnName)) {
214 partitionKeyFieldHandlers[j] = fmd;
216 if (logger.isDetailEnabled()) logger.detail(
217 "NdbOpenJPADomainTypeHandlerImpl.registerPrimaryKeyColumn "
218 +
"mismatch between partition key column name: " + partitionKeyColumnNames[j]
219 +
" and primary key column name: " + columnName);
229 public Class<?> getOidClass() {
233 public String getTableName() {
237 public DomainFieldHandler getFieldHandler(
String fieldName) {
238 if (logger.isDetailEnabled()) logger.detail(
"In " + getName() +
" looking for " + fieldName);
239 for (NdbOpenJPADomainFieldHandlerImpl domainFieldHandler: fields) {
240 if (fieldName.equals(domainFieldHandler.getName())) {
241 return domainFieldHandler;
244 throw new ClusterJFatalInternalException(
245 local.message(
"ERR_Unknown_Field_Name", fieldName,
this.getName()));
248 public Class<T> getProxyClass() {
252 public T newInstance() {
253 throw new ClusterJFatalInternalException(
254 local.message(
"ERR_Implementation_Should_Not_Occur"));
257 public void objectMarkModified(ValueHandler
handler,
String fieldName) {
258 throw new ClusterJFatalInternalException(
259 local.message(
"ERR_Implementation_Should_Not_Occur"));
262 public void objectSetKeys(Object keys, Object instance) {
263 throw new ClusterJFatalInternalException(
264 local.message(
"ERR_Implementation_Should_Not_Occur"));
267 public void objectSetValues(ResultData rs, ValueHandler handler) {
268 for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
269 fmd.objectSetValue(rs, handler);
273 public void objectSetValuesExcept(ResultData rs, ValueHandler handler,
String indexName) {
274 throw new ClusterJFatalInternalException(
275 local.message(
"ERR_Implementation_Should_Not_Occur"));
278 public void objectSetCacheManager(CacheManager cm, Object instance) {
281 public void objectResetModified(ValueHandler handler) {
284 public void operationGetValues(Operation op) {
285 for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
286 fmd.operationGetValue(op);
295 fmd.operationGetValue(op);
304 if (fields == null) {
305 operationGetValues(op);
309 if (fields.get(i++)) {
310 fmd.operationGetValue(op);
318 if (logger.isDetailEnabled()) {
319 logger.detail(
"Class: " + typeName
320 +
" Primary Key Field: " + fmd.getName() + handler.pkToString(
this));
322 fmd.operationSetValue(handler, op);
326 public void operationSetModifiedValues(ValueHandler handler, Operation op) {
327 for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
328 fmd.operationSetModifiedValue(handler, op);
332 public void operationSetValuesExcept(ValueHandler handler, Operation op,
String index) {
334 for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
335 if (!fmd.includedInIndex(index)) {
336 fmd.operationSetValue(handler, op);
339 }
catch (Exception exception) {
340 exception.printStackTrace();
341 throw new RuntimeException(
"NdbOpenJPADomainTypeHandlerImpl.operationSetValuesExcept caught exception", exception);
345 public void operationSetModifiedNonPKValues(ValueHandler handler, Operation op) {
347 for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
348 if (!fmd.isPrimaryKey()) {
349 fmd.operationSetModifiedValue(handler, op);
352 }
catch (Exception exception) {
353 exception.printStackTrace();
354 throw new RuntimeException(
"NdbOpenJPADomainTypeHandlerImpl.operationSetModifiedValuesExcept caught " + exception);
358 @SuppressWarnings(
"unchecked")
359 public T getInstance(ValueHandler handler) {
360 OpenJPAStateManager sm = ((NdbOpenJPAValueHandler)handler).getStateManager();
361 sm.initialize(describedType, PCState.PNONTRANS);
362 Object instance= sm.getManagedInstance();
367 public ValueHandler createKeyValueHandler(Object keys) {
369 FieldMapping[] primaryKeyFieldMappings =
370 classMapping.getPrimaryKeyFieldMappings();
371 int numberOfFields = classMapping.getFieldMappings().length;
372 Object[] keyValues =
new Object[numberOfFields];
373 boolean nullKeyValue =
false;
374 if (primaryKeyFieldMappings.length != 1) {
377 for (NdbOpenJPADomainFieldHandlerImpl fmd: primaryKeyFields) {
380 Object keyValue = fmd.getKeyValue(keys);
381 keyValues[fmd.getFieldNumber()] = keyValue;
382 if (keyValue == null) {
387 keyValues[primaryKeyFieldMappings[0].getIndex()] = keys;
389 KeyValueHandlerImpl keyHandler =
new KeyValueHandlerImpl(keyValues);
390 return nullKeyValue?null:keyHandler;
393 public ValueHandler getValueHandler(Object instance) {
394 if (instance instanceof ValueHandler) {
395 return (ValueHandler)instance;
397 OpenJPAStateManager sm = (OpenJPAStateManager)instance;
398 return new NdbOpenJPAValueHandler(sm);
402 public ValueHandler getValueHandler(OpenJPAStateManager sm, NdbOpenJPAStoreManager store) {
403 return new NdbOpenJPAValueHandler(sm, store);
406 public int[] getKeyFieldNumbers() {
407 return primaryKeyFieldNumbers;
410 public void newInstance(OpenJPAStateManager sm) {
412 sm.initialize(describedType, PCState.PNONTRANS);
423 result[i++] = indexHandler.toCandidateIndexImpl();
436 BitSet fields, JDBCFetchConfiguration fetch, Object context)
throws SQLException {
437 if (logger.isDetailEnabled()) {
438 StringBuilder buffer =
new StringBuilder(
"load for ");
439 buffer.append(typeName);
440 buffer.append(
" for fields ");
442 logger.detail(buffer.toString());
444 boolean loadedAny =
false;
445 List<NdbOpenJPADomainFieldHandlerImpl> requestedFields =
new ArrayList<NdbOpenJPADomainFieldHandlerImpl>();
446 for (
int i=fields.nextSetBit(0);
i>=0;
i=fields.nextSetBit(
i+1)) {
447 if (!sm.getLoaded().get(
i)) {
450 if (logger.isDebugEnabled()) logger.debug(
451 "loading field " + fieldHandler.getName()
452 +
" for column " + fieldHandler.getColumnName());
453 if (fieldHandler.isRelation()) {
455 fieldHandler.
load(sm, store, fetch);
459 requestedFields.add(fieldHandler);
463 if (requestedFields.size() != 0) {
468 fieldHandler.load(sm, store, fetch, result);
481 JDBCFetchConfiguration fetch,
NdbOpenJPAResult result)
throws SQLException {
483 if (logger.isDebugEnabled()) logger.debug(
"loading field " + fieldHandler.getName()
484 +
" for column " + fieldHandler.getColumnName() +
" from result data.");
485 fieldHandler.load(sm, store, fetch, result);
494 if (fields == null) {
495 return allStoreColumns;
497 Set<com.mysql.clusterj.core.store.Column> result =
498 new HashSet<com.mysql.clusterj.core.store.Column>();
499 for (
int i=fields.nextSetBit(0);
i>=0;
i=fields.nextSetBit(
i+1)) {
501 for (com.mysql.clusterj.core.store.Column column: fieldHandler.getStoreColumns()) {
515 if (fm.equals(domainFieldHandler.getFieldMapping())) {
516 return domainFieldHandler;
520 local.message(
"ERR_Unknown_Field_Mapping",
521 this.getName(), fm.getName()));
540 int currentIndex = indexHandlerImpls.size();
541 indexHandlerImpls.add(indexHandler);
542 int[][] result =
new int[1][2];
543 result[0][0] = currentIndex;
548 public com.mysql.clusterj.core.store.Table getTable() {
552 public Table getStoreTable() {
564 if (logger.isDetailEnabled()) logger.detail(
565 "Field number " + fmd.getFieldNumber()
566 +
" column name " + fmd.getColumnName() +
" field name " + fmd.getName());
567 fmd.partitionKeySetPart(result, handler);
576 NdbOpenJPADomainTypeHandlerImpl<?> domainTypeHandler =
578 dependencies.add(domainTypeHandler);
579 return domainTypeHandler;
585 private enum Status {
591 private Status supportStatus() {
595 public void initializeRelations() {
596 for (NdbOpenJPADomainFieldHandlerImpl fieldHandler: fieldHandlers) {
597 fieldHandler.initializeRelations();
601 boolean supported = status != Status.BAD;
602 boolean workToDo = !supported;
605 new ArrayList<NdbOpenJPADomainTypeHandlerImpl<?>>(dependencies);
606 for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: copyOfDependencies) {
608 this.dependencies.addAll(dependent.getDependencies());
609 switch (dependent.supportStatus()) {
619 String message = local.message(
"ERR_Bad_Dependency", dependent.typeName);
620 reasons.add(message);
621 if (logger.isDebugEnabled()) logger.debug(message);
623 String message =
"Processing class " + typeName +
" found dependency " + dependent.typeName
624 +
" support status is: " + dependent.supportStatus();
625 if (logger.isDetailEnabled()) logger.detail(message);
630 for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: dependencies) {
631 dependent.setUnsupported();
634 for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: dependencies) {
635 dependent.setSupported();
641 if (logger.isDetailEnabled()) logger.detail(
"Processing class " + typeName +
" has dependencies " + dependencies);
642 if (logger.isDetailEnabled()) logger.detail(
"Processing class " + typeName +
" has dependencies " + dependencies);
649 private void setUnsupported() {
650 if (status != Status.BAD) {
651 if (logger.isDetailEnabled()) logger.detail(
"Class " + typeName +
" marked as BAD.");
656 private void setUnsupported(
String reason) {
657 if (status != Status.BAD) {
658 if (logger.isDetailEnabled()) logger.detail(
"Class " + typeName +
" marked as BAD.");
664 private void setSupported() {
665 if (status != Status.GOOD) {
666 if (logger.isDetailEnabled()) logger.detail(
"Class " + typeName +
" marked as GOOD.");
667 status = Status.GOOD;
671 public boolean isSupportedType() {
672 return Status.GOOD == status;
675 public String getReasons() {
676 if (reasons.size() == 0) {
679 StringBuilder result =
new StringBuilder(
680 local.message(
"MSG_Unsupported_Class", getName()));
681 for (
String reason:reasons) {
683 result.append(reason);
687 return result.toString();
691 public String toString() {
692 return "NdbOpenJPADomainTypeHandlerImpl:" + typeName;
695 public String[] getFieldNames() {
696 throw new ClusterJFatalInternalException(
697 local.message(
"ERR_Implementation_Should_Not_Occur"));
700 public void operationSetValues(ValueHandler valueHandler, Operation op) {
702 for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
703 fmd.operationSetValue(valueHandler, op);
705 }
catch (Exception exception) {
706 exception.printStackTrace();
707 throw new RuntimeException(
"NdbOpenJPADomainTypeHandlerImpl.operationSetValues caught exception", exception);
711 public void operationSetNonPKValues(ValueHandler valueHandler, Operation op) {
713 for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
714 if (!fmd.isPrimaryKey()) {
715 fmd.operationSetValue(valueHandler, op);
718 }
catch (Exception exception) {
719 exception.printStackTrace();
720 throw new RuntimeException(
"NdbOpenJPADomainTypeHandlerImpl.operationSetNonPKValues caught exception", exception);