Project

General

Profile

Download (18.3 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
package eu.etaxonomy.cdm.io.berlinModel.in;
10

    
11
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.T_STATUS_ACCEPTED;
12
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.T_STATUS_PARTIAL_SYN;
13
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.T_STATUS_PRO_PARTE_SYN;
14
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.T_STATUS_SYNONYM;
15
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.T_STATUS_UNRESOLVED;
16

    
17
import java.lang.reflect.Method;
18
import java.sql.ResultSet;
19
import java.sql.SQLException;
20
import java.util.Arrays;
21
import java.util.HashMap;
22
import java.util.HashSet;
23
import java.util.List;
24
import java.util.Map;
25
import java.util.Set;
26
import java.util.UUID;
27

    
28
import org.apache.commons.lang3.StringUtils;
29
import org.apache.logging.log4j.LogManager;
30
import org.apache.logging.log4j.Logger;
31
import org.springframework.stereotype.Component;
32

    
33
import eu.etaxonomy.cdm.common.CdmUtils;
34
import eu.etaxonomy.cdm.database.update.DatabaseTypeNotSupportedException;
35
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
36
import eu.etaxonomy.cdm.io.berlinModel.in.validation.BerlinModelTaxonImportValidator;
37
import eu.etaxonomy.cdm.io.common.IOValidator;
38
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
39
import eu.etaxonomy.cdm.model.common.CdmBase;
40
import eu.etaxonomy.cdm.model.common.Extension;
41
import eu.etaxonomy.cdm.model.common.ExtensionType;
42
import eu.etaxonomy.cdm.model.common.Identifier;
43
import eu.etaxonomy.cdm.model.common.Language;
44
import eu.etaxonomy.cdm.model.common.Marker;
45
import eu.etaxonomy.cdm.model.common.MarkerType;
46
import eu.etaxonomy.cdm.model.description.Feature;
47
import eu.etaxonomy.cdm.model.description.TaxonDescription;
48
import eu.etaxonomy.cdm.model.description.TextData;
49
import eu.etaxonomy.cdm.model.name.TaxonName;
50
import eu.etaxonomy.cdm.model.reference.Reference;
51
import eu.etaxonomy.cdm.model.taxon.Synonym;
52
import eu.etaxonomy.cdm.model.taxon.Taxon;
53
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
54
import eu.etaxonomy.cdm.model.term.IdentifierType;
55

    
56

    
57
/**
58
 * @author a.mueller
59
 * @since 20.03.2008
60
 */
61
@Component
62
public class BerlinModelTaxonImport  extends BerlinModelImportBase {
63

    
64
    private static final long serialVersionUID = -1186364983750790695L;
65
    private static final Logger logger = LogManager.getLogger();
66

    
67
	public static final String NAMESPACE = "Taxon";
68

    
69
	private static final String pluralString = "Taxa";
70
	private static final String dbTableName = "PTaxon";
71

    
72
	private static final String LAST_SCRUTINY_FK = "lastScrutinyFk";
73

    
74
	/**
75
	 * How should the publish flag in table PTaxon be interpreted
76
	 * NO_MARKER: No marker is set
77
	 * ONLY_FALSE:
78
	 */
79
	public enum PublishMarkerChooser{
80
		NO_MARKER,
81
		ONLY_FALSE,
82
		ONLY_TRUE,
83
		ALL;
84

    
85
		boolean doMark(boolean value){
86
			if (value == true){
87
				return this == ALL || this == ONLY_TRUE;
88
			}else{
89
				return this == ALL || this == ONLY_FALSE;
90
			}
91
		}
92
	}
93

    
94
	public BerlinModelTaxonImport(){
95
		super(dbTableName, pluralString);
96
	}
97

    
98
	@Override
99
	protected String getIdQuery(BerlinModelImportState state) {
100
		String sqlSelect = " SELECT RIdentifier";
101
		String taxonTable = state.getConfig().getTaxonTable();
102
		String sqlFrom = String.format(" FROM %s ", taxonTable);
103
		String sqlWhere = "";
104

    
105
		String sql = sqlSelect + " " + sqlFrom + " " + sqlWhere ;
106
		return sql;
107
	}
108

    
109
	@Override
110
	protected String getRecordQuery(BerlinModelImportConfigurator config) {
111
		String sqlSelect = " SELECT pt.* ";
112
		String sqlFrom = " FROM PTaxon pt ";
113
		if (config.isEuroMed()){
114
			sqlFrom = " FROM PTaxon AS pt "
115
			                + " INNER JOIN v_cdm_exp_taxaAll AS em ON pt.RIdentifier = em.RIdentifier "
116
							+ " LEFT OUTER JOIN Name n ON pt.PTNameFk = n.nameId ";
117
			if (!config.isUseLastScrutinyAsSec()){
118
			    sqlFrom += " LEFT OUTER JOIN Reference r ON pt.LastScrutinyFk = r.RefId ";
119
			}
120
			sqlSelect += ", n.notes nameNotes , em.MA ";
121
			if (!config.isUseLastScrutinyAsSec()){
122
			    sqlSelect += ", r.RefCache as LastScrutiny ";
123
            }
124
		}
125

    
126
		String sqlWhere = " WHERE ( pt.RIdentifier IN (" + ID_LIST_TOKEN + ") )";
127

    
128
		String strRecordQuery =sqlSelect + " " + sqlFrom + " " + sqlWhere ;
129
//			" SELECT * " +
130
//			" FROM PTaxon " + state.getConfig().getTaxonTable();
131
//			" WHERE ( RIdentifier IN (" + ID_LIST_TOKEN + ") )";
132
		return strRecordQuery;
133
	}
134

    
135
	@Override
136
	protected boolean doCheck(BerlinModelImportState state){
137
		IOValidator<BerlinModelImportState> validator = new BerlinModelTaxonImportValidator();
138
		return validator.validate(state);
139
	}
140

    
141
	@Override
142
	public boolean doPartition(@SuppressWarnings("rawtypes") ResultSetPartitioner partitioner, BerlinModelImportState state) {
143

    
144
	    boolean success = true ;
145
		BerlinModelImportConfigurator config = state.getConfig();
146
		@SuppressWarnings("rawtypes")
147
        Set<TaxonBase> taxaToSave = new HashSet<>();
148
		@SuppressWarnings("unchecked")
149
        Map<String, TaxonName> taxonNameMap = partitioner.getObjectMap(BerlinModelTaxonNameImport.NAMESPACE);
150
		@SuppressWarnings("unchecked")
151
        Map<String, Reference> refMap = partitioner.getObjectMap(BerlinModelReferenceImport.REFERENCE_NAMESPACE);
152

    
153
		ResultSet rs = partitioner.getResultSet();
154
		try{
155
			boolean publishFlagExists = state.getConfig().getSource().checkColumnExists("PTaxon", "PublishFlag");
156
			boolean isEuroMed = config.isEuroMed();
157
			while (rs.next()){
158

    
159
			//	if ((i++ % modCount) == 0 && i!= 1 ){ logger.info("PTaxa handled: " + (i-1));}
160

    
161
				//create TaxonName element
162
				int taxonId = rs.getInt("RIdentifier");
163
				int statusFk = rs.getInt("statusFk");
164

    
165
				int nameFk = rs.getInt("PTNameFk");
166
				int refFkInt = rs.getInt("PTRefFk");
167
				String doubtful = rs.getString("DoubtfulFlag");
168
				String uuid = null;
169
				if (resultSetHasColumn(rs,"UUID")){
170
					uuid = rs.getString("UUID");
171
				}
172

    
173
				TaxonName taxonName = null;
174
				taxonName  = taxonNameMap.get(String.valueOf(nameFk));
175

    
176
				Reference reference = null;
177
				String refFkStr = String.valueOf(refFkInt);
178
				reference = refMap.get(refFkStr);
179

    
180
				Reference lastScrutinyRef = null;
181
                if (state.getConfig().isUseLastScrutinyAsSec() && resultSetHasColumn(rs,LAST_SCRUTINY_FK)){
182
                    Integer lastScrutinyFk = nullSafeInt(rs,LAST_SCRUTINY_FK);
183
                    if (lastScrutinyFk != null){
184
                        String lastScrutinyFkStr = String.valueOf(lastScrutinyFk);
185
                        if (lastScrutinyFkStr != null){
186
                            lastScrutinyRef = refMap.get(lastScrutinyFkStr);
187
                            if (lastScrutinyRef == null){
188
                                logger.warn("Last scrutiny reference "+lastScrutinyFkStr+" could not be found "
189
                                        + "for taxon " + taxonId);
190
                            }
191
                            //MANs do have last scrutiny => the following is not correct
192
//                            if(!StringUtils.right(refFkStr, 5).equals("00000")){
193
//                                logger.warn("Unexpected secFk " + refFkStr + " for taxon with last scrutiny. Taxon id " + taxonId);
194
//                            }
195
                        }
196
                    }
197
                }
198

    
199
				if(! config.isIgnoreNull()){
200
					if (taxonName == null ){
201
						logger.warn("TaxonName belonging to taxon (RIdentifier = " + taxonId + ") could not be found in store. Taxon will not be imported");
202
						success = false;
203
						continue; //next taxon
204
					}else if (reference == null ){
205
						logger.warn("Sec Reference belonging to taxon could not be found in store. Taxon will not be imported");
206
						success = false;
207
						continue; //next taxon
208
					}
209
				}
210
				TaxonBase<?> taxonBase;
211
				Synonym synonym;
212
				Taxon taxon;
213
				Reference sec = (lastScrutinyRef != null && isRightAccessSec(refFkInt)) ? lastScrutinyRef: reference;
214
				try {
215
					logger.debug(statusFk);
216
					if (statusFk == T_STATUS_ACCEPTED || statusFk == T_STATUS_UNRESOLVED
217
					        || statusFk == T_STATUS_PRO_PARTE_SYN || statusFk == T_STATUS_PARTIAL_SYN ){
218
						taxon = Taxon.NewInstance(taxonName, sec);
219
						taxonBase = taxon;
220
						if (statusFk == T_STATUS_UNRESOLVED){
221
							taxon.setTaxonStatusUnknown(true);
222
						}
223
						//TODO marker for pp and partial?
224
					}else if (statusFk == T_STATUS_SYNONYM ){
225
						synonym = Synonym.NewInstance(taxonName, sec);
226
						taxonBase = synonym;
227
//						if (statusFk == T_STATUS_PRO_PARTE_SYN){
228
//						    synonym.setProParte(true);
229
//						}
230
//						if (statusFk == T_STATUS_PARTIAL_SYN){
231
//							synonym.setPartial(true);
232
//						}
233
					}else{
234
						logger.warn("TaxonStatus " + statusFk + " not yet implemented. Taxon (RIdentifier = " + taxonId + ") left out.");
235
						success = false;
236
						continue;
237
					}
238
					if (uuid != null){
239
						taxonBase.setUuid(UUID.fromString(uuid));
240
					}
241

    
242
					//doubtful
243
					if (doubtful.equals("a")){
244
						taxonBase.setDoubtful(false);
245
					}else if(doubtful.equals("d")){
246
						taxonBase.setDoubtful(true);
247
					}else if(doubtful.equals("i")){
248
						taxonBase.setDoubtful(false);
249
						logger.warn("Doubtful = i (inactivated) does not exist in CDM. Doubtful set to false. RIdentifier: " + taxonId);
250
					}
251

    
252
					//detail
253
					String detail = rs.getString("Detail");
254
					if (isNotBlank(detail)){
255
//						ExtensionType detailExtensionType = getExtensionType(state, BerlinModelTransformer.DETAIL_EXT_UUID, "micro reference","micro reference","micro ref.");
256
//						Extension.NewInstance(taxonBase, detail, detailExtensionType);
257
						taxonBase.setSecMicroReference(detail.trim());
258
					}
259
					//idInSource
260
					String idInSource = rs.getString("IdInSource");
261
					if (isNotBlank(idInSource)){
262
						if(!state.getConfig().isEuroMed() && !state.getConfig().isMcl()){
263
						    ExtensionType detailExtensionType = getExtensionType(state, BerlinModelTransformer.ID_IN_SOURCE_EXT_UUID, "Berlin Model IdInSource","Berlin Model IdInSource","BM source id");
264
						    Extension.NewInstance(taxonBase, idInSource.trim(), detailExtensionType);
265
						}else if(isMclIdentifier(state,rs, idInSource) || state.getConfig().isMcl()){
266
						    IdentifierType identifierType = getIdentiferType(state, BerlinModelTransformer.uuidEM_MCLIdentifierType, "MCL identifier", "Med-Checklist identifier", "MCL ID", null);
267
						    Identifier.NewInstance(taxonBase, idInSource.trim(), identifierType);
268
						}
269
						//maybe we want to handle it as fact in future for MCL
270
//						if (state.getConfig().isMcl()) {
271
//						}
272
					}
273
					//namePhrase
274
					String namePhrase = rs.getString("NamePhrase");
275
					if (StringUtils.isNotBlank(namePhrase)){
276
						taxonBase.setAppendedPhrase(namePhrase);
277
					}
278
					//useNameCache
279
					Boolean useNameCacheFlag = rs.getBoolean("UseNameCacheFlag");
280
					if (useNameCacheFlag){
281
						taxonBase.setUseNameCache(true);
282
					}
283
					//publisheFlag
284
					if (publishFlagExists){
285
						Boolean publishFlag = rs.getBoolean("PublishFlag");
286
						Boolean misapplied = false;
287
						if (isEuroMed){
288
							misapplied = rs.getBoolean("MA");
289
						}
290

    
291
						if ( ! misapplied){
292
							taxonBase.setPublish(publishFlag);
293
						}
294
					}
295

    
296
					//  does not exist anymore as we use last scrutiny now as sec ref
297
					if (!state.getConfig().isUseLastScrutinyAsSec() && resultSetHasColumn(rs, "LastScrutiny")){
298
						String lastScrutiny = rs.getString("LastScrutiny");
299
						//TODO strange, why not Extension last scrutiny? To match PESI? Is there a difference
300
						//to LastScrutinyFK and SpeciesExpertFK?
301
						if (isNotBlank(lastScrutiny)){
302
						    ExtensionType extensionTypeSpeciesExpert = getExtensionType(state, BerlinModelTransformer.uuidSpeciesExpertName, "Species Expert", "Species Expert", "Species Expert");
303
						    taxonBase.addExtension(lastScrutiny, extensionTypeSpeciesExpert);
304
						    ExtensionType extensionTypeExpert = getExtensionType(state, BerlinModelTransformer.uuidExpertName, "Expert", "Expert for a taxonomic group", "Expert");
305
						    taxonBase.addExtension(lastScrutiny, extensionTypeExpert);
306
						}
307
					}
308
					//
309
					if (resultSetHasColumn(rs, "IsExcludedMarker")){
310
					    boolean isExcluded = rs.getBoolean("IsExcludedMarker");
311
					    if (isExcluded){
312
					        String extension = rs.getString("IsExcludedExtension");
313
					        String valueless = "not accepted: taxonomically valueless local or singular biotype";
314
					        String provisional = "provisional: probably a taxonomically valueless local or singular biotype";
315

    
316
					        MarkerType markerType = null;
317
					        if (valueless.equals(extension)){
318
					            markerType = getMarkerType(state, BerlinModelTransformer.uuidTaxonomicallyValueless, "taxonomically valueless", valueless, "valueless", getEuroMedMarkerTypeVoc(state));
319
					        }else if (provisional.equals(extension)){
320
                                markerType = getMarkerType(state, BerlinModelTransformer.uuidProbablyTaxonomicallyValueless, "probably taxonomically valueless", provisional, "provisional", getEuroMedMarkerTypeVoc(state));
321
                            }
322
					        if (markerType != null){
323
					            taxonBase.addMarker(Marker.NewInstance(markerType, true));
324
					        }else{
325
					            logger.warn("IsExcludedExtension not regonized for taxon " + taxonId + "; " + extension);
326
					        }
327
					    }
328
					}
329

    
330
					//Notes
331
					boolean excludeNotes = state.getConfig().isTaxonNoteAsFeature() && taxonBase.isInstanceOf(Taxon.class);
332
					String notes = rs.getString("Notes");
333
					if (state.getConfig().isEuroMed()){
334
					    if (isNotBlank(notes) && notes.startsWith("non ")){
335
					        taxonBase.setAppendedPhrase(CdmUtils.concat("; ", taxonBase.getAppendedPhrase(), notes));
336
					        notes = null;
337
					    }
338
					    String nameNotes = rs.getString("nameNotes");
339
					    nameNotes = BerlinModelTaxonNameImport.filterNotes(nameNotes, 900000000 + taxonId);
340
					    if (BerlinModelTaxonNameImport.isPostulatedParentalSpeciesNote(nameNotes)){
341
					        nameNotes = nameNotes.replace("{", "").replace("}", "");
342
					        String text = "For intermediate, so-called \"collective\" species in the genus Pilosella, a combination of the postulated parental basic species is given.";
343
					        UUID parSpecUuid = BerlinModelTransformer.PARENTAL_SPECIES_EXT_UUID;
344
					        ExtensionType parentalSpeciesExtType = getExtensionType(state, parSpecUuid, " Postulated parental species", text, "par. spec.");
345
					        Extension.NewInstance(taxonBase, nameNotes, parentalSpeciesExtType);
346
					    }
347
					}
348

    
349
					doIdCreatedUpdatedNotes(state, taxonBase, rs, taxonId, NAMESPACE, false, excludeNotes || notes == null);
350
					if (excludeNotes && notes != null){
351
					    makeTaxonomicNote(state, CdmBase.deproxy(taxonBase, Taxon.class), rs.getString("Notes"));
352
					}
353

    
354
					//external url
355
					if (config.getMakeUrlForTaxon() != null){
356
						Method urlMethod = config.getMakeUrlForTaxon();
357
						urlMethod.invoke(null, taxonBase, rs);
358
					}
359

    
360
					partitioner.startDoSave();
361
					taxaToSave.add(taxonBase);
362
				} catch (Exception e) {
363
					logger.warn("An exception (" +e.getMessage()+") occurred when creating taxon with id " + taxonId + ". Taxon could not be saved.");
364
					success = false;
365
				}
366
			}
367
		} catch (DatabaseTypeNotSupportedException e) {
368
			logger.error("MethodNotSupportedException:" +  e);
369
			return false;
370
		} catch (Exception e) {
371
			logger.error("SQLException:" +  e);
372
			return false;
373
		}
374

    
375
		getTaxonService().save(taxaToSave);
376
		return success;
377
	}
378

    
379
    private boolean isMclIdentifier(BerlinModelImportState state, ResultSet rs, String idInSource) throws SQLException {
380
        if (idInSource.contains("-")){
381
            return true;
382
        }else if (idInSource.matches("(293|303)")){
383
            String created = rs.getString("Created_Who");
384
            if (created.endsWith(".xml")){
385
                return true;
386
            }
387
        }
388
        return false;
389
    }
390

    
391
    @Override
392
    protected String getIdInSource(BerlinModelImportState state, ResultSet rs) throws SQLException {
393
        String id = rs.getString("idInSource");
394
        return id;
395
    }
396

    
397

    
398
    /**
399
     * @param refFkInt
400
     * @return
401
     */
402
    private boolean isRightAccessSec(Integer refFkInt) {
403
        List<Integer> rightAccessSecs = Arrays.asList(new Integer[]{7000000, 7100000, 7200000, 7300000,
404
                7400000, 7500000, 7600000, 7700000, 8000000, 8500000, 9000000});
405
        return rightAccessSecs.contains(refFkInt);
406
    }
407

    
408
    /**
409
     * @param state
410
     * @param taxonBase
411
	 * @param notes
412
     */
413
    private void makeTaxonomicNote(BerlinModelImportState state, Taxon taxon, String notes) {
414
        if (isNotBlank(notes)){
415
            TaxonDescription desc = getTaxonDescription(taxon, false, true);
416
            desc.setDefault(true);  //hard coded for Salvador, not used elsewhere as far as I can see
417
            TextData textData = TextData.NewInstance(Feature.NOTES() , notes, Language.SPANISH_CASTILIAN(), null);
418
            desc.addElement(textData);
419
        }
420
    }
421

    
422
    @Override
423
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, BerlinModelImportState state) {
424

    
425
        String nameSpace;
426
		Set<String> idSet;
427
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<>();
428

    
429
		try{
430
			Set<String> nameIdSet = new HashSet<>();
431
			Set<String> referenceIdSet = new HashSet<>();
432
			while (rs.next()){
433
				handleForeignKey(rs, nameIdSet, "PTNameFk");
434
				handleForeignKey(rs, referenceIdSet, "PTRefFk");
435
				if (state.getConfig().isUseLastScrutinyAsSec() && resultSetHasColumn(rs, LAST_SCRUTINY_FK)){
436
				    handleForeignKey(rs, referenceIdSet, LAST_SCRUTINY_FK);
437
				}
438
			}
439

    
440
			//name map
441
			nameSpace = BerlinModelTaxonNameImport.NAMESPACE;
442
			idSet = nameIdSet;
443
			Map<String, TaxonName> nameMap = getCommonService().getSourcedObjectsByIdInSourceC(TaxonName.class, idSet, nameSpace);
444
			result.put(nameSpace, nameMap);
445

    
446
			//reference map
447
			nameSpace = BerlinModelReferenceImport.REFERENCE_NAMESPACE;
448
			idSet = referenceIdSet;
449
			Map<String, Reference> referenceMap = getCommonService().getSourcedObjectsByIdInSourceC(Reference.class, idSet, nameSpace);
450
			result.put(nameSpace, referenceMap);
451

    
452
		} catch (SQLException e) {
453
			throw new RuntimeException(e);
454
		}
455
		return result;
456
	}
457

    
458
	@Override
459
	protected String getTableName() {
460
		return dbTableName;
461
	}
462

    
463
	@Override
464
	public String getPluralString() {
465
		return pluralString;
466
	}
467

    
468
	@Override
469
	protected boolean isIgnore(BerlinModelImportState state){
470
		return ! state.getConfig().isDoTaxa();
471
	}
472

    
473
}
(15-15/22)