Project

General

Profile

Download (23.4 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.common.CdmUtils;
25
import eu.etaxonomy.cdm.io.common.DbImportStateBase;
26
import eu.etaxonomy.cdm.io.common.IOValidator;
27
import eu.etaxonomy.cdm.io.common.mapping.DbIgnoreMapper;
28
import eu.etaxonomy.cdm.io.common.mapping.DbImportAnnotationMapper;
29
import eu.etaxonomy.cdm.io.common.mapping.DbImportExtensionMapper;
30
import eu.etaxonomy.cdm.io.common.mapping.DbImportLsidMapper;
31
import eu.etaxonomy.cdm.io.common.mapping.DbImportMapping;
32
import eu.etaxonomy.cdm.io.common.mapping.DbImportMarkerMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.DbImportMethodMapper;
34
import eu.etaxonomy.cdm.io.common.mapping.DbImportObjectCreationMapper;
35
import eu.etaxonomy.cdm.io.common.mapping.DbImportStringMapper;
36
import eu.etaxonomy.cdm.io.common.mapping.DbNotYetImplementedMapper;
37
import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
38
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
39
import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
40
import eu.etaxonomy.cdm.io.pesi.erms.validation.ErmsTaxonImportValidator;
41
import eu.etaxonomy.cdm.io.pesi.out.PesiTaxonExport;
42
import eu.etaxonomy.cdm.io.pesi.out.PesiTransformer;
43
import eu.etaxonomy.cdm.model.common.AnnotationType;
44
import eu.etaxonomy.cdm.model.common.CdmBase;
45
import eu.etaxonomy.cdm.model.common.ExtensionType;
46
import eu.etaxonomy.cdm.model.common.Language;
47
import eu.etaxonomy.cdm.model.common.MarkerType;
48
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
49
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
50
import eu.etaxonomy.cdm.model.name.Rank;
51
import eu.etaxonomy.cdm.model.name.TaxonName;
52
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
53
import eu.etaxonomy.cdm.model.reference.Reference;
54
import eu.etaxonomy.cdm.model.taxon.Synonym;
55
import eu.etaxonomy.cdm.model.taxon.Taxon;
56
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
57
import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
58

    
59
/**
60
 * @author a.mueller
61
 * @since 20.02.2010
62
 */
63
@Component
64
public class ErmsTaxonImport
65
        extends ErmsImportBase<TaxonBase<?>>
66
        implements IMappingImport<TaxonBase<?>, ErmsImportState>{
67

    
68
    private static final long serialVersionUID = -7111568277264140051L;
69
    private static final Logger logger = Logger.getLogger(ErmsTaxonImport.class);
70

    
71
	private DbImportMapping<ErmsImportState, ErmsImportConfigurator> mapping;
72

    
73
	private static final String pluralString = "taxa";
74
	private static final String dbTableName = "tu";
75
	private static final Class<?> cdmTargetClass = TaxonBase.class;
76

    
77
	public ErmsTaxonImport(){
78
		super(pluralString, dbTableName, cdmTargetClass);
79
	}
80

    
81
	@Override
82
	protected String getIdQuery() {
83
		String strQuery = " SELECT id FROM tu " ;  //WHERE id NOT IN (147415) for now we exclude Monera as it has no children and is unclear what classification it has. In ERMS it is alternative accepted name (in https://en.wikipedia.org/wiki/Monera it might be a super taxon to bacteria).
84
		return strQuery;
85
	}
86

    
87
	@Override
88
    protected DbImportMapping<ErmsImportState, ErmsImportConfigurator> getMapping() {
89
		if (mapping == null){
90
			mapping = new DbImportMapping<>();
91

    
92
			mapping.addMapper(DbImportObjectCreationMapper.NewInstance(this, "id", TAXON_NAMESPACE)); //id + tu_status
93
			mapping.addMapper(DbImportLsidMapper.NewInstance("GUID", "lsid"));
94

    
95
			UUID tsnUuid = ErmsTransformer.uuidExtTsn;
96
			ExtensionType tsnExtType = getExtensionType(tsnUuid, "TSN", "TSN", "TSN");
97
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tsn", tsnExtType));
98
//			mapping.addMapper(DbImportStringMapper.NewInstance("tu_name", "(NonViralName)name.nameCache"));
99

    
100
			ExtensionType displayNameExtType = getExtensionType(ErmsTransformer.uuidExtDisplayName, "display name", "display name", "display name");
101
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_displayname", displayNameExtType));
102
            //Ignore fuzzyName
103
            //  ExtensionType fuzzyNameExtType = getExtensionType(ErmsTransformer.uuidExtFuzzyName, "fuzzy name", "fuzzy name", "fuzzy name");
104
            //  mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_fuzzyname", fuzzyNameExtType));
105
			mapping.addMapper(DbImportStringMapper.NewInstance("tu_authority", "name.authorshipCache"));
106

    
107
			ExtensionType fossilStatusExtType = getExtensionType(ErmsTransformer.uuidExtFossilStatus, "fossil status", "fossil status", "fos. stat.");
108
			mapping.addMapper(DbImportExtensionMapper.NewInstance("fossil_name", fossilStatusExtType));
109

    
110
			ExtensionType unacceptExtType = getExtensionType(ErmsTransformer.uuidExtUnacceptReason, "unaccept reason", "unaccept reason", "reason");
111
			mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_unacceptreason", unacceptExtType));
112

    
113
			ExtensionType qualityStatusExtType = getExtensionType(ErmsTransformer.uuidExtQualityStatus, "quality status", "quality status", "quality status");
114
			mapping.addMapper(DbImportExtensionMapper.NewInstance("qualitystatus_name", qualityStatusExtType)); //checked by Tax Editor ERMS1.1, Added by db management team (2x), checked by Tax Editor
115

    
116
			ExtensionType cacheCitationExtType = getExtensionType(PesiTransformer.uuidExtCacheCitation, "cache_citation", "quality status", "cache_citation");
117
            mapping.addMapper(DbImportExtensionMapper.NewInstance("cache_citation", cacheCitationExtType));
118

    
119
            //flags
120
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_marine", ErmsTransformer.uuidMarkerMarine, "marine", "marine", "marine", null));
121
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_brackish", ErmsTransformer.uuidMarkerBrackish, "brackish", "brackish", "brackish", null));
122
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_fresh", ErmsTransformer.uuidMarkerFreshwater, "freshwater", "fresh", "fresh", null));
123
			mapping.addMapper(DbImportMarkerMapper.NewInstance("tu_terrestrial", ErmsTransformer.uuidMarkerTerrestrial, "terrestrial", "terrestrial", "terrestrial", null));
124

    
125
			//last action, species expert
126
			ExtensionType speciesExpertNameExtType = getExtensionType(PesiTransformer.uuidExtSpeciesExpertName, "species expert name", "species expert name", "species expert name");
127
            mapping.addMapper(DbImportExtensionMapper.NewInstance("ExpertName", speciesExpertNameExtType)); //according to sql script ExpertName maps to SpeciesExpertName in ERMS
128
            AnnotationType lastActionDateType = getAnnotationType(DbLastActionMapper.uuidAnnotationTypeLastActionDate, "Last action date", "Last action date", null);
129
			mapping.addMapper(DbImportAnnotationMapper.NewInstance("lastActionDate", lastActionDateType));
130
            AnnotationType lastActionType = getAnnotationType(DbLastActionMapper.uuidAnnotationTypeLastAction, "Last action", "Last action", null);
131
            MarkerType hasNoLastActionMarkerType = getMarkerType(DbLastActionMapper.uuidMarkerTypeHasNoLastAction, "has no last action", "No last action information available", "no last action");
132
            mapping.addMapper(DbImportAnnotationMapper.NewInstance("lastAction", lastActionType, hasNoLastActionMarkerType));
133

    
134
            //titleCache compare
135
            mapping.addMapper(DbImportMethodMapper.NewDefaultInstance(this, "testTitleCache", ErmsImportState.class));
136

    
137
			//not yet implemented
138
			mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_sp", "included in rank/object creation"));
139

    
140
			//ignore
141
			mapping.addMapper(DbIgnoreMapper.NewInstance("tu_fossil", "tu_fossil implemented as foreign key"));
142

    
143
		}
144
		return mapping;
145
	}
146

    
147
	@Override
148
	protected String getRecordQuery(ErmsImportConfigurator config) {
149
		String strSelect = " SELECT tu.*, parent1.tu_name AS parent1name, parent2.tu_name AS parent2name, parent3.tu_name AS parent3name, parent4.tu_name AS parent4name, " +
150
		            " parent1.tu_rank AS parent1rank, parent2.tu_rank AS parent2rank, parent3.tu_rank AS parent3rank, " +
151
		            " status.status_id as status_id, status.status_name, fossil.fossil_name, qualitystatus.qualitystatus_name," +
152
		            " s.sessiondate lastActionDate, a.action_name lastAction, s.ExpertName ";
153
		String strFrom = " FROM tu  LEFT OUTER JOIN  tu AS parent1 ON parent1.id = tu.tu_parent " +
154
				" LEFT OUTER JOIN   tu AS parent2  ON parent2.id = parent1.tu_parent " +
155
				" LEFT OUTER JOIN tu AS parent3 ON parent2.tu_parent = parent3.id " +
156
				" LEFT OUTER JOIN tu AS parent4 ON parent3.tu_parent = parent4.id " +
157
                " LEFT OUTER JOIN status ON tu.tu_status = status.status_id " +
158
				" LEFT OUTER JOIN fossil ON tu.tu_fossil = fossil.fossil_id " +
159
				" LEFT OUTER JOIN qualitystatus ON tu.tu_qualitystatus = qualitystatus.id " +
160
				" LEFT OUTER JOIN tu_sessions ts ON ts.tu_id = tu.id " +
161
                " LEFT OUTER JOIN [sessions] s ON s.id = ts.session_id " +
162
                " LEFT OUTER JOIN actions a ON a.id = ts.action_id ";
163
		String strWhere = " WHERE ( tu.id IN (" + ID_LIST_TOKEN + ") )";
164
		String strOrderBy = " ORDER BY tu.id, s.sessiondate DESC, a.id DESC ";
165
		String strRecordQuery = strSelect + strFrom + strWhere + strOrderBy;
166
		return strRecordQuery;
167
	}
168

    
169
	@Override
170
	protected void doInvoke(ErmsImportState state) {
171
		state.setAcceptedTaxaKeys(getAcceptedTaxaKeys(state));
172

    
173
		//first path
174
		super.doInvoke(state);
175
		return;
176
	}
177

    
178
	Integer lastTaxonId = null;
179
    @Override
180
    protected boolean ignoreRecord(ResultSet rs) throws SQLException {
181
        Integer id = rs.getInt("id");
182
        boolean result = id.equals(lastTaxonId);
183
        lastTaxonId = id;
184
        return result;
185
    }
186

    
187
	private Set<Integer> getAcceptedTaxaKeys(ErmsImportState state) {
188
		Set<Integer> result = new HashSet<>();
189
		String idCol = " id ";
190
		String tuFk = "tu_id";
191
		String vernacularsTable = "vernaculars";
192
		String distributionTable = "dr";
193
		String notesTable = "notes";
194
		String sql =
195
                "          SELECT id FROM tu WHERE tu_accfinal is NULL" //id of taxa not having accepted taxon
196
                + " UNION  SELECT DISTINCT tu_accfinal FROM tu "  //fk to accepted taxon (either the accepted taxon or the taxon itself, if accepted)
197
                + " UNION  SELECT id FROM tu WHERE trim(tu.tu_unacceptreason) like 'misidentification' OR trim(tu.tu_unacceptreason) like 'misidentifications' OR "
198
                            + " tu.tu_unacceptreason like 'misapplied %%name' OR "
199
                            + " tu.tu_unacceptreason like '%%misapplication%%' OR "
200
                            + " tu.tu_unacceptreason like 'incorrect identification%%'" //Misapplications, see ErmsTransformer.getSynonymRelationTypesByKey
201
                + " UNION  SELECT syn.id FROM tu syn INNER JOIN tu acc ON syn.tu_accfinal = acc.id WHERE syn.id = acc.tu_parent AND acc.id <> syn.id "  //see also ErmsTaxonRelationImport.isAccepted, there are some autonyms being the accepted taxon of there own parents
202
                + " UNION  SELECT DISTINCT %s FROM %s " //vernaculars
203
                + " UNION  SELECT DISTINCT %s FROM %s "  //distributions
204
                + " UNION  SELECT DISTINCT %s FROM %s ";  //notes
205
		sql = String.format(sql,
206
		        tuFk, vernacularsTable,
207
				tuFk, distributionTable,
208
				tuFk, notesTable);
209
		ResultSet rs = state.getConfig().getSource().getResultSet(sql);
210
		try {
211
			while (rs.next()){
212
				Integer id;
213
				id = rs.getInt(idCol.trim());
214
				result.add(id);
215
			}
216
			return result;
217
		} catch (SQLException e) {
218
			e.printStackTrace();
219
			throw new RuntimeException(e);
220
		}
221
	}
222

    
223
	@Override
224
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, ErmsImportState state) {
225
		//currently no referencing objects needed
226
	    Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<>();
227
		return result;
228
	}
229

    
230
	@Override
231
	public TaxonBase<?> createObject(ResultSet rs, ErmsImportState state) throws SQLException {
232
		int statusId = rs.getInt("status_id");
233
//		Object accTaxonId = rs.getObject("tu_accfinal");
234
		Integer meId = rs.getInt("id");
235

    
236
        TaxonName taxonName = getTaxonName(rs, state);
237
		fillTaxonName(taxonName, rs, state, meId);
238

    
239
		//add original source for taxon name (taxon original source is added in mapper)
240
		Reference citation = state.getTransactionalSourceReference();
241
		addOriginalSource(rs, taxonName, "id", NAME_NAMESPACE, citation);
242

    
243
		TaxonBase<?> result;
244
		//handle accepted<-> synonym, we create more accepted taxa as we need them within the tree or to attache factual data
245
		if (state.getAcceptedTaxaKeys().contains(meId)){
246
			Taxon taxon = Taxon.NewInstance(taxonName, citation);
247
			if (statusId != 1){
248
				logger.info("Taxon created as taxon but has status <> 1 ("+statusId+"): " + meId);
249
				handleNotAcceptedTaxon(taxon, statusId, state, rs);
250
			}
251
			result = taxon;
252
		}else{
253
			result = Synonym.NewInstance(taxonName, citation);
254
		}
255

    
256
		handleNameStatus(result.getName(), rs, state);
257
		return result;
258
	}
259

    
260
    private void handleNameStatus(TaxonName name, ResultSet rs, ErmsImportState state) throws SQLException {
261
        NomenclaturalStatusType nomStatus = null;
262
        int tuStatus = rs.getInt("tu_status");
263
        //the order is bottom up from SQL script as there values are overriden from top to bottom
264
        if (tuStatus == 8){
265
            //species inquirenda
266
            nomStatus = getNomenclaturalStatusType(state, ErmsTransformer.uuidNomStatusSpeciesInquirenda, "species inquirenda", "species inquirenda", null, Language.LATIN(), null);
267
        }else if (tuStatus == 7){
268
            //temporary name
269
            nomStatus = getNomenclaturalStatusType(state, PesiTransformer.uuidNomStatusTemporaryName, "temporary name", "temporary name", null, Language.ENGLISH(), null);
270
        }else if (tuStatus == 6){
271
            //nomen dubium
272
            nomStatus = NomenclaturalStatusType.DOUBTFUL();
273
        }else if (tuStatus == 5){
274
            //"alternate representation"
275
            nomStatus = getNomenclaturalStatusType(state, ErmsTransformer.uuidNomStatusAlternateRepresentation, "alternate representation", "alternate representation", null, Language.ENGLISH(), null);
276
        }else if (tuStatus == 3){
277
            //nomen nudum
278
            nomStatus = NomenclaturalStatusType.NUDUM();
279
        }
280
        if (nomStatus == null){
281
            //IN SQL Script it is set first by unacceptreason and then overriden if above tu_status exists
282
            String unacceptReason = rs.getString("tu_unacceptreason");
283
            try {
284
                nomStatus = state.getTransformer().getNomenclaturalStatusByKey(unacceptReason);
285
            } catch (UndefinedTransformerMethodException e) {logger.warn("Unhandled method");
286
            }
287
        }
288
        if (nomStatus != null){
289
            name.addStatus(nomStatus, null, null);
290
        }
291
    }
292

    
293
    private TaxonName fillTaxonName(TaxonName taxonName, ResultSet rs, ErmsImportState state, Integer meId) throws SQLException {
294
        String tuName = rs.getString("tu_name");
295
		String displayName = rs.getString("tu_displayname").trim();
296

    
297
		String parent1Name = rs.getString("parent1name");
298
		Integer parent1Rank = rs.getInt("parent1rank");
299

    
300
		String parent2Name = rs.getString("parent2name");
301
		Integer parent2Rank = rs.getInt("parent2rank");
302

    
303
		String parent3Name = rs.getString("parent3name");
304
		Integer parent3Rank = rs.getInt("parent3rank");
305

    
306
	    String parent4Name = rs.getString("parent4name");
307

    
308
		//set epithets
309
		if (taxonName.isGenus() || taxonName.isSupraGeneric()){
310
			taxonName.setGenusOrUninomial(tuName);
311
		}else if (taxonName.isInfraGeneric()){
312
			taxonName.setInfraGenericEpithet(tuName);
313
			taxonName.setGenusOrUninomial(parent1Name);
314
		}else if (taxonName.isSpecies()){
315
			taxonName.setSpecificEpithet(tuName);
316
			getGenusAndInfraGenus(parent1Name, parent2Name, parent1Rank, taxonName);
317
		}else if (taxonName.isInfraSpecific()){
318
			if (parent1Rank < 220){
319
				handleException(parent1Rank, taxonName, displayName, meId);
320
			}
321
			taxonName.setInfraSpecificEpithet(tuName);
322
			if (parent1Rank > 220){  //parent is still infraspecific
323
			    taxonName.setSpecificEpithet(parent2Name);
324
			    getGenusAndInfraGenus(parent3Name, parent4Name, parent3Rank, taxonName);
325
			}else{
326
			    //default
327
			    taxonName.setSpecificEpithet(parent1Name);
328
			    getGenusAndInfraGenus(parent2Name, parent3Name, parent2Rank, taxonName);
329
			}
330
		}else if (taxonName.getRank()== null){
331
			if ("Biota".equalsIgnoreCase(tuName)){
332
				Rank rank = Rank.DOMAIN();  //should be Superdomain
333
				taxonName.setRank(rank);
334
				taxonName.setGenusOrUninomial(tuName);
335
			}else{
336
				String warning = "TaxonName has no rank. Use namecache.";
337
				logger.warn(warning);
338
				taxonName.setNameCache(tuName);
339
			}
340
		}
341

    
342
		//e.g. Leucon [Platyhelminthes] ornatus
343
		if (containsBrackets(displayName)){
344
			taxonName.setNameCache(displayName);
345
			logger.warn("Set name cache: " +  displayName + "; id =" + meId);
346
		}
347
        if (!taxonName.getNameCache().equals(displayName)){
348
            int pos = CdmUtils.diffIndex(taxonName.getNameCache(), displayName);
349
            logger.warn("Computed name cache differs at "+pos+".\n Computed   : " + taxonName.getNameCache()+"\n DisplayName: " +displayName);
350
            taxonName.setNameCache(displayName, true);
351
        }
352
		taxonName.getTitleCache();
353
        return taxonName;
354
    }
355

    
356
    @SuppressWarnings("unused")  //used by MethodMapper
357
    private static TaxonBase<?> testTitleCache(ResultSet rs, ErmsImportState state) throws SQLException{
358
        TaxonBase<?> taxon = (TaxonBase<?>)state.getRelatedObject(DbImportStateBase.CURRENT_OBJECT_NAMESPACE, DbImportStateBase.CURRENT_OBJECT_ID);
359
        TaxonName taxonName = taxon.getName();
360
         String displayName = rs.getString("tu_displayname");
361
         displayName = displayName == null ? null : displayName.trim();
362
         String titleCache = taxonName.resetTitleCache(); //calling titleCache should always be kept to have a computed titleCache in the CDM DB.
363
         String expectedTitleCache = getExpectedTitleCache(rs);
364
         //TODO check titleCache, but beware of autonyms
365
         if (!titleCache.equals(expectedTitleCache)){
366
             int pos = CdmUtils.diffIndex(titleCache, expectedTitleCache);
367
             logger.warn("Computed title cache differs at "+pos+".\n Computed             : " + titleCache + "\n DisplayName+Authority: " + expectedTitleCache);
368
             taxonName.setNameCache(displayName, true);
369
         }
370
         return taxon;
371
     }
372

    
373
     //see also PesiErmsValidation.srcFullName()
374
     private static String getExpectedTitleCache(ResultSet srcRs) throws SQLException {
375
        String result;
376
        String epi = srcRs.getString("tu_name");
377
        epi = " a" + epi;
378
        String display = srcRs.getString("tu_displayname");
379
        String sp = srcRs.getString("tu_sp");
380
        if (display.indexOf(epi) != display.lastIndexOf(epi) && !sp.startsWith("#2#")){ //homonym, animal
381
            result = srcRs.getString("tu_displayname").replaceFirst(epi+" ", CdmUtils.concat(" ", " "+epi, srcRs.getString("tu_authority")))+" ";
382
        }else{
383
            result = CdmUtils.concat(" ", srcRs.getString("tu_displayname"), srcRs.getString("tu_authority"));
384
        }
385
        return result.trim();
386
    }
387

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

    
392
		if (statusId > 1){
393
			taxon.addExtension(statusName, notAccExtensionType);
394
		}
395
	}
