Project

General

Profile

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

    
10
package eu.etaxonomy.cdm.io.pesi.erms;
11

    
12
import java.sql.ResultSet;
13
import java.sql.SQLException;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import org.apache.commons.lang3.StringUtils;
21
import org.apache.log4j.Logger;
22
import org.springframework.stereotype.Component;
23

    
24
import eu.etaxonomy.cdm.io.common.IOValidator;
25
import eu.etaxonomy.cdm.io.common.mapping.DbIgnoreMapper;
26
import eu.etaxonomy.cdm.io.common.mapping.DbImportExtensionMapper;
27
import eu.etaxonomy.cdm.io.common.mapping.DbImportLsidMapper;
28
import eu.etaxonomy.cdm.io.common.mapping.DbImportMapping;
29
import eu.etaxonomy.cdm.io.common.mapping.DbImportMarkerMapper;
30
import eu.etaxonomy.cdm.io.common.mapping.DbImportObjectCreationMapper;
31
import eu.etaxonomy.cdm.io.common.mapping.DbImportStringMapper;
32
import eu.etaxonomy.cdm.io.common.mapping.DbNotYetImplementedMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
34
import eu.etaxonomy.cdm.io.pesi.erms.validation.ErmsTaxonImportValidator;
35
import eu.etaxonomy.cdm.io.pesi.out.PesiTaxonExport;
36
import eu.etaxonomy.cdm.model.common.CdmBase;
37
import eu.etaxonomy.cdm.model.common.ExtensionType;
38
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
39
import eu.etaxonomy.cdm.model.name.Rank;
40
import eu.etaxonomy.cdm.model.name.TaxonName;
41
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
42
import eu.etaxonomy.cdm.model.reference.Reference;
43
import eu.etaxonomy.cdm.model.taxon.Synonym;
44
import eu.etaxonomy.cdm.model.taxon.Taxon;
45
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
46
import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
47

    
48
/**
49
 * @author a.mueller
50
 * @since 20.02.2010
51
 */
52
@Component
53
public class ErmsTaxonImport
54
        extends ErmsImportBase<TaxonBase<?>>
55
        implements IMappingImport<TaxonBase<?>, ErmsImportState>{
56

    
57
    private static final long serialVersionUID = -7111568277264140051L;
58
    private static final Logger logger = Logger.getLogger(ErmsTaxonImport.class);
59

    
60
	public static final UUID TNS_EXT_UUID = UUID.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
61

    
62
	private DbImportMapping<ErmsImportState, ErmsImportConfigurator> mapping;
63

    
64
	private static final String pluralString = "taxa";
65
	private static final String dbTableName = "tu";
66
	private static final Class<?> cdmTargetClass = TaxonBase.class;
67

    
68
	public ErmsTaxonImport(){
69
		super(pluralString, dbTableName, cdmTargetClass);
70
	}
71

    
72
//	@Override
73
//	protected String getIdQuery() {
74
//		String strQuery = " SELECT id FROM tu WHERE id < 300000 " ;
75
//		return strQuery;
76
//	}
77

    
78

    
79
	@Override
80
    protected DbImportMapping<ErmsImportState, ErmsImportConfigurator> getMapping() {
81
		if (mapping == null){
82
			mapping = new DbImportMapping<>();
83

    
84
			mapping.addMapper(DbImportObjectCreationMapper.NewInstance(this, "id", TAXON_NAMESPACE)); //id + tu_status
85
			UUID tsnUuid = ErmsTransformer.uuidTsn;
86
			mapping.addMapper(DbImportLsidMapper.NewInstance("GUID", "lsid"));
87

    
88
			ExtensionType tsnExtType = getExtensionType(tsnUuid, "TSN", "TSN", "TSN");
89
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tsn", tsnExtType));
90
//			mapping.addMapper(DbImportStringMapper.NewInstance("tu_name", "(NonViralName)name.nameCache"));
91

    
92
			ExtensionType displayNameExtType = getExtensionType(ErmsTransformer.uuidDisplayName, "display name", "display name", "display name");
93
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_displayname", displayNameExtType));
94
			ExtensionType fuzzyNameExtType = getExtensionType(ErmsTransformer.uuidFuzzyName, "fuzzy name", "fuzzy name", "fuzzy name");
95
		//	mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_fuzzyname", fuzzyNameExtType));
96
			mapping.addMapper(DbImportStringMapper.NewInstance("tu_authority", "name.authorshipCache"));
97

    
98
			ExtensionType fossilStatusExtType = getExtensionType(ErmsTransformer.uuidFossilStatus, "fossil status", "fossil status", "fos. stat.");
99
			mapping.addMapper(DbImportExtensionMapper.NewInstance("fossil_name", fossilStatusExtType));
100
//			mapping.addMapper(DbImportExtensionTypeCreationMapper.NewInstance("fossil_name", EXTENSION_TYPE_NAMESPACE, "fossil_name", "fossil_name", "fossil_name"));
101

    
102
			ExtensionType unacceptExtType = getExtensionType(ErmsTransformer.uuidUnacceptReason, "unaccept reason", "unaccept reason", "reason");
103
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_unacceptreason", unacceptExtType));
104

    
105
			ExtensionType qualityStatusExtType = getExtensionType(ErmsTransformer.uuidQualityStatus, "quality status", "quality status", "quality status");
106
			mapping.addMapper(DbImportExtensionMapper.NewInstance("qualitystatus_name", qualityStatusExtType)); //checked by Tax Editor ERMS1.1, Added by db management team (2x), checked by Tax Editor
107

    
108
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_marine", ErmsTransformer.uuidMarkerMarine, "marine", "marine", "marine", null));
109
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_brackish", ErmsTransformer.uuidMarkerBrackish, "brackish", "brackish", "brackish", null));
110
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_fresh", ErmsTransformer.uuidMarkerFreshwater, "freshwater", "fresh", "fresh", null));
111
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_terrestrial", ErmsTransformer.uuidMarkerTerrestrial, "terrestrial", "terrestrial", "terrestrial", null));
112

    
113
//			UUID hiddenUuid = ErmsTransformer.uuidHidden;
114
//			mapping.addMapper(DbImportMarkerCreationMapper.Mapper.NewInstance("qualitystatus_name", qualityUuid, "quality status", "quality status", "quality status")); //checked by Tax Editor ERMS1.1, Added by db management team (2x), checked by Tax Editor
115

    
116
			//not yet implemented
117
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_sp", "included in rank/object creation"));
118
			mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "Needs check if this is needed in PESI"));
119

    
120
			//ignore
121
			mapping.addMapper(DbIgnoreMapper.NewInstance("tu_fossil", "tu_fossil implemented as foreign key"));
122

    
123
		}
