Project

General

Profile

Download (19.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

    
10
package eu.etaxonomy.cdm.io.berlinModel.in;
11

    
12
import java.io.IOException;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.sql.ResultSet;
16
import java.sql.SQLException;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.UUID;
22

    
23
import org.apache.commons.lang.StringUtils;
24
import org.apache.http.HttpException;
25
import org.apache.log4j.Logger;
26
import org.springframework.stereotype.Component;
27

    
28
import eu.etaxonomy.cdm.common.CdmUtils;
29
import eu.etaxonomy.cdm.common.media.ImageInfo;
30
import eu.etaxonomy.cdm.database.update.DatabaseTypeNotSupportedException;
31
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
32
import eu.etaxonomy.cdm.io.berlinModel.in.validation.BerlinModelFactsImportValidator;
33
import eu.etaxonomy.cdm.io.common.IOValidator;
34
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
35
import eu.etaxonomy.cdm.io.common.Source;
36
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
37
import eu.etaxonomy.cdm.model.common.Annotation;
38
import eu.etaxonomy.cdm.model.common.CdmBase;
39
import eu.etaxonomy.cdm.model.common.Language;
40
import eu.etaxonomy.cdm.model.common.Marker;
41
import eu.etaxonomy.cdm.model.common.MarkerType;
42
import eu.etaxonomy.cdm.model.common.TermType;
43
import eu.etaxonomy.cdm.model.common.TermVocabulary;
44
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
45
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
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.media.ImageFile;
50
import eu.etaxonomy.cdm.model.media.Media;
51
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
52
import eu.etaxonomy.cdm.model.reference.Reference;
53
import eu.etaxonomy.cdm.model.taxon.Taxon;
54
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
55
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
56

    
57
/**
58
 * @author a.mueller
59
 * @created 20.03.2008
60
 * @version 1.0
61
 */
62
@Component
63
public class BerlinModelFactsImport  extends BerlinModelImportBase {
64
	private static final Logger logger = Logger.getLogger(BerlinModelFactsImport.class);
65

    
66
	public static final String NAMESPACE = "Fact";
67

    
68
	public static final String SEQUENCE_PREFIX = "ORDER: ";
69

    
70
	private int modCount = 10000;
71
	private static final String pluralString = "facts";
72
	private static final String dbTableName = "Fact";
73

    
74
	//FIXME don't use as class variable
75
	private Map<Integer, Feature> featureMap;
76

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

    
81

    
82
	private TermVocabulary<Feature> getFeatureVocabulary(){
83
		try {
84
			//TODO work around until service method works
85
			TermVocabulary<Feature> featureVocabulary =  BerlinModelTransformer.factCategory2Feature(1).getVocabulary();
86
			//TermVocabulary<Feature> vocabulary = getTermService().getVocabulary(vocabularyUuid);
87
			return featureVocabulary;
88
		} catch (UnknownCdmTypeException e) {
89
			logger.error("Feature vocabulary not available. New vocabulary created");
90
			return TermVocabulary.NewInstance(TermType.Feature, "User Defined Feature Vocabulary", "User Defined Feature Vocabulary", null, null);
91
		}
92
	}
93

    
94
	private Map<Integer, Feature>  invokeFactCategories(BerlinModelImportState state){
95

    
96
		Map<Integer, Feature>  result = state.getConfig().getFeatureMap();
97
		Source source = state.getConfig().getSource();
98

    
99
		try {
100
			//get data from database
101
			String strQuery =
102
					" SELECT FactCategory.* " +
103
					" FROM FactCategory "+
104
                    " WHERE (1=1)";
105
			ResultSet rs = source.getResultSet(strQuery) ;
106

    
107

    
108
			TermVocabulary<Feature> featureVocabulary = getFeatureVocabulary();
109
			int i = 0;
110
			//for each reference
111
			while (rs.next()){
112

    
113
				if ((i++ % modCount) == 0 && i!= 1 ){ logger.info("FactCategories handled: " + (i-1));}
114

    
115
				int factCategoryId = rs.getInt("factCategoryId");
116
				String factCategory = rs.getString("factCategory");
117

    
118
				Feature feature;
119
				try {
120
					feature = BerlinModelTransformer.factCategory2Feature(factCategoryId);
121
				} catch (UnknownCdmTypeException e) {
122
					UUID featureUuid = null;
123
					featureUuid = BerlinModelTransformer.getFeatureUuid(String.valueOf(factCategoryId+"-"+factCategory));
124
					if (featureUuid == null){
125
						logger.warn("New Feature (FactCategoryId: " + factCategoryId + ")");
126
						featureUuid = UUID.randomUUID();
127
					}
128
					feature = getFeature(state, featureUuid, factCategory, factCategory, null, featureVocabulary);
129

    
130
					//TODO
131
//					MaxFactNumber	int	Checked
132
//					ExtensionTableName	varchar(100)	Checked
133
//					Description	nvarchar(1000)	Checked
134
//					locExtensionFormName	nvarchar(80)	Checked
135
//					RankRestrictionFk	int	Checked
136
				}
137

    
138
				result.put(factCategoryId, feature);
139
			}
140
			return result;
141
		} catch (SQLException e) {
142
			logger.error("SQLException:" +  e);
143
			return null;
144
		} catch (UndefinedTransformerMethodException e1) {
145
			logger.error("UndefinedTransformerMethodException:" +  e1);
146
			e1.printStackTrace();
147
			return null;
148
		}
149

    
150
	}
151

    
152
	@Override
153
	protected void doInvoke(BerlinModelImportState state) {
154
		featureMap = invokeFactCategories(state);
155
		super.doInvoke(state);
156
		return;
157
	}
158

    
159

    
160
	@Override
161
	protected String getIdQuery(BerlinModelImportState state) {
162
		String result = super.getIdQuery(state);
163
		if (StringUtils.isNotBlank(state.getConfig().getFactFilter())){
164
			result += " WHERE " + state.getConfig().getFactFilter();
165
		}else{
166
			result = super.getIdQuery(state);
167
		}
168
		result += getOrderBy(state.getConfig());
169
		return result;
170
	}
171

    
172
	@Override
173
	protected String getRecordQuery(BerlinModelImportConfigurator config) {
174
			String strQuery =
175
					" SELECT Fact.*, PTaxon.RIdentifier as taxonId, RefDetail.Details " +
176
					" FROM Fact " +
177
                      	" INNER JOIN PTaxon ON Fact.PTNameFk = PTaxon.PTNameFk AND Fact.PTRefFk = PTaxon.PTRefFk " +
178
                      	" LEFT OUTER JOIN RefDetail ON Fact.FactRefDetailFk = RefDetail.RefDetailId AND Fact.FactRefFk = RefDetail.RefFk " +
179
              	" WHERE (FactId IN (" + ID_LIST_TOKEN + "))";
180
			    strQuery += getOrderBy(config);
181

    
182
		return strQuery;
183
	}
184

    
185

    
186
	private String getOrderBy(BerlinModelImportConfigurator config) {
187
		String result;
188
		try{
189
			if (config.getSource().checkColumnExists("Fact", "Sequence")){
190
				result = " ORDER By Fact.Sequence, Fact.FactId";
191
			}else{
192
				result = " ORDER By Fact.FactId";
193
			}
194
		} catch (DatabaseTypeNotSupportedException e) {
195
			logger.info("checkColumnExists not supported");
196
			result = " ORDER By Fact.FactId";
197
		}
198
		return result;
199
	}
200

    
201
	@Override
202
	public boolean doPartition(ResultSetPartitioner partitioner, BerlinModelImportState state) {
203
		boolean success = true ;
204
		BerlinModelImportConfigurator config = state.getConfig();
205
		Set<TaxonBase> taxaToSave = new HashSet<TaxonBase>();
206
		Map<String, TaxonBase> taxonMap = partitioner.getObjectMap(BerlinModelTaxonImport.NAMESPACE);
207
		Map<String, Reference> refMap = partitioner.getObjectMap(BerlinModelReferenceImport.REFERENCE_NAMESPACE);
208

    
209
		ResultSet rs = partitioner.getResultSet();
210

    
211
		Reference sourceRef = state.getTransactionalSourceReference();
212

    
213
		try{
214
			int i = 0;
215
			//for each fact
216
			while (rs.next()){
217
				try{
218
					if ((i++ % modCount) == 0){ logger.info("Facts handled: " + (i-1));}
219

    
220
					int factId = rs.getInt("factId");
221
					Integer taxonId = nullSafeInt(rs, "taxonId");
222
					Integer factRefFkInt = nullSafeInt(rs, "factRefFk");
223
					Integer categoryFkInt = nullSafeInt(rs, "factCategoryFk");
224
					String details = rs.getString("Details");
225
					String fact = CdmUtils.Nz(rs.getString("Fact"));
226
					String notes = CdmUtils.Nz(rs.getString("notes"));
227
					Boolean doubtfulFlag = rs.getBoolean("DoubtfulFlag");
228

    
229
					TaxonBase<?> taxonBase = getTaxon(taxonMap, taxonId, taxonId);
230
					Feature feature = getFeature(featureMap, categoryFkInt) ;
231

    
232
					if (taxonBase == null){
233
						logger.warn("Taxon for Fact " + factId + " does not exist in store");
234
						success = false;
235
					}else{
236
						TaxonDescription taxonDescription;
237
						if ( (taxonDescription = getMyTaxonDescripion(taxonBase, state, categoryFkInt, taxonId, factId, fact, sourceRef)) == null){
238
							success = false;
239
							continue;
240
						}
241

    
242
						//textData
243
						TextData textData = null;
244
						boolean newTextData = true;
245

    
246
						// For Cichorieae DB: If fact category is 31 (Systematics) and there is already a Systematics TextData
247
						// description element append the fact text to the existing TextData
248
						if(categoryFkInt.equals(31)) {
249
							Set<DescriptionElementBase> descriptionElements = taxonDescription.getElements();
250
							for (DescriptionElementBase descriptionElement : descriptionElements) {
251
								String featureString = descriptionElement.getFeature().getRepresentation(Language.DEFAULT()).getLabel();
252
								if (descriptionElement instanceof TextData && featureString.equals("Systematics")) { // TODO: test
253
									textData = (TextData)descriptionElement;
254
									String factTextStr = textData.getText(Language.DEFAULT());
255
									// FIXME: Removing newlines doesn't work
256
									if (factTextStr.contains("\\r\\n")) {
257
										factTextStr = factTextStr.replaceAll("\\r\\n","");
258
									}
259
									StringBuilder factText = new StringBuilder(factTextStr);
260
									factText.append(fact);
261
									fact = factText.toString();
262
									newTextData = false;
263
									break;
264
								}
265
							}
266
						}
267

    
268
						if(newTextData == true)	{
269
							textData = TextData.NewInstance();
270
						}
271

    
272
						//for diptera database
273
						if (categoryFkInt.equals(99) && notes.contains("<OriginalName>")){
274
//							notes = notes.replaceAll("<OriginalName>", "");
275
//							notes = notes.replaceAll("</OriginalName>", "");
276
							fact = notes + ": " +  fact ;
277
						}
278
						//for E+M maps
279
						if (categoryFkInt.equals(14) && state.getConfig().isRemoveHttpMapsAnchor() && fact.contains("<a href")){
280
							//example <a href="http://euromed.luomus.fi/euromed_map.php?taxon=280629&size=medium">distribution</a>
281
							fact = fact.replace("<a href=\"", "").replace("\">distribution</a>", "");
282
						}
283

    
284
						//TODO textData.putText(fact, bmiConfig.getFactLanguage());  //doesn't work because  bmiConfig.getFactLanguage() is not not a persistent Language Object
285
						//throws  in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: eu.etaxonomy.cdm.model.common.Language; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: eu.etaxonomy.cdm.model.common.Language
286
						if (! taxonDescription.isImageGallery()){
287
							textData.putText(Language.DEFAULT(), fact);
288
							textData.setFeature(feature);
289
						}
290

    
291
						//reference
292
						Reference citation = null;
293
						String factRefFk = String.valueOf(factRefFkInt);
294
						if (factRefFkInt != null){
295
							citation = refMap.get(factRefFk);
296
						}
297
						if (citation == null && (factRefFkInt != null)){
298
							logger.warn("Citation not found in referenceMap: " + factRefFk);
299
							success = false;
300
						}
301
						if (citation != null || StringUtils.isNotBlank(details)){
302
							DescriptionElementSource originalSource = DescriptionElementSource.NewPrimarySourceInstance(citation, details);
303
							textData.addSource(originalSource);
304
						}
305
						taxonDescription.addElement(textData);
306
						//doubtfulFlag
307
						if (doubtfulFlag){
308
							textData.addMarker(Marker.NewInstance(MarkerType.IS_DOUBTFUL(), true));
309
						}
310
						//publisheFlag
311
						String strPublishFlag = "publishFlag";
312
						boolean publishFlagExists = state.getConfig().getSource().checkColumnExists(dbTableName, strPublishFlag);
313
						if (publishFlagExists){
314
							Boolean publishFlag = rs.getBoolean(strPublishFlag);
315
							textData.addMarker(Marker.NewInstance(MarkerType.PUBLISH(), publishFlag));
316
						}
317

    
318
						//Sequence
319
						Integer sequence = rs.getInt("Sequence");
320
						if (sequence != null && sequence != 999){
321
							String strSequence = String.valueOf(sequence);
322
							strSequence = SEQUENCE_PREFIX + strSequence;
323
							//TODO make it an Extension when possible
324
							//Extension datesExtension = Extension.NewInstance(textData, strSequence, ExtensionType.ORDER());
325
							Annotation annotation = Annotation.NewInstance(strSequence, Language.DEFAULT());
326
							textData.addAnnotation(annotation);
327
						}
328

    
329
						//						if (categoryFkObj == FACT_DESCRIPTION){
330
	//						//;
331
	//					}else if (categoryFkObj == FACT_OBSERVATION){
332
	//						//;
333
	//					}else if (categoryFkObj == FACT_DISTRIBUTION_EM){
334
	//						//
335
	//					}else {
336
	//						//TODO
337
	//						//logger.warn("FactCategory " + categoryFk + " not yet implemented");
338
	//					}
339

    
340
						//notes
341
						doCreatedUpdatedNotes(state, textData, rs);
342
						doId(state, textData, factId, "Fact");
343

    
344
						//TODO
345
						//Designation References -> unclear how to map to CDM
346

    
347

    
348
						//sequence -> textData is not an identifiable entity therefore extensions are not possible
349
						//fact category better
350

    
351
						taxaToSave.add(taxonBase);
352
					}
353
				} catch (Exception re){
354
					logger.error("An exception occurred during the facts import");
355
					re.printStackTrace();
356
					success = false;
357
				}
358
				//put
359
			}
360
			logger.info("Facts handled: " + (i-1));
361
			logger.info("Taxa to save: " + taxaToSave.size());
362
			getTaxonService().save(taxaToSave);
363
		}catch(SQLException e){
364
			throw new RuntimeException(e);
365
		}
366
		return success;
367
	}
368

    
369
	private TaxonDescription getMyTaxonDescripion(TaxonBase taxonBase, BerlinModelImportState state, Integer categoryFk, Integer taxonId, int factId, String fact, Reference sourceRef) {
370
		Taxon taxon = null;
371
		if ( taxonBase instanceof Taxon ) {
372
			taxon = (Taxon) taxonBase;
373
		}else{
374
			logger.warn("TaxonBase " + (taxonId==null?"(null)":taxonId) + " for Fact " + factId + " was not of type Taxon but: " + taxonBase.getClass().getSimpleName());
375
			return null;
376
		}
377

    
378
		TaxonDescription taxonDescription = null;
379
		Set<TaxonDescription> descriptionSet= taxon.getDescriptions();
380

    
381
		boolean isImage = false;
382
		Media media = null;
383
		//for diptera images
384
		if (categoryFk == 51){  //TODO check also FactCategory string
385
			isImage = true;
386
			media = Media.NewInstance();
387
			taxonDescription = makeImage(state, fact, media, descriptionSet, taxon);
388

    
389

    
390

    
391
			if (taxonDescription == null){
392
				return null;
393
			}
394

    
395
			TextData textData = null;
396
			for (DescriptionElementBase el:  taxonDescription.getElements()){
397
				if (el.isInstanceOf(TextData.class)){
398
					textData = CdmBase.deproxy(el, TextData.class);
399
				}
400
			}
401
			if (textData == null){
402
				textData = TextData.NewInstance(Feature.IMAGE());
403
				taxonDescription.addElement(textData);
404
			}
405
			textData.addMedia(media);
406
		}
407
		//all others (no image) -> getDescription
408
		else{
409
			for (TaxonDescription desc: descriptionSet){
410
				if (! desc.isImageGallery()){
411
					taxonDescription = desc;
412
				}
413
			}
414
			if (taxonDescription == null){
415
				taxonDescription = TaxonDescription.NewInstance();
416
				taxonDescription.setTitleCache(sourceRef == null ? null : sourceRef.getTitleCache(), true);
417
				taxon.addDescription(taxonDescription);
418
			}
419
		}
420
		return taxonDescription;
421
	}
422

    
423

    
424
	@Override
425
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, BerlinModelImportState state) {
426
		String nameSpace;
427
		Class<?> cdmClass;
428
		Set<String> idSet;
429
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
430

    
431
		try{
432
			Set<String> taxonIdSet = new HashSet<String>();
433
			Set<String> referenceIdSet = new HashSet<String>();
434
			Set<String> refDetailIdSet = new HashSet<String>();
435
			while (rs.next()){
436
				handleForeignKey(rs, taxonIdSet, "taxonId");
437
				handleForeignKey(rs, referenceIdSet, "FactRefFk");
438
				handleForeignKey(rs, referenceIdSet, "PTDesignationRefFk");
439
				handleForeignKey(rs, refDetailIdSet, "FactRefDetailFk");
440
				handleForeignKey(rs, refDetailIdSet, "PTDesignationRefDetailFk");
441
		}
442

    
443
			//taxon map
444
			nameSpace = BerlinModelTaxonImport.NAMESPACE;
445
			cdmClass = TaxonBase.class;
446
			idSet = taxonIdSet;
447
			Map<String, TaxonBase> taxonMap = (Map<String, TaxonBase>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
448
			result.put(nameSpace, taxonMap);
449

    
450
			//reference map
451
			nameSpace = BerlinModelReferenceImport.REFERENCE_NAMESPACE;
452
			cdmClass = Reference.class;
453
			idSet = referenceIdSet;
454
			Map<String, Reference> referenceMap = (Map<String, Reference>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
455
			result.put(nameSpace, referenceMap);
456

    
457
			//refDetail map
458
			nameSpace = BerlinModelRefDetailImport.REFDETAIL_NAMESPACE;
459
			cdmClass = Reference.class;
460
			idSet = refDetailIdSet;
461
			Map<String, Reference> refDetailMap= (Map<String, Reference>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
462
			result.put(nameSpace, refDetailMap);
463

    
464
		} catch (SQLException e) {
465
			throw new RuntimeException(e);
466
	}
467
		return result;
468
	}
469

    
470

    
471
	/**
472
	 * @param state
473
	 * @param media
474
	 * @param media
475
	 * @param descriptionSet
476
	 *
477
	 */
478
	private TaxonDescription makeImage(BerlinModelImportState state, String fact, Media media, Set<TaxonDescription> descriptionSet, Taxon taxon) {
479
		TaxonDescription taxonDescription = null;
480
		Reference sourceRef = state.getTransactionalSourceReference();
481
		Integer size = null;
482
		ImageInfo imageInfo = null;
483
		URI uri;
484
		try {
485
			uri = new URI(fact.trim());
486
		} catch (URISyntaxException e) {
487
			logger.warn("URISyntaxException. Image could not be imported: " + fact);
488
			return null;
489
		}
490
		try {
491
			imageInfo = ImageInfo.NewInstance(uri, 0);
492
		} catch (IOException e) {
493
			logger.error("IOError reading image metadata." , e);
494
		} catch (HttpException e) {
495
			logger.error("HttpException reading image metadata." , e);
496
		}
497
		MediaRepresentation mediaRepresentation = MediaRepresentation.NewInstance(imageInfo.getMimeType(), null);
498
		media.addRepresentation(mediaRepresentation);
499
		ImageFile image = ImageFile.NewInstance(uri, size, imageInfo);
500
		mediaRepresentation.addRepresentationPart(image);
501

    
502
		taxonDescription = taxon.getOrCreateImageGallery(sourceRef == null ? null :sourceRef.getTitleCache());
503

    
504
		return taxonDescription;
505
	}
506

    
507
	private TaxonBase getTaxon(Map<String, TaxonBase> taxonMap, Integer taxonIdObj, Number taxonId){
508
		if (taxonIdObj != null){
509
			return taxonMap.get(String.valueOf(taxonId));
510
		}else{
511
			return null;
512
		}
513

    
514
	}
515

    
516
	private Feature getFeature(Map<Integer, Feature>  featureMap, Integer categoryFkInt){
517
		if (categoryFkInt != null){
518
			return featureMap.get(categoryFkInt);
519
		}else{
520
			return null;
521
		}
522

    
523
	}
524

    
525
	@Override
526
	protected boolean doCheck(BerlinModelImportState state){
527
		IOValidator<BerlinModelImportState> validator = new BerlinModelFactsImportValidator();
528
		return validator.validate(state);
529
	}
530

    
531
	@Override
532
	protected boolean isIgnore(BerlinModelImportState state){
533
		return ! state.getConfig().isDoFacts();
534
	}
535

    
536

    
537

    
538
}
(4-4/21)