Project

General

Profile

Download (17 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.berlinModel.in;
11

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

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

    
29
import org.apache.commons.lang.StringUtils;
30
import org.apache.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.agent.Person;
40
import eu.etaxonomy.cdm.model.common.CdmBase;
41
import eu.etaxonomy.cdm.model.common.Extension;
42
import eu.etaxonomy.cdm.model.common.ExtensionType;
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

    
55

    
56
/**
57
 * @author a.mueller
58
 * @since 20.03.2008
59
 */
60
@Component
61
public class BerlinModelTaxonImport  extends BerlinModelImportBase {
62
    /**
63
     *
64
     */
65
    private static final String LAST_SCRUTINY_FK = "lastScrutinyFk";
66

    
67
    private static final long serialVersionUID = -1186364983750790695L;
68

    
69
    private static final Logger logger = Logger.getLogger(BerlinModelTaxonImport.class);
70

    
71
	public static final String NAMESPACE = "Taxon";
72

    
73
	private static final String pluralString = "Taxa";
74
	private static final String dbTableName = "PTaxon";
75

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

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

    
96
	public BerlinModelTaxonImport(){
97
		super(dbTableName, pluralString);
98
	}
99

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

    
107
		String sql = sqlSelect + " " + sqlFrom + " " + sqlWhere ;
108
		return sql;
109
	}
110

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

    
128

    
129
		String sqlWhere = " WHERE ( pt.RIdentifier IN (" + ID_LIST_TOKEN + ") )";
130

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

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

    
144
	@Override
145
	public boolean doPartition(ResultSetPartitioner partitioner, BerlinModelImportState state) {
146
		boolean success = true ;
147

    
148
		BerlinModelImportConfigurator config = state.getConfig();
149
		Set<TaxonBase> taxaToSave = new HashSet<>();
150
		Map<String, TaxonName> taxonNameMap = partitioner.getObjectMap(BerlinModelTaxonNameImport.NAMESPACE);
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

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

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

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

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

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

    
253
					//detail
254
					String detail = rs.getString("Detail");
255
					if (isNotBlank(detail)){
256
						ExtensionType detailExtensionType = getExtensionType(state, BerlinModelTransformer.DETAIL_EXT_UUID, "micro reference","micro reference","micro ref.");
257
						Extension.NewInstance(taxonBase, detail, detailExtensionType);
258
					}
259
					//idInSource
260
					String idInSource = rs.getString("IdInSource");
261
					if (isNotBlank(idInSource)){
262
						ExtensionType detailExtensionType = getExtensionType(state, BerlinModelTransformer.ID_IN_SOURCE_EXT_UUID, "Berlin Model IdInSource","Berlin Model IdInSource","BM source id");
263
						Extension.NewInstance(taxonBase, idInSource, detailExtensionType);
264
					}
265
					//namePhrase
266
					String namePhrase = rs.getString("NamePhrase");
267
					if (StringUtils.isNotBlank(namePhrase)){
268
						taxonBase.setAppendedPhrase(namePhrase);
269
					}
270
					//useNameCache
271
					Boolean useNameCacheFlag = rs.getBoolean("UseNameCacheFlag");
272
					if (useNameCacheFlag){
273
						taxonBase.setUseNameCache(true);
274
					}
275
					//publisheFlag
276
					if (publishFlagExists){
277
						Boolean publishFlag = rs.getBoolean("PublishFlag");
278
						Boolean misapplied = false;
279
						if (isEuroMed){
280
							misapplied = rs.getBoolean("MA");
281
						}
282

    
283
						if ( ! misapplied){
284
							taxonBase.setPublish(publishFlag);
285
						}
286
					}
287

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

    
308
					        MarkerType markerType = null;
309
					        if (valueless.equals(extension)){
310
					            markerType = getMarkerType(state, BerlinModelTransformer.uuidTaxonomicallyValueless, "taxonomically valueless", valueless, "valueless", getEuroMedMarkerTypeVoc());
311
					        }else if (provisional.equals(extension)){
312
                                markerType = getMarkerType(state, BerlinModelTransformer.uuidProbablyTaxonomicallyValueless, "probably taxonomically valueless", provisional, "provisional", getEuroMedMarkerTypeVoc());
313
                            }
314
					        if (markerType != null){
315
					            taxonBase.addMarker(Marker.NewInstance(markerType, true));
316
					        }else{
317
					            logger.warn("IsExcludedExtension not regonized for taxon " + taxonId + "; " + extension);
318
					        }
319
					    }
320
					}
