OSDN Git Service

8a78be4338e7f8b61e5f1a2090d27c7e4c74d66c
[ea2ddl/ea2ddl.git] / ea2ddl-gen / dbflute / templates / om / java / allcommon / dbmeta / hierarchy / HierarchyArranger.vm
1 ${database.allClassCopyright}package ${glPackageBaseCommonDBMetaHierarchy};\r
2 \r
3 #set ($myClassName = "${glHierarchyArrangerName}")\r
4 \r
5 import java.lang.reflect.Method;\r
6 import java.util.ArrayList;\r
7 import java.util.HashMap;\r
8 import java.util.List;\r
9 import java.util.Map;\r
10 import java.util.Set;\r
11 \r
12 import ${glPackageBaseCommon}.${glEntityInterfaceName};\r
13 import ${glPackageBaseCommonDBMeta}.${glDBMetaInterfaceName};\r
14 import ${glPackageBaseCommonDBMetaInfo}.${glColumnInfoName};\r
15 import ${glPackageBaseCommonDBMetaInfo}.${glForeignInfoName};\r
16 import ${glPackageBaseCommonDBMetaInfo}.${glReferrerInfoName};\r
17 import ${glPackageBaseCommonDBMetaInfo}.${glRelationInfoName};\r
18 \r
19 /**\r
20  * The arranger of hierarchy.\r
21  * <pre>\r
22  * ex) LIBRARY Hierarchy\r
23  * \r
24  * LIBRARY\r
25  *  |1\r
26  *  |--* NEXT_LIBRARY (Referrer)\r
27  *  |       |*\r
28  *  |       |--1 LIBRARY (Foreign)\r
29  *  |\r
30  *  |--* COLLECTION (Referrer)\r
31  *  |       |1 \r
32  *  |       |--1 COLLECTION_STATUS (Referrer)\r
33  *  |       |       |*\r
34  *  |       |       |--1 COLLECTION_STATUS_LOOKUP (Foreign)\r
35  *  |       |\r
36  *  |       |--1 BOOK (Foreign)\r
37  *  |       |     |*\r
38  *  |       |     |--1 AUTHOR (Foreign)\r
39  *  |       |     |--1 PUBLISER (Foreign)\r
40  *  |       |     |--1 GENRE (Foreign)\r
41  *  |       |           |*\r
42  *  |       |           |--1 GENRE (Foreign)\r
43  *  |       |\r
44  *  |       |--* LENDING_COLLECTION (Referrer)\r
45  *  |       |\r
46  *  |\r
47  *  |--* LIBRARY_USER (Referrer)\r
48  *         |*  |1\r
49  *         |   |--* LENDING (Referrer)\r
50  *         |         |1\r
51  *         |         |--* LENDING_COLLECTION (Referrer)\r
52  *         |\r
53  *         |--1 LB_USER (Foreign)\r
54  *                 |1\r
55  *                 |--* BLACK_LIST (Referrer)\r
56  *                         |1\r
57  *                         |--* BLACK_ACTION (Referrer)\r
58  *                                 |*\r
59  *                                 |--1 BLACK_ACTION_LOOKUP (Foreign)\r
60  *          \r
61  *          \r
62  * ex) The SQL of LIBRARY Hierarchy as FLAT\r
63  * \r
64  * select library.LIBRARY_ID as LIBRARY_ID\r
65  *      , library.LIBRARY_NAME as LIBRARY_NAME\r
66  *      , library.R_USER as R_USER\r
67  *      , library.R_TIMESTAMP as R_TIMESTAMP\r
68  *      , nextBase.LIBRARY_ID as BASE_LIBRARY_ID\r
69  *      , nextBase.NEXT_LIBRARY_ID as NEXT_LIBRARY_ID\r
70  *      , nextBaseNextLibrary.LIBRARY_ID as NEXT_LIBRARY_NEXT_LIBRARY_ID\r
71  *      , nextBaseNextLibrary.LIBRARY_NAME as NEXT_LIBRARY_NEXT_LIBRARY_NAME\r
72  *      , collection.COLLECTION_ID as COLLECTION_ID\r
73  *      , collection.ARRIVAL_DATE as COLLECTION_ARRIVAL_DATE\r
74  *      , collectionStatus.COLLECTION_ID as COLLECTION_STATUS_ID\r
75  *      , collectionStatus.COLLECTION_STATUS_CODE as COLLECTION_STATUS_CODE\r
76  *      , collectionStatusLookup.COLLECTION_STATUS_CODE as COLLECTION_STATUS_CODE\r
77  *      , collectionStatusLookup.COLLECTION_STATUS_NAME as COLLECTION_STATUS_NAME\r
78  *      , book.BOOK_ID as COLLECTION_BOOK_ID\r
79  *      , book.BOOK_NAME as COLLECTION_BOOK_NAME\r
80  *      , author.AUTHOR_ID as COLLECTION_BOOK_AUTHOR_ID\r
81  *      , author.AUTHOR_NAME as COLLECTION_BOOK_AUTHOR_NAME\r
82  *      , libraryUser.LIBRARY_ID as LIBRARY_USER_LIBRARY_ID \r
83  *      , libraryUser.LB_USER_ID as LIBRARY_USER_LB_USER_ID\r
84  *      , lending.LIBRARY_ID as LENDING_LIBRARY_ID\r
85  *      , lending.LB_USER_ID as LENDING_LB_USER_ID\r
86  *      , lending.LENDING_DATE as LENDING_DATE\r
87  *      , lending.U_USER as LENDING_U_USER\r
88  *      , lending.U_MODULE as LENDING_U_MODULE\r
89  *      , lbUser.LB_USER_ID as LB_USER_ID\r
90  *      , lbUser.LB_USER_NAME as LB_USER_NAME\r
91  *   from LIBRARY library\r
92  *     left outer join NEXT_LIBRARY nextBase on library.LIBRARY_ID = nextBase.LIBRARY_ID\r
93  *       left outer join LIBRARY nextBaseNextLibrary on nextBase.NEXT_LIBRARY_ID = nextBaseNextLibrary.LIBRARY_ID\r
94  *     left outer join COLLECTION collection on library.LIBRARY_ID = collection.LIBRARY_ID\r
95  *       left outer join COLLECTION_STATUS collectionStatus on collection.COLLECTION_ID = collectionStatus.COLLECTION_ID\r
96  *         left outer join COLLECTION_STATUS_LOOKUP collectionStatusLookup on collectionStatus.COLLECTION_STATUS_CODE = collectionStatusLookup.COLLECTION_STATUS_CODE\r
97  *       left outer join BOOK book on collection.BOOK_ID = book.BOOK_ID\r
98  *         left outer join AUTHOR author on book.AUTHOR_ID = author.AUTHOR_ID\r
99  *     left outer join LIBRARY_USER libraryUser on library.LIBRARY_ID = libraryUser.LIBRARY_ID\r
100  *       left outer join LENDING lending on libraryUser.LIBRARY_ID = lending.LIBRARY_ID and libraryUser.LB_USER_ID = lending.LB_USER_ID\r
101  *       left outer join LB_USER lbUser on libraryUser.LB_USER_ID = lbUser.LB_USER_ID\r
102  * \r
103  * \r
104  * ex) Invoking Hierarchy Arranger\r
105  * \r
106  * private List&lt;Library&gt; makeLibraryList() {\r
107  *     final HierarchyRequest&lt;Library&gt; request = createHierarchyRequest(createFlatLibraryList());\r
108  *     return new HierarchyArranger&lt;Library&gt;().arrangeHierarchy(request);\r
109  * }\r
110  * \r
111  * \r
112  * ex) Creating Hierarchy Request\r
113  * \r
114  * private HierarchyRequest&lt;Library&gt; createHierarchsyRequest(java.util.List&gt;HierarchyFlatLibrary&gt; flatLibraryList) {\r
115  * \r
116  *     // Define dbmeta.\r
117  *     final HierarchyFlatLibraryDbm sourceDbm = HierarchyFlatLibraryDbm.getInstance();\r
118  *\r
119  *     // Define hierarychy request as library.\r
120  *     final HierarchyRequest&lt;Library&gt; request = new HierarchyRequest&lt;Library&gt;(Library.class);\r
121  * \r
122  *     // Register the list of source iterator. (by calling creator for flat library list)\r
123  *     request.registerSourceList(flatLibraryList);\r
124  *\r
125  *     // Create relation trace.\r
126  *     final LibraryRelationTrace trace = LibraryDbm.getInstance().createRelationTrace(null);\r
127  *     \r
128  *     // Register column [libraryId]\r
129  *     request.mapping(sourceDbm.columnLibraryId(), trace.columnLibraryId());\r
130  *\r
131  *     // Register column [libraryName]\r
132  *     request.mapping(sourceDbm.columnLibraryName(), trace.columnLibraryName());\r
133  *\r
134  *     // Register column [RUser]\r
135  *     request.mapping(sourceDbm.columnRUser(), trace.columnRUser());\r
136  *\r
137  *     // Register column [RTimestamp]\r
138  *     request.mapping(sourceDbm.columnRTimestamp(), trace.columnRTimestamp());\r
139  *\r
140  *     // Register column [baseLibraryId]\r
141  *     request.mapping(sourceDbm.columnBaseLibraryId(), trace.referrerNextLibraryByBaseIdList().columnLibraryId());\r
142  *\r
143  *     // Register column [nextLibraryId]\r
144  *     request.mapping(sourceDbm.columnNextLibraryId(), trace.referrerNextLibraryByBaseIdList().columnNextLibraryId());\r
145  *\r
146  *     // Register column [nextLibraryNextLibraryId]\r
147  *     request.mapping(sourceDbm.columnNextLibraryNextLibraryId(), trace.referrerNextLibraryByBaseIdList().foreignLibraryByNextId().columnLibraryId());\r
148  *\r
149  *     // Register column [nextLibraryNextLibraryName]\r
150  *     request.mapping(sourceDbm.columnNextLibraryNextLibraryName(), trace.referrerNextLibraryByBaseIdList().foreignLibraryByNextId().columnLibraryName());\r
151  *\r
152  *     // Register column [collectionId]\r
153  *     request.mapping(sourceDbm.columnCollectionId(), trace.referrerCollectionList().columnCollectionId());\r
154  *\r
155  *     // Register column [arrivalDate]\r
156  *     request.mapping(sourceDbm.columnCollectionArrivalDate(), trace.referrerCollectionList().columnArrivalDate());\r
157  *\r
158  *     // Register column [collectionStatusId]\r
159  *     request.mapping(sourceDbm.columnCollectionStatusId(), trace.referrerCollectionList().foreignCollectionStatusAsOne().columnCollectionId());\r
160  *\r
161  *     // Register column [collectionStatusCode]\r
162  *     request.mapping(sourceDbm.columnCollectionStatusCode(), trace.referrerCollectionList().foreignCollectionStatusAsOne().foreignCollectionStatusLookup().columnCollectionStatusCode());\r
163  *\r
164  *     // Register column [collectionStatusName]\r
165  *     request.mapping(sourceDbm.columnCollectionStatusName(), trace.referrerCollectionList().foreignCollectionStatusAsOne().foreignCollectionStatusLookup().columnCollectionStatusName());\r
166  *\r
167  *     // Register column [collectionBookId]\r
168  *     request.mapping(sourceDbm.columnCollectionBookId(), trace.referrerCollectionList().foreignBook().columnBookId());\r
169  *\r
170  *     // Register column [collectionBookName]\r
171  *     request.mapping(sourceDbm.columnCollectionBookName(), trace.referrerCollectionList().foreignBook().columnBookName());\r
172  *\r
173  *     // Register column [collectionBookAuthorId]\r
174  *     request.mapping(sourceDbm.columnCollectionBookAuthorId(), trace.referrerCollectionList().foreignBook().foreignAuthor().columnAuthorId());\r
175  *\r
176  *     // Register column [collectionBookAuthorName]\r
177  *     request.mapping(sourceDbm.columnCollectionBookAuthorName(), trace.referrerCollectionList().foreignBook().foreignAuthor().columnAuthorName());\r
178  *\r
179  *     // Register column [libraryUserLibraryId]\r
180  *     request.mapping(sourceDbm.columnLibraryUserLibraryId(), trace.referrerLibraryUserList().columnLibraryId());\r
181  *\r
182  *     // Register column [libraryUserLbUserId]\r
183  *     request.mapping(sourceDbm.columnLibraryUserLbUserId(), trace.referrerLibraryUserList().columnLbUserId());\r
184  *\r
185  *     // Register column [lendingLibraryId]\r
186  *     request.mapping(sourceDbm.columnLendingLibraryId(), trace.referrerLibraryUserList().referrerLendingList().columnLibraryId());\r
187  *\r
188  *     // Register column [lendingLbUserId]\r
189  *     request.mapping(sourceDbm.columnLendingLbUserId(), trace.referrerLibraryUserList().referrerLendingList().columnLbUserId());\r
190  *\r
191  *     // Register column [lendingDate]\r
192  *     request.mapping(sourceDbm.columnLendingDate(), trace.referrerLibraryUserList().referrerLendingList().columnLendingDate());\r
193  *\r
194  *     // Register column [lendingUUser]\r
195  *     request.mapping(sourceDbm.columnLendingUUser(), trace.referrerLibraryUserList().referrerLendingList().columnUUser());\r
196  *\r
197  *     // Register column [lendingUModule]\r
198  *     request.mapping(sourceDbm.columnLendingUModule(), trace.referrerLibraryUserList().referrerLendingList().columnUModule());\r
199  *\r
200  *     // Register column [lbUserId]\r
201  *     request.mapping(sourceDbm.columnLbUserId(), trace.referrerLibraryUserList().foreignLbUser().columnLbUserId());\r
202  *\r
203  *     // Register column [lbUserName]\r
204  *     request.mapping(sourceDbm.columnLbUserName(), trace.referrerLibraryUserList().foreignLbUser().columnLbUserName());\r
205  *\r
206  *     return request;\r
207  * }\r
208  * \r
209  * private java.util.List&gt;HierarchyFlatLibrary&gt; createFlatLibraryList() {\r
210  *     (...select and get list)\r
211  *     return flatLibraryList;\r
212  * }\r
213  * \r
214  * \r
215  * === Relation Trace Tips ===\r
216  * \r
217  *   RelationTrace.f + [Code Assist] -- go to Foreign\r
218  *   RelationTrace.r + [Code Assist] -- go to Referrer\r
219  *   RelationTrace.c + [Code Assist] -- end relation by Column\r
220  *\r
221  * \r
222  * <pre>\r
223  * @author ${database.ClassAuthor}\r
224  * @param <LOCAL_ENTITY> The type of local entity extends Entity\r
225  */${database.outputSuppressWarningsAfterLineSeparator()}\r
226 public class ${myClassName}<LOCAL_ENTITY extends ${glEntityInterfaceName}> {\r
227 \r
228     // ===================================================================================\r
229     //                                                                                Main\r
230     //                                                                                ====\r
231     /**\r
232      * Arrange hierarchy.\r
233      * \r
234      * @param request Hierarchy request. (NotNull)\r
235      * @return The list of local entity. (NotNull)\r
236      */\r
237     public List<LOCAL_ENTITY> arrangeHierarchy(${glHierarchyRequestName}<LOCAL_ENTITY> request) {\r
238         final List<LOCAL_ENTITY> localTableList = new ArrayList<LOCAL_ENTITY>();\r
239         final Map<String, ${glEntityInterfaceName}> alreadyRegisteredEntityMap = new HashMap<String, ${glEntityInterfaceName}>();\r
240 \r
241         // ============\r
242         // Record Loop!\r
243         // ============\r
244         final ${glHierarchySourceIteratorName} sourceIterator = request.getSourceIterator();\r
245         while (sourceIterator.hasNext()) {\r
246             final ${glHierarchySourceRowName} sourceRow = sourceIterator.next();\r
247             final TopInfo<LOCAL_ENTITY> topInfo = new TopInfo<LOCAL_ENTITY>();\r
248             topInfo.setHierarchyRequest(request);\r
249             topInfo.setSourceRow(sourceRow);\r
250             topInfo.setAlreadyRegisteredEntityMap(alreadyRegisteredEntityMap);\r
251 \r
252             final Map<String, Object> primaryKeyMap = extractTopPrimaryKeyMapFromSource(topInfo);\r
253             final String alreadyRegisteredKey = buildTopAlreadyRegisteredKey(primaryKeyMap);\r
254             if (alreadyRegisteredEntityMap.containsKey(alreadyRegisteredKey)) {\r
255                 final ${glEntityInterfaceName} localEntity = alreadyRegisteredEntityMap.get(alreadyRegisteredKey);\r
256                 topInfo.setLocalEntity(localEntity);\r
257             } else {\r
258                 // Make local entity and register it to the result list.\r
259                 final LOCAL_ENTITY localEntity = newLocalEntity(request.getDestinationDBMeta());\r
260                 topInfo.setLocalEntity(localEntity);\r
261                 localTableList.add(localEntity);\r
262                 alreadyRegisteredEntityMap.put(alreadyRegisteredKey, localEntity);\r
263             }\r
264 \r
265             // ============\r
266             // Column Loop!\r
267             // ============\r
268             doColumnLoop(topInfo);\r
269         }\r
270 \r
271         // Clear modified properties.\r
272         final java.util.Set<String> alreadyRegisteredEntityKeySet = alreadyRegisteredEntityMap.keySet();\r
273         for (String key : alreadyRegisteredEntityKeySet) {\r
274             final ${glEntityInterfaceName} currentRegisteredEntity = alreadyRegisteredEntityMap.get(key);\r
275             currentRegisteredEntity.clearModifiedPropertyNames();\r
276         }\r
277 \r
278         return localTableList;\r
279     }\r
280 \r
281     /**\r
282      * Build top already-registered key.\r
283      * \r
284      * @param primaryKeyMap The map of primary key. (NotNull)\r
285      * @return Top already-registered key. (NotNull)\r
286      */\r
287     protected String buildTopAlreadyRegisteredKey(Map<String, Object> primaryKeyMap) {\r
288         return ${glHierarchyRequestElementName}.TOP_KEY + ":" + primaryKeyMap;\r
289     }\r
290 \r
291     /**\r
292      * Do column loop.\r
293      * \r
294      * @param topInfo The information object of top that has generics of the type of local entity. (NotNull)\r
295      */\r
296     protected void doColumnLoop(TopInfo<LOCAL_ENTITY> topInfo) {\r
297         final ${glHierarchyRequestName}<LOCAL_ENTITY> request = topInfo.getHierarchyRequest();\r
298         final ${glEntityInterfaceName} localEntity = topInfo.getLocalEntity();\r
299         final List<${glHierarchyRequestElementName}> requestElementList = request.getRequestElementList();\r
300 \r
301         // ============\r
302         // Column Loop!\r
303         // ============\r
304         for (${glHierarchyRequestElementName} requestElement : requestElementList) {\r
305             final List<String> relationPropertyNameList = requestElement.getRelationPropertyNameList();\r
306 \r
307             // If the column belongs to local entity, inject the value to entity and continue loop.\r
308             if (relationPropertyNameList == null || relationPropertyNameList.isEmpty()) {\r
309                 final ${glHierarchySourceColumnName} sourceColumn = requestElement.getSourceColumnInfo();\r
310                 final ${glHierarchySourceRowName} sourceRow = topInfo.getSourceRow();\r
311                 final Object sourceColumnValue = extractColumnValueFromSource(sourceRow, sourceColumn);\r
312                 final ${glColumnInfoName} destinationColumnInfo = requestElement.getDestinationColumnInfo();\r
313                 injectColumnValueToDestinationIfNotNull(localEntity, destinationColumnInfo, sourceColumnValue);\r
314                 continue;\r
315             }\r
316 \r
317             // ==============\r
318             // Relation Loop!\r
319             // ==============\r
320             doRelationLoop(topInfo, requestElement, relationPropertyNameList);\r
321         }\r
322     }\r
323 \r
324     /**\r
325      * Do relation loop.\r
326      * \r
327      * @param topInfo The information object of top that has generics of local entity. (NotNull)\r
328      * @param requestElement The element of request. This is relation loop resource. (NotNull)\r
329      * @param relationPropNameList The list of relation property name that has generics of string. (NotNull)\r
330      */\r
331     protected void doRelationLoop(TopInfo<LOCAL_ENTITY> topInfo, ${glHierarchyRequestElementName} requestElement, java.util.List<String> relationPropNameList) {\r
332         final ${glHierarchyRequestName}<LOCAL_ENTITY> request = topInfo.getHierarchyRequest();\r
333         final Map<String, ${glEntityInterfaceName}> alreadyRegisteredEntityMap = topInfo.getAlreadyRegisteredEntityMap();\r
334 \r
335         // Temporary variables for local\r
336         ${glEntityInterfaceName} localEntity = topInfo.getLocalEntity();// as Default\r
337         ${glDBMetaInterfaceName} localDBMeta = request.getDestinationDBMeta();// as Default\r
338         String localRelationPath = ${glHierarchyRequestElementName}.TOP_KEY;// as Default\r
339 \r
340         // ==============\r
341         // Relation Loop!\r
342         // ==============\r
343         final StringBuilder relationPropKeyStringBuilder = new StringBuilder();\r
344         int relationLoopCount = 0;\r
345         for (String relationPropName : relationPropNameList) {\r
346             if (relationPropKeyStringBuilder.length() > 0) {\r
347                 relationPropKeyStringBuilder.append("_");\r
348             }\r
349             relationPropKeyStringBuilder.append(relationPropName);\r
350             final String targetRelationPath = relationPropKeyStringBuilder.toString();\r
351             final ${glRelationInfoName} relationInfo = localDBMeta.findRelationInfo(relationPropName);\r
352 \r
353             final Map<String, Object> targetPrimaryKeyMap;\r
354             final String alreadyRegisteredEntityKey;\r
355             if (!relationInfo.isReferrer()) {\r
356                 // =======\r
357                 // Foreign\r
358                 // =======\r
359                 final ${glForeignInfoName} foreignInfo = localDBMeta.findForeignInfo(relationPropName);\r
360                 final String foreignPropName = foreignInfo.getForeignPropertyName();\r
361 \r
362                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
363                 // If the value of primary key does not exist, break this relation path!\r
364                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
365                 if (isNotExistPrimaryKey(topInfo, targetRelationPath)) {\r
366                     break;\r
367                 }\r
368 \r
369                 targetPrimaryKeyMap = extractPrimaryKeyMapFromSource(topInfo, targetRelationPath);\r
370                 alreadyRegisteredEntityKey = targetRelationPath + ":" + targetPrimaryKeyMap.toString();\r
371                 if (!alreadyRegisteredEntityMap.containsKey(alreadyRegisteredEntityKey)) {\r
372                     // - - - - - - - - - - - - - - - - - - - - - - -\r
373                     // Initialize the foreign entity and inject it.\r
374                     // - - - - - - - - - - - - - - - - - - - - - - -\r
375                     final ${glEntityInterfaceName} foreignEntity = foreignInfo.getForeignDBMeta().newEntity();\r
376                     injectForeignEntity(localEntity, foreignPropName, foreignEntity);\r
377 \r
378                     // - - - - - - - - - - - - - - - - - -\r
379                     // Initialize primary key of foreign.\r
380                     // - - - - - - - - - - - - - - - - - -\r
381                     injectForeignPrimaryKey(foreignEntity, targetPrimaryKeyMap);\r
382 \r
383                     // - - - - - - - - - - - - - - - - - -\r
384                     // Initialize foreign key of local.\r
385                     // - - - - - - - - - - - - - - - - - -\r
386                     injectLocalForeignKey(topInfo, localEntity, foreignInfo, targetRelationPath);\r
387 \r
388                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
389                     // Put foreign entity to the map of already-registered-entity.\r
390                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
391                     alreadyRegisteredEntityMap.put(alreadyRegisteredEntityKey.toString(), foreignEntity);\r
392                 } else {\r
393                     // - - - - - - - - - - - - - -\r
394                     // Inject the foreign entity.\r
395                     // - - - - - - - - - - - - - -\r
396                     final ${glEntityInterfaceName} foreignEntity = alreadyRegisteredEntityMap.get(alreadyRegisteredEntityKey);\r
397                     injectForeignEntity(localEntity, foreignPropName, foreignEntity);\r
398                 }\r
399             } else {\r
400                 // =======\r
401                 // Referrer\r
402                 // =======\r
403                 final ${glReferrerInfoName} referrerInfo = localDBMeta.findReferrerInfo(relationPropName);\r
404 \r
405                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
406                 // Extract referrer list from current local entity and initialize it if needs.\r
407                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
408                 List<${glEntityInterfaceName}> referrerList = extractReferrerList(localEntity, referrerInfo);\r
409                 if (referrerList == null) {\r
410 #if (!$database.isOneToManyReturnNullIfNonSelect())\r
411                     String msg = "The referrer list should not be null: localEntity=" + localEntity + " referrerInfo=" + referrerInfo;\r
412                     throw new IllegalStateException(msg);\r
413 #else\r
414                     // Initialize the list of referrer and inject it.\r
415                     referrerList = new ArrayList<${glEntityInterfaceName}>();\r
416                     injectReferrerList(localEntity, referrerInfo, referrerList);\r
417 #end\r
418                 }\r
419 \r
420                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
421                 // If the value of primary key does not exist, break this relation path!\r
422                 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
423                 if (isNotExistPrimaryKey(topInfo, targetRelationPath)) {\r
424                     break;\r
425                 }\r
426 \r
427                 targetPrimaryKeyMap = extractPrimaryKeyMapFromSource(topInfo, targetRelationPath);\r
428                 alreadyRegisteredEntityKey = targetRelationPath + ":" + targetPrimaryKeyMap.toString();\r
429                 if (!alreadyRegisteredEntityMap.containsKey(alreadyRegisteredEntityKey)) {\r
430                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
431                     // Initialize referrer entity and register it to the list of referrer with primary key value.\r
432                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
433                     final ${glEntityInterfaceName} referrerEntity = relationInfo.getTargetDBMeta().newEntity();\r
434                     referrerList.add(referrerEntity);\r
435 \r
436                     // - - - - - - - - - - - - - - - - - -\r
437                     // Initialize primary key of referrer.\r
438                     // - - - - - - - - - - - - - - - - - -\r
439                     injectReferrerPrimaryKey(referrerEntity, targetPrimaryKeyMap);\r
440 \r
441                     // - - - - - - - - - - - - - - - - - -\r
442                     // Initialize foreign key of referrer.\r
443                     // - - - - - - - - - - - - - - - - - -\r
444                     injectReferrerForeignKey(topInfo, referrerEntity, referrerInfo, localRelationPath);\r
445 \r
446                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
447                     // Put referrer entity to the map of already-registered-entity.\r
448                     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\r
449                     alreadyRegisteredEntityMap.put(alreadyRegisteredEntityKey.toString(), referrerEntity);\r
450                 }\r
451             }\r
452 \r
453             // - - - - - - - - - - - - - - - - - -\r
454             // Set next value to current element.\r
455             // - - - - - - - - - - - - - - - - - -\r
456             localEntity = alreadyRegisteredEntityMap.get(alreadyRegisteredEntityKey);\r
457             localDBMeta = localEntity.getDBMeta();\r
458             localRelationPath = targetRelationPath;\r
459 \r
460             if (relationLoopCount == (relationPropNameList.size() - 1)) {// The last loop!\r
461                 // - - - - - - - - - - - -  \r
462                 // Here is the last loop!\r
463                 // - - - - - - - - - - - - \r
464                 doLastLoopInjection(topInfo, requestElement, localEntity, targetPrimaryKeyMap);\r
465             }\r
466             ++relationLoopCount;\r
467         }\r
468     }\r
469 \r
470     /**\r
471      * Is not existing primary key at the relation path?.\r
472      * \r
473      * @param topInfo The information object of top that has generics of local entity. (NotNull)\r
474      * @param relationPath The path of relation. (NotNull)\r
475      * @return Determination.\r
476      */\r
477     protected boolean isNotExistPrimaryKey(TopInfo<LOCAL_ENTITY> topInfo, String relationPath) {\r
478         final Map<String, Object> primaryKeyMap = extractPrimaryKeyMapFromSource(topInfo, relationPath);\r
479         final Set<String> keySet = primaryKeyMap.keySet();\r
480         for (String key : keySet) {\r
481             final Object value = primaryKeyMap.get(key);\r
482             if (value == null) {\r
483                 return true;\r
484             }\r
485         }\r
486         return false;\r
487     }\r
488 \r
489     /**\r
490      * Do last loop injection.\r
491      * \r
492      * @param topInfo The information object of top that has generics of local entity. (NotNull)\r
493      * @param requestElement The element of request. This is relation loop resource. (NotNull)\r
494      * @param localEntity The interface of local entity. (NotNull)\r
495      * @param primaryKeyMap The map of primary key. (NotNull)\r
496      */\r
497     protected void doLastLoopInjection(TopInfo<LOCAL_ENTITY> topInfo, ${glHierarchyRequestElementName} requestElement,\r
498                                        ${glEntityInterfaceName} localEntity, Map<String, Object> primaryKeyMap) {\r
499         final ${glColumnInfoName} destinationColumnInfo = requestElement.getDestinationColumnInfo();\r
500         if (!primaryKeyMap.containsKey(destinationColumnInfo.getColumnDbName())) {// The column is primary key!\r
501             final ${glHierarchySourceRowName} sourceRow = topInfo.getSourceRow();\r
502             final ${glHierarchySourceColumnName} sourceColumnInfo = requestElement.getSourceColumnInfo();\r
503             final Object sourceColumnValue = extractColumnValueFromSource(sourceRow, sourceColumnInfo);\r
504             if (sourceColumnValue != null) {\r
505                 injectColumnValueToDestinationIfNotNull(localEntity, destinationColumnInfo, sourceColumnValue);\r
506             }\r
507         }\r
508     }\r
509 \r
510     // ===================================================================================\r
511     //                                                                       Extract Logic\r
512     //                                                                       =============\r
513     protected Map<String, Object> extractTopPrimaryKeyMapFromSource(TopInfo<LOCAL_ENTITY> topInfo) {\r
514         return extractPrimaryKeyMapFromSource(topInfo, ${glHierarchyRequestElementName}.TOP_KEY);\r
515     }\r
516 \r
517     protected Map<String, Object> extractPrimaryKeyMapFromSource(TopInfo<LOCAL_ENTITY> topInfo, String relationPath) {\r
518         final ${glHierarchyRequestName}<LOCAL_ENTITY> request = topInfo.getHierarchyRequest();\r
519         final ${glHierarchySourceRowName} sourceRow = topInfo.getSourceRow();\r
520         final java.util.List<${glHierarchyRequestElementName}> primaryKeyElement = request.findPrimaryKeyElement(relationPath);\r
521         final java.util.Map<String, Object> primaryKeyMap = new java.util.LinkedHashMap<String, Object>();\r
522         for (${glHierarchyRequestElementName} element : primaryKeyElement) {\r
523             final ${glHierarchySourceColumnName} sourcePrimaryKey = element.getSourceColumnInfo();\r
524             final Object sourcePrimaryKeyValue = extractColumnValueFromSource(sourceRow, sourcePrimaryKey);\r
525             primaryKeyMap.put(element.getDestinationColumnInfo().getColumnDbName(), sourcePrimaryKeyValue);\r
526         }\r
527         return primaryKeyMap;\r
528     }\r
529 \r
530     protected Object extractColumnValueFromSource(${glHierarchySourceRowName} sourceRow,\r
531             ${glHierarchySourceColumnName} sourceColumn) {\r
532         return sourceRow.extractColumnValue(sourceColumn);\r
533     }\r
534 \r
535     @SuppressWarnings("unchecked")\r
536     protected java.util.List<${glEntityInterfaceName}> extractReferrerList(${glEntityInterfaceName} entity, ${glReferrerInfoName} referrerInfo) {\r
537         return (java.util.List<${glEntityInterfaceName}>) invoke(referrerInfo.findGetter(), entity, new Object[] {});\r
538     }\r
539 \r
540     // ===================================================================================\r
541     //                                                                        Inject Logic\r
542     //                                                                        ============\r
543     /**\r
544      * @param entity Entity. (NotNull)\r
545      * @param columnInfo Column info. (NotNull)\r
546      * @param columnValue Column value. (NotNull)\r
547      */\r
548     protected void injectColumnValueToDestinationIfNotNull(${glEntityInterfaceName} entity, ${glColumnInfoName} columnInfo, final Object columnValue) {\r
549         if (columnValue != null) {\r
550             injectColumnValueToDestination(entity, columnInfo.getColumnDbName(), columnValue);\r
551         }\r
552     }\r
553 \r
554     protected void injectColumnValueToDestination(${glEntityInterfaceName} entity, String columnDbName, final Object columnValue) {\r
555         if (columnValue == null) {\r
556             String msg = "The argument[columnValue] should not be null: ";\r
557             msg = msg + " table=" + entity.getTableDbName() + " column=" + columnDbName;\r
558             throw new IllegalStateException(msg);\r
559         }\r
560         invoke(entity.getDBMeta().findColumnInfo(columnDbName).findSetter(), entity, new Object[] { columnValue });\r
561     }\r
562 \r
563     protected void injectColumnValueMapToDestination(${glEntityInterfaceName} entity, final Map<String, Object> columnValueMap) {\r
564         final Set<String> columnNameSet = columnValueMap.keySet();\r
565         for (String columnName : columnNameSet) {\r
566             final Object columnValue = columnValueMap.get(columnName);\r
567             injectColumnValueToDestination(entity, columnName, columnValue);\r
568         }\r
569     }\r
570 \r
571     protected void injectForeignEntity(${glEntityInterfaceName} entity, String foreignPropName, ${glEntityInterfaceName} foreignEntity) {\r
572         final String capPropReferrerName = initCap(foreignPropName);\r
573         final Method method = findMethod(entity.getClass(), "set" + capPropReferrerName, new Class[] { foreignEntity.getDBMeta().getEntityType() });\r
574         invoke(method, entity, new Object[] { foreignEntity });\r
575     }\r
576 \r
577     protected void injectReferrerList(${glEntityInterfaceName} entity, ${glReferrerInfoName} referrerInfo, java.util.List<${glEntityInterfaceName}> referrerList) {\r
578         invoke(referrerInfo.findSetter(), entity, new Object[] { referrerList });\r
579     }\r
580 \r
581     protected void injectForeignPrimaryKey(${glEntityInterfaceName} foreignEntity, Map<String, Object> foreigPrimaryKeyMap) {\r
582         injectColumnValueMapToDestination(foreignEntity, foreigPrimaryKeyMap);\r
583     }\r
584 \r
585     protected void injectReferrerPrimaryKey(${glEntityInterfaceName} referrerEntity, Map<String, Object> referrerPrimaryKeyMap) {\r
586         injectColumnValueMapToDestination(referrerEntity, referrerPrimaryKeyMap);\r
587     }\r
588 \r
589     protected void injectLocalForeignKey(TopInfo<LOCAL_ENTITY> topInfo, ${glEntityInterfaceName} localEntity, ${glForeignInfoName} foreignInfo, String foreignRelationPath) {\r
590         final ${glHierarchyRequestName}<LOCAL_ENTITY> request = topInfo.getHierarchyRequest();\r
591         final Map<String, Object> foreignPrimaryKeyMap = extractPrimaryKeyMapFromSource(topInfo, foreignRelationPath);\r
592         final List<${glHierarchyRequestElementName}> primaryKeyElementList = request.findPrimaryKeyElement(foreignRelationPath);\r
593         final Map<String, Object> localForeignKeyMap = new HashMap<String, Object>();\r
594         for (${glHierarchyRequestElementName} foreignElement : primaryKeyElementList) {\r
595             final String foreignPrimaryKeyColumnName = foreignElement.getDestinationColumnInfo().getColumnDbName();\r
596             final ${glColumnInfoName} localForeignKeyInfo = foreignInfo.findLocalByForeign(foreignPrimaryKeyColumnName);\r
597             final Object localForeignKeyValue = foreignPrimaryKeyMap.get(foreignPrimaryKeyColumnName);\r
598             localForeignKeyMap.put(localForeignKeyInfo.getColumnDbName(), localForeignKeyValue);\r
599         }\r
600         injectColumnValueMapToDestination(localEntity, localForeignKeyMap);\r
601     }\r
602 \r
603     protected void injectReferrerForeignKey(TopInfo<LOCAL_ENTITY> topInfo, ${glEntityInterfaceName} referrerEntity,\r
604             ${glReferrerInfoName} referrerInfo, String localRelationPath) {\r
605         final ${glHierarchyRequestName}<LOCAL_ENTITY> request = topInfo.getHierarchyRequest();\r
606         final Map<String, Object> localPrimaryKeyMap = extractPrimaryKeyMapFromSource(topInfo, localRelationPath);\r
607         final List<${glHierarchyRequestElementName}> primaryKeyElementList = request.findPrimaryKeyElement(localRelationPath);\r
608         final Map<String, Object> referrerForeignKeyMap = new HashMap<String, Object>();\r
609         for (${glHierarchyRequestElementName} localElement : primaryKeyElementList) {\r
610             final String localPrimaryKeyName = localElement.getDestinationColumnInfo().getColumnDbName();\r
611             final ${glColumnInfoName} referrerForeignKeyInfo = referrerInfo.findReferrerByLocal(localPrimaryKeyName);\r
612             final Object referrerForeignKeyValue = localPrimaryKeyMap.get(localPrimaryKeyName);\r
613             referrerForeignKeyMap.put(referrerForeignKeyInfo.getColumnDbName(), referrerForeignKeyValue);\r
614         }\r
615         injectColumnValueMapToDestination(referrerEntity, referrerForeignKeyMap);\r
616     }\r
617 \r
618     // ===================================================================================\r
619     //                                                                         Other Logic\r
620     //                                                                         ===========\r
621     @SuppressWarnings("unchecked")\r
622     protected LOCAL_ENTITY newLocalEntity(final ${glDBMetaInterfaceName} destinationDBMeta) {\r
623         final LOCAL_ENTITY localEntity;\r
624         try {\r
625             localEntity = (LOCAL_ENTITY) destinationDBMeta.getEntityType().newInstance();\r
626         } catch (InstantiationException e) {\r
627             throw new IllegalStateException(e);\r
628         } catch (IllegalAccessException e) {\r
629             throw new IllegalStateException(e);\r
630         }\r
631         return localEntity;\r
632     }\r
633 \r
634     // ===================================================================================\r
635     //                                                                              Helper\r
636     //                                                                              ======\r
637     protected String initCap(final String name) {\r
638         final String capPropReferrerName = name.substring(0, 1).toUpperCase() + name.substring(1);\r
639         return capPropReferrerName;\r
640     }\r
641 \r
642     private java.lang.reflect.Method findMethod(Class clazz, String methodName, Class[] argTypes) {\r
643         try {\r
644             return clazz.getMethod(methodName, argTypes);\r
645         } catch (NoSuchMethodException ex) {\r
646             String msg = "class=" + clazz + " method=" + methodName + "-" + java.util.Arrays.asList(argTypes);\r
647             throw new RuntimeException(msg, ex);\r
648         }\r
649     }\r
650 \r
651     private Object invoke(java.lang.reflect.Method method, Object target, Object[] args) {\r
652         try {\r
653             return method.invoke(target, args);\r
654         } catch (RuntimeException e) {\r
655             final String lineSeparator = System.getProperty("line.separator");\r
656             final Class<?>[] parameterTypes = method.getParameterTypes();\r
657             String msg = "Invoking method threw the exception:" + lineSeparator;\r
658             msg = msg + "/* * * * * * * * * * * * * * * * * * * * * * * * * * * *" + lineSeparator;\r
659             msg = msg + "[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()]" + lineSeparator;\r
660             msg = msg + " methodArgTypes     = {" + createTypeViewFromTypeArray(parameterTypes) + "}" + lineSeparator;\r
661             msg = msg + " specifiedArgValues = {" + createValueViewFromValueArray(args) + "}" + lineSeparator;\r
662             msg = msg + " specifiedArgTypes  = {" + createTypeViewFromValueArray(args) + "}" + lineSeparator;\r
663             if (parameterTypes.length > 0 && args.length > 0 && args[0] != null && !parameterTypes[0].equals(args[0].getClass())) {\r
664                 msg = msg + " " + lineSeparator;\r
665                 final String compareString = "{" + parameterTypes[0] + " -- " + args[0].getClass() + "}";\r
666                 msg = msg + " *Warning! The argType is ummatched: " + compareString + lineSeparator;    \r
667             }\r
668             msg = msg + "* * * * * * * * * */" + lineSeparator;\r
669             throw new RuntimeException(msg, e);\r
670         } catch (java.lang.reflect.InvocationTargetException ex) {\r
671             Throwable t = ex.getCause();\r
672             if (t instanceof RuntimeException) {\r
673                 throw (RuntimeException) t;\r
674             }\r
675             if (t instanceof Error) {\r
676                 throw (Error) t;\r
677             }\r
678             String msg = "target=" + target + " method=" + method + "-" + java.util.Arrays.asList(args);\r
679             throw new RuntimeException(msg, ex);\r
680         } catch (IllegalAccessException ex) {\r
681             String msg = "target=" + target + " method=" + method + "-" + java.util.Arrays.asList(args);\r
682             throw new RuntimeException(msg, ex);\r
683         }\r
684     }\r
685 \r
686     private String createValueViewFromValueArray(Object[] array) {\r
687         final StringBuffer sb = new StringBuffer();\r
688         for (int i=0; i < array.length; i++) {\r
689             final Object value = array[i];\r
690             if (sb.length() == 0) {\r
691                 sb.append(value);\r
692             } else {\r
693                 sb.append(", ").append(value);\r
694             }\r
695         }\r
696         return sb.toString();\r
697     }\r
698     \r
699     private String createTypeViewFromValueArray(Object[] array) {\r
700         final StringBuffer sb = new StringBuffer();\r
701         for (int i=0; i < array.length; i++) {\r
702             final Object value = array[i];\r
703             final String typeName = value != null ? value.getClass().getSimpleName() : "null";\r
704             if (sb.length() == 0) {\r
705                 sb.append(typeName);\r
706             } else {\r
707                 sb.append(", ").append(typeName);\r
708             }\r
709         }\r
710         return sb.toString();\r
711     }\r
712     \r
713     private String createTypeViewFromTypeArray(Class[] array) {\r
714         final StringBuffer sb = new StringBuffer();\r
715         for (int i=0; i < array.length; i++) {\r
716             final Class type = array[i];\r
717             if (sb.length() == 0) {\r
718                 sb.append(type.getSimpleName());\r
719             } else {\r
720                 sb.append(", ").append(type.getSimpleName());\r
721             }\r
722         }\r
723         return sb.toString();\r
724     }\r
725 \r
726     // ===================================================================================\r
727     //                                                                          Info Class\r
728     //                                                                          ==========\r
729     protected static class TopInfo<LOCAL_ENTITY extends ${glEntityInterfaceName}> {\r
730         private ${glHierarchyRequestName}<LOCAL_ENTITY> hierarchyRequest;\r
731 \r
732         private ${glHierarchySourceRowName} sourceRow;\r
733 \r
734         private ${glEntityInterfaceName} localEntity;\r
735 \r
736         private Map<String, ${glEntityInterfaceName}> alreadyRegisteredEntityMap;\r
737 \r
738         public ${glHierarchySourceRowName} getSourceRow() {\r
739             return sourceRow;\r
740         }\r
741 \r
742         public void setSourceRow(${glHierarchySourceRowName} sourceRow) {\r
743             this.sourceRow = sourceRow;\r
744         }\r
745 \r
746         public ${glEntityInterfaceName} getLocalEntity() {\r
747             return localEntity;\r
748         }\r
749 \r
750         public void setLocalEntity(${glEntityInterfaceName} localEntity) {\r
751             this.localEntity = localEntity;\r
752         }\r
753 \r
754         public Map<String, ${glEntityInterfaceName}> getAlreadyRegisteredEntityMap() {\r
755             return alreadyRegisteredEntityMap;\r
756         }\r
757 \r
758         public void setAlreadyRegisteredEntityMap(Map<String, ${glEntityInterfaceName}> alreadyRegisteredEntityMap) {\r
759             this.alreadyRegisteredEntityMap = alreadyRegisteredEntityMap;\r
760         }\r
761 \r
762         public ${glHierarchyRequestName}<LOCAL_ENTITY> getHierarchyRequest() {\r
763             return hierarchyRequest;\r
764         }\r
765 \r
766         public void setHierarchyRequest(${glHierarchyRequestName}<LOCAL_ENTITY> hierarchyRequest) {\r
767             this.hierarchyRequest = hierarchyRequest;\r
768         }\r
769     }\r
770 }\r