handling missing features
[cdmlib-apps.git] / cdm-pesi / src / main / java / eu / etaxonomy / cdm / io / pesi / out / PesiDescriptionExport.java
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 static java.util.EnumSet.of;
13
14 import java.sql.Connection;
15 import java.sql.PreparedStatement;
16 import java.sql.SQLException;
17 import java.util.Arrays;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.apache.log4j.Logger;
24 import org.springframework.stereotype.Component;
25 import org.springframework.transaction.TransactionStatus;
26
27 import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
28 import eu.etaxonomy.cdm.io.common.DbExportStateBase;
29 import eu.etaxonomy.cdm.io.common.Source;
30 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
31 import eu.etaxonomy.cdm.io.common.mapping.out.CollectionExportMapping;
32 import eu.etaxonomy.cdm.io.common.mapping.out.DbAreaMapper;
33 import eu.etaxonomy.cdm.io.common.mapping.out.DbDescriptionElementTaxonMapper;
34 import eu.etaxonomy.cdm.io.common.mapping.out.DbDistributionStatusMapper;
35 import eu.etaxonomy.cdm.io.common.mapping.out.DbExportIgnoreMapper;
36 import eu.etaxonomy.cdm.io.common.mapping.out.DbExportNotYetImplementedMapper;
37 import eu.etaxonomy.cdm.io.common.mapping.out.DbLanguageMapper;
38 import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
39 import eu.etaxonomy.cdm.io.common.mapping.out.DbOriginalNameMapper;
40 import eu.etaxonomy.cdm.io.common.mapping.out.DbSimpleFilterMapper;
41 import eu.etaxonomy.cdm.io.common.mapping.out.DbSingleSourceMapper;
42 import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
43 import eu.etaxonomy.cdm.io.common.mapping.out.DbTextDataMapper;
44 import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
45 import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
46 import eu.etaxonomy.cdm.io.profiler.ProfilerController;
47 //import eu.etaxonomy.cdm.io.profiler.ProfilerController;
48 import eu.etaxonomy.cdm.model.common.CdmBase;
49 import eu.etaxonomy.cdm.model.common.Extension;
50 import eu.etaxonomy.cdm.model.common.ExtensionType;
51 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
52 import eu.etaxonomy.cdm.model.common.Language;
53 import eu.etaxonomy.cdm.model.common.LanguageString;
54 import eu.etaxonomy.cdm.model.common.Marker;
55 import eu.etaxonomy.cdm.model.common.MarkerType;
56 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
57 import eu.etaxonomy.cdm.model.description.DescriptionBase;
58 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
59 import eu.etaxonomy.cdm.model.description.Distribution;
60 import eu.etaxonomy.cdm.model.description.Feature;
61 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
62 import eu.etaxonomy.cdm.model.description.TaxonInteraction;
63 import eu.etaxonomy.cdm.model.description.TextData;
64 import eu.etaxonomy.cdm.model.location.NamedArea;
65 import eu.etaxonomy.cdm.model.location.TdwgArea;
66 import eu.etaxonomy.cdm.model.name.NonViralName;
67 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
68
69 import eu.etaxonomy.cdm.model.taxon.Taxon;
70 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
71 /**
72 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
73 * Inserts into DataWarehouse database table <code>Note</code>.<p>
74 * It is divided into two phases:<ul>
75 * <li>Phase 1: Export of DescriptionElements as Notes.
76 * <li>Phase 2: Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
77 * @author e.-m.lee
78 * @date 23.02.2010
79 *
80 */
81 @Component
82 public class PesiDescriptionExport extends PesiExportBase {
83 private static final Logger logger = Logger.getLogger(PesiDescriptionExport.class);
84
85 private static final Class<? extends CdmBase> standardMethodParameter = DescriptionElementBase.class;
86
87 private static int modCount = 1000;
88 private static final String dbNoteTableName = "Note";
89 private static final String dbOccurrenceTableName = "Occurrence";
90 private static final String dbVernacularTableName = "CommonName";
91 private static final String dbImageTableName = "Image";
92 private static final String dbAdditionalSourceTableName = "AdditionalTaxonSource";
93 private static final String pluralString = "attached infos";
94 private static final String parentPluralString = "Taxa";
95
96 //debugging
97 private static int countDescriptions;
98 private static int countTaxa;
99 private static int countDistribution;
100 private static int countAdditionalSources;
101 private static int countImages;
102 private static int countNotes;
103
104 private static int countCommonName;
105 private static int countOccurrence;
106 private static int countOthers;
107
108 public PesiDescriptionExport() {
109 super();
110 }
111
112 /* (non-Javadoc)
113 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
114 */
115 @Override
116 public Class<? extends CdmBase> getStandardMethodParameter() {
117 return standardMethodParameter;
118 }
119
120 /* (non-Javadoc)
121 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
122 */
123 @Override
124 protected boolean doCheck(PesiExportState state) {
125 boolean result = true;
126 return result;
127 }
128
129 /* (non-Javadoc)
130 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
131 */
132 @Override
133 protected void doInvoke(PesiExportState state) {
134 try {
135 logger.info("*** Started Making " + pluralString + " ...");
136
137 // Stores whether this invoke was successful or not.
138 boolean success = true;
139
140 // PESI: Clear the database table Note.
141 // doDelete(state);
142
143 // Start transaction
144 success &= doPhase01(state);
145
146
147 logger.info("PHASE 2...");
148 success &= doPhase02(state);
149
150
151 logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
152
153 if (!success){
154 state.setUnsuccessfull();
155 }
156 return;
157 } catch (SQLException e) {
158 e.printStackTrace();
159 logger.error(e.getMessage());
160 state.setUnsuccessfull();
161 }
162 }
163
164 //PHASE 01: Description Elements
165 private boolean doPhase01(PesiExportState state) throws SQLException {
166 logger.info("PHASE 1...");
167 int count = 0;
168 int pastCount = 0;
169 boolean success = true;
170 int limit = state.getConfig().getLimitSave();
171
172 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Note
173 PesiExportMapping notesMapping = getNotesMapping();
174 notesMapping.initialize(state);
175
176 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Occurrence
177 PesiExportMapping occurrenceMapping = getOccurrenceMapping();
178 occurrenceMapping.initialize(state);
179
180 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Additional taxon source
181 PesiExportMapping addittionalSourceMapping = getAdditionalTaxonSourceMapping();
182 addittionalSourceMapping.initialize(state);
183
184 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Additional taxon source
185 PesiExportMapping vernacularMapping = getVernacularNamesMapping();
186 vernacularMapping.initialize(state);
187
188 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Additional taxon source
189 PesiExportMapping imageMapping = getImageMapping();
190 imageMapping.initialize(state);
191
192
193 List<Taxon> list = null;
194
195 TransactionStatus txStatus = startTransaction(true);
196 logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
197 List<String> propPath = Arrays.asList(new String[]{"descriptions.elements.*"});
198
199 logger.debug("Start snapshot, before starting loop");
200 ProfilerController.memorySnapshot();
201 //taxon descriptions
202 int partitionCount = 0;
203 while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, propPath )) != null ) {
204
205 logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
206
207 logger.debug("Start snapshot, beginning of loop, fetched " + list.size() + " " + pluralString);
208 ProfilerController.memorySnapshot();
209
210 for (Taxon taxon : list) {
211 countTaxa++;
212 doCount(count++, modCount, pluralString);
213 success &= handleSingleTaxon(taxon, state, notesMapping, occurrenceMapping, addittionalSourceMapping, vernacularMapping, imageMapping);
214 }
215 list = null;
216 state.setCurrentTaxon(null);
217
218 // Commit transaction
219 commitTransaction(txStatus);
220 logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
221 pastCount = count;
222
223 // Start transaction
224 txStatus = startTransaction(true);
225 logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") for description import ...");
226 logger.debug("Start snapshot, end of loop, fetched " + " " + pluralString);
227 ProfilerController.memorySnapshot();
228 }
229
230 // //name descriptions
231 // while ((list = getNextNameDescriptionPartition( limit, partitionCount++, propPath )) != null ) {
232 //
233 // logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
234 //
235 //
236 // for (Taxon taxon : list) {
237 // countTaxa++;
238 // doCount(count++, modCount, pluralString);
239 // success &= handleSingleTaxon(taxon, state, notesMapping, occurrenceMapping, addittionalSourceMapping, vernacularMapping, imageMapping);
240 // }
241 // state.setCurrentTaxon(null);
242 //
243 // // Commit transaction
244 // commitTransaction(txStatus);
245 // logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
246 // pastCount = count;
247 //
248 // // Start transaction
249 // txStatus = startTransaction(true);
250 // logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") for description import ...");
251 // }
252
253
254
255 if (list == null) {
256 logger.info("No " + pluralString + " left to fetch.");
257 logger.info("Partition: " + partitionCount);
258 logger.info("Taxa: " + countTaxa);
259 logger.info("Desc: " + countDescriptions);
260 logger.info("Distr: " + countDistribution);
261 logger.info("Occur: " + countOccurrence);
262 logger.info("Commons: " + countCommonName);
263 logger.info("AddSrc: " + countAdditionalSources);
264 logger.info("Images: " + countImages);
265 logger.info("Notes: " + countNotes);
266 logger.info("Others: " + countOthers);
267
268 }
269
270 list = null;
271 // Commit transaction
272 commitTransaction(txStatus);
273 logger.debug("Committed transaction.");
274 return success;
275 }
276
277 private boolean handleSingleTaxon(Taxon taxon, PesiExportState state, PesiExportMapping notesMapping, PesiExportMapping occurrenceMapping,
278 PesiExportMapping addittionalSourceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping) throws SQLException {
279 boolean success = true;
280 Set<DescriptionBase<?>> descriptions = new HashSet<DescriptionBase<?>>();
281 descriptions.addAll(taxon.getDescriptions());
282
283 //FIXME incorrect as this creates duplicates
284 descriptions.addAll(taxon.getName().getDescriptions());
285
286 state.setCurrentTaxon(taxon);
287 for (DescriptionBase<?> desc : descriptions){
288 countDescriptions++;
289
290 boolean isImageGallery = desc.isImageGallery();
291 for (DescriptionElementBase element : desc.getElements()){
292 success &= handleDescriptionElement(state, notesMapping, occurrenceMapping, vernacularMapping, imageMapping,
293 isImageGallery, element);
294 }
295 }
296 return success;
297 }
298
299 private boolean handleDescriptionElement(PesiExportState state, PesiExportMapping notesMapping,
300 PesiExportMapping occurrenceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping,
301 boolean isImageGallery, DescriptionElementBase element) throws SQLException {
302 try {
303 boolean success = true;
304 if (isImageGallery){
305 //TODO handle Images
306 countImages++;
307 success &= imageMapping.invoke(element);
308 }else if (isCommonName(element)){
309 countCommonName++;
310 if (element.isInstanceOf(TextData.class)){
311 //
312 }else{
313 success &= vernacularMapping.invoke(element);
314 }
315 }else if (isOccurrence(element)){
316 countOccurrence++;
317 Distribution distribution = CdmBase.deproxy(element, Distribution.class);
318 MarkerType markerType = getUuidMarkerType(PesiTransformer.uuidMarkerTypeHasNoLastAction, state);
319
320 distribution.addMarker(Marker.NewInstance(markerType, true));
321 if (isPesiDistribution(state, distribution)){
322 countDistribution++;
323 success &=occurrenceMapping.invoke(element);
324 }
325 }else if (isAdditionalTaxonSource(element)){
326 countAdditionalSources++;
327 // success &= addittionalSourceMapping.invoke(element);
328 }else if (isPesiNote(element)){
329 countNotes++;
330 success &= notesMapping.invoke(element);
331 }else{
332 countOthers++;
333 String featureTitle = element.getFeature() == null ? "no feature" :element.getFeature().getTitleCache();
334 logger.warn("Description element type not yet handled by PESI export: " + element.getUuid() + ", " + element.getClass() + ", " + featureTitle);
335 }
336 return success;
337 } catch (Exception e) {
338 logger.warn("Exception appeared in description element handling: " + e);
339 e.printStackTrace();
340 return false;
341 }
342 }
343
344 private boolean isPesiDistribution(PesiExportState state, Distribution distribution) {
345 //currently we use the E+M summary status to decide if a distribution should be exported
346 if (distribution.getStatus() == null){
347 return false;
348 }
349
350 //...this may change in future so we keep the following code
351 Integer key;
352 //area filter
353 NamedArea area = distribution.getArea();
354 if (area == null){
355 logger.warn("Area is null for distribution " + distribution.getUuid());
356 return false;
357 }else if (area.getUuid().equals(BerlinModelTransformer.euroMedUuid)){
358 //E+M area only holds endemic status information and therefore is not exported to PESI
359 return false;
360 }else if (area.equals(TdwgArea.getAreaByTdwgAbbreviation("1"))){
361 //Europe area never holds status information (may probably be deleted in E+M)
362 return false;
363 // }else if (area.equals(TdwgArea.getAreaByTdwgAbbreviation("21"))){
364 // //Macaronesia records should not be exported to PESI
365 // return false;
366 // //TODO exclude Russion areas Rs*, and maybe ohters
367
368 } else
369 try {
370 if (state.getTransformer().getKeyByNamedArea(area) == null){
371 logger.warn("Area not available in PESI transformer " + area.getTitleCache() + ", " + area.getRepresentation(Language.ENGLISH()).getAbbreviatedLabel());
372 return false;
373 }
374 } catch (UndefinedTransformerMethodException e1) {
375 logger.warn("Area not available in PESI transformer " + area.getTitleCache());
376 return false;
377 }
378 return true;
379
380 //
381 // //status
382 // PresenceAbsenceTermBase<?> status = distribution.getStatus();
383 // if (status == null){
384 // logger.warn("No status for distribution: " + distribution.getUuid());
385 // return false;
386 // }
387 // try {
388 // key = (Integer)state.getTransformer().getKeyByPresenceAbsenceTerm(status);
389 // if (key != null){
390 // return true;
391 // }else{
392 // logger.warn("PresenceAbsenceTerm " + status.getTitleCache() + "not handled in transformer");
393 // return false;
394 // }
395 // } catch (UndefinedTransformerMethodException e) {
396 // logger.warn("PresenceAbsenceTerm " + status.getTitleCache() + "not handled in transformer");
397 // return false;
398 // }
399 }
400
401 private boolean isPesiNote(DescriptionElementBase element) {
402 return (getNoteCategoryFk(element) != null);
403 }
404
405 private boolean isAdditionalTaxonSource(DescriptionElementBase element) {
406 Feature feature = element.getFeature();
407 if (feature == null){
408 return false;
409 }
410 return (feature.equals(Feature.CITATION()));
411 }
412
413 private boolean isOccurrence(DescriptionElementBase element) {
414 Feature feature = element.getFeature();
415 if (feature == null){
416 return false;
417 }
418 if (feature.equals(Feature.DISTRIBUTION())){
419 return true;
420 }else if (element.isInstanceOf(Distribution.class)){
421 logger.warn("Description element has class 'Distribution' but has no feature 'Distribution'");
422 return true;
423 }else{
424 return false;
425 }
426 }
427
428 private boolean isCommonName(DescriptionElementBase element) {
429 Feature feature = element.getFeature();
430 if (feature == null){
431 return false;
432 }
433 return (feature.equals(Feature.COMMON_NAME()));
434 }
435
436 //PHASE 02: Name extensions
437 private boolean doPhase02(PesiExportState state) {
438 TransactionStatus txStatus;
439 boolean success = true;
440
441 // Get the limit for objects to save within a single transaction.
442 int limit = state.getConfig().getLimitSave();
443
444 txStatus = startTransaction(true);
445 ExtensionType taxCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.taxCommentUuid);
446 ExtensionType fauCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauCommentUuid);
447 ExtensionType fauExtraCodesExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauExtraCodesUuid);
448 List<TaxonNameBase> taxonNameList = null;
449
450 int count = 0;
451 int pastCount = 0;
452 Connection connection = state.getConfig().getDestination().getConnection();
453 logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
454 logger.warn("TODO handle extensions on taxon level, not name level (");
455 while ((taxonNameList = getNameService().list(null, limit, count, null, null)).size() > 0) {
456
457 logger.info("Fetched " + taxonNameList.size() + " names. Exporting...");
458 for (TaxonNameBase<?,?> taxonName : taxonNameList) {
459 Set<Extension> extensions = taxonName.getExtensions();
460 for (Extension extension : extensions) {
461 if (extension.getType().equals(taxCommentExtensionType)) {
462 String taxComment = extension.getValue();
463 invokeNotes(taxComment,
464 PesiTransformer.getNoteCategoryFk(PesiTransformer.taxCommentUuid),
465 PesiTransformer.getNoteCategoryCache(PesiTransformer.taxCommentUuid),
466 null, null, getTaxonKey(taxonName, state),connection);
467 } else if (extension.getType().equals(fauCommentExtensionType)) {
468 String fauComment = extension.getValue();
469 invokeNotes(fauComment,
470 PesiTransformer.getNoteCategoryFk(PesiTransformer.fauCommentUuid),
471 PesiTransformer.getNoteCategoryCache(PesiTransformer.fauCommentUuid),
472 null, null, getTaxonKey(taxonName, state),connection);
473 } else if (extension.getType().equals(fauExtraCodesExtensionType)) {
474 String fauExtraCodes = extension.getValue();
475 invokeNotes(fauExtraCodes,
476 PesiTransformer.getNoteCategoryFk(PesiTransformer.fauExtraCodesUuid),
477 PesiTransformer.getNoteCategoryCache(PesiTransformer.fauExtraCodesUuid),
478 null, null, getTaxonKey(taxonName, state),connection);
479 }
480 }
481
482 doCount(count++, modCount, pluralString);
483 }
484
485 // Commit transaction
486 commitTransaction(txStatus);
487 logger.debug("Committed transaction.");
488 logger.info("Exported " + (count - pastCount) + " names. Total: " + count);
489 pastCount = count;
490
491 // Start transaction
492 txStatus = startTransaction(true);
493 logger.info("Started new transaction. Fetching some names first (max: " + limit + ") ...");
494 }
495 if (taxonNameList.size() == 0) {
496 logger.info("No names left to fetch.");
497 }
498 taxonNameList = null;
499 // Commit transaction
500 commitTransaction(txStatus);
501 logger.debug("Committed transaction.");
502 return success;
503 }
504
505 /**
506 * @param taxComment
507 * @param noteCategoryFk
508 * @param noteCategoryCache
509 * @param object
510 * @param object2
511 */
512 private void invokeNotes(String note, Integer noteCategoryFk,
513 String noteCategoryCache, Integer languageFk, String languageCache,
514 Integer taxonFk, Connection connection) {
515 String notesSql = "UPDATE Note SET Note_1 = ?, NoteCategoryFk = ?, NoteCategoryCache = ?, LanguageFk = ?, LanguageCache = ? WHERE TaxonFk = ?";
516 try {
517 PreparedStatement notesStmt = connection.prepareStatement(notesSql);
518
519 if (note != null) {
520 notesStmt.setString(1, note);
521 } else {
522 notesStmt.setObject(1, null);
523 }
524
525 if (noteCategoryFk != null) {
526 notesStmt.setInt(2, noteCategoryFk);
527 } else {
528 notesStmt.setObject(2, null);
529 }
530
531 if (noteCategoryCache != null) {
532 notesStmt.setString(3, noteCategoryCache);
533 } else {
534 notesStmt.setObject(3, null);
535 }
536
537 if (languageFk != null) {
538 notesStmt.setInt(4, languageFk);
539 } else {
540 notesStmt.setObject(4, null);
541 }
542
543 if (languageCache != null) {
544 notesStmt.setString(5, languageCache);
545 } else {
546 notesStmt.setObject(5, null);
547 }
548
549 if (taxonFk != null) {
550 notesStmt.setInt(6, taxonFk);
551 } else {
552 notesStmt.setObject(6, null);
553 }
554
555 notesStmt.executeUpdate();
556 } catch (SQLException e) {
557 logger.error("Note could not be created: " + note);
558 e.printStackTrace();
559 }
560
561
562 }
563
564 /**
565 * Deletes all entries of database tables related to <code>Note</code>.
566 * @param state The PesiExportState
567 * @return Whether the delete operation was successful or not.
568 */
569 protected boolean doDelete(PesiExportState state) {
570 PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
571
572 String sql;
573 Source destination = pesiConfig.getDestination();
574
575 // Clear NoteSource
576 sql = "DELETE FROM NoteSource";
577 destination.setQuery(sql);
578 destination.update(sql);
579
580 // Clear Note
581 sql = "DELETE FROM " + dbNoteTableName;
582 destination.setQuery(sql);
583 destination.update(sql);
584 return true;
585 }
586
587 /* (non-Javadoc)
588 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
589 */
590 @Override
591 protected boolean isIgnore(PesiExportState state) {
592 return ! state.getConfig().isDoDescription();
593 }
594
595
596 /**
597 * Returns the <code>Note_2</code> attribute.
598 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
599 * @return The <code>Note_2</code> attribute.
600 * @see MethodMapper
601 */
602 @SuppressWarnings("unused")
603 private static String getNote_2(DescriptionElementBase descriptionElement) {
604 logger.warn("Not yet implemented");
605 return null;
606 }
607
608 /**
609 * Returns the <code>NoteCategoryFk</code> attribute.
610 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
611 * @return The <code>NoteCategoryFk</code> attribute.
612 * @see MethodMapper
613 */
614 private static Integer getNoteCategoryFk(DescriptionElementBase descriptionElement) {
615 Integer result = null;
616 result = PesiTransformer.feature2NoteCategoryFk(descriptionElement.getFeature());
617 return result;
618 }
619
620 /**
621 * Returns the <code>NoteCategoryCache</code> attribute.
622 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
623 * @return The <code>NoteCategoryCache</code> attribute.
624 * @see MethodMapper
625 */
626 @SuppressWarnings("unused")
627 private static String getNoteCategoryCache(DescriptionElementBase descriptionElement, PesiExportState state) {
628 return state.getTransformer().getCacheByFeature(descriptionElement.getFeature());
629 }
630
631
632
633
634 /**
635 * Returns the <code>LanguageFk</code> attribute.
636 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
637 * @return The <code>LanguageFk</code> attribute.
638 * @see MethodMapper
639 */
640 @SuppressWarnings("unused")
641 private static Integer getLanguageFk(DescriptionElementBase descriptionElement) {
642 Language language = getLanguage(descriptionElement);
643
644 return PesiTransformer.language2LanguageId(language);
645 }
646
647 /**
648 * Returns the <code>LanguageCache</code> attribute.
649 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
650 * @return The <code>LanguageCache</code> attribute.
651 * @throws UndefinedTransformerMethodException
652 * @see MethodMapper
653 */
654 @SuppressWarnings("unused")
655 private static String getLanguageCache(DescriptionElementBase descriptionElement, PesiExportState state) throws UndefinedTransformerMethodException {
656 Language language = getLanguage(descriptionElement);
657 return state.getTransformer().getCacheByLanguage(language);
658 }
659
660 private static Language getLanguage(DescriptionElementBase descriptionElement) {
661 Language language = null;
662
663 Map<Language, LanguageString> multilanguageText = null;
664 if (descriptionElement.isInstanceOf(CommonTaxonName.class)) {
665 CommonTaxonName commonTaxonName = CdmBase.deproxy(descriptionElement, CommonTaxonName.class);
666 language = commonTaxonName.getLanguage();
667 } else if (descriptionElement.isInstanceOf(TextData.class)) {
668 TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
669 multilanguageText = textData.getMultilanguageText();
670 } else if (descriptionElement.isInstanceOf(IndividualsAssociation.class)) {
671 IndividualsAssociation individualsAssociation = CdmBase.deproxy(descriptionElement, IndividualsAssociation.class);
672 multilanguageText = individualsAssociation.getDescription();
673 } else if (descriptionElement.isInstanceOf(TaxonInteraction.class)) {
674 TaxonInteraction taxonInteraction = CdmBase.deproxy(descriptionElement, TaxonInteraction.class);
675 multilanguageText = taxonInteraction.getDescriptions();
676 } else {
677 logger.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement.getUuid());
678 }
679
680 if (multilanguageText != null) {
681 Set<Language> languages = multilanguageText.keySet();
682
683 // TODO: Think of something more sophisticated than this
684 if (languages.size() > 0) {
685 language = languages.iterator().next();
686 }
687 if (languages.size() > 1){
688 logger.warn("There is more than 1 language for a given description (" + descriptionElement.getClass().getSimpleName() + "):" + descriptionElement.getUuid());
689 }
690 }
691 return language;
692 }
693
694 // /**
695 // * Returns the <code>Region</code> attribute.
696 // * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
697 // * @return The <code>Region</code> attribute.
698 // * @see MethodMapper
699 // */
700 // @SuppressWarnings("unused")
701 // private static String getRegion(DescriptionElementBase descriptionElement) {
702 // String result = null;
703 // DescriptionBase<?> inDescription = descriptionElement.getInDescription();
704 //
705 // // Area information are associated to TaxonDescriptions and Distributions.
706 // if (descriptionElement.isInstanceOf(Distribution.class)) {
707 // Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
708 // result = PesiTransformer.area2AreaCache(distribution.getArea());
709 // } else if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
710 // TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
711 // Set<NamedArea> namedAreas = taxonDescription.getGeoScopes();
712 // if (namedAreas.size() == 1) {
713 // result = PesiTransformer.area2AreaCache(namedAreas.iterator().next());
714 // } else if (namedAreas.size() > 1) {
715 // logger.warn("This TaxonDescription contains more than one NamedArea: " + taxonDescription.getTitleCache());
716 // }
717 // }
718 // return result;
719 // }
720
721
722 /**
723 * Returns the TaxonFk for a given TaxonName or Taxon.
724 * @param state The {@link DbExportStateBase DbExportState}.
725 * @return
726 */
727 @SuppressWarnings("unused") //used by mapper
728 private static Integer getTaxonFk(DescriptionElementBase deb, PesiExportState state) {
729 IdentifiableEntity<?> entity = state.getCurrentTaxon();
730 return state.getDbId(entity);
731 }
732
733 /**
734 * Returns the TaxonFk for a given TaxonName.
735 * @param taxonName The {@link TaxonNameBase TaxonName}.
736 * @param state The {@link DbExportStateBase DbExportState}.
737 * @return
738 */
739 private static Integer getTaxonKey(TaxonNameBase<?,?> taxonName, DbExportStateBase<?, PesiTransformer> state) {
740 return state.getDbId(taxonName);
741 }
742
743 /**
744 * Returns the <code>FullName</code> attribute.
745 * @param taxonName The {@link NonViralName NonViralName}.
746 * @return The <code>FullName</code> attribute.
747 * @see MethodMapper
748 */
749 @SuppressWarnings("unused")
750 private static String getTaxonFullNameCache(DescriptionElementBase deb, PesiExportState state) {
751
752 IdentifiableEntity<?> taxon = state.getCurrentTaxon();
753 TaxonBase<?> taxonDeproxy = CdmBase.deproxy(taxon, TaxonBase.class);
754 TaxonNameBase<?,?> taxonName = taxonDeproxy.getName();
755 taxonDeproxy = null;
756 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
757 String result = getCacheStrategy(nvn).getTitleCache(nvn);
758 nvn = null;
759 return result;
760 }
761
762
763 /**
764 * Returns the CDM to PESI specific export mappings for PESI notes.
765 * @return The {@link PesiExportMapping PesiExportMapping}.
766 */
767 private PesiExportMapping getNotesMapping() {
768 PesiExportMapping mapping = new PesiExportMapping(dbNoteTableName);
769
770 mapping.addMapper(IdMapper.NewInstance("NoteId"));
771 mapping.addMapper(DbTextDataMapper.NewInstance(Language.ENGLISH(), "Note_1"));
772 //TODO
773 mapping.addMapper(DbExportNotYetImplementedMapper.NewInstance("Note_2", "Need to research what Note_2 is for"));
774 mapping.addMapper(MethodMapper.NewInstance("NoteCategoryFk", this, DescriptionElementBase.class ));
775
776 mapping.addMapper(MethodMapper.NewInstance("NoteCategoryCache", this, DescriptionElementBase.class, PesiExportState.class ));
777 mapping.addMapper(MethodMapper.NewInstance("LanguageFk", this));
778 mapping.addMapper(MethodMapper.NewInstance("LanguageCache", this, DescriptionElementBase.class, PesiExportState.class));
779
780 // mapping.addMapper(MethodMapper.NewInstance("Region", this));
781 mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
782 mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
783 mapping.addCollectionMapping(getNoteSourceMapping());
784 return mapping;
785 }
786
787 private CollectionExportMapping<PesiExportState, PesiExportConfigurator,PesiTransformer> getNoteSourceMapping() {
788 String tableName = "NoteSource";
789 String collectionAttribute = "sources";
790 IdMapper parentMapper = IdMapper.NewInstance("NoteFk");
791 CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
792 mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource", "Sources with idInSource currently handle data lineage"));
793 mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
794 mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
795 mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
796 return mapping;
797 }
798
799
800 /**
801 * Returns the CDM to PESI specific export mappings for occurrences.
802 * @return The {@link PesiExportMapping PesiExportMapping}.
803 */
804 private PesiExportMapping getOccurrenceMapping() {
805 PesiExportMapping mapping = new PesiExportMapping(dbOccurrenceTableName);
806
807 mapping.addMapper(IdMapper.NewInstance("OccurrenceId"));
808 mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
809 mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("TaxonFullNameCache", true, true, null));
810
811 mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaFk", ! IS_CACHE));
812 mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaNameCache", IS_CACHE));
813 mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusFk", ! IS_CACHE));
814 mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusCache", IS_CACHE));
815
816 // Use Occurrence source instead
817 mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceFk", "Use OccurrenceSource table for sources instead"));
818 mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceNameCache", "Use OccurrenceSource table for sources instead"));
819
820
821 mapping.addMapper(DbExportNotYetImplementedMapper.NewInstance("Notes", "Needs reimplementation in description export"));
822 mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
823 mapping.addCollectionMapping(getOccurrenceSourceMapping());
824
825 return mapping;
826 }
827
828 private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getOccurrenceSourceMapping() {
829 String tableName = "OccurrenceSource";
830 String collectionAttribute = "sources";
831 IdMapper parentMapper = IdMapper.NewInstance("OccurrenceFk");
832 CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
833 mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource", "Sources with idInSource currently handle data lineage"));
834 mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
835 mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
836 mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
837
838 return mapping;
839 }
840
841 /**
842 * Returns the CDM to PESI specific export mappings for additional taxon sources.
843 * @return The {@link PesiExportMapping PesiExportMapping}.
844 */
845 private PesiExportMapping getAdditionalTaxonSourceMapping() {
846 PesiExportMapping mapping = new PesiExportMapping(dbAdditionalSourceTableName);
847
848 mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this, DescriptionElementBase.class, PesiExportState.class));
849
850
851 mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceFk", of (DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
852 mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceNameCache", of(DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
853
854 // mapping.addMapper(MethodMapper.NewInstance("SourceUseFk", this));
855 // mapping.addMapper(MethodMapper.NewInstance("SourceUseCache", this));
856 // mapping.addMapper(MethodMapper.NewInstance("SourceFk", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
857 // mapping.addMapper(MethodMapper.NewInstance("SourceNameCache", this));
858 // mapping.addMapper(MethodMapper.NewInstance("SourceDetail", this));
859
860 return mapping;
861 }
862
863 /**
864 * Returns the CDM to PESI specific export mappings for common names.
865 * @return The {@link PesiExportMapping PesiExportMapping}.
866 */
867 private PesiExportMapping getVernacularNamesMapping() {
868 PesiExportMapping mapping = new PesiExportMapping(dbVernacularTableName);
869
870 mapping.addMapper(IdMapper.NewInstance("CommonNameId"));
871 mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
872
873 mapping.addMapper(DbStringMapper.NewInstance("Name", "CommonName"));
874 mapping.addMapper(DbAreaMapper.NewInstance(CommonTaxonName.class, "Area", "Region", IS_CACHE));
875
876 mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageFk", ! IS_CACHE));
877 mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageCache", IS_CACHE));
878
879 mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceFk", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
880 mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceNameCache", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , IS_CACHE));
881 mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
882 return mapping;
883
884 }
885
886 private PesiExportMapping getImageMapping() {
887 PesiExportMapping mapping = new PesiExportMapping(dbImageTableName);
888 mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
889
890 //TODO xxx
891
892 return mapping;
893 }
894
895 }