321

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

    
341
					doIdCreatedUpdatedNotes(state, taxonBase, rs, taxonId, NAMESPACE, false, excludeNotes || notes == null);
342
					if (excludeNotes && notes != null){
343
					    makeTaxonomicNote(state, CdmBase.deproxy(taxonBase, Taxon.class), rs.getString("Notes"));
344
					}
345

    
346
					//external url
347
					if (config.getMakeUrlForTaxon() != null){
348
						Method urlMethod = config.getMakeUrlForTaxon();
349
						urlMethod.invoke(null, taxonBase, rs);
350
					}
351

    
352
					partitioner.startDoSave();
353
					taxaToSave.add(taxonBase);
354
				} catch (Exception e) {
355
					logger.warn("An exception (" +e.getMessage()+") occurred when creating taxon with id " + taxonId + ". Taxon could not be saved.");
356
					success = false;
357
				}
358
			}
359
		} catch (DatabaseTypeNotSupportedException e) {
360
			logger.error("MethodNotSupportedException:" +  e);
361
			return false;
362
		} catch (Exception e) {
363
			logger.error("SQLException:" +  e);
364
			return false;
365
		}
366

    
367
		getTaxonService().save(taxaToSave);
368
		return success;
369
	}
370

    
371

    
372
    /**
373
     * @param refFkInt
374
     * @return
375
     */
376
    private boolean isRightAccessSec(Integer refFkInt) {
377
        List<Integer> rightAccessSecs = Arrays.asList(new Integer[]{7000000, 7100000, 7200000, 7300000,
378
                7400000, 7500000, 7600000, 7700000, 8000000, 8500000, 9000000});
379
        return rightAccessSecs.contains(refFkInt);
380
    }
381

    
382
    /**
383
     * @param state
384
     * @param taxonBase
385
	 * @param notes
386
     */
387
    private void makeTaxonomicNote(BerlinModelImportState state, Taxon taxon, String notes) {
388
        if (isNotBlank(notes)){
389
            TaxonDescription desc = getTaxonDescription(taxon, false, true);
390
            desc.setDefault(true);  //hard coded for Salvador, not used elsewhere as far as I can see
391
            TextData textData = TextData.NewInstance(Feature.NOTES() , notes, Language.SPANISH_CASTILIAN(), null);
392
            desc.addElement(textData);
393
        }
394
    }
395

    
396
    @Override
397
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, BerlinModelImportState state) {
398
		String nameSpace;
399
		Class<?> cdmClass;
400
		Set<String> idSet;
401
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<>();
402

    
403
		try{
404
			Set<String> nameIdSet = new HashSet<>();
405
			Set<String> referenceIdSet = new HashSet<>();
406
			while (rs.next()){
407
				handleForeignKey(rs, nameIdSet, "PTNameFk");
408
				handleForeignKey(rs, referenceIdSet, "PTRefFk");
409
				if (state.getConfig().isUseLastScrutinyAsSec() && resultSetHasColumn(rs, LAST_SCRUTINY_FK)){
410
				    handleForeignKey(rs, referenceIdSet, LAST_SCRUTINY_FK);
411
				}
412
			}
413

    
414
			//name map
415
			nameSpace = BerlinModelTaxonNameImport.NAMESPACE;
416
			cdmClass = TaxonName.class;
417
			idSet = nameIdSet;
418
			Map<String, Person> nameMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
419
			result.put(nameSpace, nameMap);
420

    
421
			//reference map
422
			nameSpace = BerlinModelReferenceImport.REFERENCE_NAMESPACE;
423
			cdmClass = Reference.class;
424
			idSet = referenceIdSet;
425
			Map<String, Reference> referenceMap = (Map<String, Reference>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
426
			result.put(nameSpace, referenceMap);
427

    
428
		} catch (SQLException e) {
429
			throw new RuntimeException(e);
430
		}
431
		return result;
432
	}
433

    
434
	@Override
435
	protected String getTableName() {
436
		return dbTableName;
437
	}
438

    
439
	@Override
440
	public String getPluralString() {
441
		return pluralString;
442
	}
443

    
444
	@Override
445
	protected boolean isIgnore(BerlinModelImportState state){
446
		return ! state.getConfig().isDoTaxa();
447
	}
448

    
449
}
(15-15/22)