Project

General

Profile

Download (30.3 KB) Statistics
| Branch: | Tag: | 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.common;
11

    
12
import java.net.MalformedURLException;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.sql.ResultSet;
16
import java.sql.SQLException;
17
import java.util.Arrays;
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22

    
23
import org.apache.log4j.Logger;
24

    
25
import eu.etaxonomy.cdm.api.service.pager.Pager;
26
import eu.etaxonomy.cdm.common.CdmUtils;
27
import eu.etaxonomy.cdm.common.media.ImageInfo;
28
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
29
import eu.etaxonomy.cdm.io.common.mapping.IInputTransformer;
30
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
31
import eu.etaxonomy.cdm.io.markup.MarkupTransformer;
32
import eu.etaxonomy.cdm.model.common.AnnotationType;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
35
import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
36
import eu.etaxonomy.cdm.model.common.ExtensionType;
37
import eu.etaxonomy.cdm.model.common.Figure;
38
import eu.etaxonomy.cdm.model.common.IOriginalSource;
39
import eu.etaxonomy.cdm.model.common.ISourceable;
40
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
41
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
42
import eu.etaxonomy.cdm.model.common.Language;
43
import eu.etaxonomy.cdm.model.common.Marker;
44
import eu.etaxonomy.cdm.model.common.MarkerType;
45
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
46
import eu.etaxonomy.cdm.model.common.TermVocabulary;
47
import eu.etaxonomy.cdm.model.description.DescriptionBase;
48
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
49
import eu.etaxonomy.cdm.model.description.Feature;
50
import eu.etaxonomy.cdm.model.description.PresenceTerm;
51
import eu.etaxonomy.cdm.model.description.TaxonDescription;
52
import eu.etaxonomy.cdm.model.description.TextData;
53
import eu.etaxonomy.cdm.model.location.NamedArea;
54
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
55
import eu.etaxonomy.cdm.model.location.NamedAreaType;
56
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
57
import eu.etaxonomy.cdm.model.media.ImageFile;
58
import eu.etaxonomy.cdm.model.media.Media;
59
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
60
import eu.etaxonomy.cdm.model.name.NonViralName;
61
import eu.etaxonomy.cdm.model.name.Rank;
62
import eu.etaxonomy.cdm.model.reference.Reference;
63
import eu.etaxonomy.cdm.model.taxon.Classification;
64
import eu.etaxonomy.cdm.model.taxon.Synonym;
65
import eu.etaxonomy.cdm.model.taxon.Taxon;
66
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67

    
68
/**
69
 * @author a.mueller
70
 * @created 01.07.2008
71
 * @version 1.0
72
 */
