Project

General

Profile

Download (27.2 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.model.common.AnnotationType;
32
import eu.etaxonomy.cdm.model.common.CdmBase;
33
import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
34
import eu.etaxonomy.cdm.model.common.ExtensionType;
35
import eu.etaxonomy.cdm.model.common.IOriginalSource;
36
import eu.etaxonomy.cdm.model.common.ISourceable;
37
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
38
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
39
import eu.etaxonomy.cdm.model.common.Language;
40
import eu.etaxonomy.cdm.model.common.MarkerType;
41
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
42
import eu.etaxonomy.cdm.model.common.TermVocabulary;
43
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
44
import eu.etaxonomy.cdm.model.description.Feature;
45
import eu.etaxonomy.cdm.model.description.PresenceTerm;
46
import eu.etaxonomy.cdm.model.description.TaxonDescription;
47
import eu.etaxonomy.cdm.model.location.NamedArea;
48
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
49
import eu.etaxonomy.cdm.model.location.NamedAreaType;
50
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
51
import eu.etaxonomy.cdm.model.media.ImageFile;
52
import eu.etaxonomy.cdm.model.media.Media;
53
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
54
import eu.etaxonomy.cdm.model.name.NonViralName;
55
import eu.etaxonomy.cdm.model.name.Rank;
56
import eu.etaxonomy.cdm.model.reference.Reference;
57
import eu.etaxonomy.cdm.model.taxon.Classification;
58
import eu.etaxonomy.cdm.model.taxon.Synonym;
59
import eu.etaxonomy.cdm.model.taxon.Taxon;
60
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
61

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

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

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

    
159
		// use defined uuid for first tree
160
		CONFIG config = (CONFIG)state.getConfig();
161
		if (state.countTrees() < 1 ){
162
			tree.setUuid(config.getClassificationUuid());
163
		}
164
		getClassificationService().save(tree);
165
		state.putTreeUuid(ref, tree);
166
		return tree;
167
	}
168
	
169
	
170
	protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
171
		return getExtensionType(state, uuid, label, text, labelAbbrev, null);
172
	}
173
	protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<ExtensionType> voc){
174
		if (uuid == null){
175
			uuid = UUID.randomUUID();
176
		}
177
		ExtensionType extensionType = state.getExtensionType(uuid);
178
		if (extensionType == null){
179
			extensionType = (ExtensionType)getTermService().find(uuid);
180
			if (extensionType == null){
181
				extensionType = ExtensionType.NewInstance(text, label, labelAbbrev);
182
				extensionType.setUuid(uuid);
183
				if (voc == null){
184
					boolean isOrdered = false;
185
					voc = getVocabulary(uuidUserDefinedExtensionTypeVocabulary, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered);
186
				}
187
				voc.addTerm(extensionType);
188
				getTermService().saveOrUpdate(extensionType);
189
			}
190
			state.putExtensionType(extensionType);
191
		}
192
		return extensionType;
193
	}
194
	
195
	
196
	protected MarkerType getMarkerType(STATE state, String keyString) {
197
		IInputTransformer transformer = state.getTransformer();
198
		MarkerType markerType = null;
199
		try {
200
			markerType = transformer.getMarkerTypeByKey(keyString);
201
		} catch (UndefinedTransformerMethodException e) {
202
			logger.info("getMarkerTypeByKey not yet implemented for this import");
203
		}
204
		if (markerType == null ){
205
			UUID uuid;
206
			try {
207
				uuid = transformer.getMarkerTypeUuid(keyString);
208
				return getMarkerType(state, uuid, keyString, keyString, keyString);
209
			} catch (UndefinedTransformerMethodException e) {
210
				logger.warn("getMarkerTypeUuid not yet implemented for this import");
211
			}
212
		}
213
		return null;
214
	}
215
	
216
	protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
217
		if (uuid == null){
218
			uuid = UUID.randomUUID();
219
		}
220
		MarkerType markerType = state.getMarkerType(uuid);
