Project

General

Profile

Download (24.6 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.IMappingImport;
37
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
38
import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
39
import eu.etaxonomy.cdm.io.pesi.erms.validation.ErmsTaxonImportValidator;
40
import eu.etaxonomy.cdm.io.pesi.out.PesiTaxonExport;
41
import eu.etaxonomy.cdm.io.pesi.out.PesiTransformer;
42
import eu.etaxonomy.cdm.model.common.AnnotationType;
43
import eu.etaxonomy.cdm.model.common.CdmBase;
44
import eu.etaxonomy.cdm.model.common.ExtensionType;
45
import eu.etaxonomy.cdm.model.common.Language;
46
import eu.etaxonomy.cdm.model.common.MarkerType;
47
import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
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.model.taxon.TaxonRelationshipType;
58
import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
59

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

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

    
72
	private DbImportMapping<ErmsImportState, ErmsImportConfigurator> mapping;
73

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

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

    
82
	@Override
83
	protected String getIdQuery() {
84
		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).
85
		return strQuery;
86
	}
87

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

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

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

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

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

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

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

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

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

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

    
135
            //MAN authorshipCache => appendedPhrase
136
            mapping.addMapper(DbImportMethodMapper.NewDefaultInstance(this, "appendedPhraseForMisapplications", ErmsImportState.class));
137

    
138
            //titleCache compare
139
            mapping.addMapper(DbImportMethodMapper.NewDefaultInstance(this, "testTitleCache", ErmsImportState.class));
140

    
141
			//ignore
142
            mapping.addMapper(DbIgnoreMapper.NewInstance("tu_sp", "included in rank/object creation, only needed for defining kingdom"));
143
			mapping.addMapper(DbIgnoreMapper.NewInstance("tu_fossil", "tu_fossil implemented as foreign key"));
144

    
145
		}
146
		return mapping;
147
	}
148

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

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

    
175
		//first path
176
		super.doInvoke(state);
177
		return;
178
	}
179

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

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

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

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

    
238
        TaxonName taxonName = getTaxonName(rs, state);
239
		fillTaxonName(taxonName, rs, state, meId);
240

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

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

    
258
		handleNameStatus(result.getName(), rs, state);
259
		return result;
260
	}
261

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

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

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

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

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

    
308
	    String parent4Name = rs.getString("parent4name");
309

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

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

    
358
    @SuppressWarnings("unused")  //used by MethodMapper
359
    private static TaxonBase<?> appendedPhraseForMisapplications(ResultSet rs, ErmsImportState state) throws SQLException{
360
        TaxonBase<?> taxon = (TaxonBase<?>)state.getRelatedObject(DbImportStateBase.CURRENT_OBJECT_NAMESPACE, DbImportStateBase.CURRENT_OBJECT_ID);
361
        TaxonName taxonName = taxon.getName();
362
         String unacceptreason = rs.getString("tu_unacceptreason");
363
         RelationshipTermBase<?>[] rels = state.getTransformer().getSynonymRelationTypesByKey(unacceptreason, state);
364
         if (rels[1]!= null && rels[1].equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
365
             taxon.setAppendedPhrase(taxonName.getAuthorshipCache());
366
             taxon.setSec(null);
367
             taxonName.setAuthorshipCache(null, taxonName.isProtectedAuthorshipCache());
368
             //TODO maybe some further authorship handling is needed if authors get parsed, but not very likely for MAN authorship
369
         }
370
         return taxon;
371
     }
372

    
373
    @SuppressWarnings("unused")  //used by MethodMapper
374
    private static TaxonBase<?> testTitleCache(ResultSet rs, ErmsImportState state) throws SQLException{
375
        TaxonBase<?> taxon = (TaxonBase<?>)state.getRelatedObject(DbImportStateBase.CURRENT_OBJECT_NAMESPACE, DbImportStateBase.CURRENT_OBJECT_ID);
376
        TaxonName taxonName = taxon.getName();
377
        String displayName = rs.getString("tu_displayname");
378
        displayName = displayName == null ? null : displayName.trim();
379
        String titleCache = taxonName.resetTitleCache(); //calling titleCache should always be kept to have a computed titleCache in the CDM DB.
380
        String expectedTitleCache = getExpectedTitleCache(rs);
381
        //TODO check titleCache, but beware of autonyms
382
        if (!titleCache.equals(expectedTitleCache)){
383
            int pos = CdmUtils.diffIndex(titleCache, expectedTitleCache);
384
            logger.warn("Computed title cache differs at "+pos+".\n Computed             : " + titleCache + "\n DisplayName+Authority: " + expectedTitleCache);
385
            taxonName.setNameCache(displayName, true);
386
        }
387
        return taxon;
388
    }
389

    
390
    //see also PesiErmsValidation.srcFullName()