73
public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE extends ImportStateBase> extends CdmIoBase<STATE> implements ICdmImport<CONFIG, STATE>{
74
	private static Logger logger = Logger.getLogger(CdmImportBase.class);
75
	
76
	protected static final boolean CREATE = true;
77
	protected static final boolean IMAGE_GALLERY = true;
78
	protected static final boolean READ_MEDIA_DATA = true;
79

    
80
	public static final UUID uuidUserDefinedNamedAreaLevelVocabulary = UUID.fromString("255144da-8d95-457e-a327-9752a8f85e5a");
81
	public static final UUID uuidUserDefinedNamedAreaVocabulary = UUID.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
82
	public static final UUID uuidUserDefinedExtensionTypeVocabulary = UUID.fromString("e28c1394-1be8-4847-8b81-ab44eb6d5bc8");
83
	public static final UUID uuidUserDefinedReferenceSystemVocabulary = UUID.fromString("467591a3-10b4-4bf1-9239-f06ece33e90a");
84
	public static final UUID uuidUserDefinedFeatureVocabulary = UUID.fromString("fe5fccb3-a2f2-4b97-b199-6e2743cf1627");
85
	public static final UUID uuidUserDefinedAnnotationTypeVocabulary = UUID.fromString("cd9ecdd2-9cae-4890-9032-ad83293ae883");
86
	public static final UUID uuidUserDefinedMarkerTypeVocabulary = UUID.fromString("5f02a261-fd7d-4fce-bbe4-21472de8cd51");
87
	
88
	
89
	private static final String UuidOnly = "UUIDOnly";
90
	private static final String UuidLabel = "UUID or label";
91
	private static final String UuidLabelAbbrev = "UUID, label or abbreviation";
92
	private static final String UuidAbbrev = "UUID or abbreviation";
93
	
94
	public enum TermMatchMode{
95
		UUID_ONLY(0, UuidOnly)
96
		,UUID_LABEL(1, UuidLabel)
97
		,UUID_LABEL_ABBREVLABEL(2, UuidLabelAbbrev)
98
		,UUID_ABBREVLABEL(3, UuidAbbrev)
99
		;
100
		
101
		
102
		private int id;
103
		private String representation;
104
		private TermMatchMode(int id, String representation){
105
			this.id = id;
106
			this.representation = representation;
107
		}
108
		public int getId() {
109
			return id;
110
		}
111
		public String getRepresentation() {
112
			return representation;
113
		}
114
		public TermMatchMode valueOf(int id){
115
			switch (id){
116
				case 0: return UUID_ONLY;
117
				case 1: return UUID_LABEL;
118
				case 2: return UUID_LABEL_ABBREVLABEL;
119
				case 3: return UUID_ABBREVLABEL;
120
				default: return UUID_ONLY;
121
			}
122
 		}
123
		
124
		
125
	}
126
	
127
	protected Classification makeTree(STATE state, Reference reference){
128
		Reference ref = CdmBase.deproxy(reference, Reference.class);
129
		String treeName = "Classification (Import)";
130
		if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){
131
			treeName = ref.getTitleCache();
132
		}
133
		Classification tree = Classification.NewInstance(treeName);
134
		tree.setReference(ref);
135
		
136

    
137
		// use defined uuid for first tree
138
		CONFIG config = (CONFIG)state.getConfig();
139
		if (state.countTrees() < 1 ){
140
			tree.setUuid(config.getClassificationUuid());
141
		}
142
		getClassificationService().save(tree);
143
		state.putTree(ref, tree);
144
		return tree;
145
	}
146
	
147
	
148
	/**
149
	 * Alternative memory saving method variant of
150
	 * {@link #makeTree(STATE state, Reference ref)} which stores only the
151
	 * UUID instead of the full tree in the <code>ImportStateBase</code> by 
152
	 * using <code>state.putTreeUuid(ref, tree);</code>
153
	 * 
154
	 * @param state
155
	 * @param ref
156
	 * @return
157
	 */
158
	protected Classification makeTreeMemSave(STATE state, Reference ref){
159
		String treeName = "Classification (Import)";
160
		if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){
161
			treeName = ref.getTitleCache();
162
		}
163
		Classification tree = Classification.NewInstance(treeName);
164
		tree.setReference(ref);
165
		
166

    
167
		// use defined uuid for first tree
168
		CONFIG config = (CONFIG)state.getConfig();
169
		if (state.countTrees() < 1 ){
170
			tree.setUuid(config.getClassificationUuid());
171
		}
172
		getClassificationService().save(tree);
173
		state.putTreeUuid(ref, tree);
174
		return tree;
175
	}
176
	
177
	
178
	protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
179
		return getExtensionType(state, uuid, label, text, labelAbbrev, null);
180
	}
181
	protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<ExtensionType> voc){
182
		if (uuid == null){
183
			uuid = UUID.randomUUID();
184
		}
185
		ExtensionType extensionType = state.getExtensionType(uuid);
186
		if (extensionType == null){
187
			extensionType = (ExtensionType)getTermService().find(uuid);
188
			if (extensionType == null){
189
				extensionType = ExtensionType.NewInstance(text, label, labelAbbrev);
190
				extensionType.setUuid(uuid);
191
				if (voc == null){
192
					boolean isOrdered = false;
193
					voc = getVocabulary(uuidUserDefinedExtensionTypeVocabulary, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered, extensionType);
194
				}
195
				voc.addTerm(extensionType);
196
				getTermService().saveOrUpdate(extensionType);
197
			}
198
			state.putExtensionType(extensionType);
199
		}
200
		return extensionType;
201
	}