396

    
397
	private void handleException(Integer parentRank, TaxonName taxonName, String displayName, Integer meId) {
398
		logger.warn("Parent of infra specific taxon is of higher rank ("+parentRank+") than species. Used nameCache: " + displayName +  "; id=" + meId) ;
399
		taxonName.setNameCache(displayName);
400
	}
401

    
402
	private boolean containsBrackets(String displayName) {
403
		int index = displayName.indexOf("[");
404
		return (index > -1);
405
	}
406

    
407
	private void getGenusAndInfraGenus(String parentName, String grandParentName, Integer parent1Rank, TaxonName taxonName) {
408
		if (parent1Rank <220 && parent1Rank > 180){
409
			//parent is infrageneric
410
			taxonName.setInfraGenericEpithet(parentName);
411
			taxonName.setGenusOrUninomial(grandParentName);
412
		}else{
413
			taxonName.setGenusOrUninomial(parentName);
414
		}
415
	}
416

    
417
	/**
418
	 * Returns an empty Taxon Name instance according to the given rank and kingdom.
419
	 */
420
	private TaxonName getTaxonName(ResultSet rs, ErmsImportState state) throws SQLException {
421
	    TaxonName result;
422
		int kingdomId = parseKingdomId(rs);
423
		Integer intRank = rs.getInt("tu_rank");
424

    
425
		NomenclaturalCode nc = ErmsTransformer.kingdomId2NomCode(kingdomId);
426
		Rank rank = null;
427
		rank = state.getRank(intRank, kingdomId);
428

    
429
		if (rank == null){
430
			logger.warn("Rank is null. KingdomId: " + kingdomId + ", rankId: " +  intRank);
431
		}
432
		if (nc != null){
433
			result = nc.getNewTaxonNameInstance(rank);
434
		}else{
435
			result = TaxonNameFactory.NewNonViralInstance(rank);
436
		}
437
		//cache strategy
438
		if (result.isZoological()){
439
		    TaxonNameDefaultCacheStrategy cacheStrategy = PesiTaxonExport.zooNameStrategy;
440
			result.setCacheStrategy(cacheStrategy);
441
		}
442

    
443
		return result;
444
	}