221
		if (markerType == null){
222
			markerType = (MarkerType)getTermService().find(uuid);
223
			if (markerType == null){
224
				markerType = MarkerType.NewInstance(label, text, labelAbbrev);
225
				markerType.setUuid(uuid);
226
				UUID uuidMarkerTypeVoc = UUID.fromString("19dffff7-e142-429c-a420-5d28e4ebe305");
227
				TermVocabulary voc = getVocabularyService().find(uuidMarkerTypeVoc);
228
				voc.addTerm(markerType);
229
				getTermService().save(markerType);
230
			}
231
			state.putMarkerType(markerType);
232
		}
233
		return markerType;
234
	}
235
	
236
	protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<AnnotationType> voc){
237
		if (uuid == null){
238
			uuid = UUID.randomUUID();
239
		}
240
		AnnotationType annotationType = state.getAnnotationType(uuid);
241
		if (annotationType == null){
242
			annotationType = (AnnotationType)getTermService().find(uuid);
243
			if (annotationType == null){
244
				annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
245
				annotationType.setUuid(uuid);
246
				if (voc == null){
247
					boolean isOrdered = false;
248
					voc = getVocabulary(uuidUserDefinedAnnotationTypeVocabulary, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered);
249
				}
250
				
251
				voc.addTerm(annotationType);
252
				getTermService().save(annotationType);
253
			}
254
			state.putAnnotationType(annotationType);
255
		}
256
		return annotationType;
257
	}
258
	
259
	
260
	protected ReferenceSystem getReferenceSystem(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary voc){
261
		if (uuid == null){
262
			uuid = UUID.randomUUID();
263
		}
264
		ReferenceSystem refSystem = state.getReferenceSystem(uuid);
265
		if (refSystem == null){
266
			refSystem = (ReferenceSystem)getTermService().find(uuid);
267
			if (refSystem == null){
268
				refSystem = ReferenceSystem.NewInstance(text, label, labelAbbrev);
269
				if (voc == null){
270
					boolean isOrdered = false;
271
					voc = getVocabulary(uuidUserDefinedReferenceSystemVocabulary, "User defined vocabulary for named areas", "User Defined Reference System", null, null, isOrdered);
272
				}
273
				voc.addTerm(refSystem);
274
				refSystem.setUuid(uuid);
275
				getTermService().save(refSystem);
276
			}
277
			state.putReferenceSystem(refSystem);
278
		}
279
		return refSystem;
280
		
281
	}
282
	
283
	/**
284
	 * Returns a named area for a given uuid by first . If the named area does not
285
	 * @param state
286
	 * @param uuid
287
	 * @param label
288
	 * @param text
289
	 * @param labelAbbrev
290
	 * @param areaType
291
	 * @param level
292
	 * @return
293
	 */
294
	protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level){
295
		return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, null, null);
296
	}
297

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

    
355

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

    
429

    
430
	/**
431
	 * Returns a presence term for a given uuid by first ...
432
	 * @param state
433
	 * @param uuid
434
	 * @param label
435
	 * @param text
436
	 * @param labelAbbrev
437
	 * @return
438
	 */
439
	protected PresenceTerm getPresenceTerm(STATE state, UUID uuid, String label, String text, String labelAbbrev){
440
		if (uuid == null){
441
			return null;
442
		}
443
		PresenceTerm presenceTerm = state.getPresenceTerm(uuid);
444
		if (presenceTerm == null){
445
			presenceTerm = (PresenceTerm)getTermService().find(uuid);
446
			if (presenceTerm == null){
447
				presenceTerm = PresenceTerm.NewInstance(text, label, labelAbbrev);
448
				presenceTerm.setUuid(uuid);
449
				//set vocabulary ; FIXME use another user-defined vocabulary
450
				UUID uuidPresenceVoc = UUID.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05"); 
451
				TermVocabulary<PresenceTerm> voc = getVocabularyService().find(uuidPresenceVoc);
452
				voc.addTerm(presenceTerm);
453
				getTermService().save(presenceTerm);
454
			}
455
			state.putPresenceTerm(presenceTerm);
456
		}
457
		return presenceTerm;
458
	}
459

    
460
	/**
461
	 * Returns a language for a given uuid by first ...
462
	 * @param state
463
	 * @param uuid
464
	 * @param label
465
	 * @param text
466
	 * @param labelAbbrev
467
	 * @return
468
	 */