202
	
203
	
204
	protected MarkerType getMarkerType(STATE state, String keyString) {
205
		IInputTransformer transformer = state.getTransformer();
206
		MarkerType markerType = null;
207
		try {
208
			markerType = transformer.getMarkerTypeByKey(keyString);
209
		} catch (UndefinedTransformerMethodException e) {
210
			logger.info("getMarkerTypeByKey not yet implemented for this import");
211
		}
212
		if (markerType == null ){
213
			UUID uuid;
214
			try {
215
				uuid = transformer.getMarkerTypeUuid(keyString);
216
				return getMarkerType(state, uuid, keyString, keyString, keyString);
217
			} catch (UndefinedTransformerMethodException e) {
218
				logger.warn("getMarkerTypeUuid not yet implemented for this import");
219
			}
220
		}
221
		return null;
222
	}
223
	
224
	protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
225
		return getMarkerType(state, uuid, label, text, labelAbbrev, null);
226
	}
227

    
228
	
229
	protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<MarkerType> voc){
230
		if (uuid == null){
231
			uuid = UUID.randomUUID();
232
		}
233
		MarkerType markerType = state.getMarkerType(uuid);
234
		if (markerType == null){
235
			markerType = (MarkerType)getTermService().find(uuid);
236
			if (markerType == null){
237
				markerType = MarkerType.NewInstance(label, text, labelAbbrev);
238
				markerType.setUuid(uuid);
239
				if (voc == null){
240
					boolean isOrdered = false;
241
					voc = getVocabulary(uuidUserDefinedMarkerTypeVocabulary, "User defined vocabulary for marker types", "User Defined Marker Types", null, null, isOrdered, markerType);
242
				}
243
				voc.addTerm(markerType);
244
				getTermService().save(markerType);
245
			}
246
			state.putMarkerType(markerType);
247
		}
248
		return markerType;
249
	}
250
	
251
	protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<AnnotationType> voc){
252
		if (uuid == null){
253
			uuid = UUID.randomUUID();
254
		}
255
		AnnotationType annotationType = state.getAnnotationType(uuid);
256
		if (annotationType == null){
257
			annotationType = (AnnotationType)getTermService().find(uuid);
258
			if (annotationType == null){
259
				annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
260
				annotationType.setUuid(uuid);
261
				if (voc == null){
262
					boolean isOrdered = false;
263
					voc = getVocabulary(uuidUserDefinedAnnotationTypeVocabulary, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered, annotationType);
264
				}
265
				
266
				voc.addTerm(annotationType);
267
				getTermService().save(annotationType);
268
			}
269
			state.putAnnotationType(annotationType);
270
		}
271
		return annotationType;
272
	}
273
	
274
	
275
	protected ReferenceSystem getReferenceSystem(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary voc){
276
		if (uuid == null){
277
			uuid = UUID.randomUUID();
278
		}
279
		ReferenceSystem refSystem = state.getReferenceSystem(uuid);
280
		if (refSystem == null){
281
			refSystem = (ReferenceSystem)getTermService().find(uuid);
282
			if (refSystem == null){
283
				refSystem = ReferenceSystem.NewInstance(text, label, labelAbbrev);
284
				if (voc == null){
285
					boolean isOrdered = false;
286
					voc = getVocabulary(uuidUserDefinedReferenceSystemVocabulary, "User defined vocabulary for named areas", "User Defined Reference System", null, null, isOrdered, refSystem);
287
				}
288
				voc.addTerm(refSystem);
289
				refSystem.setUuid(uuid);
290
				getTermService().save(refSystem);
291
			}
292
			state.putReferenceSystem(refSystem);
293
		}
294
		return refSystem;
295
		
296
	}
297
	
298
	/**
299
	 * Returns a named area for a given uuid by first . If the named area does not
300
	 * @param state
301
	 * @param uuid
302
	 * @param label
303
	 * @param text
304
	 * @param labelAbbrev
305
	 * @param areaType
306
	 * @param level
307
	 * @return
308
	 */
309
	protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level){
310
		return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, null, null);
311
	}