124
		return mapping;
125
	}
126

    
127
	@Override
128
	protected String getRecordQuery(ErmsImportConfigurator config) {
129
		String strSelect = " SELECT tu.*, parent1.tu_name AS parent1name, parent2.tu_name AS parent2name, parent3.tu_name AS parent3name, "
130
			+ " parent1.tu_rank AS parent1rank, parent2.tu_rank AS parent2rank, parent3.tu_rank AS parent3rank, " +
131
			" status.status_id as status_id, status.status_name, fossil.fossil_name, qualitystatus.qualitystatus_name";
132
		String strFrom = " FROM tu  LEFT OUTER JOIN  tu AS parent1 ON parent1.id = tu.tu_parent " +
133
				" LEFT OUTER JOIN   tu AS parent2  ON parent2.id = parent1.tu_parent " +
134
				" LEFT OUTER JOIN tu AS parent3 ON parent2.tu_parent = parent3.id " +
135
				" LEFT OUTER JOIN status ON tu.tu_status = status.status_id " +
136
				" LEFT OUTER JOIN fossil ON tu.tu_fossil = fossil.fossil_id " +
137
				" LEFT OUTER JOIN qualitystatus ON tu.tu_qualitystatus = qualitystatus.id ";
138
		String strWhere = " WHERE ( tu.id IN (" + ID_LIST_TOKEN + ") )";
139
		String strRecordQuery = strSelect + strFrom + strWhere;
140
		return strRecordQuery;
141
	}
142

    
143
	@Override
144
	protected void doInvoke(ErmsImportState state) {
145
		state.setAcceptedTaxaKeys(getAcceptedTaxaKeys(state));
146

    
147
		//first path
148
		super.doInvoke(state);
149
		return;
150
	}
151

    
152
	private Set<Integer> getAcceptedTaxaKeys(ErmsImportState state) {
153
		Set<Integer> result = new HashSet<>();
154
		String parentCol = "tu_parent";
155
		String accCol = " tu_acctaxon";
156
		String idCol = " id ";
157
		String tuFk = "tu_id";
158
		String taxonTable = "tu";
159
		String vernacularsTable = "vernaculars";
160
		String distributionTable = "dr";
161
		String sql =
162
		        " SELECT DISTINCT %s FROM %s  "  //fk to parent
163
		        + " UNION  SELECT %s FROM %s WHERE %s is NULL" //id of taxa not having accepted taxon
164
		        + " UNION  SELECT DISTINCT %s FROM %s "  //fk to accepted taxon
165
		        + " UNION  SELECT DISTINCT %s FROM %s " //vernaculars
166
		        + " UNION  SELECT DISTINCT %s FROM %s ";  //distributions
167
		sql = String.format(sql,
168
				parentCol, taxonTable,
169
				idCol, taxonTable, accCol,
170
				accCol, taxonTable,
171
				tuFk, vernacularsTable,
172
				tuFk, distributionTable);
173
		ResultSet rs = state.getConfig().getSource().getResultSet(sql);
174
		try {
175
			while (rs.next()){
176
				Integer id;
177
				id = rs.getInt(parentCol);
178
				result.add(id);
179
			}
180
			return result;
181
		} catch (SQLException e) {
182
			e.printStackTrace();
183
			throw new RuntimeException(e);
184
		}
185
	}
