move DbExportMappers to common.mapping.out
[cdmlib-apps.git] / cdm-pesi / src / main / java / eu / etaxonomy / cdm / io / pesi / out / PesiNoteExport.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 java.sql.Connection;
13 import java.sql.PreparedStatement;
14 import java.sql.SQLException;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18
19 import org.apache.log4j.Logger;
20 import org.joda.time.DateTime;
21 import org.springframework.stereotype.Component;
22 import org.springframework.transaction.TransactionStatus;
23
24 import eu.etaxonomy.cdm.io.common.DbExportStateBase;
25 import eu.etaxonomy.cdm.io.common.Source;
26 import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
27 import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
28 import eu.etaxonomy.cdm.model.common.CdmBase;
29 import eu.etaxonomy.cdm.model.common.Extension;
30 import eu.etaxonomy.cdm.model.common.ExtensionType;
31 import eu.etaxonomy.cdm.model.common.Language;
32 import eu.etaxonomy.cdm.model.common.LanguageString;
33 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
34 import eu.etaxonomy.cdm.model.description.DescriptionBase;
35 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
36 import eu.etaxonomy.cdm.model.description.Distribution;
37 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
38 import eu.etaxonomy.cdm.model.description.TaxonDescription;
39 import eu.etaxonomy.cdm.model.description.TaxonInteraction;
40 import eu.etaxonomy.cdm.model.description.TextData;
41 import eu.etaxonomy.cdm.model.location.NamedArea;
42 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
43 import eu.etaxonomy.cdm.model.taxon.Taxon;
44
45 /**
46 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
47 * Inserts into DataWarehouse database table <code>Note</code>.<p>
48 * It is divided into two phases:<ul>
49 * <li>Phase 1: Export of DescriptionElements as Notes.
50 * <li>Phase 2: Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
51 * @author e.-m.lee
52 * @date 23.02.2010
53 *
54 */
55 @Component
56 public class PesiNoteExport extends PesiExportBase {
57 private static final Logger logger = Logger.getLogger(PesiNoteExport.class);
58 private static final Class<? extends CdmBase> standardMethodParameter = DescriptionElementBase.class;
59
60 private static int modCount = 1000;
61 private static final String dbTableName = "Note";
62 private static final String pluralString = "Notes";
63 private static final String parentPluralString = "Taxa";
64
65 public PesiNoteExport() {
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 // Get the limit for objects to save within a single transaction.
95 int limit = state.getConfig().getLimitSave();
96 int pageSize = 1000;
97
98 // Calculate the pageNumber
99 int pageNumber = 1;
100
101 // Stores whether this invoke was successful or not.
102 boolean success = true;
103
104 // PESI: Clear the database table Note.
105 doDelete(state);
106
107 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Note
108 PesiExportMapping mapping = getMapping();
109
110 // Initialize the db mapper
111 mapping.initialize(state);
112
113 // PESI: Create the Notes
114 int count = 0;
115 int pastCount = 0;
116 TransactionStatus txStatus = null;
117 List<DescriptionElementBase> list = null;
118
119 // Start transaction
120 logger.error("PHASE 1...");
121 txStatus = startTransaction(true);
122 logger.error("Started new transaction. Fetching some " + pluralString + " (max: " + pageSize + ") ...");
123 while ((list = getDescriptionService().listDescriptionElements(null, null, null, pageSize, pageNumber, null)).size() > 0) {
124
125 logger.error("Fetched " + list.size() + " " + pluralString + ". Exporting...");
126 for (DescriptionElementBase description : list) {
127
128 if (getNoteCategoryFk(description) != null) {
129 doCount(count++, modCount, pluralString);
130 success &= mapping.invoke(description);
131 }
132 }
133
134 // Commit transaction
135 commitTransaction(txStatus);
136 logger.error("Committed transaction.");
137 logger.error("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
138 pastCount = count;
139
140 // Start transaction
141 txStatus = startTransaction(true);
142 logger.error("Started new transaction. Fetching some " + pluralString + " (max: " + pageSize + ") ...");
143
144 // Increment pageNumber
145 pageNumber++;
146 }
147 if (list.size() == 0) {
148 logger.error("No " + pluralString + " left to fetch.");
149 }
150 // Commit transaction
151 commitTransaction(txStatus);
152 logger.error("Committed transaction.");
153
154
155 logger.error("PHASE 2...");
156 txStatus = startTransaction(true);
157 List<TaxonNameBase> taxonNameList = null;
158 ExtensionType taxCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.taxCommentUuid);
159 ExtensionType fauCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauCommentUuid);
160 ExtensionType fauExtraCodesExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauExtraCodesUuid);
161 String taxComment = null;
162 String fauComment = null;
163 String fauExtraCodes = null;
164
165 Connection connection = state.getConfig().getDestination().getConnection();
166 logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
167 while ((taxonNameList = getNameService().list(null, limit, count, null, null)).size() > 0) {
168
169 logger.error("Fetched " + list.size() + " " + parentPluralString + ". Exporting...");
170 for (TaxonNameBase<?,?> taxonName : taxonNameList) {
171 Set<Extension> extensions = taxonName.getExtensions();
172 for (Extension extension : extensions) {
173 if (extension.getType().equals(taxCommentExtensionType)) {
174 taxComment = extension.getValue();
175 invokeNotes(taxComment,
176 PesiTransformer.getNoteCategoryFk(PesiTransformer.taxCommentUuid),
177 PesiTransformer.getNoteCategoryCache(PesiTransformer.taxCommentUuid),
178 null, null, getTaxonFk(taxonName, state),connection);
179 } else if (extension.getType().equals(fauCommentExtensionType)) {
180 fauComment = extension.getValue();
181 invokeNotes(fauComment,
182 PesiTransformer.getNoteCategoryFk(PesiTransformer.fauCommentUuid),
183 PesiTransformer.getNoteCategoryCache(PesiTransformer.fauCommentUuid),
184 null, null, getTaxonFk(taxonName, state),connection);
185 } else if (extension.getType().equals(fauExtraCodesExtensionType)) {
186 fauExtraCodes = extension.getValue();
187 invokeNotes(fauExtraCodes,
188 PesiTransformer.getNoteCategoryFk(PesiTransformer.fauExtraCodesUuid),
189 PesiTransformer.getNoteCategoryCache(PesiTransformer.fauExtraCodesUuid),
190 null, null, getTaxonFk(taxonName, state),connection);
191 }
192 }
193
194 doCount(count++, modCount, pluralString);
195 }
196
197 // Commit transaction
198 commitTransaction(txStatus);
199 logger.error("Committed transaction.");
200 logger.error("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
201 pastCount = count;
202
203 // Start transaction
204 txStatus = startTransaction(true);
205 logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
206 }
207 if (list.size() == 0) {
208 logger.error("No " + parentPluralString + " left to fetch.");
209 }
210 // Commit transaction
211 commitTransaction(txStatus);
212 logger.error("Committed transaction.");
213
214
215 logger.error("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
216
217 if (!success){
218 state.setUnsuccessfull();
219 }
220 return;
221 } catch (SQLException e) {
222 e.printStackTrace();
223 logger.error(e.getMessage());
224 state.setUnsuccessfull();
225 }
226 }
227
228 /**
229 * @param taxComment
230 * @param noteCategoryFk
231 * @param noteCategoryCache
232 * @param object
233 * @param object2
234 */
235 private void invokeNotes(String note, Integer noteCategoryFk,
236 String noteCategoryCache, Integer languageFk, String languageCache,
237 Integer taxonFk, Connection connection) {
238 String notesSql = "UPDATE Note SET Note_1 = ?, NoteCategoryFk = ?, NoteCategoryCache = ?, LanguageFk = ?, LanguageCache = ? WHERE TaxonFk = ?";
239 try {
240 PreparedStatement notesStmt = connection.prepareStatement(notesSql);
241
242 if (note != null) {
243 notesStmt.setString(1, note);
244 } else {
245 notesStmt.setObject(1, null);
246 }
247
248 if (noteCategoryFk != null) {
249 notesStmt.setInt(2, noteCategoryFk);
250 } else {
251 notesStmt.setObject(2, null);
252 }
253
254 if (noteCategoryCache != null) {
255 notesStmt.setString(3, noteCategoryCache);
256 } else {
257 notesStmt.setObject(3, null);
258 }
259
260 if (languageFk != null) {
261 notesStmt.setInt(4, languageFk);
262 } else {
263 notesStmt.setObject(4, null);
264 }
265
266 if (languageCache != null) {
267 notesStmt.setString(5, languageCache);
268 } else {
269 notesStmt.setObject(5, null);
270 }
271
272 if (taxonFk != null) {
273 notesStmt.setInt(6, taxonFk);
274 } else {
275 notesStmt.setObject(6, null);
276 }
277
278 notesStmt.executeUpdate();
279 } catch (SQLException e) {
280 logger.error("Note could not be created: " + note);
281 e.printStackTrace();
282 }
283
284
285 }
286
287 /**
288 * Deletes all entries of database tables related to <code>Note</code>.
289 * @param state The PesiExportState
290 * @return Whether the delete operation was successful or not.
291 */
292 protected boolean doDelete(PesiExportState state) {
293 PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
294
295 String sql;
296 Source destination = pesiConfig.getDestination();
297
298 // Clear NoteSource
299 sql = "DELETE FROM NoteSource";
300 destination.setQuery(sql);
301 destination.update(sql);
302
303 // Clear Note
304 sql = "DELETE FROM " + dbTableName;
305 destination.setQuery(sql);
306 destination.update(sql);
307 return true;
308 }
309
310 /* (non-Javadoc)
311 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
312 */
313 @Override
314 protected boolean isIgnore(PesiExportState state) {
315 // TODO Auto-generated method stub
316 return false;
317 }
318
319 /**
320 * Returns the <code>Note_1</code> attribute.
321 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
322 * @return The <code>Note_1</code> attribute.
323 * @see MethodMapper
324 */
325 @SuppressWarnings("unused")
326 private static String getNote_1(DescriptionElementBase descriptionElement) {
327 String result = null;
328
329 if (descriptionElement.isInstanceOf(TextData.class)) {
330 TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
331 result = textData.getText(Language.DEFAULT());
332 }
333
334 return result;
335 }
336
337 /**
338 * Returns the <code>Note_2</code> attribute.
339 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
340 * @return The <code>Note_2</code> attribute.
341 * @see MethodMapper
342 */
343 @SuppressWarnings("unused")
344 private static String getNote_2(DescriptionElementBase descriptionElement) {
345 logger.warn("Not yet implemented");
346 return null;
347 }
348
349 /**
350 * Returns the <code>NoteCategoryFk</code> attribute.
351 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
352 * @return The <code>NoteCategoryFk</code> attribute.
353 * @see MethodMapper
354 */
355 private static Integer getNoteCategoryFk(DescriptionElementBase descriptionElement) {
356 Integer result = null;
357
358 result = PesiTransformer.textData2NodeCategoryFk(descriptionElement.getFeature());
359
360 return result;
361 }
362
363 /**
364 * Returns the <code>NoteCategoryCache</code> attribute.
365 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
366 * @return The <code>NoteCategoryCache</code> attribute.
367 * @see MethodMapper
368 */
369 @SuppressWarnings("unused")
370 private static String getNoteCategoryCache(DescriptionElementBase descriptionElement) {
371 String result = null;
372
373 if (descriptionElement.isInstanceOf(TextData.class)) {
374 result = PesiTransformer.textData2NodeCategoryCache(descriptionElement.getFeature());
375 }
376
377 return result;
378 }
379
380 /**
381 * Returns the <code>LanguageFk</code> attribute.
382 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
383 * @return The <code>LanguageFk</code> attribute.
384 * @see MethodMapper
385 */
386 @SuppressWarnings("unused")
387 private static Integer getLanguageFk(DescriptionElementBase descriptionElement) {
388 Language language = getLanguage(descriptionElement);
389
390 return PesiTransformer.language2LanguageId(language);
391 }
392
393 /**
394 * Returns the <code>LanguageCache</code> attribute.
395 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
396 * @return The <code>LanguageCache</code> attribute.
397 * @see MethodMapper
398 */
399 @SuppressWarnings("unused")
400 private static String getLanguageCache(DescriptionElementBase descriptionElement) {
401 Language language = getLanguage(descriptionElement);
402
403 return PesiTransformer.language2LanguageCache(language);
404 }
405
406 private static Language getLanguage(DescriptionElementBase descriptionElement) {
407 Language language = null;
408
409 Map<Language, LanguageString> multilanguageText = null;
410 if (descriptionElement.isInstanceOf(CommonTaxonName.class)) {
411 CommonTaxonName commonTaxonName = CdmBase.deproxy(descriptionElement, CommonTaxonName.class);
412 language = commonTaxonName.getLanguage();
413 } else if (descriptionElement.isInstanceOf(TextData.class)) {
414 TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
415 multilanguageText = textData.getMultilanguageText();
416 } else if (descriptionElement.isInstanceOf(IndividualsAssociation.class)) {
417 IndividualsAssociation individualsAssociation = CdmBase.deproxy(descriptionElement, IndividualsAssociation.class);
418 multilanguageText = individualsAssociation.getDescription();
419 } else if (descriptionElement.isInstanceOf(TaxonInteraction.class)) {
420 TaxonInteraction taxonInteraction = CdmBase.deproxy(descriptionElement, TaxonInteraction.class);
421 multilanguageText = taxonInteraction.getDescriptions();
422 } else {
423 logger.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement.getUuid());
424 }
425
426 if (multilanguageText != null) {
427 Set<Language> languages = multilanguageText.keySet();
428
429 // TODO: Think of something more sophisticated than this
430 if (languages.size() > 0) {
431 language = languages.iterator().next();
432 }
433 if (languages.size() > 1){
434 logger.warn("There is more than 1 language for a given description (" + descriptionElement.getClass().getSimpleName() + "):" + descriptionElement.getUuid());
435 }
436 }
437 return language;
438 }
439
440 /**
441 * Returns the <code>Region</code> attribute.
442 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
443 * @return The <code>Region</code> attribute.
444 * @see MethodMapper
445 */
446 @SuppressWarnings("unused")
447 private static String getRegion(DescriptionElementBase descriptionElement) {
448 String result = null;
449 DescriptionBase<?> inDescription = descriptionElement.getInDescription();
450
451 // Area information are associated to TaxonDescriptions and Distributions.
452 if (descriptionElement.isInstanceOf(Distribution.class)) {
453 Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
454 result = PesiTransformer.area2AreaCache(distribution.getArea());
455 } else if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
456 TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
457 Set<NamedArea> namedAreas = taxonDescription.getGeoScopes();
458 if (namedAreas.size() == 1) {
459 result = PesiTransformer.area2AreaCache(namedAreas.iterator().next());
460 } else if (namedAreas.size() > 1) {
461 logger.warn("This TaxonDescription contains more than one NamedArea: " + taxonDescription.getTitleCache());
462 }
463 }
464 return result;
465 }
466
467 /**
468 * Returns the <code>TaxonFk</code> attribute.
469 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
470 * @param state The {@link PesiExportState PesiExportState}.
471 * @return The <code>TaxonFk</code> attribute.
472 * @see MethodMapper
473 */
474 @SuppressWarnings("unused")
475 private static Integer getTaxonFk(DescriptionElementBase descriptionElement, DbExportStateBase<?> state) {
476 Integer result = null;
477 DescriptionBase<?> inDescription = descriptionElement.getInDescription();
478 if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
479 TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
480 Taxon taxon = taxonDescription.getTaxon();
481 result = state.getDbId(taxon.getName());
482 }
483 return result;
484 }
485
486 /**
487 * Returns the TaxonFk for a given TaxonName.
488 * @param taxonName The {@link TaxonNameBase TaxonName}.
489 * @param state The {@link DbExportStateBase DbExportState}.
490 * @return
491 */
492 private static Integer getTaxonFk(TaxonNameBase<?,?> taxonName, DbExportStateBase<?> state) {
493 return state.getDbId(taxonName);
494 }
495
496 /**
497 * Returns the <code>LastAction</code> attribute.
498 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
499 * @return The <code>LastAction</code> attribute.
500 * @see MethodMapper
501 */
502 @SuppressWarnings("unused")
503 private static String getLastAction(DescriptionElementBase descriptionElement) {
504 // TODO
505 return null;
506 }
507
508 /**
509 * Returns the <code>LastActionDate</code> attribute.
510 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
511 * @return The <code>LastActionDate</code> attribute.
512 * @see MethodMapper
513 */
514 @SuppressWarnings("unused")
515 private static DateTime getLastActionDate(DescriptionElementBase descriptionElement) {
516 DateTime result = null;
517 return result;
518 }
519
520 /**
521 * Returns the CDM to PESI specific export mappings.
522 * @return The {@link PesiExportMapping PesiExportMapping}.
523 */
524 private PesiExportMapping getMapping() {
525 PesiExportMapping mapping = new PesiExportMapping(dbTableName);
526
527 mapping.addMapper(IdMapper.NewInstance("NoteId"));
528 mapping.addMapper(MethodMapper.NewInstance("Note_1", this));
529 mapping.addMapper(MethodMapper.NewInstance("Note_2", this));
530 mapping.addMapper(MethodMapper.NewInstance("NoteCategoryFk", this));
531 mapping.addMapper(MethodMapper.NewInstance("NoteCategoryCache", this));
532 mapping.addMapper(MethodMapper.NewInstance("LanguageFk", this));
533 mapping.addMapper(MethodMapper.NewInstance("LanguageCache", this));
534 mapping.addMapper(MethodMapper.NewInstance("Region", this));
535 mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this.getClass(), "getTaxonFk", standardMethodParameter, DbExportStateBase.class));
536 mapping.addMapper(MethodMapper.NewInstance("LastAction", this));
537 mapping.addMapper(MethodMapper.NewInstance("LastActionDate", this));
538
539 return mapping;
540 }
541
542 }