312

    
313
	protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc, TermMatchMode matchMode){
314
		if (uuid == null){
315
			uuid = UUID.randomUUID();
316
		}
317
		if (matchMode == null){
318
			matchMode = TermMatchMode.UUID_ONLY;
319
		}
320
		NamedArea namedArea = state.getNamedArea(uuid);
321
		if (namedArea == null){
322
			//TODO matching still experimental
323
			namedArea = (NamedArea)getTermService().find(uuid);
324
			if (namedArea == null && matchMode.equals(TermMatchMode.UUID_LABEL)){
325
				logger.warn("UUID_LABEL not yet implemented");
326
			}
327
			if (namedArea == null && matchMode.equals(TermMatchMode.UUID_ABBREVLABEL)){
328
				Pager<NamedArea> areaPager = getTermService().findByRepresentationAbbreviation(labelAbbrev, NamedArea.class, null, null);
329
				namedArea = findBestMatchingArea(areaPager, uuid, label, text, labelAbbrev, areaType, level, voc);
330
			}
331
			if (namedArea == null && matchMode.equals(TermMatchMode.UUID_LABEL_ABBREVLABEL)){
332
				logger.warn("UUID_LABEL not yet implemented");
333
			}
334
			
335
			if (namedArea == null){
336
				namedArea = NamedArea.NewInstance(text, label, labelAbbrev);
337
				if (voc == null){
338
					boolean isOrdered = true;
339
					voc = getVocabulary(uuidUserDefinedNamedAreaVocabulary, "User defined vocabulary for named areas", "User Defined Named Areas", null, null, isOrdered, namedArea);
340
				}
341
				voc.addTerm(namedArea);
342
				namedArea.setType(areaType);
343
				namedArea.setLevel(level);
344
				namedArea.setUuid(uuid);
345
				getTermService().save(namedArea);
346
			}
347
			state.putNamedArea(namedArea);
348
		}
349
		return namedArea;
350
	}
351
	
352
	
353
	private NamedArea findBestMatchingArea(Pager<NamedArea> areaPager, UUID uuid, String label, String text, String abbrev,
354
			NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc) {
355
		// TODO preliminary implementation
356
		List<NamedArea> list = areaPager.getRecords();
357
		if (list.size() == 0){
358
			return null;
359
		}else if (list.size() == 1){
360
			return list.get(0);
361
		}else if (list.size() > 1){
362
			String message = "There is more than 1 matching area for %s, %s, %s. As a preliminary implementation I take the first";
363
			message = String.format(message, label, abbrev, text);
364
			logger.warn(message);
365
			return list.get(0);
366
		}
367
		return null;
368
	}
369

    
370

    
371
	protected NamedAreaLevel getNamedAreaLevel(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<NamedAreaLevel> voc){
372
		if (uuid == null){
373
			uuid = UUID.randomUUID();
374
		}
375
		NamedAreaLevel namedAreaLevel = state.getNamedAreaLevel(uuid);
376
		if (namedAreaLevel == null){
377
			namedAreaLevel = CdmBase.deproxy(getTermService().find(uuid), NamedAreaLevel.class);
378
			if (namedAreaLevel == null){
379
				namedAreaLevel = NamedAreaLevel.NewInstance(text, label, labelAbbrev);
380
				if (voc == null){
381
					boolean isOrdered = true;
382
					voc = getVocabulary(uuidUserDefinedNamedAreaLevelVocabulary, "User defined vocabulary for named area levels", "User Defined Named Area Levels", null, null, isOrdered, namedAreaLevel);
383
				}
384
				voc.addTerm(namedAreaLevel);
385
				namedAreaLevel.setUuid(uuid);
386
				getTermService().save(namedAreaLevel);
387
			}
388
			state.putNamedAreaLevel(namedAreaLevel);
389
		}
390
		return namedAreaLevel;
391
	}
392
	
393
	
394
	/**
395
	 * Returns a feature if it exists, null otherwise.
396
	 * @see #getFeature(ImportStateBase, UUID, String, String, String, TermVocabulary)
397
	 * @param state
398
	 * @param uuid
399
	 * @return
400
	 */
