Project

General

Profile

Download (20.4 KB) Statistics
| Branch: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2009 EDIT
4
* European Distributed Institute of Taxonomy 
5
* http://www.e-taxonomy.eu
6
* 
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.io.pesi.out;
11

    
12
import java.sql.Connection;
13
import java.sql.PreparedStatement;
14
import java.sql.SQLException;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.List;
18
import java.util.Set;
19

    
20
import org.apache.log4j.Logger;
21
import org.springframework.stereotype.Component;
22
import org.springframework.transaction.TransactionStatus;
23

    
24
import eu.etaxonomy.cdm.io.berlinModel.out.mapper.MethodMapper;
25
import eu.etaxonomy.cdm.io.common.DbExportStateBase;
26
import eu.etaxonomy.cdm.io.common.Source;
27
import eu.etaxonomy.cdm.model.common.CdmBase;
28
import eu.etaxonomy.cdm.model.common.RelationshipBase;
29
import eu.etaxonomy.cdm.model.name.NameRelationship;
30
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
31
import eu.etaxonomy.cdm.model.name.Rank;
32
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
33
import eu.etaxonomy.cdm.model.taxon.Synonym;
34
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
35
import eu.etaxonomy.cdm.model.taxon.Taxon;
36
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
37
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
38
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
39
import eu.etaxonomy.cdm.model.taxon.Classification;
40

    
41
/**
42
 * The export class for relations between {@link eu.etaxonomy.cdm.model.taxon.TaxonBase TaxonBases}.<p>
43
 * Inserts into DataWarehouse database table <code>RelTaxon</code>.
44
 * @author e.-m.lee
45
 * @date 23.02.2010
46
 *
47
 */
