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
.ResultSet
;
15 import java
.sql
.SQLException
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
20 import org
.apache
.log4j
.Logger
;
21 import org
.springframework
.stereotype
.Component
;
22 import org
.springframework
.transaction
.TransactionStatus
;
24 import eu
.etaxonomy
.cdm
.io
.common
.IExportConfigurator
.DO_REFERENCES
;
25 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
26 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.MethodMapper
;
27 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
28 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
29 import eu
.etaxonomy
.cdm
.model
.common
.DescriptionElementSource
;
30 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
31 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
32 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
33 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
34 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
37 * The export class for additional information linked to {@link eu.etaxonomy.cdm.model.description.Distribution Distributions} and {@link eu.etaxonomy.cdm.model.common.DescriptionElementSource DescriptionElements}.<p>
38 * Inserts into DataWarehouse database table <code>OccurrenceSource</code>.
44 @SuppressWarnings("unchecked")
45 public class PesiOccurrenceSourceExport
extends PesiExportBase
{
46 private static final Logger logger
= Logger
.getLogger(PesiOccurrenceSourceExport
.class);
47 private static final Class
<?
extends CdmBase
> standardMethodParameter
= AnnotatableEntity
.class;
49 private static int modCount
= 1000;
50 private static final String dbTableName
= "OccurrenceSource";
51 private static final String pluralString
= "OccurrenceSources";
52 private static final String parentPluralString
= "Taxa";
53 private static Taxon taxon
= null;
55 public PesiOccurrenceSourceExport() {
60 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
63 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
64 return standardMethodParameter
;
68 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
71 protected boolean doCheck(PesiExportState state
) {
72 boolean result
= true;
77 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
80 protected void doInvoke(PesiExportState state
) {
82 logger
.error("*** Started Making " + pluralString
+ " ...");
84 String occurrenceSql
= "Insert into OccurrenceSource (OccurrenceFk, SourceFk, SourceNameCache, OldTaxonName) " +
85 "values (?, ?, ?, ?)";
86 Connection con
= state
.getConfig().getDestination().getConnection();
87 PreparedStatement stmt
= con
.prepareStatement(occurrenceSql
);
89 // Get the limit for objects to save within a single transaction.
90 int limit
= state
.getConfig().getLimitSave();
92 // Stores whether this invoke was successful or not.
93 boolean success
= true;
95 // PESI: Clear the database table OccurrenceSource.
98 // Get specific mappings: (CDM) ? -> (PESI) OccurrenceSource
99 PesiExportMapping mapping
= getMapping();
101 // Initialize the db mapper
102 mapping
.initialize(state
);
104 // PESI: Create the OccurrenceSource
108 TransactionStatus txStatus
= null;
109 List
<TaxonBase
> list
= null;
112 txStatus
= startTransaction(true);
113 logger
.error("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
114 while ((list
= getTaxonService().list(null, limit
, taxonCount
, null, null)).size() > 0) {
116 logger
.error("Fetched " + list
.size() + " " + parentPluralString
+ ".");
117 taxonCount
+= list
.size();
118 for (TaxonBase taxonBase
: list
) {
119 if (taxonBase
.isInstanceOf(Taxon
.class)) {
121 // Set the current Taxon
122 taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
124 // Determine the TaxonDescriptions
125 Set
<TaxonDescription
> taxonDescriptions
= taxon
.getDescriptions();
127 // Determine the DescriptionElements (Citations) for the current Taxon
128 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
129 Set
<DescriptionElementBase
> descriptionElements
= taxonDescription
.getElements();
130 for (DescriptionElementBase descriptionElement
: descriptionElements
) {
131 Set
<DescriptionElementSource
> elementSources
= descriptionElement
.getSources();
133 // Focus on descriptionElements with sources.
134 if (elementSources
.size() > 0) {
135 for (DescriptionElementSource elementSource
: elementSources
) {
136 Reference reference
= elementSource
.getCitation();
138 // Citations can be empty (null): Is it wrong data or just a normal case?
139 if (reference
!= null) {
142 Integer sourceFk
= getSourceFk(reference
, state
);
144 if (sourceFk
!= null && ! state
.alreadyProcessedSource(sourceFk
)) {
145 doCount(count
++, modCount
, pluralString
);
147 // Add to processed sourceFk's since sourceFk's can be scanned more than once.
148 state
.addToProcessedSources(sourceFk
);
150 // Query the database for all entries in table 'Occurrence' with the sourceFk just determined.
151 Set
<Integer
> occurrenceIds
= getOccurrenceIds(sourceFk
, state
);
153 // Insert as many entries in database table 'OccurrenceSource' as occurrenceId's were determined.
154 insertColumns(stmt
, reference
, sourceFk
, occurrenceIds
);
166 state
.clearAlreadyProcessedSources();
168 // Commit transaction
169 commitTransaction(txStatus
);
170 logger
.error("Committed transaction.");
171 logger
.error("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
175 txStatus
= startTransaction(true);
176 logger
.error("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
178 if (list
.size() == 0) {
179 logger
.error("No " + pluralString
+ " left to fetch.");
181 // Commit transaction
182 commitTransaction(txStatus
);
183 logger
.error("Committed transaction.");
185 logger
.error("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
187 state
.setUnsuccessfull();
190 } catch (SQLException e
) {
192 logger
.error(e
.getMessage());
193 state
.setUnsuccessfull();
199 * Inserts columns in the database table OccurrenceSource.
200 * @param stmt The prepared statement.
201 * @param reference {@link Reference Reference}.
202 * @param sourceFk The SourceFk.
203 * @param occurrenceIds A {@link java.util.Set Set} of OccurrenceId's.
205 private void insertColumns(PreparedStatement stmt
, Reference reference
,
206 Integer sourceFk
, Set
<Integer
> occurrenceIds
) {
207 for (Integer occurrenceId
: occurrenceIds
) {
209 stmt
.setInt(1, occurrenceId
);
210 stmt
.setInt(2, sourceFk
);
211 stmt
.setString(3, getSourceNameCache(reference
));
212 stmt
.setString(4, null); // TODO: This is the name of the former taxon (accepted taxon as well as synonym) the source was associated to. How can we get a hand on it?
214 } catch (SQLException e
) {
215 logger
.error("SQLException during getOccurrenceId invoke.");
222 * Returns a Set of OccurrenceId's associated to a given SourceFk.
223 * @param state The {@link PesiExportState PesiExportState}.
224 * @return Existing OccurrenceId's for a given SourceFk.
226 private static Set
<Integer
> getOccurrenceIds(Integer sourceFk
, PesiExportState state
) {
227 String occurrenceSql
= "Select OccurrenceId From Occurrence where SourceFk = ?";
228 Connection con
= state
.getConfig().getDestination().getConnection();
229 PreparedStatement stmt
= null;
230 Set
<Integer
> occurrenceIds
= new HashSet();
233 stmt
= con
.prepareStatement(occurrenceSql
);
234 stmt
.setInt(1, sourceFk
);
235 ResultSet resultSet
= stmt
.executeQuery();
236 while (resultSet
.next()) {
237 occurrenceIds
.add(resultSet
.getInt(1));
239 } catch (SQLException e
) {
240 logger
.error("SQLException during getOccurrenceId invoke. (2)");
244 return occurrenceIds
;
248 * Deletes all entries of database tables related to <code>OccurrenceSource</code>.
249 * @param state The {@link PesiExportState PesiExportState}.
250 * @return Whether the delete operation was successful or not.
252 protected boolean doDelete(PesiExportState state
) {
253 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
256 Source destination
= pesiConfig
.getDestination();
258 // Clear OccurrenceSource
259 sql
= "DELETE FROM " + dbTableName
;
260 destination
.setQuery(sql
);
261 destination
.update(sql
);
266 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
269 protected boolean isIgnore(PesiExportState state
) {
270 return ! ( state
.getConfig().isDoOccurrenceSource() && state
.getConfig().isDoOccurrence() && state
.getConfig().getDoReferences().equals(DO_REFERENCES
.ALL
));
274 * Returns the <code>OccurrenceFk</code> attribute.
275 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
276 * @param state The {@link PesiExportState PesiExportState}.
277 * @return The <code>OccurrenceFk</code> attribute.
280 @SuppressWarnings("unused")
281 private static Integer
getOccurrenceFk(AnnotatableEntity entity
, PesiExportState state
) {
282 Integer result
= null;
287 * Returns the <code>SourceFk</code> attribute.
288 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
289 * @param state The {@link PesiExportState PesiExportState}.
290 * @return The <code>SourceFk</code> attribute.
293 private static Integer
getSourceFk(AnnotatableEntity entity
, PesiExportState state
) {
294 Integer result
= null;
295 if (state
!= null && entity
!= null && entity
.isInstanceOf(Reference
.class)) {
296 Reference reference
= CdmBase
.deproxy(entity
, Reference
.class);
297 result
= state
.getDbId(reference
);
303 * Returns the <code>SourceNameCache</code> attribute.
304 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
305 * @return The <code>SourceNameCache</code> attribute.
308 private static String
getSourceNameCache(AnnotatableEntity entity
) {
309 String result
= null;
310 if (entity
!= null && entity
.isInstanceOf(Reference
.class)) {
311 Reference reference
= CdmBase
.deproxy(entity
, Reference
.class);
312 result
= reference
.getTitle();
318 * Returns the <code>OldTaxonName</code> attribute.
319 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
320 * @return The <code>OldTaxonName</code> attribute.
323 @SuppressWarnings("unused")
324 private static String
getOldTaxonName(AnnotatableEntity entity
) {
325 // TODO: This is the name of the former taxon (accepted taxon as well as synonym) the source was associated to.
330 * Returns the CDM to PESI specific export mappings.
331 * @return The {@link PesiExportMapping PesiExportMapping}.
333 private PesiExportMapping
getMapping() {
334 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
336 // These mapping are not used.
337 mapping
.addMapper(MethodMapper
.NewInstance("OccurrenceFk", this.getClass(), "getOccurrenceFk", standardMethodParameter
, PesiExportState
.class));
338 mapping
.addMapper(MethodMapper
.NewInstance("SourceFk", this.getClass(), "getSourceFk", standardMethodParameter
, PesiExportState
.class));
339 mapping
.addMapper(MethodMapper
.NewInstance("SourceNameCache", this));
340 mapping
.addMapper(MethodMapper
.NewInstance("OldTaxonName", this));