401
	protected Feature getFeature(STATE state, UUID uuid){
402
		return getFeature(state, uuid, null, null, null, null);
403
	}
404
	
405
	/**
406
	 * Returns a feature for a given uuid by first checking if the uuid has already been used in this import, if not
407
	 * checking if the feature exists in the database, if not creating it anew (with vocabulary etc.).
408
	 * If label, text and labelAbbrev are all <code>null</code> no feature is created.
409
	 * @param state
410
	 * @param uuid
411
	 * @param label
412
	 * @param text
413
	 * @param labelAbbrev
414
	 * @return
415
	 */
416
	protected Feature getFeature(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<Feature> voc){
417
		if (uuid == null){
418
			return null;
419
		}
420
		Feature feature = state.getFeature(uuid);
421
		if (feature == null){
422
			feature = (Feature)getTermService().find(uuid);
423
			if (feature == null && ! hasNoLabel(label, text, labelAbbrev)){
424
				feature = Feature.NewInstance(text, label, labelAbbrev);
425
				feature.setUuid(uuid);
426
				feature.setSupportsTextData(true);
427
//				UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8"); 
428
				if (voc == null){
429
					boolean isOrdered = false;
430
					voc = getVocabulary(uuidUserDefinedFeatureVocabulary, "User defined vocabulary for features", "User Defined Features", null, null, isOrdered, feature);
431
				}
432
				voc.addTerm(feature);
433
				getTermService().save(feature);
434
			}
435
			state.putFeature(feature);
436
		}
437
		return feature;
438
	}
439
	
440
	private boolean hasNoLabel(String label, String text, String labelAbbrev) {
441
		return label == null && text == null && labelAbbrev == null;
442
	}
443

    
444

    
445
	/**
446
	 * Returns a presence term for a given uuid by first ...
447
	 * @param state
448
	 * @param uuid
449
	 * @param label
450
	 * @param text
451
	 * @param labelAbbrev
452
	 * @return
453
	 */
454
	protected PresenceTerm getPresenceTerm(STATE state, UUID uuid, String label, String text, String labelAbbrev){
455
		if (uuid == null){
456
			return null;
457
		}
458
		PresenceTerm presenceTerm = state.getPresenceTerm(uuid);
459
		if (presenceTerm == null){
460
			presenceTerm = (PresenceTerm)getTermService().find(uuid);
461
			if (presenceTerm == null){
462
				presenceTerm = PresenceTerm.NewInstance(text, label, labelAbbrev);
463
				presenceTerm.setUuid(uuid);
464
				//set vocabulary ; FIXME use another user-defined vocabulary
465
				UUID uuidPresenceVoc = UUID.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05"); 
466
				TermVocabulary<PresenceTerm> voc = getVocabularyService().find(uuidPresenceVoc);
467
				voc.addTerm(presenceTerm);
468
				getTermService().save(presenceTerm);
469
			}
470
			state.putPresenceTerm(presenceTerm);
471
		}
472
		return presenceTerm;
473
	}
474

    
475
	/**
476
	 * Returns a language for a given uuid by first ...
477
	 * @param state
478
	 * @param uuid
479
	 * @param label
480
	 * @param text
481
	 * @param labelAbbrev
482
	 * @return
483
	 */
484
	protected Language getLanguage(STATE state, UUID uuid, String label, String text, String labelAbbrev){
485
		if (uuid == null){
486
			return null;
487
		}
488
		Language language = state.getLanguage(uuid);
489
		if (language == null){
490
			language = (Language)getTermService().find(uuid);
491
			if (language == null){
492
				language = Language.NewInstance(text, label, labelAbbrev);
493
				
494
				language.setUuid(uuid);
495
				//set vocabulary ; FIXME use another user-defined vocabulary
496
				UUID uuidLanguageVoc = UUID.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de"); 
497
				TermVocabulary<Language> voc = getVocabularyService().find(uuidLanguageVoc);
498
				voc.addTerm(language);
499
				getTermService().save(language);
500
			}
501
			state.putLanguage(language);
502
		}
503
		return language;
504
	}
505
	
506

    
507
	/**
508
	 * @param uuid 
509
	 * @return
510
	 * 
511
	 */