391
    private static String getExpectedTitleCache(ResultSet srcRs) throws SQLException {
392
        String result;
393
        String epi = srcRs.getString("tu_name");
394
        epi = " a" + epi;
395
        String display = srcRs.getString("tu_displayname");
396
        String sp = srcRs.getString("tu_sp");
397
        if (display.indexOf(epi) != display.lastIndexOf(epi) && !sp.startsWith("#2#")){ //homonym, animal
398
            result = srcRs.getString("tu_displayname").replaceFirst(epi+" ", CdmUtils.concat(" ", " "+epi, srcRs.getString("tu_authority")))+" ";
399
        }else{
400
            result = CdmUtils.concat(" ", srcRs.getString("tu_displayname"), srcRs.getString("tu_authority"));
401
        }
402
        return result.trim();
403
    }
404

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

    
409
		if (statusId > 1){
410
			taxon.addExtension(statusName, notAccExtensionType);
411
		}
412
	}
413

    
414
	private void handleException(Integer parentRank, TaxonName taxonName, String displayName, Integer meId) {
415
		logger.warn("Parent of infra specific taxon is of higher rank ("+parentRank+") than species. Used nameCache: " + displayName +  "; id=" + meId) ;
416
		taxonName.setNameCache(displayName);
417
	}
418

    
419
	private boolean containsBrackets(String displayName) {
420
		int index = displayName.indexOf("[");
421
		return (index > -1);
422
	}
423

    
424
	private void getGenusAndInfraGenus(String parentName, String grandParentName, Integer parent1Rank, TaxonName taxonName) {
425
		if (parent1Rank <220 && parent1Rank > 180){
426
			//parent is infrageneric
427
			taxonName.setInfraGenericEpithet(parentName);
428
			taxonName.setGenusOrUninomial(grandParentName);
429
		}else{
430
			taxonName.setGenusOrUninomial(parentName);
431
		}
432
	}
433

    
434
	/**
435
	 * Returns an empty Taxon Name instance according to the given rank and kingdom.
436
	 */
437
	private TaxonName getTaxonName(ResultSet rs, ErmsImportState state) throws SQLException {
438
	    TaxonName result;
439
		int kingdomId = parseKingdomId(rs);
440
		Integer intRank = rs.getInt("tu_rank");
441

    
442
		NomenclaturalCode nc = ErmsTransformer.kingdomId2NomCode(kingdomId);
443
		Rank rank = null;
444
		rank = state.getRank(intRank, kingdomId);
445

    
446
		if (rank == null){
447
			logger.warn("Rank is null. KingdomId: " + kingdomId + ", rankId: " +  intRank);
448
		}
449
		if (nc != null){
450
			result = nc.getNewTaxonNameInstance(rank);
451
		}else{
452
			result = TaxonNameFactory.NewNonViralInstance(rank);
453
		}
454
		//cache strategy
455
		if (result.isZoological()){
456
		    TaxonNameDefaultCacheStrategy cacheStrategy = PesiTaxonExport.zooNameStrategy;
457
			result.setCacheStrategy(cacheStrategy);
458
		}
459

    
460
		return result;
461
	}
462

    
463
	/**
464
	 * Returns the kingdom id by extracting it from the second character in the <code>tu_sp</code>
465
	 * attribute. If the attribute can not be parsed to a valid id <code>null</code>
466
	 * is returned. If the attribute is <code>null</code> the id of the record is returned.
467
	 * @param rs
468
	 * @return
469
	 * @throws SQLException
470
	 */
471
	private int parseKingdomId(ResultSet rs) throws SQLException {
472
		String treeString = rs.getString("tu_sp");
473
		if (treeString != null){
474
		    if (StringUtils.isNotBlank(treeString) && treeString.length() > 1){
475
				String strKingdom = treeString.substring(1,2);
476

    
477
				if (! treeString.substring(0, 1).equals("#") && ! treeString.substring(2, 3).equals("#") ){
478
					String message = "Tree string " + treeString + " has no recognized format";
479
                    logger.warn(message);
480
                    throw new RuntimeException(message);
481
				}else{
482
					try {
483
						return Integer.valueOf(strKingdom);
484
					} catch (NumberFormatException e) {
485
					    String message = "Kingdom string " + strKingdom + "could not be recognized as a valid number";
486
						logger.warn(message);
487
						throw new RuntimeException(message);
488
					}
489
				}
490
			}else{
491
                String message = "Tree string for kingdom recognition is to short: " + treeString;
492
                logger.warn(message);
493
                throw new RuntimeException(message);
494
			}
495
		}else{
496
			int tu_id = rs.getInt("id");
497
			return tu_id;
498
		}
499
	}
500

    
501
	@Override
502
	protected boolean doCheck(ErmsImportState state){
503
		IOValidator<ErmsImportState> validator = new ErmsTaxonImportValidator();
504
		return validator.validate(state);
505
	}
506

    
507
	@Override
508
    protected boolean isIgnore(ErmsImportState state){
509
		return ! state.getConfig().isDoTaxa();
510
	}
511
}
(13-13/17)