186

    
187
	@Override
188
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, ErmsImportState state) {
189
//		String nameSpace;
190
//		Class<?> cdmClass;
191
//		Set<String> idSet;
192
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<>();
193

    
194
		try{
195
//				Set<String> referenceIdSet = new HashSet<>();
196
				while (rs.next()){
197
	//				handleForeignKey(rs, referenceIdSet, "PTRefFk");
198
				}
199

    
200
			//reference map
201
//			nameSpace = "Reference";
202
//			cdmClass = Reference.class;
203
//			Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
204
//			result.put(Reference.class, referenceMap);
205

    
206
		} catch (SQLException e) {
207
			throw new RuntimeException(e);
208
		}
209
		return result;
210
	}
211

    
212
	@Override
213
	public TaxonBase<?> createObject(ResultSet rs, ErmsImportState state) throws SQLException {
214
		int statusId = rs.getInt("status_id");
215
//		Object accTaxonId = rs.getObject("tu_acctaxon");
216
		Integer meId = rs.getInt("id");
217

    
218
		String tuName = rs.getString("tu_name");
219
		String displayName = rs.getString("tu_displayname");
220

    
221
		String parent1Name = rs.getString("parent1name");
222
		Integer parent1Rank = rs.getInt("parent1rank");
223

    
224
		String parent2Name = rs.getString("parent2name");
225
		Integer parent2Rank = rs.getInt("parent2rank");
226

    
227
		String parent3Name = rs.getString("parent3name");
228
//		Integer parent3Rank = rs.getInt("parent3rank");
229

    
230
		TaxonName taxonName = getTaxonName(rs, state);
231
		//set epithets
232
		if (taxonName.isGenus() || taxonName.isSupraGeneric()){
233
			taxonName.setGenusOrUninomial(tuName);
234
		}else if (taxonName.isInfraGeneric()){
235
			taxonName.setInfraGenericEpithet(tuName);
236
			taxonName.setGenusOrUninomial(parent1Name);
237
		}else if (taxonName.isSpecies()){
238
			taxonName.setSpecificEpithet(tuName);
239
			getGenusAndInfraGenus(parent1Name, parent2Name, parent1Rank, taxonName);
240
		}else if (taxonName.isInfraSpecific()){
241
			if (parent1Rank < 220){
242
				handleException(parent1Rank, taxonName, displayName, meId);
243
			}
244
			taxonName.setInfraSpecificEpithet(tuName);
245
			taxonName.setSpecificEpithet(parent1Name);
246
			getGenusAndInfraGenus(parent2Name, parent3Name, parent2Rank, taxonName);
247
		}else if (taxonName.getRank()== null){
248
			logger.warn("rank super domain still needs to be implemented. Used domain instead.");
249
			if ("Biota".equalsIgnoreCase(tuName)){
250
				Rank rank = Rank.DOMAIN();  //should be Superdomain
251
				taxonName.setRank(rank);
252
				taxonName.setGenusOrUninomial(tuName);
253
			}else{
254
				String warning = "TaxonName has no rank. Use namecache.";
255
				logger.warn(warning);
256
				taxonName.setNameCache(tuName);
257
			}
258

    
259
		}
260
		//e.g. Leucon [Platyhelminthes] ornatus
261
		if (containsBrackets(displayName)){
262
			taxonName.setNameCache(displayName);
263
			logger.warn("Set name cache: " +  displayName + ";id =" + meId);
264
		}
265

    
266
		//add original source for taxon name (taxon original source is added in mapper
267
		Reference citation = state.getTransactionalSourceReference();
268
		addOriginalSource(rs, taxonName, "id", NAME_NAMESPACE, citation);
269

    
270
		//old: if (statusId == 1){
271
		if (state.getAcceptedTaxaKeys().contains(meId)){
272
			Taxon result = Taxon.NewInstance(taxonName, citation);
273
			if (statusId != 1){
274
				logger.info("Taxon created as taxon but has status <> 1 ("+statusId+"): " + meId);
275
				handleNotAcceptedTaxon(result, statusId, state, rs);
276
			}
277
			return result;
278
		}else{
279
			return Synonym.NewInstance(taxonName, citation);
280
		}
281
	}