512
	protected <T extends DefinedTermBase> TermVocabulary<T> getVocabulary(UUID uuid, String text, String label, String abbrev, URI termSourceUri, boolean isOrdered, T type) {
513
		List<String> propPath = Arrays.asList(new String[]{"terms"});
514
		TermVocabulary<T> voc = getVocabularyService().load(uuid, propPath);
515
		if (voc == null){
516
			if (isOrdered){
517
				voc = OrderedTermVocabulary.NewInstance(text, label, abbrev, termSourceUri);
518
			}else{
519
				voc = TermVocabulary.NewInstance(text, label, abbrev, termSourceUri);
520
			}
521
			voc.setUuid(uuid);
522
			getVocabularyService().save(voc);
523
		}
524
		return voc;
525
	}
526
	
527
	/**
528
	 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
529
	 * If cdmBase is not sourceable nothing happens.
530
	 * TODO Move to DbImportBase once this exists.
531
	 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
532
	 * @param rs
533
	 * @param cdmBase
534
	 * @param dbIdAttribute
535
	 * @param namespace
536
	 * @param citation
537
	 * @throws SQLException
538
	 */
539
	public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, Reference citation)  {
540
		if (cdmBase instanceof ISourceable ){
541
			IOriginalSource source;
542
			ISourceable sourceable = (ISourceable)cdmBase;
543
			Object id = idAttributeValue;
544
			String strId = String.valueOf(id);
545
			String microCitation = null;
546
			if (cdmBase instanceof IdentifiableEntity){
547
				source = IdentifiableSource.NewInstance(strId, namespace, citation, microCitation);
548
			}else if (cdmBase instanceof DescriptionElementBase){
549
				source = DescriptionElementSource.NewInstance(strId, namespace, citation, microCitation);
550
			}else{
551
				logger.warn("ISourceable not beeing identifiable entities or description element base are not yet supported. CdmBase is of type " + cdmBase.getClass().getName() + ". Original source not added.");
552
				return;
553
			}
554
			sourceable.addSource(source);
555
		}else if (cdmBase != null){
556
			logger.warn("Sourced object does not implement ISourceable: " + cdmBase.getClass() + "," + cdmBase.getUuid());
557
		}else{
558
			logger.warn("Sourced object is null");
559
		}
560
	}
561
	
562
	/**
563
	 * @see #addOriginalSource(CdmBase, Object, String, Reference)
564
	 * @param rs
565
	 * @param cdmBase
566
	 * @param dbIdAttribute
567
	 * @param namespace
568
	 * @param citation
569
	 * @throws SQLException
570
	 */
571
	public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, Reference citation) throws SQLException {
572
		Object id = rs.getObject(dbIdAttribute);
573
		addOriginalSource(cdmBase, id, namespace, citation);
574
	}
575
	
576

    
577
	/**
578
	 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
579
	 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
580
	 * If the name is an autonym and has no combination author/basionym author the authors are taken from
581
	 * the parent.
582
	 * @param parentTaxon
583
	 * @param childTaxon
584
	 */
585
	protected void fillMissingEpithetsForTaxa(Taxon parentTaxon, Taxon childTaxon) {
586
		NonViralName parentName = HibernateProxyHelper.deproxy(parentTaxon.getName(), NonViralName.class);
587
		NonViralName childName = HibernateProxyHelper.deproxy(childTaxon.getName(), NonViralName.class);
588
		fillMissingEpithets(parentName, childName);
589
	}
590
	
591
	/**
592
	 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
593
	 * or <i>species</i> respectively the according epithets are taken from the parent name.
594
	 * If the name is an autonym and has no combination author/basionym author the authors are taken from
595
	 * the parent.
596
	 * @param parentTaxon
597
	 * @param childTaxon
598
	 */
