3 * Copyright (C) 2009 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.io
.pesi
.out
;
12 import java
.sql
.Connection
;
13 import java
.sql
.PreparedStatement
;
14 import java
.sql
.SQLException
;
15 import java
.util
.List
;
19 import org
.apache
.log4j
.Logger
;
20 import org
.joda
.time
.DateTime
;
21 import org
.springframework
.stereotype
.Component
;
22 import org
.springframework
.transaction
.TransactionStatus
;
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
;
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>
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;
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";
65 public PesiNoteExport() {
70 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
73 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
74 return standardMethodParameter
;
78 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
81 protected boolean doCheck(PesiExportState state
) {
82 boolean result
= true;
87 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
90 protected void doInvoke(PesiExportState state
) {
92 logger
.error("*** Started Making " + pluralString
+ " ...");
94 // Get the limit for objects to save within a single transaction.
95 int limit
= state
.getConfig().getLimitSave();
98 // Calculate the pageNumber
101 // Stores whether this invoke was successful or not.
102 boolean success
= true;
104 // PESI: Clear the database table Note.
107 // Get specific mappings: (CDM) DescriptionElement -> (PESI) Note
108 PesiExportMapping mapping
= getMapping();
110 // Initialize the db mapper
111 mapping
.initialize(state
);
113 // PESI: Create the Notes
116 TransactionStatus txStatus
= null;
117 List
<DescriptionElementBase
> list
= null;
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) {
125 logger
.error("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
126 for (DescriptionElementBase description
: list
) {
128 if (getNoteCategoryFk(description
) != null) {
129 doCount(count
++, modCount
, pluralString
);
130 success
&= mapping
.invoke(description
);
134 // Commit transaction
135 commitTransaction(txStatus
);
136 logger
.error("Committed transaction.");
137 logger
.error("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
141 txStatus
= startTransaction(true);
142 logger
.error("Started new transaction. Fetching some " + pluralString
+ " (max: " + pageSize
+ ") ...");
144 // Increment pageNumber
147 if (list
.size() == 0) {
148 logger
.error("No " + pluralString
+ " left to fetch.");
150 // Commit transaction
151 commitTransaction(txStatus
);
152 logger
.error("Committed transaction.");
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;
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) {
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
);
194 doCount(count
++, modCount
, pluralString
);
197 // Commit transaction
198 commitTransaction(txStatus
);
199 logger
.error("Committed transaction.");
200 logger
.error("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
204 txStatus
= startTransaction(true);
205 logger
.error("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
207 if (list
.size() == 0) {
208 logger
.error("No " + parentPluralString
+ " left to fetch.");
210 // Commit transaction
211 commitTransaction(txStatus
);
212 logger
.error("Committed transaction.");
215 logger
.error("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
218 state
.setUnsuccessfull();
221 } catch (SQLException e
) {
223 logger
.error(e
.getMessage());
224 state
.setUnsuccessfull();
230 * @param noteCategoryFk
231 * @param noteCategoryCache
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 = ?";
240 PreparedStatement notesStmt
= connection
.prepareStatement(notesSql
);
243 notesStmt
.setString(1, note
);
245 notesStmt
.setObject(1, null);
248 if (noteCategoryFk
!= null) {
249 notesStmt
.setInt(2, noteCategoryFk
);
251 notesStmt
.setObject(2, null);
254 if (noteCategoryCache
!= null) {
255 notesStmt
.setString(3, noteCategoryCache
);
257 notesStmt
.setObject(3, null);
260 if (languageFk
!= null) {
261 notesStmt
.setInt(4, languageFk
);
263 notesStmt
.setObject(4, null);
266 if (languageCache
!= null) {
267 notesStmt
.setString(5, languageCache
);
269 notesStmt
.setObject(5, null);
272 if (taxonFk
!= null) {
273 notesStmt
.setInt(6, taxonFk
);
275 notesStmt
.setObject(6, null);
278 notesStmt
.executeUpdate();
279 } catch (SQLException e
) {
280 logger
.error("Note could not be created: " + note
);
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.
292 protected boolean doDelete(PesiExportState state
) {
293 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
296 Source destination
= pesiConfig
.getDestination();
299 sql
= "DELETE FROM NoteSource";
300 destination
.setQuery(sql
);
301 destination
.update(sql
);
304 sql
= "DELETE FROM " + dbTableName
;
305 destination
.setQuery(sql
);
306 destination
.update(sql
);
311 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
314 protected boolean isIgnore(PesiExportState state
) {
315 // TODO Auto-generated method stub
320 * Returns the <code>Note_1</code> attribute.
321 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
322 * @return The <code>Note_1</code> attribute.
325 @SuppressWarnings("unused")
326 private static String
getNote_1(DescriptionElementBase descriptionElement
) {
327 String result
= null;
329 if (descriptionElement
.isInstanceOf(TextData
.class)) {
330 TextData textData
= CdmBase
.deproxy(descriptionElement
, TextData
.class);
331 result
= textData
.getText(Language
.DEFAULT());
338 * Returns the <code>Note_2</code> attribute.
339 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
340 * @return The <code>Note_2</code> attribute.
343 @SuppressWarnings("unused")
344 private static String
getNote_2(DescriptionElementBase descriptionElement
) {
345 logger
.warn("Not yet implemented");
350 * Returns the <code>NoteCategoryFk</code> attribute.
351 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
352 * @return The <code>NoteCategoryFk</code> attribute.
355 private static Integer
getNoteCategoryFk(DescriptionElementBase descriptionElement
) {
356 Integer result
= null;
358 result
= PesiTransformer
.textData2NodeCategoryFk(descriptionElement
.getFeature());
364 * Returns the <code>NoteCategoryCache</code> attribute.
365 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
366 * @return The <code>NoteCategoryCache</code> attribute.
369 @SuppressWarnings("unused")
370 private static String
getNoteCategoryCache(DescriptionElementBase descriptionElement
) {
371 String result
= null;
373 if (descriptionElement
.isInstanceOf(TextData
.class)) {
374 result
= PesiTransformer
.textData2NodeCategoryCache(descriptionElement
.getFeature());
381 * Returns the <code>LanguageFk</code> attribute.
382 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
383 * @return The <code>LanguageFk</code> attribute.
386 @SuppressWarnings("unused")
387 private static Integer
getLanguageFk(DescriptionElementBase descriptionElement
) {
388 Language language
= getLanguage(descriptionElement
);
390 return PesiTransformer
.language2LanguageId(language
);
394 * Returns the <code>LanguageCache</code> attribute.
395 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
396 * @return The <code>LanguageCache</code> attribute.
399 @SuppressWarnings("unused")
400 private static String
getLanguageCache(DescriptionElementBase descriptionElement
) {
401 Language language
= getLanguage(descriptionElement
);
403 return PesiTransformer
.language2LanguageCache(language
);
406 private static Language
getLanguage(DescriptionElementBase descriptionElement
) {
407 Language language
= null;
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();
423 logger
.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement
.getUuid());
426 if (multilanguageText
!= null) {
427 Set
<Language
> languages
= multilanguageText
.keySet();
429 // TODO: Think of something more sophisticated than this
430 if (languages
.size() > 0) {
431 language
= languages
.iterator().next();
433 if (languages
.size() > 1){
434 logger
.warn("There is more than 1 language for a given description (" + descriptionElement
.getClass().getSimpleName() + "):" + descriptionElement
.getUuid());
441 * Returns the <code>Region</code> attribute.
442 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
443 * @return The <code>Region</code> attribute.
446 @SuppressWarnings("unused")
447 private static String
getRegion(DescriptionElementBase descriptionElement
) {
448 String result
= null;
449 DescriptionBase
<?
> inDescription
= descriptionElement
.getInDescription();
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());
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.
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());
487 * Returns the TaxonFk for a given TaxonName.
488 * @param taxonName The {@link TaxonNameBase TaxonName}.
489 * @param state The {@link DbExportStateBase DbExportState}.
492 private static Integer
getTaxonFk(TaxonNameBase
<?
,?
> taxonName
, DbExportStateBase
<?
> state
) {
493 return state
.getDbId(taxonName
);
497 * Returns the <code>LastAction</code> attribute.
498 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
499 * @return The <code>LastAction</code> attribute.
502 @SuppressWarnings("unused")
503 private static String
getLastAction(DescriptionElementBase descriptionElement
) {
509 * Returns the <code>LastActionDate</code> attribute.
510 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
511 * @return The <code>LastActionDate</code> attribute.
514 @SuppressWarnings("unused")
515 private static DateTime
getLastActionDate(DescriptionElementBase descriptionElement
) {
516 DateTime result
= null;
521 * Returns the CDM to PESI specific export mappings.
522 * @return The {@link PesiExportMapping PesiExportMapping}.
524 private PesiExportMapping
getMapping() {
525 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
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));