48
@Component
49
@SuppressWarnings("unchecked")
50
public class PesiRelTaxonExport extends PesiExportBase {
51
	private static final Logger logger = Logger.getLogger(PesiRelTaxonExport.class);
52
	private static final Class<? extends CdmBase> standardMethodParameter = RelationshipBase.class;
53

    
54
	private static int modCount = 1000;
55
	private static final String dbTableName = "RelTaxon";
56
	private static final String pluralString = "Relationships";
57
	private static PreparedStatement synonymsStmt;
58
	private HashMap<Rank, Rank> rankMap = new HashMap<Rank, Rank>();
59
	private List<Rank> rankList = new ArrayList<Rank>();
60
	private PesiExportMapping mapping;
61
	private int count = 0;
62
	private boolean success = true;
63
	private static NomenclaturalCode nomenclaturalCode;
64
	
65
	public PesiRelTaxonExport() {
66
		super();
67
	}
68

    
69
	/* (non-Javadoc)
70
	 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
71
	 */
72
	@Override
73
	public Class<? extends CdmBase> getStandardMethodParameter() {
74
		return standardMethodParameter;
75
	}
76

    
77
	/* (non-Javadoc)
78
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
79
	 */
80
	@Override
81
	protected boolean doCheck(PesiExportState state) {
82
		boolean result = true;
83
		return result;
84
	}
85

    
86
	/* (non-Javadoc)
87
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
88
	 */
89
	@Override
90
	protected void doInvoke(PesiExportState state) {
91
		try {
92
			logger.error("*** Started Making " + pluralString + " ...");
93
	
94
			Connection connection = state.getConfig().getDestination().getConnection();
95
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?"; 
96
			synonymsStmt = connection.prepareStatement(synonymsSql);
97
			
98
			// Get the limit for objects to save within a single transaction.
99
			int pageSize = 1000;
100

    
101
			// Get the limit for objects to save within a single transaction.
102
			int limit = state.getConfig().getLimitSave();
103

    
104
			// Stores whether this invoke was successful or not.
105
			boolean success = true;
106

    
107
			// PESI: Clear the database table RelTaxon.
108
			doDelete(state);
109
	
110
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
111
			mapping = getMapping();
112

    
113
			// Initialize the db mapper
114
			mapping.initialize(state);
115

    
116
			TransactionStatus txStatus = null;
117
			List<Classification> classificationList = null;
118
			
119
			// Specify starting ranks for tree traversing
120
			rankList.add(Rank.KINGDOM());
121
			rankList.add(Rank.GENUS());
122

    
123
			// Specify where to stop traversing (value) when starting at a specific Rank (key)
124
			rankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
125
			rankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
126
			
127
			// Retrieve list of classifications
128
			txStatus = startTransaction(true);
129
			logger.error("Started transaction. Fetching all classifications...");
130
			classificationList = getClassificationService().listClassifications(null, 0, null, null);
131
			commitTransaction(txStatus);
132
			logger.error("Committed transaction.");
133

    
134
			logger.error("Fetched " + classificationList.size() + " classification(s).");
135

    
136
			for (Classification classification : classificationList) {
137
				for (Rank rank : rankList) {
138
					
139
					txStatus = startTransaction(true);
140
					logger.error("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
141

    
142
					List<TaxonNode> rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null);
143
					logger.error("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
144

    
145
					commitTransaction(txStatus);
146
					logger.error("Committed transaction.");
147

    
148
					for (TaxonNode rootNode : rankSpecificRootNodes) {
149
						txStatus = startTransaction(false);
150
						Rank endRank = rankMap.get(rank);
151
						if (endRank != null) {
152
							logger.error("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
153
						} else {
154
							logger.error("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
155
						}
156

    
157
						TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
158

    
159
						TaxonNode parentNode = newNode.getParent();
160

    
161
						traverseTree(newNode, parentNode, rankMap.get(rank), state);
162

    
163
						commitTransaction(txStatus);
164
						logger.error("Committed transaction.");
165

    
166
					}
167
				}
168
			}
169

    
170
			logger.error("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
171

    
172
			if (!success){
173
				state.setUnsuccessfull();
174
			}
175
			return;
176
		} catch (SQLException e) {
177
			e.printStackTrace();
178
			logger.error(e.getMessage());
179
			state.setUnsuccessfull();
180
			return;
181
		}
182
	}
183

    
184
	/**
185
	 * Traverses the classification recursively and stores determined values for every Taxon.
186
	 * @param childNode
187
	 * @param parentNode
188
	 * @param treeIndex
189
	 * @param fetchLevel
190
	 * @param state
191
	 */
192
	private void traverseTree(TaxonNode childNode, TaxonNode parentNode, Rank fetchLevel, PesiExportState state) {
193
		// Traverse all branches from this childNode until specified fetchLevel is reached.
194
		if (childNode.getTaxon() != null) {
195
			TaxonNameBase taxonName = childNode.getTaxon().getName();
196
			if (taxonName != null) {
197
				Rank childTaxonNameRank = taxonName.getRank();
198
				if (childTaxonNameRank != null) {
199
					if (! childTaxonNameRank.equals(fetchLevel)) {
200

    
201
						saveData(childNode, parentNode, state);
202

    
203
						for (TaxonNode newNode : childNode.getChildNodes()) {
204
							traverseTree(newNode, childNode, fetchLevel, state);
205
						}
206
						
207
					} else {
208
//						logger.error("Target Rank " + fetchLevel.getLabel() + " reached");
209
						return;
210
					}
211
				} else {
212
					logger.error("Rank is NULL. FetchLevel can not be checked: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
213
				}
214
			} else {
215
				logger.error("TaxonName is NULL for this node: " + childNode.getUuid());
216
			}
217

    
218
		} else {
219
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
220
		}
221
	}
222

    
223
	/**
224
	 * Stores values in database for every recursive round.
225
	 * @param childNode
226
	 * @param parentNode
227
	 * @param treeIndex
228
	 * @param state
229
	 * @param currentTaxonFk
230
	 */
231
	private void saveData(TaxonNode childNode, TaxonNode parentNode, PesiExportState state) {
232
		Taxon childNodeTaxon = childNode.getTaxon();
233
		if (childNodeTaxon != null) {
234
			TaxonNameBase childNodeTaxonName = childNodeTaxon.getName();
235
			nomenclaturalCode = PesiTransformer.getNomenclaturalCode(childNodeTaxonName);
236

    
237
			if (childNodeTaxonName != null) {
238

    
239
				// TaxonRelationships
240
				Set<Taxon> taxa = childNodeTaxonName.getTaxa(); // accepted taxa
241
				if (taxa.size() == 1) {
242
					Taxon taxon = CdmBase.deproxy(taxa.iterator().next(), Taxon.class);
243
					Set<TaxonRelationship> taxonRelations = taxon.getRelationsToThisTaxon();
244
					for (TaxonRelationship taxonRelationship : taxonRelations) {
245
						try {
246
							if (neededValuesNotNull(taxonRelationship, state)) {
247
								doCount(count++, modCount, pluralString);
248
								success &= mapping.invoke(taxonRelationship);
249
							}
250
						} catch (SQLException e) {
251
							logger.error("TaxonRelationship could not be created for this TaxonRelation (" + taxonRelationship.getUuid() + "): " + e.getMessage());
252
						}
253
					}
254
				} else if (taxa.size() > 1) {
255
					logger.error("TaxonRelationship could not be created. This TaxonNode has " + taxa.size() + " Taxa: " + childNodeTaxon.getUuid() + " (" + childNodeTaxon.getTitleCache() + ")");
256
				}
257
				
258
				// TaxonNameRelationships
259
				Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
260
				for (NameRelationship nameRelation : nameRelations) {
261
					try {
262
						if (neededValuesNotNull(nameRelation, state)) {
263
							doCount(count++, modCount, pluralString);
264
							success &= mapping.invoke(nameRelation);
265
						}
266
					} catch (SQLException e) {
267
						logger.error("NameRelationship could not be created: " + e.getMessage());
268
					}
269
				}
270

    
271
			}
272
			
273
			// SynonymRelationships
274
			Set<Synonym> synonyms = childNodeTaxon.getSynonyms(); // synonyms of accepted taxon
275
			for (Synonym synonym : synonyms) {
276
				TaxonNameBase synonymTaxonName = synonym.getName();
277
				
278
				// Store synonym data in Taxon table
279
				invokeSynonyms(state, synonymTaxonName);
280

    
281
				Set<SynonymRelationship> synonymRelations = synonym.getSynonymRelations();
282
				for (SynonymRelationship synonymRelationship : synonymRelations) {
283
					try {
284
						if (neededValuesNotNull(synonymRelationship, state)) {
285
							doCount(count++, modCount, pluralString);
286
							success &= mapping.invoke(synonymRelationship);
287
							
288
						}
289
					} catch (SQLException e) {
290
						logger.error("SynonymRelationship could not be created for this SynonymRelation (" + synonymRelationship.getUuid() + "): " + e.getMessage());
291
					}
292
				}
293

    
294
				// SynonymNameRelationship
295
				Set<NameRelationship> nameRelations = synonymTaxonName.getRelationsFromThisName();
296
				for (NameRelationship nameRelation : nameRelations) {
297
					try {
298
						if (neededValuesNotNull(nameRelation, state)) {
299
							doCount(count++, modCount, pluralString);
300
							success &= mapping.invoke(nameRelation);
301
						}
302
					} catch (SQLException e) {
303
						logger.error("NameRelationship could not be created for this NameRelation (" + nameRelation.getUuid() + "): " + e.getMessage());
304
					}
305
				}
306

    
307
			}
308
			
309
		}
310
		
311
	}
312

    
313
	/**
314
	 * Determines synonym related data and saves them.
315
	 * @param state
316
	 * @param sr
317
	 */
318
	private static void invokeSynonyms(PesiExportState state, TaxonNameBase synonymTaxonName) {
319
		// Store KingdomFk and Rank information in Taxon table
320
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
321
		Integer synonymFk = state.getDbId(synonymTaxonName);
322

    
323
		saveSynonymData(synonymTaxonName, nomenclaturalCode, kingdomFk, synonymFk);
324
	}
325

    
326
	/**
327
	 * Stores synonym data.
328
	 * @param taxonName
329
	 * @param nomenclaturalCode
330
	 * @param kingdomFk
331
	 * @param synonymParentTaxonFk
332
	 * @param currentTaxonFk
333
	 */
334
	private static boolean saveSynonymData(TaxonNameBase taxonName,
335
			NomenclaturalCode nomenclaturalCode, Integer kingdomFk,
336
			Integer currentSynonymFk) {
337
		try {
338
			if (kingdomFk != null) {
339
				synonymsStmt.setInt(1, kingdomFk);
340
			} else {
341
				synonymsStmt.setObject(1, null);
342
			}
343
			
344
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
345
			if (rankFk != null) {
346
				synonymsStmt.setInt(2, rankFk);
347
			} else {
348
				synonymsStmt.setObject(2, null);
349
			}
350
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode));
351
			
352
			if (currentSynonymFk != null) {
353
				synonymsStmt.setInt(4, currentSynonymFk);
354
			} else {
355
				synonymsStmt.setObject(4, null);
356
			}
357
			synonymsStmt.executeUpdate();
358
			return true;
359
		} catch (SQLException e) {
360
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
361
			e.printStackTrace();
362
			return false;
363
		}
364
	}
365

    
366
	/**
367
	 * Checks whether needed values for an entity are NULL.
368
	 * @return
369
	 */
370
	private boolean neededValuesNotNull(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
371
		boolean result = true;
372
		if (getTaxonFk1(relationship, state) == null) {
373
			logger.error("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
374
			result = false;
375
		}
376
		if (getTaxonFk2(relationship, state) == null) {
377
			logger.error("TaxonFk2 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
378
			result = false;
379
		}
380
		return result;
381
	}
382
	
383
	/**
384
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
385
	 * @param state The {@link PesiExportState PesiExportState}.
386
	 * @return Whether the delete operation was successful or not.
387
	 */
388
	protected boolean doDelete(PesiExportState state) {
389
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
390
		
391
		String sql;
392
		Source destination =  pesiConfig.getDestination();
393

    
394
		// Clear RelTaxon
395
		sql = "DELETE FROM " + dbTableName;
396
		destination.setQuery(sql);
397
		destination.update(sql);
398
		return true;
399
	}
400

    
401
	/* (non-Javadoc)
402
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
403
	 */
404
	@Override
405
	protected boolean isIgnore(PesiExportState state) {
406
		return ! state.getConfig().isDoRelTaxa();
407
	}
408

    
409
	/**
410
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
411
	 * @param relationship The {@link RelationshipBase Relationship}.
412
	 * @param state The {@link PesiExportState PesiExportState}.
413
	 * @return The <code>TaxonFk1</code> attribute.
414
	 * @see MethodMapper
415
	 */
416
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
417
		return getObjectFk(relationship, state, true);
418
	}
419
	
420
	/**
421
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
422
	 * @param relationship The {@link RelationshipBase Relationship}.
423
	 * @param state The {@link PesiExportState PesiExportState}.
424
	 * @return The <code>TaxonFk2</code> attribute.
425
	 * @see MethodMapper
426
	 */
427
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
428
		return getObjectFk(relationship, state, false);
429
	}
430
	
431
	/**
432
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
433
	 * @param relationship The {@link RelationshipBase Relationship}.
434
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
435
	 * @see MethodMapper
436
	 */
437
	@SuppressWarnings("unused")
438
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
439
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
440
	}
441
	
442
	/**
443
	 * Returns the <code>RelQualifierCache</code> attribute.
444
	 * @param relationship The {@link RelationshipBase Relationship}.
445
	 * @return The <code>RelQualifierCache</code> attribute.
446
	 * @see MethodMapper
447
	 */
448
	@SuppressWarnings("unused")
449
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship) {
450
		String result = null;
451
		if (nomenclaturalCode != null) {
452
			if (nomenclaturalCode.equals(NomenclaturalCode.ICZN)) {
453
				result = PesiTransformer.zoologicalTaxonRelation2RelTaxonQualifierCache(relationship);
454
			} else {
455
				result = PesiTransformer.taxonRelation2RelTaxonQualifierCache(relationship);
456
			}
457
		} else {
458
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
459
		}
460
		return result;
461
	}
462
	
463
	/**
464
	 * Returns the <code>Notes</code> attribute.
465
	 * @param relationship The {@link RelationshipBase Relationship}.
466
	 * @return The <code>Notes</code> attribute.
467
	 * @see MethodMapper
468
	 */
469
	@SuppressWarnings("unused")
470
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
471
		// TODO
472
		return null;
473
	}
474

    
475
	/**
476
	 * Returns the database key of an object in the given relationship.
477
	 * @param relationship {@link RelationshipBase RelationshipBase}.
478
	 * @param state {@link PesiExportState PesiExportState}.
479
	 * @param isFrom A boolean value indicating whether the database key of the parent or child in this relationship is searched. <code>true</code> means the child is searched. <code>false</code> means the parent is searched.
480
	 * @return The database key of an object in the given relationship.
481
	 */
482
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
483
		TaxonBase<?> taxon = null;
484
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
485
			TaxonRelationship tr = (TaxonRelationship)relationship;
486
			taxon = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
487
		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
488
			SynonymRelationship sr = (SynonymRelationship)relationship;
489
			taxon = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
490
		} else if (relationship.isInstanceOf(NameRelationship.class)) {
491
			NameRelationship nr = (NameRelationship)relationship;
492
			TaxonNameBase taxonName = (isFrom) ? nr.getFromName() : nr.getToName();
493
			return state.getDbId(taxonName);
494
		}