599
	protected void fillMissingEpithets(NonViralName parentName, NonViralName childName) {
600
		if (CdmUtils.isEmpty(childName.getGenusOrUninomial()) && childName.getRank().isLower(Rank.GENUS()) ){
601
			childName.setGenusOrUninomial(parentName.getGenusOrUninomial());
602
		}
603
		
604
		if (CdmUtils.isEmpty(childName.getSpecificEpithet()) && childName.getRank().isLower(Rank.SPECIES()) ){
605
			childName.setSpecificEpithet(parentName.getSpecificEpithet());
606
		}
607
		if (childName.isAutonym() && childName.getCombinationAuthorTeam() == null && childName.getBasionymAuthorTeam() == null ){
608
			childName.setCombinationAuthorTeam(parentName.getCombinationAuthorTeam());
609
			childName.setBasionymAuthorTeam(parentName.getBasionymAuthorTeam());
610
		}	
611
	}
612
	
613
	/**
614
	 * Returns the taxon description for a taxon. If there are multiple taxon descriptions
615
	 * an arbitrary one is chosen.
616
	 * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>
617
	 * is <code>true</code>.
618
	 * @param createNewIfNotExists
619
	 * @param isImageGallery if true only taxon description being image galleries are considered.
620
	 * If false only taxon description being no image galleries are considered.
621
	 * @return
622
	 */
623
	public TaxonDescription getTaxonDescription(Taxon taxon, boolean isImageGallery, boolean createNewIfNotExists) {
624
		Reference ref = null;
625
		return getTaxonDescription(taxon, ref, isImageGallery, createNewIfNotExists);
626
	}
627
	
628
	/**
629
	 * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}
630
	 * Only matches a description if the given reference is a source of the description.<BR>
631
	 * If a new description is created the given reference will be added as a source.
632
	 * 
633
	 * @see #getTaxonDescription(Taxon, boolean, boolean)
634
	 */
635
	public TaxonDescription getTaxonDescription(Taxon taxon, Reference ref, boolean isImageGallery, boolean createNewIfNotExists) {
636
		TaxonDescription result = null;
637
		Set<TaxonDescription> descriptions= taxon.getDescriptions();
638
		for (TaxonDescription description : descriptions){
639
			if (description.isImageGallery() == isImageGallery){
640
				if (hasCorrespondingSource(ref, description)){
641
					result = description;
642
					break;
643
				}
644
			}
645
		}
646
		if (result == null && createNewIfNotExists){
647
			result = TaxonDescription.NewInstance(taxon);
648
			result.setImageGallery(isImageGallery);
649
			if (ref != null){
650
				result.addSource(null, null, ref, null);
651
			}
652
		}
653
		return result;
654
	}
655
	
656

    
657
	/**
658
	 * Returns the textdata that holds general information about a feature for a taxon description.
659
	 * This is mainly necessary for descriptions that have more than one description element for
660
	 * a given feature such as 'distribution', 'description' or 'common name'. It may also hold
661
	 * for hierarchical features where no description element exists for a higher hierarchie level.
662
	 * Example: the description feature has subfeatures. But some information like authorship, figures,
663
	 * sources need to be added to the description itself.
664
	 * Currently a feature placeholder is marked by a marker of type 'feature placeholder'. Maybe in future
665
	 * there will be a boolean marker in the TextData class itself.
666
	 * @param state 
667
	 * @param feature 
668
	 * @param taxon
669
	 * @param ref
670
	 * @param createIfNotExists
671
	 * @return
672
	 */
673
	protected TextData getFeaturePlaceholder(STATE state, DescriptionBase<?> description, Feature feature, boolean createIfNotExists) {
674
		UUID featurePlaceholderUuid = MarkupTransformer.uuidFeaturePlaceholder;
675
		for (DescriptionElementBase element : description.getElements()){
676
			if (element.isInstanceOf(TextData.class)){
677
				TextData textData = CdmBase.deproxy(element, TextData.class);
678
				if (textData.getFeature() == null || ! textData.getFeature().equals(feature)){
679
					continue;
680
				}
681
				for (Marker marker : textData.getMarkers()){
682
					MarkerType markerType = marker.getMarkerType();
683
					if (markerType != null && 
684
							markerType.getUuid().equals(featurePlaceholderUuid) && 
685
							marker.getValue() == true){
686
						return textData;
687
					}
688
				}
689
			}
690
		}
691
		if (createIfNotExists){
692
			TextData newPlaceholder = TextData.NewInstance(feature);
693
			MarkerType placeholderMarkerType = getMarkerType(state, featurePlaceholderUuid, "Feature Placeholder", "Feature Placeholder", null);
694
			Marker marker = Marker.NewInstance(placeholderMarkerType, true);
695
			newPlaceholder.addMarker(marker);
696
			description.addElement(newPlaceholder);
697
			return newPlaceholder;
698
		}else{
699
			return null;
700
		}
701
	}