282

    
283
	private void handleNotAcceptedTaxon(Taxon taxon, int statusId, ErmsImportState state, ResultSet rs) throws SQLException {
284
		ExtensionType notAccExtensionType = getExtensionType(state, ErmsTransformer.uuidErmsTaxonStatus, "ERMS taxon status", "ERMS taxon status", "status", null);
285
		String statusName = rs.getString("status_name");
286

    
287
		if (statusId > 1){
288
			taxon.addExtension(statusName, notAccExtensionType);
289
		}
290
	}
291

    
292
	/**
293
	 * @param parent1Rank
294
	 * @param displayName
295
	 * @param taxonName
296
	 * @param meId
297
	 */
298
	private void handleException(Integer parent1Rank, TaxonName taxonName, String displayName, Integer meId) {
299
		logger.warn("Parent of infra specific taxon is higher than species. Used nameCache: " + displayName +  "; id=" + meId) ;
300
		taxonName.setNameCache(displayName);
301
	}
302

    
303
	/**
304
	 * @param displayName
305
	 * @return
306
	 */
307
	private boolean containsBrackets(String displayName) {
308
		int index = displayName.indexOf("[");
309
		return (index > -1);
310
	}
311

    
312
	/**
313
	 * @param parent1Name
314
	 * @param parent2Name
315
	 * @param parent1Rank
316
	 * @param taxonName
317
	 */
318
	private void getGenusAndInfraGenus(String parentName, String grandParentName, Integer parent1Rank, TaxonName taxonName) {
319
		if (parent1Rank <220 && parent1Rank > 180){
320
			//parent is infrageneric
321
			taxonName.setInfraGenericEpithet(parentName);
322
			taxonName.setGenusOrUninomial(grandParentName);
323
		}else{
324
			taxonName.setGenusOrUninomial(parentName);
325
		}
326
	}
327

    
328
	/**
329
	 * Returns an empty Taxon Name instance according to the given rank and kingdom.
330
	 * @param rs
331
	 * @return
332
	 * @throws SQLException
333
	 */
334
	private TaxonName getTaxonName(ResultSet rs, ErmsImportState state) throws SQLException {
335
	    TaxonName result;
336
		Integer kingdomId = parseKingdomId(rs);
337
		Integer intRank = rs.getInt("tu_rank");
338

    
339
		NomenclaturalCode nc = ErmsTransformer.kingdomId2NomCode(kingdomId);
340
		Rank rank = null;
341
		if (kingdomId != null){
342
			rank = state.getRank(intRank, kingdomId);
343
		}else{
344
			logger.warn("KingdomId is null");
345
		}
346
		if (rank == null){
347
			logger.warn("Rank is null. KingdomId: " + kingdomId + ", rankId: " +  intRank);
348
		}
349
		if (nc != null){
350
			result = nc.getNewTaxonNameInstance(rank);
351
		}else{
352
			result = TaxonNameFactory.NewNonViralInstance(rank);
353
		}
354
		//cache strategy
355
		if (result.isZoological()){
356
		    TaxonNameDefaultCacheStrategy cacheStrategy = PesiTaxonExport.zooNameStrategy;
357
			result.setCacheStrategy(cacheStrategy);
358
		}
359

    
360
		return result;
361
	}
362

    
363
	/**
364
	 * Returns the kingdom id by extracting it from the second character in the <code>tu_sp</code>
365
	 * attribute. If the attribute can not be parsed to a valid id <code>null</code>
366
	 * is returned. If the attribute is <code>null</code> the id of the record is returned.
367
	 * @param rs
368
	 * @return
369
	 * @throws SQLException
370
	 */
371
	private int parseKingdomId(ResultSet rs) throws SQLException {
372
		Integer result = null;
373
		String treeString = rs.getString("tu_sp");
374
		if (treeString != null){
375
			if (StringUtils.isNotBlank(treeString) && treeString.length() > 1){
376
				String strKingdom = treeString.substring(1,2);
377

    
378
				if (! treeString.substring(0, 1).equals("#") && ! treeString.substring(2, 3).equals("#") ){
379
					logger.warn("Tree string " + treeString + " has no recognized format");
380
				}else{
381
					try {
382
						result = Integer.valueOf(strKingdom);
383
					} catch (NumberFormatException e) {
384
						logger.warn("Kingdom string " + strKingdom + "could not be recognized as a valid number");
385
					}
386
				}
387
			}
388
		}else{
389
			Integer tu_id = rs.getInt("id");
390
			result = tu_id;
391
		}
392
		return result;
393
	}
394

    
395
	@Override
396
	protected boolean doCheck(ErmsImportState state){
397
		IOValidator<ErmsImportState> validator = new ErmsTaxonImportValidator();
398
		return validator.validate(state);
399
	}
400

    
401
	@Override
402
    protected boolean isIgnore(ErmsImportState state){
403
		return ! state.getConfig().isDoTaxa();
404
	}
405
}
(13-13/17)