Project

General

Profile

Download (30 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.IOriginalSource;
38
import eu.etaxonomy.cdm.model.common.ISourceable;
39
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
40
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
41
import eu.etaxonomy.cdm.model.common.Language;
42
import eu.etaxonomy.cdm.model.common.Marker;
43
import eu.etaxonomy.cdm.model.common.MarkerType;
44
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
45
import eu.etaxonomy.cdm.model.common.TermVocabulary;
46
import eu.etaxonomy.cdm.model.description.DescriptionBase;
47
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
48
import eu.etaxonomy.cdm.model.description.Feature;
49
import eu.etaxonomy.cdm.model.description.PresenceTerm;
50
import eu.etaxonomy.cdm.model.description.TaxonDescription;
51
import eu.etaxonomy.cdm.model.description.TextData;
52
import eu.etaxonomy.cdm.model.location.NamedArea;
53
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
54
import eu.etaxonomy.cdm.model.location.NamedAreaType;
55
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
56
import eu.etaxonomy.cdm.model.media.ImageFile;
57
import eu.etaxonomy.cdm.model.media.Media;
58
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
59
import eu.etaxonomy.cdm.model.name.NonViralName;
60
import eu.etaxonomy.cdm.model.name.Rank;
61
import eu.etaxonomy.cdm.model.reference.Reference;
62
import eu.etaxonomy.cdm.model.taxon.Classification;
63
import eu.etaxonomy.cdm.model.taxon.Synonym;
64
import eu.etaxonomy.cdm.model.taxon.Taxon;
65
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
66

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

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

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

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

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

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

    
368

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

    
442

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

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

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

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

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

    
701

    
702

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

    
765
	
766

    
767
	/**
768
	 * @param derivedUnitFacade
769
	 * @param multimediaObject
770
	 * @throws MalformedURLException
771
	 */
772
	protected Media getImageMedia(String multimediaObject, boolean readDataFromUrl) throws MalformedURLException {
773
		if( multimediaObject == null){
774
			return null;
775
		} else {
776
			ImageInfo imageInfo = null;
777
			URI uri;
778
			try {
779
				uri = new URI(multimediaObject);
780
				try {
781
					if (readDataFromUrl){
782
						imageInfo = ImageInfo.NewInstance(uri, 0);
783
					}
784
				} catch (Exception e) {
785
					String message = "An error occurred when trying to read image meta data: " +  e.getMessage();
786
					logger.warn(message);
787
				}
788
				ImageFile imageFile = ImageFile.NewInstance(uri, null, imageInfo);
789
				MediaRepresentation representation = MediaRepresentation.NewInstance();
790
				if(imageInfo != null){
791
					representation.setMimeType(imageInfo.getMimeType());
792
				}
793
				representation.addRepresentationPart(imageFile);
794
				Media media = Media.NewInstance();
795
				media.addRepresentation(representation);
796
				return media;
797
			} catch (URISyntaxException e1) {
798
				String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " +  multimediaObject;
799
				logger.warn(message);
800
				return null;
801
			}
802
		}
803
	}
804

    
805
	
806
}
(9-9/48)