]> review.fuel-infra Code Review - packages/trusty/mysql-wsrep-5.6.git/blob
8ef1a26a7f315890531a3c94f3994b15ecd6ac75
[packages/trusty/mysql-wsrep-5.6.git] /
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.openjpa;
19
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;
27 import java.util.Set;
28
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;
34
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;
51
52 /**
53  *
54  */
55 public class NdbOpenJPADomainTypeHandlerImpl<T> implements DomainTypeHandler<T> {
56
57     /** My message translator */
58     static final I18NHelper local = I18NHelper.getInstance(NdbOpenJPADomainTypeHandlerImpl.class);
59
60     /** My logger */
61     static final Logger logger = LoggerFactoryService.getFactory().getInstance(NdbOpenJPADomainTypeHandlerImpl.class);
62
63     private String typeName;
64     private Class<T> describedType;
65     private Class<?> oidClass;
66     private Table storeTable;
67     private String tableName;
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;
74
75     /** The field handlers for this persistent type*/
76     private NdbOpenJPADomainFieldHandlerImpl[] fieldHandlers;
77
78     /** All columns in the mapped table. */
79     private Set<com.mysql.clusterj.core.store.Column> allStoreColumns = 
80         new HashSet<com.mysql.clusterj.core.store.Column>();
81
82     /** The indexes defined for this domain type */
83     private List<IndexHandlerImpl> indexHandlerImpls = new ArrayList<IndexHandlerImpl>();
84
85     private String[] partitionKeyColumnNames;
86
87     private int numberOfPartitionKeyColumns;
88
89     private NdbOpenJPADomainFieldHandlerImpl[] partitionKeyFieldHandlers;
90
91     private NdbOpenJPAConfigurationImpl domainTypeHandlerFactory;
92
93     private Dictionary dictionary;
94
95     private Set<NdbOpenJPADomainTypeHandlerImpl<?>> dependencies =
96         new HashSet<NdbOpenJPADomainTypeHandlerImpl<?>>();
97
98     private Status status = Status.IN_PROCESS;
99
100     /** Reasons why this class is not supported by clusterjpa */
101     private List<String> reasons = new ArrayList<String>();
102
103     @SuppressWarnings("unchecked")
104     NdbOpenJPADomainTypeHandlerImpl(
105             Dictionary dictionary, ClassMapping classMapping, 
106             NdbOpenJPAConfigurationImpl domainTypeHandlerFactory) {
107         String message = null;
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) {
115             // persistent subclasses are not supported
116             message = local.message("ERR_Subclass", this.describedType);
117             setUnsupported(message);
118         }
119         if (classMapping.getPCSubclasses() != null && classMapping.getPCSubclasses().length > 0) {
120             // persistent superclasses are not supported
121             message = local.message("ERR_Superclass", this.describedType);
122             setUnsupported(message);
123         }
124         int modifiers = describedType.getClass().getModifiers();
125         if (Modifier.isAbstract(modifiers)) {
126             // abstract classes are not supported
127             message = local.message("ERR_Abstract_Class", describedType.getClass().getName());
128             setUnsupported(message);
129         }
130         this.typeName = describedType.getName();
131         org.apache.openjpa.jdbc.schema.Table table = classMapping.getTable();
132         if (table != null) {
133             this.tableName = table.getFullName();
134             this.storeTable = dictionary.getTable(tableName);
135             if (storeTable == null) {
136                 // classes with mapped tables not in cluster are not supported
137                 message = local.message("ERR_No_Table", describedType.getClass().getName(), tableName);
138                 logger.info(message);
139                 setUnsupported(message);
140             } else {
141                 if (logger.isTraceEnabled()) {
142                     logger.trace("initialize for class: " + typeName
143                             + " mapped to table: " + storeTable.getName());
144                 }
145                 // set up the partition keys
146                 // the partition key field handlers will be initialized via registerPrimaryKeyColumn
147                 partitionKeyColumnNames = storeTable.getPartitionKeyColumnNames();
148                 numberOfPartitionKeyColumns = partitionKeyColumnNames.length;
149                 partitionKeyFieldHandlers = new NdbOpenJPADomainFieldHandlerImpl[numberOfPartitionKeyColumns];
150                 if (logger.isDetailEnabled()) {
151                     logger.detail("partition key columns for class: "+ typeName
152                             + " partition key columns: " + numberOfPartitionKeyColumns
153                             + " names: " + Arrays.toString(partitionKeyColumnNames));
154                 }
155             }
156         } else {
157             // classes without mapped tables are not supported
158             message = local.message("ERR_No_Mapped_Table", describedType.getClass().getName());
159             logger.info(message);
160             setUnsupported(message);
161         }
162         // set up the fields
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);
168         }
169         for (FieldMapping fm: allFieldMappings) {
170             if (logger.isDetailEnabled()) logger.detail("field name: " + fm.getName() + " of type: " + fm.getTypeCode());
171             NdbOpenJPADomainFieldHandlerImpl fmd = new NdbOpenJPADomainFieldHandlerImpl(
172                     dictionary, this, domainTypeHandlerFactory, fm);
173             fields.add(fmd);
174             if (!fmd.isSupported()) {
175                 setUnsupported(fmd.getReason());
176             } else {
177                 // add column names to allColumnNames
178                 for (com.mysql.clusterj.core.store.Column column: fmd.getStoreColumns()) {
179                     allStoreColumns.add(column);
180                 }
181                 if (fmd.isPrimaryKey()) {
182                     primaryKeyFields.add(fmd);
183                 }
184             }
185         }
186         primaryKeyFieldNumbers = new int[primaryKeyFields.size()];
187         int i = 0;
188         for (NdbOpenJPADomainFieldHandlerImpl fmd: primaryKeyFields) {
189             primaryKeyFieldNumbers[i++] = fmd.getFieldNumber();
190         }
191         fieldHandlers = fields.toArray(new NdbOpenJPADomainFieldHandlerImpl[fields.size()]);
192         // check to make sure all partition keys have registered
193         for (int j = 0; j < numberOfPartitionKeyColumns; ++j) {
194             if (partitionKeyFieldHandlers[j] == null) {
195                 setUnsupported();
196                 reasons.add("Unmapped partition key " + partitionKeyColumnNames[j]);
197             }
198         }
199     }
200
201     /** Register a primary key column field. This is used to associate
202      * primary key and partition key column names with field handlers.
203      * This method is called by the NdbOpenJPADomainFieldHandlerImpl constructor
204      * after the mapped column name is known. It is only called by fields
205      * that are mapped to primary key columns.
206      * @param fmd the field handler instance calling us
207      * @param columnName the name of the column
208      */
209     protected void registerPrimaryKeyColumn(NdbOpenJPADomainFieldHandlerImpl fmd,
210             String columnName) {
211         // find the partition key column that matches the primary key column
212         for (int j = 0; j < partitionKeyColumnNames.length; ++j) {
213             if (partitionKeyColumnNames[j].equals(columnName)) {
214                 partitionKeyFieldHandlers[j] = fmd;
215             } else {
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);
220             }
221         }
222         return;
223     }
224
225     public String getName() {
226         return typeName;
227     }
228
229     public Class<?> getOidClass() {
230         return oidClass;
231     }
232
233     public String getTableName() {
234         return tableName;
235     }
236
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;
242             }
243         }
244         throw new ClusterJFatalInternalException(
245                 local.message("ERR_Unknown_Field_Name", fieldName, this.getName()));
246     }
247
248     public Class<T> getProxyClass() {
249         return null;
250     }
251
252     public T newInstance() {
253         throw new ClusterJFatalInternalException(
254                 local.message("ERR_Implementation_Should_Not_Occur"));
255     }
256
257     public void objectMarkModified(ValueHandler handler, String fieldName) {
258         throw new ClusterJFatalInternalException(
259                 local.message("ERR_Implementation_Should_Not_Occur"));
260     }
261
262     public void objectSetKeys(Object keys, Object instance) {
263         throw new ClusterJFatalInternalException(
264                 local.message("ERR_Implementation_Should_Not_Occur"));
265     }
266
267     public void objectSetValues(ResultData rs, ValueHandler handler) {
268         for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
269             fmd.objectSetValue(rs, handler);
270         }
271     }
272
273     public void objectSetValuesExcept(ResultData rs, ValueHandler handler, String indexName) {
274         throw new ClusterJFatalInternalException(
275                 local.message("ERR_Implementation_Should_Not_Occur"));
276     }
277
278     public void objectSetCacheManager(CacheManager cm, Object instance) {
279     }
280
281     public void objectResetModified(ValueHandler handler) {
282     }
283
284     public void operationGetValues(Operation op) {
285         for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
286             fmd.operationGetValue(op);
287         }
288     }
289
290     /** Specify that the key columns are to be returned in the result.
291      * @param op the operation
292      */
293     public void operationGetKeys(Operation op) {
294         for (NdbOpenJPADomainFieldHandlerImpl fmd: primaryKeyFields) {
295             fmd.operationGetValue(op);
296         }
297     }
298
299     /** Specify the fields to be returned in the result.
300      * @param op the operation
301      * @param fields the fields to be returned by the operation
302      */
303     public void operationGetValues(Operation op, BitSet fields) {
304         if (fields == null) {
305             operationGetValues(op);
306         } else {
307             int i = 0;
308             for (NdbOpenJPADomainFieldHandlerImpl fmd: this.fields) {
309                 if (fields.get(i++)) {
310                     fmd.operationGetValue(op);
311                 }
312             }
313         }
314     }
315
316     public void operationSetKeys(ValueHandler handler, Operation op) {
317         for (NdbOpenJPADomainFieldHandlerImpl fmd: primaryKeyFields) {
318             if (logger.isDetailEnabled()) {
319                 logger.detail("Class: " + typeName
320                         + " Primary Key Field: " + fmd.getName() + handler.pkToString(this));
321             }
322             fmd.operationSetValue(handler, op);
323         }
324     }
325
326     public void operationSetModifiedValues(ValueHandler handler, Operation op) {
327         for (NdbOpenJPADomainFieldHandlerImpl fmd: fields) {
328             fmd.operationSetModifiedValue(handler, op);
329         }
330     }
331
332     public void operationSetValuesExcept(ValueHandler handler, Operation op, String index) {
333         try {
334             for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
335                 if (!fmd.includedInIndex(index)) {
336                     fmd.operationSetValue(handler, op);
337                 }
338             }
339         } catch (Exception exception) {
340             exception.printStackTrace();
341             throw new RuntimeException("NdbOpenJPADomainTypeHandlerImpl.operationSetValuesExcept caught exception", exception);
342         }
343     }
344
345     public void operationSetModifiedNonPKValues(ValueHandler handler, Operation op) {
346         try {
347             for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
348                 if (!fmd.isPrimaryKey()) {
349                     fmd.operationSetModifiedValue(handler, op);
350                 }
351             }
352         } catch (Exception exception) {
353             exception.printStackTrace();
354             throw new RuntimeException("NdbOpenJPADomainTypeHandlerImpl.operationSetModifiedValuesExcept caught " + exception);
355         }
356     }
357
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();
363         // System.out.println("NdbOpenJPADomainTypeHandlerImpl.getInstance returned " + instance.getClass() + " " + instance);
364         return (T) instance;
365     }
366
367     public ValueHandler createKeyValueHandler(Object keys) {
368
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) {
375         // for each key field, use the field value accessor to get the
376         // value from the Oid and put it into the proper place in keyValues
377             for (NdbOpenJPADomainFieldHandlerImpl fmd: primaryKeyFields) {
378                 // store the key value from the oid into the keyValues array
379                 // this can be improved with a smarter KeyValueHandlerImpl
380                 Object keyValue = fmd.getKeyValue(keys);
381                 keyValues[fmd.getFieldNumber()] = keyValue;
382                 if (keyValue == null) {
383                     nullKeyValue = true;
384                 }
385             }
386         } else {
387             keyValues[primaryKeyFieldMappings[0].getIndex()] = keys;
388         }
389         KeyValueHandlerImpl keyHandler = new KeyValueHandlerImpl(keyValues);
390         return nullKeyValue?null:keyHandler;
391     }
392
393     public ValueHandler getValueHandler(Object instance) {
394         if (instance instanceof ValueHandler) {
395             return (ValueHandler)instance;
396         } else {
397             OpenJPAStateManager sm = (OpenJPAStateManager)instance;
398             return new NdbOpenJPAValueHandler(sm);
399         }
400     }
401
402     public ValueHandler getValueHandler(OpenJPAStateManager sm, NdbOpenJPAStoreManager store) {
403         return new NdbOpenJPAValueHandler(sm, store);
404     }
405
406     public int[] getKeyFieldNumbers() {
407         return primaryKeyFieldNumbers;
408     }
409
410     public void newInstance(OpenJPAStateManager sm) {
411         // TODO: accommodate subclasses based on results of select
412         sm.initialize(describedType, PCState.PNONTRANS);
413     }
414
415     /** Create a list of candidate indexes to evaluate query terms and
416      * decide what type of scan to use.
417      * @return a new array of CandidateIndexImpl
418      */
419     public CandidateIndexImpl[] createCandidateIndexes() {
420         CandidateIndexImpl[] result = new CandidateIndexImpl[indexHandlerImpls.size()];
421         int i = 0;
422         for (IndexHandlerImpl indexHandler: indexHandlerImpls) {
423             result[i++] = indexHandler.toCandidateIndexImpl();
424         }
425         return result;
426     }
427
428     /** Load the fields for the persistent instance owned by the sm.
429      * @param sm the StateManager
430      * @param store the StoreManager
431      * @param fields the fields to load
432      * @param fetch the FetchConfiguration
433      * @return true if any field was loaded
434      */
435     public boolean load(OpenJPAStateManager sm, NdbOpenJPAStoreManager store, 
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 ");
441             buffer.append(NdbOpenJPAUtility.printBitSet(sm, fields));
442             logger.detail(buffer.toString());
443         }
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)) {
448                 // this field is not loaded
449                 NdbOpenJPADomainFieldHandlerImpl fieldHandler = fieldHandlers[i];
450                 if (logger.isDebugEnabled()) logger.debug(
451                         "loading field " + fieldHandler.getName()
452                         + " for column " + fieldHandler.getColumnName());
453                 if (fieldHandler.isRelation()) {
454                     // if relation, load each field individually with its own query
455                     fieldHandler.load(sm, store, fetch);
456                     loadedAny = true;
457                 } else {
458                     // if not relation, get a list of all fields to load with one lookup
459                     requestedFields.add(fieldHandler);
460                 }
461             }
462         }
463         if (requestedFields.size() != 0) {
464             // load fields via primary key lookup
465             NdbOpenJPAResult result = store.lookup(sm, this, requestedFields);
466             for (NdbOpenJPADomainFieldHandlerImpl fieldHandler: fieldHandlers) {
467                 loadedAny = true;
468                 fieldHandler.load(sm, store, fetch, result);
469             }
470         }
471         return loadedAny;
472     }
473
474     /** Load the fields for the persistent instance owned by the sm.
475      * This is the normal way for fields to be loaded into the instance from a result.
476      * @param sm the StateManager
477      * @param store the StoreManager
478      * @param fetch the FetchConfiguration
479      */
480     public void load(OpenJPAStateManager sm, NdbOpenJPAStoreManager store, 
481             JDBCFetchConfiguration fetch, NdbOpenJPAResult result) throws SQLException {
482         for (NdbOpenJPADomainFieldHandlerImpl fieldHandler: fieldHandlers) {
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);
486         }
487     }
488
489     /** Get StoreColumns for fields identified by the BitSet
490      * 
491      */
492     public Set<com.mysql.clusterj.core.store.Column> getStoreColumns(BitSet fields) {
493         // iterate the fields and save the columns in a Set
494         if (fields == null) {
495             return allStoreColumns;
496         }
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)) {
500             NdbOpenJPADomainFieldHandlerImpl fieldHandler = fieldHandlers[i];
501             for (com.mysql.clusterj.core.store.Column column: fieldHandler.getStoreColumns()) {
502                 result.add(column);
503             }
504         }
505         return result;
506     }
507
508     /** Get the DomainFieldHandler for the related field.
509      * 
510      * @param fm the related field mapping
511      * @return the DomainFieldHandler
512      */
513     public NdbOpenJPADomainFieldHandlerImpl getDomainFieldHandler(FieldMapping fm) {
514         for (NdbOpenJPADomainFieldHandlerImpl domainFieldHandler: fieldHandlers) {
515             if (fm.equals(domainFieldHandler.getFieldMapping())) {
516                 return domainFieldHandler;
517             }
518         }
519         throw new ClusterJFatalInternalException(
520                 local.message("ERR_Unknown_Field_Mapping",
521                         this.getName(), fm.getName()));
522     }
523
524     /** Register an index from a field and return a special int[][] that
525      * contains all indexHandlerImpls in which the
526      * field participates. One index can be defined in the field annotation
527      * and this index is identified here. This method is called by the
528      * FieldHandler constructor after the Index annotation is processed
529      * and the mapped column name is known.
530      * TODO: Currently, only one index is supported per field.
531      * @param fieldHandler the FieldHandler
532      * @param indexName the index name
533      * @param dictionary the dictionary used to validate index metadata
534      * @return the array of array identifying the indexes into the IndexHandler
535      * list and columns in the IndexHandler corresponding to the field
536      */
537     public int[][] createIndexHandler( NdbOpenJPADomainFieldHandlerImpl fieldHandler,
538             Dictionary dictionary, String indexName) {
539         IndexHandlerImpl indexHandler = new IndexHandlerImpl(this, dictionary, indexName, fieldHandler);
540         int currentIndex = indexHandlerImpls.size();
541         indexHandlerImpls.add(indexHandler);
542         int[][] result = new int[1][2];
543         result[0][0] = currentIndex;
544         result[0][1] = 0;
545         return result;
546     }
547
548     public com.mysql.clusterj.core.store.Table getTable() {
549         return storeTable;
550     }
551
552     public Table getStoreTable() {
553         return storeTable;
554     }
555
556     /** Create a partition key for any operation that knows the primary key. 
557      * @param handler the handler that contains the values of the primary key
558      */
559     public PartitionKey createPartitionKey(ValueHandler handler) {
560         // create the partition key based on the mapped table
561         PartitionKey result = storeTable.createPartitionKey();
562         // add partition key part value for each partition key field
563         for (NdbOpenJPADomainFieldHandlerImpl fmd: partitionKeyFieldHandlers) {
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);
568         }
569         return result;
570     }
571
572     /** Register a dependency on another class. If the class is not already known,
573      * add it to the list of dependencies.
574      */
575     public NdbOpenJPADomainTypeHandlerImpl<?> registerDependency(ClassMapping mapping) {
576         NdbOpenJPADomainTypeHandlerImpl<?> domainTypeHandler = 
577             domainTypeHandlerFactory.getDomainTypeHandler(mapping, dictionary);
578         dependencies.add(domainTypeHandler);
579         return domainTypeHandler;
580     }
581
582     /** Status of this class with regard to usability with clusterjpa.
583      * 
584      */
585     private enum Status {
586         IN_PROCESS,
587         GOOD,
588         BAD;
589     }
590
591     private Status supportStatus() {
592         return status;
593     }
594
595     public void initializeRelations() {
596         for (NdbOpenJPADomainFieldHandlerImpl fieldHandler: fieldHandlers) {
597             fieldHandler.initializeRelations();
598         }
599
600         // iterate the dependencies and see if any are not supported
601         boolean supported = status != Status.BAD;
602         boolean workToDo = !supported;
603         // iterate a copy of dependencies to avoid concurrent modification of dependencies
604         List<NdbOpenJPADomainTypeHandlerImpl<?>> copyOfDependencies =
605                 new ArrayList<NdbOpenJPADomainTypeHandlerImpl<?>>(dependencies);
606         for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: copyOfDependencies) {
607             // top level class will have recursive list of dependencies including itself
608             this.dependencies.addAll(dependent.getDependencies());
609             switch (dependent.supportStatus()) {
610                 case IN_PROCESS:
611                     workToDo = true;
612                     break;
613                 case GOOD:
614                     break;
615                 case BAD:
616                     setUnsupported();
617                     supported = false;
618                     workToDo = true;
619                     String message = local.message("ERR_Bad_Dependency", dependent.typeName);
620                     reasons.add(message);
621                     if (logger.isDebugEnabled()) logger.debug(message);
622             }
623             String message = "Processing class " + typeName + " found dependency " + dependent.typeName
624             + " support status is: " + dependent.supportStatus();
625             if (logger.isDetailEnabled()) logger.detail(message);
626         }
627         if (workToDo) {
628             if (!supported) {
629                 // found an unsupported class in the dependency list
630                 for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: dependencies) {
631                     dependent.setUnsupported();
632                 }
633             } else {
634                 for (NdbOpenJPADomainTypeHandlerImpl<?> dependent: dependencies) {
635                     dependent.setSupported();
636                 }
637             }
638         } else {
639             this.setSupported();
640         }
641         if (logger.isDetailEnabled()) logger.detail("Processing class " + typeName + " has dependencies " + dependencies);
642         if (logger.isDetailEnabled()) logger.detail("Processing class " + typeName + " has dependencies " + dependencies);
643     }
644
645     private Set<NdbOpenJPADomainTypeHandlerImpl<?>> getDependencies() {
646         return dependencies;
647     }
648
649     private void setUnsupported() {
650         if (status != Status.BAD) {
651             if (logger.isDetailEnabled()) logger.detail("Class " + typeName + " marked as BAD.");
652             status = Status.BAD;
653         }
654     }
655
656     private void setUnsupported(String reason) {
657         if (status != Status.BAD) {
658             if (logger.isDetailEnabled()) logger.detail("Class " + typeName + " marked as BAD.");
659             status = Status.BAD;
660         }
661         reasons.add(reason);
662     }
663
664     private void setSupported() {
665         if (status != Status.GOOD) {
666             if (logger.isDetailEnabled()) logger.detail("Class " + typeName + " marked as GOOD.");
667             status = Status.GOOD;
668         }
669     }
670
671     public boolean isSupportedType() {
672         return Status.GOOD == status;
673     }
674
675     public String getReasons() {
676         if (reasons.size() == 0) {
677             return null;
678         }
679         StringBuilder result = new StringBuilder(
680                 local.message("MSG_Unsupported_Class", getName()));
681         for (String reason:reasons) {
682             result.append('\n');
683             result.append(reason);
684             result.append(';');
685         }
686         result.append('\n');
687         return result.toString();
688     }
689
690     @Override
691     public String toString() {
692         return "NdbOpenJPADomainTypeHandlerImpl:" + typeName;
693     }
694
695     public String[] getFieldNames() {
696         throw new ClusterJFatalInternalException(
697                 local.message("ERR_Implementation_Should_Not_Occur"));
698     }
699
700     public void operationSetValues(ValueHandler valueHandler, Operation op) {
701         try {
702             for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
703                 fmd.operationSetValue(valueHandler, op);
704             }
705         } catch (Exception exception) {
706             exception.printStackTrace();
707             throw new RuntimeException("NdbOpenJPADomainTypeHandlerImpl.operationSetValues caught exception", exception);
708         }
709     }
710
711     public void operationSetNonPKValues(ValueHandler valueHandler, Operation op) {
712         try {
713             for (NdbOpenJPADomainFieldHandlerImpl fmd : fields) {
714                 if (!fmd.isPrimaryKey()) {
715                     fmd.operationSetValue(valueHandler, op);
716                 }
717             }
718         } catch (Exception exception) {
719             exception.printStackTrace();
720             throw new RuntimeException("NdbOpenJPADomainTypeHandlerImpl.operationSetNonPKValues caught exception", exception);
721         }
722     }
723
724 }