495
		if (taxon != null) {
496
			return state.getDbId(taxon.getName());
497
		}
498
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
499
		return null;
500
	}
501

    
502
	/**
503
	 * Returns the <code>RankFk</code> attribute.
504
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
505
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
506
	 * @return The <code>RankFk</code> attribute.
507
	 * @see MethodMapper
508
	 */
509
	private static Integer getRankFk(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode) {
510
		Integer result = null;
511
		if (nomenclaturalCode != null) {
512
			if (taxonName != null && taxonName.getRank() == null) {
513
				logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
514
			}
515
			result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
516
			if (result == null) {
517
				logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
518
			}
519
		}
520
		return result;
521
	}
522

    
523
	/**
524
	 * Returns the <code>RankCache</code> attribute.
525
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
526
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
527
	 * @return The <code>RankCache</code> attribute.
528
	 * @see MethodMapper
529
	 */
530
	private static String getRankCache(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode) {
531
		String result = null;
532
		if (nomenclaturalCode != null) {
533
			result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
534
		}
535
		return result;
536
	}
537

    
538
	/**
539
	 * Returns the CDM to PESI specific export mappings.
540
	 * @return The {@link PesiExportMapping PesiExportMapping}.
541
	 */
542
	private PesiExportMapping getMapping() {
543
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
544
		
545
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
546
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
547
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
548
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this));
549
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
550

    
551
		return mapping;
552
	}
553

    
554
}
(12-12/15)