469
	protected Language getLanguage(STATE state, UUID uuid, String label, String text, String labelAbbrev){
470
		if (uuid == null){
471
			return null;
472
		}
473
		Language language = state.getLanguage(uuid);
474
		if (language == null){
475
			language = (Language)getTermService().find(uuid);
476
			if (language == null){
477
				language = Language.NewInstance(text, label, labelAbbrev);
478
				
479
				language.setUuid(uuid);
480
				//set vocabulary ; FIXME use another user-defined vocabulary
481
				UUID uuidLanguageVoc = UUID.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de"); 
482
				TermVocabulary<Language> voc = getVocabularyService().find(uuidLanguageVoc);
483
				voc.addTerm(language);
484
				getTermService().save(language);
485
			}
486
			state.putLanguage(language);
487
		}
488
		return language;
489
	}
490
	
491

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

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

    
641

    
642
	/**
643
	 * Returns true, if this description has a source with a citation equal to the given reference.
644
	 * Returns true if the given reference is null.
645
	 * @param ref
646
	 * @param description
647
	 */
648
	private boolean hasCorrespondingSource(Reference ref, TaxonDescription description) {
649
		if (ref != null){
650
			for (IdentifiableSource source : description.getSources()){
651
				if (ref.equals(source.getCitation())){
652
					return true;
653
				}
654
			}
655
			return false;
656
		}
657
		return true;
658
		
659
	}
660
	
661
	
662
	/**
663
	 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
664
	 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
665
	 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
666
	 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the 
667
	 * same secundum reference is returned. If no such single taxon exists an 
668
	 * {@link IllegalStateException illegal state exception} is thrown.  
669
	 * @param taxonBase
670
	 * @return
671
	 */
672
	protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {
673
		if (taxonBase == null){
674
			return null;
675
		}else if(taxonBase.isInstanceOf(Taxon.class)){
676
			return CdmBase.deproxy(taxonBase, Taxon.class);
677
		}else if(taxonBase.isInstanceOf(Synonym.class)){
678
			Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
679
			Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
680
			if (acceptedTaxa.size() == 0){
681
				return null;
682
			}else if (acceptedTaxa.size() == 1){
683
				return acceptedTaxa.iterator().next();
684
			}else{
685
				Reference sec = synonym.getSec();
686
				if (sec != null){
687
					Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();
688
					for (Taxon taxon: acceptedTaxa){
689
						if (sec.equals(taxon.getSec())){
690
							taxaWithSameSec.add(taxon);
691
						}
692
					}
693
					if (taxaWithSameSec.size() == 1){
694
						return taxaWithSameSec.iterator().next();
695
					}
696
				}
697
				throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
698
			}
699
		}else{
700
			throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());
701
		}
702
	}
703

    
704
	
705

    
706
	/**
707
	 * @param derivedUnitFacade
708
	 * @param multimediaObject
709
	 * @throws MalformedURLException
710
	 */
711
	protected Media getImageMedia(String multimediaObject, boolean readDataFromUrl) throws MalformedURLException {
712
		if( multimediaObject == null){
713
			return null;
714
		} else {
715
			ImageInfo imageInfo = null;
716
			URI uri;
717
			try {
718
				uri = new URI(multimediaObject);
719
				try {
720
					if (readDataFromUrl){
721
						imageInfo = ImageInfo.NewInstance(uri, 0);
722
					}
723
				} catch (Exception e) {
724
					String message = "An error occurred when trying to read image meta data: " +  e.getMessage();
725
					logger.warn(message);
726
				}
727
				ImageFile imageFile = ImageFile.NewInstance(uri, null, imageInfo);
728
				MediaRepresentation representation = MediaRepresentation.NewInstance();
729
				if(imageInfo != null){
730
					representation.setMimeType(imageInfo.getMimeType());
731
				}
732
				representation.addRepresentationPart(imageFile);
733
				Media media = Media.NewInstance();
734
				media.addRepresentation(representation);
735
				return media;
736
			} catch (URISyntaxException e1) {
737
				String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " +  multimediaObject;
738
				logger.warn(message);
739
				return null;
740
			}
741
		}
742
	}
743

    
744
	
745
}
(9-9/48)