445

    
446
	/**
447
	 * Returns the kingdom id by extracting it from the second character in the <code>tu_sp</code>
448
	 * attribute. If the attribute can not be parsed to a valid id <code>null</code>
449
	 * is returned. If the attribute is <code>null</code> the id of the record is returned.
450
	 * @param rs
451
	 * @return
452
	 * @throws SQLException
453
	 */
454
	private int parseKingdomId(ResultSet rs) throws SQLException {
455
		String treeString = rs.getString("tu_sp");
456
		if (treeString != null){
457
		    if (StringUtils.isNotBlank(treeString) && treeString.length() > 1){
458
				String strKingdom = treeString.substring(1,2);
459

    
460
				if (! treeString.substring(0, 1).equals("#") && ! treeString.substring(2, 3).equals("#") ){
461
					String message = "Tree string " + treeString + " has no recognized format";
462
                    logger.warn(message);
463
                    throw new RuntimeException(message);
464
				}else{
465
					try {
466
						return Integer.valueOf(strKingdom);
467
					} catch (NumberFormatException e) {
468
					    String message = "Kingdom string " + strKingdom + "could not be recognized as a valid number";
469
						logger.warn(message);
470
						throw new RuntimeException(message);
471
					}
472
				}
473
			}else{
474
                String message = "Tree string for kingdom recognition is to short: " + treeString;
475
                logger.warn(message);
476
                throw new RuntimeException(message);
477
			}
478
		}else{
479
			int tu_id = rs.getInt("id");
480
			return tu_id;
481
		}
482
	}
483

    
484
	@Override
485
	protected boolean doCheck(ErmsImportState state){
486
		IOValidator<ErmsImportState> validator = new ErmsTaxonImportValidator();
487
		return validator.validate(state);
488
	}
489

    
490
	@Override
491
    protected boolean isIgnore(ErmsImportState state){
492
		return ! state.getConfig().isDoTaxa();
493
	}
494
}
(13-13/17)