702

    
703

    
704

    
705
	/**
706
	 * Returns true, if this description has a source with a citation equal to the given reference.
707
	 * Returns true if the given reference is null.
708
	 * @param ref
709
	 * @param description
710
	 */
711
	private boolean hasCorrespondingSource(Reference ref, TaxonDescription description) {
712
		if (ref != null){
713
			for (IdentifiableSource source : description.getSources()){
714
				if (ref.equals(source.getCitation())){
715
					return true;
716
				}
717
			}
718
			return false;
719
		}
720
		return true;
721
		
722
	}
723
	
724
	
725
	/**
726
	 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
727
	 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
728
	 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
729
	 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the 
730
	 * same secundum reference is returned. If no such single taxon exists an 
731
	 * {@link IllegalStateException illegal state exception} is thrown.  
732
	 * @param taxonBase
733
	 * @return
734
	 */
735
	protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {
736
		if (taxonBase == null){
737
			return null;
738
		}else if(taxonBase.isInstanceOf(Taxon.class)){
739
			return CdmBase.deproxy(taxonBase, Taxon.class);
740
		}else if(taxonBase.isInstanceOf(Synonym.class)){
741
			Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
742
			Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
743
			if (acceptedTaxa.size() == 0){
744
				return null;
745
			}else if (acceptedTaxa.size() == 1){
746
				return acceptedTaxa.iterator().next();
747
			}else{
748
				Reference sec = synonym.getSec();
749
				if (sec != null){
750
					Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();
751
					for (Taxon taxon: acceptedTaxa){
752
						if (sec.equals(taxon.getSec())){
753
							taxaWithSameSec.add(taxon);
754
						}
755
					}
756
					if (taxaWithSameSec.size() == 1){
757
						return taxaWithSameSec.iterator().next();
758
					}
759
				}
760
				throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
761
			}
762
		}else{
763
			throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());
764
		}
765
	}
766

    
767
	
768

    
769
	/**
770
	 * Creates 
771
	 * @param uriString
772
	 * @param readDataFromUrl
773
	 * @see #READ_MEDIA_DATA
774
	 * @return
775
	 * @throws MalformedURLException
776
	 */
777
	protected Media getImageMedia(String uriString, boolean readMediaData, boolean isFigure) throws MalformedURLException {
778
		if( uriString == null){
779
			return null;
780
		} else {
781
			ImageInfo imageInfo = null;
782
			URI uri;
783
			try {
784
				uri = new URI(uriString);
785
				try {
786
					if (readMediaData){
787
						imageInfo = ImageInfo.NewInstance(uri, 0);
788
					}
789
				} catch (Exception e) {
790
					String message = "An error occurred when trying to read image meta data: " +  e.getMessage();
791
					logger.warn(message);
792
					fireWarningEvent(message, "unknown location", 2, 0);
793
				}
794
				ImageFile imageFile = ImageFile.NewInstance(uri, null, imageInfo);
795
				MediaRepresentation representation = MediaRepresentation.NewInstance();
796
				if(imageInfo != null){
797
					representation.setMimeType(imageInfo.getMimeType());
798
					representation.setSuffix(imageInfo.getSuffix());
799
				}
800
				representation.addRepresentationPart(imageFile);
801
				Media media = isFigure ? Figure.NewInstance() : Media.NewInstance();
802
				media.addRepresentation(representation);
803
				return media;
804
			} catch (URISyntaxException e1) {
805
				String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " +  uriString;
806
				logger.warn(message);
807
				fireWarningEvent(message, "unknown location", 4, 0);
808
				return null;
809
			}
810
		}
811
	}
812

    
813
	
814
}
(9-9/48)