Some updates for AlgaTerra Types import
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / common / CdmImportBase.java
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.ArrayList;
18 import java.util.Arrays;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.UUID;
23
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.log4j.Logger;
26
27 import eu.etaxonomy.cdm.api.service.pager.Pager;
28 import eu.etaxonomy.cdm.common.media.ImageInfo;
29 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
30 import eu.etaxonomy.cdm.io.common.mapping.IInputTransformer;
31 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
32 import eu.etaxonomy.cdm.io.markup.MarkupTransformer;
33 import eu.etaxonomy.cdm.model.common.AnnotationType;
34 import eu.etaxonomy.cdm.model.common.CdmBase;
35 import eu.etaxonomy.cdm.model.common.DefinedTerm;
36 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
37 import eu.etaxonomy.cdm.model.common.ExtensionType;
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.OriginalSourceType;
47 import eu.etaxonomy.cdm.model.common.TermType;
48 import eu.etaxonomy.cdm.model.common.TermVocabulary;
49 import eu.etaxonomy.cdm.model.description.DescriptionBase;
50 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
52 import eu.etaxonomy.cdm.model.description.Feature;
53 import eu.etaxonomy.cdm.model.description.MeasurementUnit;
54 import eu.etaxonomy.cdm.model.description.PresenceTerm;
55 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
56 import eu.etaxonomy.cdm.model.description.State;
57 import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
58 import eu.etaxonomy.cdm.model.description.TaxonDescription;
59 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
60 import eu.etaxonomy.cdm.model.description.TextData;
61 import eu.etaxonomy.cdm.model.location.Country;
62 import eu.etaxonomy.cdm.model.location.NamedArea;
63 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
64 import eu.etaxonomy.cdm.model.location.NamedAreaType;
65 import eu.etaxonomy.cdm.model.location.ReferenceSystem;
66 import eu.etaxonomy.cdm.model.media.ImageFile;
67 import eu.etaxonomy.cdm.model.media.Media;
68 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
69 import eu.etaxonomy.cdm.model.name.NonViralName;
70 import eu.etaxonomy.cdm.model.name.Rank;
71 import eu.etaxonomy.cdm.model.name.RankClass;
72 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
73 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
74 import eu.etaxonomy.cdm.model.reference.Reference;
75 import eu.etaxonomy.cdm.model.taxon.Classification;
76 import eu.etaxonomy.cdm.model.taxon.Synonym;
77 import eu.etaxonomy.cdm.model.taxon.Taxon;
78 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
79 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
80
81 /**
82 * @author a.mueller
83 * @created 01.07.2008
84 * @version 1.0
85 */
86 public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE extends ImportStateBase> extends CdmIoBase<STATE> implements ICdmImport<CONFIG, STATE>{
87 private static Logger logger = Logger.getLogger(CdmImportBase.class);
88
89 protected static final boolean CREATE = true;
90 protected static final boolean IMAGE_GALLERY = true;
91 protected static final boolean READ_MEDIA_DATA = true;
92
93 public static final UUID uuidUserDefinedNamedAreaLevelVocabulary = UUID.fromString("255144da-8d95-457e-a327-9752a8f85e5a");
94 public static final UUID uuidUserDefinedNamedAreaVocabulary = UUID.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
95 public static final UUID uuidUserDefinedExtensionTypeVocabulary = UUID.fromString("e28c1394-1be8-4847-8b81-ab44eb6d5bc8");
96 public static final UUID uuidUserDefinedReferenceSystemVocabulary = UUID.fromString("467591a3-10b4-4bf1-9239-f06ece33e90a");
97 public static final UUID uuidUserDefinedFeatureVocabulary = UUID.fromString("fe5fccb3-a2f2-4b97-b199-6e2743cf1627");
98 public static final UUID uuidUserDefinedMeasurementUnitVocabulary = UUID.fromString("d5e72bb7-f312-4080-bb86-c695d04a6e66");
99 public static final UUID uuidUserDefinedStatisticalMeasureVocabulary = UUID.fromString("62a89836-c730-4b4f-a904-3d859dbfc400");
100 public static final UUID uuidUserDefinedStateVocabulary = UUID.fromString("f7cddb49-8392-4db1-8640-65b48a0e6d13");
101 public static final UUID uuidUserDefinedTaxonRelationshipTypeVocabulary = UUID.fromString("31a324dc-408d-4877-891f-098db21744c6");
102 public static final UUID uuidUserDefinedAnnotationTypeVocabulary = UUID.fromString("cd9ecdd2-9cae-4890-9032-ad83293ae883");
103 public static final UUID uuidUserDefinedMarkerTypeVocabulary = UUID.fromString("5f02a261-fd7d-4fce-bbe4-21472de8cd51");
104 public static final UUID uuidUserDefinedRankVocabulary = UUID.fromString("4dc57931-38e2-46c3-974d-413b087646ba");
105
106 public static final UUID uuidUserDefinedModifierVocabulary = UUID.fromString("2a8b3838-3a95-49ea-9ab2-3049614b5884");
107
108
109
110 private static final String UuidOnly = "UUIDOnly";
111 private static final String UuidLabel = "UUID or label";
112 private static final String UuidLabelAbbrev = "UUID, label or abbreviation";
113 private static final String UuidAbbrev = "UUID or abbreviation";
114
115 public enum TermMatchMode{
116 UUID_ONLY(0, UuidOnly)
117 ,UUID_LABEL(1, UuidLabel)
118 ,UUID_LABEL_ABBREVLABEL(2, UuidLabelAbbrev)
119 ,UUID_ABBREVLABEL(3, UuidAbbrev)
120 ;
121
122
123 private int id;
124 private String representation;
125 private TermMatchMode(int id, String representation){
126 this.id = id;
127 this.representation = representation;
128 }
129 public int getId() {
130 return id;
131 }
132 public String getRepresentation() {
133 return representation;
134 }
135 public TermMatchMode valueOf(int id){
136 switch (id){
137 case 0: return UUID_ONLY;
138 case 1: return UUID_LABEL;
139 case 2: return UUID_LABEL_ABBREVLABEL;
140 case 3: return UUID_ABBREVLABEL;
141 default: return UUID_ONLY;
142 }
143 }
144
145
146 }
147
148 protected Classification makeTree(STATE state, Reference<?> reference){
149 String treeName = "Classification (Import)";
150 if (reference != null && StringUtils.isNotBlank(reference.getTitleCache())){
151 treeName = reference.getTitleCache();
152 }
153 Classification tree = Classification.NewInstance(treeName);
154 tree.setReference(reference);
155
156
157 // use defined uuid for first tree
158 CONFIG config = (CONFIG)state.getConfig();
159 if (state.countTrees() < 1 ){
160 tree.setUuid(config.getClassificationUuid());
161 }
162 getClassificationService().save(tree);
163 state.putTree(reference, tree);
164 return tree;
165 }
166
167
168 /**
169 * Alternative memory saving method variant of
170 * {@link #makeTree(STATE state, Reference ref)} which stores only the
171 * UUID instead of the full tree in the <code>ImportStateBase</code> by
172 * using <code>state.putTreeUuid(ref, tree);</code>
173 *
174 * @param state
175 * @param ref
176 * @return
177 */
178 protected Classification makeTreeMemSave(STATE state, Reference ref){
179 String treeName = "Classification (Import)";
180 if (ref != null && StringUtils.isNotBlank(ref.getTitleCache())){
181 treeName = ref.getTitleCache();
182 }
183 Classification tree = Classification.NewInstance(treeName);
184 tree.setReference(ref);
185
186
187 // use defined uuid for first tree
188 CONFIG config = (CONFIG)state.getConfig();
189 if (state.countTrees() < 1 ){
190 tree.setUuid(config.getClassificationUuid());
191 }
192 getClassificationService().save(tree);
193 state.putTreeUuid(ref, tree);
194 return tree;
195 }
196
197
198 protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
199 return getExtensionType(state, uuid, label, text, labelAbbrev, null);
200 }
201 protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<ExtensionType> voc){
202 if (uuid == null){
203 uuid = UUID.randomUUID();
204 }
205 ExtensionType extensionType = state.getExtensionType(uuid);
206 if (extensionType == null){
207 extensionType = (ExtensionType)getTermService().find(uuid);
208 if (extensionType == null){
209 extensionType = ExtensionType.NewInstance(text, label, labelAbbrev);
210 extensionType.setUuid(uuid);
211 if (voc == null){
212 boolean isOrdered = false;
213 voc = getVocabulary(TermType.ExtensionType, uuidUserDefinedExtensionTypeVocabulary, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered, extensionType);
214 }
215 voc.addTerm(extensionType);
216 getTermService().saveOrUpdate(extensionType);
217 }
218 state.putExtensionType(extensionType);
219 }
220 return extensionType;
221 }
222
223
224 protected MarkerType getMarkerType(STATE state, String keyString) {
225 IInputTransformer transformer = state.getTransformer();
226 MarkerType markerType = null;
227 try {
228 markerType = transformer.getMarkerTypeByKey(keyString);
229 } catch (UndefinedTransformerMethodException e) {
230 logger.info("getMarkerTypeByKey not yet implemented for this import");
231 }
232 if (markerType == null ){
233 UUID uuid;
234 try {
235 uuid = transformer.getMarkerTypeUuid(keyString);
236 return getMarkerType(state, uuid, keyString, keyString, keyString);
237 } catch (UndefinedTransformerMethodException e) {
238 logger.warn("getMarkerTypeUuid not yet implemented for this import");
239 }
240 }
241 return null;
242 }
243
244 protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
245 return getMarkerType(state, uuid, label, text, labelAbbrev, null);
246 }
247
248
249 protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<MarkerType> voc){
250 if (uuid == null){
251 uuid = UUID.randomUUID();
252 }
253 MarkerType markerType = state.getMarkerType(uuid);
254 if (markerType == null){
255 markerType = (MarkerType)getTermService().find(uuid);
256 if (markerType == null){
257 markerType = MarkerType.NewInstance(label, text, labelAbbrev);
258 markerType.setUuid(uuid);
259 if (voc == null){
260 boolean isOrdered = false;
261 voc = getVocabulary(TermType.MarkerType, uuidUserDefinedMarkerTypeVocabulary, "User defined vocabulary for marker types", "User Defined Marker Types", null, null, isOrdered, markerType);
262 }
263 voc.addTerm(markerType);
264 getTermService().save(markerType);
265 }
266 state.putMarkerType(markerType);
267 }
268 return markerType;
269 }
270
271 protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<AnnotationType> voc){
272 if (uuid == null){
273 uuid = UUID.randomUUID();
274 }
275 AnnotationType annotationType = state.getAnnotationType(uuid);
276 if (annotationType == null){
277 annotationType = (AnnotationType)getTermService().find(uuid);
278 if (annotationType == null){
279 annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
280 annotationType.setUuid(uuid);
281 if (voc == null){
282 boolean isOrdered = false;
283 voc = getVocabulary(TermType.AnnotationType, uuidUserDefinedAnnotationTypeVocabulary, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered, annotationType);
284 }
285
286 voc.addTerm(annotationType);
287 getTermService().save(annotationType);
288 }
289 state.putAnnotationType(annotationType);
290 }
291 return annotationType;
292 }
293
294
295 protected ReferenceSystem getReferenceSystem(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary voc){
296 if (uuid == null){
297 uuid = UUID.randomUUID();
298 }
299 ReferenceSystem refSystem = state.getReferenceSystem(uuid);
300 if (refSystem == null){
301 refSystem = (ReferenceSystem)getTermService().find(uuid);
302 if (refSystem == null){
303 refSystem = ReferenceSystem.NewInstance(text, label, labelAbbrev);
304 if (voc == null){
305 boolean isOrdered = false;
306 voc = getVocabulary(TermType.ReferenceSystem, uuidUserDefinedReferenceSystemVocabulary, "User defined vocabulary for reference systems", "User Defined Reference System", null, null, isOrdered, refSystem);
307 }
308 voc.addTerm(refSystem);
309 refSystem.setUuid(uuid);
310 getTermService().save(refSystem);
311 }
312 state.putReferenceSystem(refSystem);
313 }
314 return refSystem;
315
316 }
317
318
319
320 protected Rank getRank(STATE state, UUID uuid, String label, String text, String labelAbbrev,OrderedTermVocabulary<Rank> voc, Rank lowerRank, RankClass rankClass){
321 if (uuid == null){
322 uuid = UUID.randomUUID();
323 }
324 Rank rank = state.getRank(uuid);
325 if (rank == null){
326 rank = (Rank)getTermService().find(uuid);
327 if (rank == null){
328 rank = Rank.NewInstance(rankClass, text, label, labelAbbrev);
329 if (voc == null){
330 boolean isOrdered = true;
331 voc = (OrderedTermVocabulary)getVocabulary(TermType.Rank, uuidUserDefinedRankVocabulary, "User defined vocabulary for ranks", "User Defined Reference System", null, null, isOrdered, rank);
332 }
333 if (lowerRank == null){
334 voc.addTerm(rank);
335 }else{
336 voc.addTermAbove(rank, lowerRank);
337 }
338 rank.setUuid(uuid);
339 getTermService().save(rank);
340 }
341 state.putRank(rank);
342 }
343 return rank;
344
345 }
346
347 /**
348 * Returns a named area for a given uuid by first . If the named area does not
349 * @param state
350 * @param uuid
351 * @param label
352 * @param text
353 * @param labelAbbrev
354 * @param areaType
355 * @param level
356 * @return
357 */
358 protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level){
359 return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, null, null);
360 }
361
362 protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc, TermMatchMode matchMode){
363 return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, voc, matchMode, null);
364 }
365
366
367 protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc, TermMatchMode matchMode,
368 List<TermVocabulary<NamedArea>> vocabularyPreference){
369 Class<NamedArea> clazz = NamedArea.class;
370 if (uuid == null){
371 uuid = UUID.randomUUID();
372 }
373 if (matchMode == null){
374 matchMode = TermMatchMode.UUID_ONLY;
375 }
376 NamedArea namedArea = state.getNamedArea(uuid);
377 if (namedArea == null){
378 DefinedTermBase<?> term = getTermService().find(uuid);
379 namedArea = CdmBase.deproxy(term,NamedArea.class);
380
381 if (vocabularyPreference == null){
382 vocabularyPreference = new ArrayList<TermVocabulary<NamedArea>>();
383 }
384 if (vocabularyPreference.isEmpty()){
385 vocabularyPreference.add(Country.GERMANY().getVocabulary());
386 vocabularyPreference.add(TdwgAreaProvider.getAreaByTdwgAbbreviation("GER").getVocabulary());
387 }
388
389
390 //TODO matching still experimental
391 if (namedArea == null && (matchMode.equals(TermMatchMode.UUID_LABEL) || matchMode.equals(TermMatchMode.UUID_LABEL_ABBREVLABEL ))){
392 //TODO test
393 Pager<NamedArea> areaPager = (Pager)getTermService().findByTitle(clazz, label, null, null, null, null, null, null);
394 namedArea = findBestMatchingArea(areaPager, uuid, label, text, labelAbbrev, vocabularyPreference);
395 }
396 if (namedArea == null && (matchMode.equals(TermMatchMode.UUID_ABBREVLABEL) || matchMode.equals(TermMatchMode.UUID_LABEL_ABBREVLABEL))){
397 Pager<NamedArea> areaPager = getTermService().findByRepresentationAbbreviation(labelAbbrev, clazz, null, null);
398 namedArea = findBestMatchingArea(areaPager, uuid, label, text, labelAbbrev, vocabularyPreference);
399 }
400
401 if (namedArea == null){
402 namedArea = NamedArea.NewInstance(text, label, labelAbbrev);
403 if (voc == null){
404 boolean isOrdered = true;
405 voc = getVocabulary(TermType.NamedArea, uuidUserDefinedNamedAreaVocabulary, "User defined vocabulary for named areas", "User Defined Named Areas", null, null, isOrdered, namedArea);
406 }
407 voc.addTerm(namedArea);
408 namedArea.setType(areaType);
409 namedArea.setLevel(level);
410 namedArea.setUuid(uuid);
411 getTermService().saveOrUpdate(namedArea);
412 }
413 state.putNamedArea(namedArea);
414 }
415 return namedArea;
416 }
417
418
419 private NamedArea findBestMatchingArea(Pager<NamedArea> areaPager, UUID uuid, String label, String text, String abbrev, List<TermVocabulary<NamedArea>> vocabularyPreference) {
420 // TODO preliminary implementation
421 List<NamedArea> list = areaPager.getRecords();
422 if (list.size() == 0){
423 return null;
424 }else if (list.size() == 1){
425 return list.get(0);
426 }else if (list.size() > 1){
427 List<NamedArea> preferredList = new ArrayList<NamedArea>();
428 for (TermVocabulary<NamedArea> voc: vocabularyPreference){
429 for (NamedArea area : list){
430 if (voc.equals(area.getVocabulary())){
431 preferredList.add(area);
432 }
433 }
434 if (preferredList.size() > 0){
435 break;
436 }
437 }
438 if (preferredList.size() > 1 ){
439 preferredList = getLowestLevelAreas(preferredList);
440 }else if (preferredList.size() == 0 ){
441 preferredList = list;
442 }
443 if (preferredList.size() == 1 ){
444 return preferredList.get(0);
445 }else if (preferredList.size() > 1 ){
446 String message = "There is more than 1 matching area for %s, %s, %s. As a preliminary implementation I take the first";
447 message = String.format(message, label, abbrev, text);
448 logger.warn(message);
449 return list.get(0);
450 }
451 }
452 return null;
453 }
454
455
456 private List<NamedArea> getLowestLevelAreas(List<NamedArea> preferredList) {
457 List<NamedArea> result = new ArrayList<NamedArea>();
458 for (NamedArea area : preferredList){
459 if (result.isEmpty()){
460 result.add(area);
461 }else {
462 int compare = compareAreaLevel(area, result.get(0));
463 if (compare < 0){
464 result = new ArrayList<NamedArea>();
465 result.add(area);
466 }else if (compare == 0){
467 result.add(area);
468 }else{
469 //do nothing
470 }
471
472 }
473 }
474
475 return result;
476 }
477
478
479 private int compareAreaLevel(NamedArea area1, NamedArea area2) {
480 NamedAreaLevel level1 = area1.getLevel();
481 NamedAreaLevel level2 = area2.getLevel();
482 if (level1 == null){
483 return (level2 == null)? 0 : 1;
484 }else if (level2 == null){
485 return -1;
486 }else{
487 return level1.compareTo(level2);
488 }
489 }
490
491
492 protected NamedAreaLevel getNamedAreaLevel(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<NamedAreaLevel> voc){
493 if (uuid == null){
494 uuid = UUID.randomUUID();
495 }
496 NamedAreaLevel namedAreaLevel = state.getNamedAreaLevel(uuid);
497 if (namedAreaLevel == null){
498 //TODO propPath just for testing
499 List<String> propPath = Arrays.asList("vocabulary");
500 DefinedTermBase<NamedAreaLevel> term = getTermService().load(uuid, propPath);
501 namedAreaLevel = CdmBase.deproxy(term, NamedAreaLevel.class);
502 if (namedAreaLevel == null){
503 namedAreaLevel = NamedAreaLevel.NewInstance(text, label, labelAbbrev);
504 if (voc == null){
505 boolean isOrdered = true;
506 voc = getVocabulary(TermType.NamedAreaLevel, uuidUserDefinedNamedAreaLevelVocabulary, "User defined vocabulary for named area levels", "User Defined Named Area Levels", null, null, isOrdered, namedAreaLevel);
507 }
508 //FIXME only for debugging
509 Set<NamedAreaLevel> terms = voc.getTerms();
510 for (NamedAreaLevel level : terms){
511 TermVocabulary<NamedAreaLevel> levelVoc = level.getVocabulary();
512 if (levelVoc == null){
513 logger.error("ONLY FOR DEBUG: Level voc is null");
514 }else{
515 logger.info("ONLY FOR DEBUG: Level voc is not null");
516 }
517 }
518 voc.addTerm(namedAreaLevel);
519 namedAreaLevel.setUuid(uuid);
520 getTermService().save(namedAreaLevel);
521 }
522 state.putNamedAreaLevel(namedAreaLevel);
523 }
524 return namedAreaLevel;
525 }
526
527 /**
528 * Returns a {@link State} if it exists. <code>null</code> otherwise.
529 * @param state
530 * @param uuid
531 * @return {@link State}
532 */
533 protected State getStateTerm(STATE state, UUID uuid){
534 return getStateTerm(state, uuid, null, null, null, null);
535 }
536
537
538 /**
539 * Returns a {@link State} for a given uuid by first checking if the uuid has already been used in this import, if not
540 * checking if the state exists in the database, if not creating it anew (with vocabulary etc.).
541 * If label, text and labelAbbrev are all <code>null</code> no state is created.
542 * @param importState
543 * @param uuid
544 * @param label
545 * @param text
546 * @param labelAbbrev
547 * @param voc
548 * @return
549 */
550 protected State getStateTerm(STATE importState, UUID uuid, String label, String text, String labelAbbrev, OrderedTermVocabulary<State> voc) {
551 if (uuid == null){
552 return null;
553 }
554 State stateTerm = importState.getStateTerm(uuid);
555 if (stateTerm == null){
556 stateTerm = CdmBase.deproxy(getTermService().find(uuid), State.class);
557 if (stateTerm == null && ! hasNoLabel(label, text, labelAbbrev)){
558 stateTerm = State.NewInstance(text, label, labelAbbrev);
559 stateTerm.setUuid(uuid);
560 if (voc == null){
561 boolean isOrdered = true;
562 TermVocabulary<State> orderedVoc = getVocabulary(TermType.State, uuidUserDefinedStateVocabulary, "User defined vocabulary for states used by Categorical Data", "User Defined States", null, null, isOrdered, stateTerm);
563 voc = CdmBase.deproxy(orderedVoc, OrderedTermVocabulary.class);
564 }
565 voc.addTerm(stateTerm);
566 getTermService().save(stateTerm);
567 }else{
568 logger.warn("No label provided for new state with uuid " + uuid);
569 }
570 importState.putStateTerm(stateTerm);
571 }
572 return stateTerm;
573 }
574
575 /**
576 * Returns a feature if it exists, null otherwise.
577 * @see #getFeature(ImportStateBase, UUID, String, String, String, TermVocabulary)
578 * @param state
579 * @param uuid
580 * @return
581 */
582 protected Feature getFeature(STATE state, UUID uuid){
583 return getFeature(state, uuid, null, null, null, null);
584 }
585
586 /**
587 * Returns a feature for a given uuid by first checking if the uuid has already been used in this import, if not
588 * checking if the feature exists in the database, if not creating it anew (with vocabulary etc.).
589 * If label, text and labelAbbrev are all <code>null</code> no feature is created.
590 * @param state
591 * @param uuid
592 * @param label
593 * @param text
594 * @param labelAbbrev
595 * @return
596 */
597 protected Feature getFeature(STATE state, UUID uuid, String label, String description, String labelAbbrev, TermVocabulary<Feature> voc){
598 if (uuid == null){
599 return null;
600 }
601 Feature feature = state.getFeature(uuid);
602 if (feature == null){
603 feature = (Feature)getTermService().find(uuid);
604 if (feature == null && ! hasNoLabel(label, description, labelAbbrev)){
605 feature = Feature.NewInstance(description, label, labelAbbrev);
606 feature.setUuid(uuid);
607 feature.setSupportsTextData(true);
608 // UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8");
609 if (voc == null){
610 boolean isOrdered = false;
611 voc = getVocabulary(TermType.Feature, uuidUserDefinedFeatureVocabulary, "User defined vocabulary for features", "User Defined Features", null, null, isOrdered, feature);
612 }
613 voc.addTerm(feature);
614 getTermService().save(feature);
615 }
616 state.putFeature(feature);
617 }
618 return feature;
619 }
620
621 /**
622 * Returns a {@link MeasurementUnit} for a given uuid by first checking if the uuid has already been used in this import, if not
623 * checking if the {@link MeasurementUnit} exists in the database, if not creating it anew (with vocabulary etc.).
624 * If label, text and labelAbbrev are all <code>null</code> no {@link MeasurementUnit} is created.
625 * @param state
626 * @param uuid
627 * @param label
628 * @param text
629 * @param labelAbbrev
630 * @return
631 */
632 protected MeasurementUnit getMeasurementUnit(STATE state, UUID uuid, String label, String description, String labelAbbrev, TermVocabulary<MeasurementUnit> voc){
633 if (uuid == null){
634 return null;
635 }
636 MeasurementUnit unit = state.getMeasurementUnit(uuid);
637 if (unit == null){
638 unit = (MeasurementUnit)getTermService().find(uuid);
639 if (unit == null && ! hasNoLabel(label, description, labelAbbrev)){
640 unit = MeasurementUnit.NewInstance(description, label, labelAbbrev);
641 unit.setUuid(uuid);
642 if (voc == null){
643 boolean isOrdered = false;
644 voc = getVocabulary(TermType.MeasurementUnit, uuidUserDefinedMeasurementUnitVocabulary, "User defined vocabulary for measurement units", "User Defined Measurement Units", null, null, isOrdered, unit);
645 }
646 voc.addTerm(unit);
647 getTermService().save(unit);
648 }
649 state.putMeasurementUnit(unit);
650 }
651 return unit;
652 }
653
654 /**
655 * Returns a {@link StatisticalMeasure} for a given uuid by first checking if the uuid has already been used in this import, if not
656 * checking if the {@link StatisticalMeasure} exists in the database, if not creating it anew (with vocabulary etc.).
657 * If label, text and labelAbbrev are all <code>null</code> no {@link StatisticalMeasure} is created.
658 * @param state
659 * @param uuid
660 * @param label
661 * @param text
662 * @param labelAbbrev
663 * @return
664 */
665 protected StatisticalMeasure getStatisticalMeasure(STATE state, UUID uuid, String label, String description, String labelAbbrev, TermVocabulary<StatisticalMeasure> voc){
666 if (uuid == null){
667 return null;
668 }
669 StatisticalMeasure statisticalMeasure = state.getStatisticalMeasure(uuid);
670 if (statisticalMeasure == null){
671 statisticalMeasure = (StatisticalMeasure)getTermService().find(uuid);
672 if (statisticalMeasure == null && ! hasNoLabel(label, description, labelAbbrev)){
673 statisticalMeasure = StatisticalMeasure.NewInstance(description, label, labelAbbrev);
674 statisticalMeasure.setUuid(uuid);
675 if (voc == null){
676 boolean isOrdered = false;
677 voc = getVocabulary(TermType.StatisticalMeasure, uuidUserDefinedStatisticalMeasureVocabulary, "User defined vocabulary for statistical measures", "User Defined Statistical Measures", null, null, isOrdered, statisticalMeasure);
678 }
679 voc.addTerm(statisticalMeasure);
680 getTermService().save(statisticalMeasure);
681 }
682 state.putStatisticalMeasure(statisticalMeasure);
683 }
684 return statisticalMeasure;
685 }
686
687 /**
688 * Returns a {@link Modifier} for a given uuid by first checking if the uuid has already been used in this import, if not
689 * checking if the {@link Modifier} exists in the database, if not creating it anew (with vocabulary etc.).
690 * If label, text and labelAbbrev are all <code>null</code> no {@link Modifier} is created.
691 * @param state
692 * @param uuid
693 * @param label
694 * @param text
695 * @param labelAbbrev
696 * @return
697 */
698 protected DefinedTerm getModifier(STATE state, UUID uuid, String label, String description, String labelAbbrev, TermVocabulary<DefinedTerm> voc){
699 if (uuid == null){
700 return null;
701 }
702 DefinedTerm modifier = state.getModifier(uuid);
703 if (modifier == null){
704 modifier = (DefinedTerm)getTermService().find(uuid);
705 if (modifier == null && ! hasNoLabel(label, description, labelAbbrev)){
706 modifier = DefinedTerm.NewModifierInstance(description, label, labelAbbrev);
707 modifier.setUuid(uuid);
708 if (voc == null){
709 boolean isOrdered = false;
710 voc = getVocabulary(TermType.Modifier, uuidUserDefinedModifierVocabulary, "User defined vocabulary for modifier", "User Defined Modifier", null, null, isOrdered, modifier);
711 }
712 voc.addTerm(modifier);
713 getTermService().save(modifier);
714 }
715 state.putModifier(modifier);
716 }
717 return modifier;
718 }
719
720 /**
721 * Returns a taxon relationship type for a given uuid by first checking if the uuid has already been used in this import, if not
722 * checking if the taxon relationship type exists in the database, if not creating it anew (with vocabulary etc.).
723 * If label, text and labelAbbrev are all <code>null</code> no taxon relationship type is created.
724 * @param state
725 * @param uuid
726 * @param label
727 * @param text
728 * @param labelAbbrev
729 * @return
730 */
731 protected TaxonRelationshipType getTaxonRelationshipType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<TaxonRelationshipType> voc){
732 if (uuid == null){
733 return null;
734 }
735 TaxonRelationshipType relType = state.getTaxonRelationshipType(uuid);
736 if (relType == null){
737 relType = (TaxonRelationshipType)getTermService().find(uuid);
738 if (relType == null && ! hasNoLabel(label, text, labelAbbrev)){
739 relType = TaxonRelationshipType.NewInstance(text, label, labelAbbrev, false, false);
740 relType.setUuid(uuid);
741 if (voc == null){
742 boolean isOrdered = true;
743 voc = getVocabulary(TermType.TaxonRelationshipType, uuidUserDefinedTaxonRelationshipTypeVocabulary, "User defined vocabulary for taxon relationship types", "User Defined Taxon Relationship Types", null, null, isOrdered, relType);
744 }
745 voc.addTerm(relType);
746 getTermService().save(relType);
747 }
748 state.putTaxonRelationshipType(relType);
749 }
750 return relType;
751 }
752
753 private boolean hasNoLabel(String label, String text, String labelAbbrev) {
754 return label == null && text == null && labelAbbrev == null;
755 }
756
757
758 /**
759 * Returns a presence term for a given uuid by first ...
760 * @param state
761 * @param uuid
762 * @param label
763 * @param text
764 * @param labelAbbrev
765 * @return
766 */
767 protected PresenceTerm getPresenceTerm(STATE state, UUID uuid, String label, String text, String labelAbbrev){
768 if (uuid == null){
769 return null;
770 }
771 PresenceTerm presenceTerm = state.getPresenceTerm(uuid);
772 if (presenceTerm == null){
773 presenceTerm = (PresenceTerm)getTermService().find(uuid);
774 if (presenceTerm == null){
775 presenceTerm = PresenceTerm.NewInstance(text, label, labelAbbrev);
776 presenceTerm.setUuid(uuid);
777 //set vocabulary ; FIXME use another user-defined vocabulary
778 UUID uuidPresenceVoc = UUID.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05");
779 TermVocabulary<PresenceTerm> voc = getVocabularyService().find(uuidPresenceVoc);
780 voc.addTerm(presenceTerm);
781 getTermService().save(presenceTerm);
782 }
783 state.putPresenceTerm(presenceTerm);
784 }
785 return presenceTerm;
786 }
787
788 /**
789 * Returns a language for a given uuid by first ...
790 * @param state
791 * @param uuid
792 * @param label
793 * @param text
794 * @param labelAbbrev
795 * @return
796 */
797 protected Language getLanguage(STATE state, UUID uuid, String label, String text, String labelAbbrev){
798 return getLanguage(state, uuid, label, text, labelAbbrev, null);
799 }
800
801 protected Language getLanguage(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary voc){
802 if (uuid == null){
803 return null;
804 }
805 Language language = state.getLanguage(uuid);
806 if (language == null){
807 language = (Language)getTermService().find(uuid);
808 if (language == null){
809 language = Language.NewInstance(text, label, labelAbbrev);
810
811 language.setUuid(uuid);
812 if (voc == null){
813 UUID uuidLanguageVoc = UUID.fromString("463a96f1-20ba-4a4c-9133-854c1682bd9b");
814 boolean isOrdered = false;
815 voc = getVocabulary(TermType.Language, uuidLanguageVoc, "User defined languages", "User defined languages", "User defined languages", null, isOrdered, language);
816 }
817 //set vocabulary ; FIXME use another user-defined vocabulary
818
819 voc.addTerm(language);
820 getTermService().save(language);
821 }
822 state.putLanguage(language);
823 }
824 return language;
825 }
826
827
828 /**
829 * @param uuid
830 * @return
831 *
832 */
833 protected <T extends DefinedTermBase> TermVocabulary<T> getVocabulary(TermType termType, UUID uuid, String description, String label, String abbrev, URI termSourceUri, boolean isOrdered, T type) {
834 List<String> propPath = Arrays.asList(new String[]{"terms"});
835 TermVocabulary<T> voc = getVocabularyService().load(uuid, propPath);
836 if (voc == null){
837 if (isOrdered){
838 voc = OrderedTermVocabulary.NewInstance(termType, description, label, abbrev, termSourceUri);
839 }else{
840 voc = TermVocabulary.NewInstance(termType, description, label, abbrev, termSourceUri);
841 }
842 voc.setUuid(uuid);
843 getVocabularyService().save(voc);
844 }
845 return voc;
846 }
847
848 /**
849 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
850 * If cdmBase is not sourceable nothing happens.
851 * TODO Move to DbImportBase once this exists.
852 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
853 * @param rs
854 * @param cdmBase
855 * @param dbIdAttribute
856 * @param namespace
857 * @param citation
858 * @throws SQLException
859 */
860 public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, Reference citation) {
861 if (cdmBase instanceof ISourceable ){
862 IOriginalSource source;
863 ISourceable sourceable = (ISourceable<?>)cdmBase;
864 Object id = idAttributeValue;
865 String strId = String.valueOf(id);
866 String microCitation = null;
867 OriginalSourceType type = OriginalSourceType.Import;
868 if (cdmBase instanceof IdentifiableEntity){
869 source = IdentifiableSource.NewInstance(type, strId, namespace, citation, microCitation);
870 }else if (cdmBase instanceof DescriptionElementBase){
871 source = DescriptionElementSource.NewInstance(type, strId, namespace, citation, microCitation);
872 }else{
873 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.");
874 return;
875 }
876 sourceable.addSource(source);
877 }else if (cdmBase != null){
878 logger.warn("Sourced object does not implement ISourceable: " + cdmBase.getClass() + "," + cdmBase.getUuid());
879 }else{
880 logger.warn("Sourced object is null");
881 }
882 }
883
884 /**
885 * @see #addOriginalSource(CdmBase, Object, String, Reference)
886 * @param rs
887 * @param cdmBase
888 * @param dbIdAttribute
889 * @param namespace
890 * @param citation
891 * @throws SQLException
892 */
893 public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, Reference citation) throws SQLException {
894 Object id = rs.getObject(dbIdAttribute);
895 addOriginalSource(cdmBase, id, namespace, citation);
896 }
897
898
899 /**
900 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
901 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
902 * If the name is an autonym and has no combination author/basionym author the authors are taken from
903 * the parent.
904 * @param parentTaxon
905 * @param childTaxon
906 */
907 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon, Taxon childTaxon) {
908 if (parentTaxon == null){
909 logger.warn("Parent taxon is null. Missing name parts can not be taken from parent");
910 return;
911 }
912 NonViralName<?> parentName = HibernateProxyHelper.deproxy(parentTaxon.getName(), NonViralName.class);
913 NonViralName<?> childName = HibernateProxyHelper.deproxy(childTaxon.getName(), NonViralName.class);
914 fillMissingEpithets(parentName, childName);
915 }
916
917 /**
918 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
919 * or <i>species</i> respectively the according epithets are taken from the parent name.
920 * If the name is an autonym and has no combination author/basionym author the authors are taken from
921 * the parent.
922 * @param parentTaxon
923 * @param childTaxon
924 */
925 protected void fillMissingEpithets(NonViralName parentName, NonViralName childName) {
926 if (StringUtils.isBlank(childName.getGenusOrUninomial()) && childName.getRank().isLower(Rank.GENUS()) ){
927 childName.setGenusOrUninomial(parentName.getGenusOrUninomial());
928 }
929
930 if (StringUtils.isBlank(childName.getSpecificEpithet()) && childName.getRank().isLower(Rank.SPECIES()) ){
931 childName.setSpecificEpithet(parentName.getSpecificEpithet());
932 }
933 if (childName.isAutonym() && childName.getCombinationAuthorTeam() == null && childName.getBasionymAuthorTeam() == null ){
934 childName.setCombinationAuthorTeam(parentName.getCombinationAuthorTeam());
935 childName.setBasionymAuthorTeam(parentName.getBasionymAuthorTeam());
936 }
937 }
938
939 /**
940 * Returns the taxon description for a taxon. If there are multiple taxon descriptions
941 * an arbitrary one is chosen.
942 * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>
943 * is <code>true</code>.
944 * @param createNewIfNotExists
945 * @param isImageGallery if true only taxon description being image galleries are considered.
946 * If false only taxon description being no image galleries are considered.
947 * @return
948 */
949 public TaxonNameDescription getTaxonNameDescription(TaxonNameBase name, boolean isImageGallery, boolean createNewIfNotExists) {
950 Reference<?> ref = null;
951 return getTaxonNameDescription(name, ref, isImageGallery, createNewIfNotExists);
952 }
953
954 /**
955 * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}
956 * Only matches a description if the given reference is a source of the description.<BR>
957 * If a new description is created the given reference will be added as a source.
958 *
959 * @see #getTaxonDescription(Taxon, boolean, boolean)
960 */
961 public TaxonNameDescription getTaxonNameDescription(TaxonNameBase<?,?> name, Reference ref, boolean isImageGallery, boolean createNewIfNotExists) {
962 TaxonNameDescription result = null;
963 Set<TaxonNameDescription> descriptions= name.getDescriptions();
964 for (TaxonNameDescription description : descriptions){
965 if (description.isImageGallery() == isImageGallery){
966 if (hasCorrespondingSource(ref, description)){
967 result = description;
968 break;
969 }
970 }
971 }
972 if (result == null && createNewIfNotExists){
973 result = TaxonNameDescription.NewInstance(name);
974 result.setImageGallery(isImageGallery);
975 if (ref != null){
976 result.addImportSource(null, null, ref, null);
977 }
978 }
979 return result;
980 }
981
982 /**
983 * Returns the taxon description for a taxon. If there are multiple taxon descriptions
984 * an arbitrary one is chosen.
985 * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>
986 * is <code>true</code>.
987 * @param createNewIfNotExists
988 * @param isImageGallery if true only taxon description being image galleries are considered.
989 * If false only taxon description being no image galleries are considered.
990 * @return
991 */
992 public TaxonDescription getTaxonDescription(Taxon taxon, boolean isImageGallery, boolean createNewIfNotExists) {
993 Reference<?> ref = null;
994 return getTaxonDescription(taxon, ref, isImageGallery, createNewIfNotExists);
995 }
996
997 /**
998 * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}
999 * Only matches a description if the given reference is a source of the description.<BR>
1000 * If a new description is created the given reference will be added as a source.
1001 *
1002 * @see #getTaxonDescription(Taxon, boolean, boolean)
1003 */
1004 public TaxonDescription getTaxonDescription(Taxon taxon, Reference ref, boolean isImageGallery, boolean createNewIfNotExists) {
1005 TaxonDescription result = null;
1006 Set<TaxonDescription> descriptions= taxon.getDescriptions();
1007 for (TaxonDescription description : descriptions){
1008 if (description.isImageGallery() == isImageGallery){
1009 if (hasCorrespondingSource(ref, description)){
1010 result = description;
1011 break;
1012 }
1013 }
1014 }
1015 if (result == null && createNewIfNotExists){
1016 result = TaxonDescription.NewInstance(taxon);
1017 result.setImageGallery(isImageGallery);
1018 if (ref != null){
1019 result.addImportSource(null, null, ref, null);
1020 }
1021 }
1022 return result;
1023 }
1024
1025
1026 /**
1027 * Returns the {@link SpecimenDescription specimen description} for a {@link SpecimenOrObservationBase specimen or observation}.
1028 * If there are multiple specimen descriptions an arbitrary one is chosen.
1029 * If no specimen description exists, a new one is created if <code>createNewIfNotExists</code> is <code>true</code>.
1030 * @param createNewIfNotExists
1031 * @param isImageGallery if true only specimen description being image galleries are considered.
1032 * If false only specimen description being no image galleries are considered.
1033 * @return
1034 */
1035 public SpecimenDescription getSpecimenDescription(SpecimenOrObservationBase specimen, boolean isImageGallery, boolean createNewIfNotExists) {
1036 Reference ref = null;
1037 return getSpecimenDescription(specimen, ref, isImageGallery, createNewIfNotExists);
1038 }
1039
1040 /**
1041 * Like {@link #getSpecimenDescription(SpecimenOrObservationBase, boolean, boolean)}
1042 * Only matches a description if the given reference is a source of the description.<BR>
1043 * If a new description is created the given reference will be added as a source.
1044 *
1045 * @see #getTaxonDescription(Taxon, boolean, boolean)
1046 */
1047 public SpecimenDescription getSpecimenDescription(SpecimenOrObservationBase specimen, Reference ref, boolean isImageGallery, boolean createNewIfNotExists) {
1048 SpecimenDescription result = null;
1049 Set<SpecimenDescription> descriptions= specimen.getDescriptions();
1050 for (SpecimenDescription description : descriptions){
1051 if (description.isImageGallery() == isImageGallery){
1052 if (hasCorrespondingSource(ref, description)){
1053 result = description;
1054 break;
1055 }
1056 }
1057 }
1058 if (result == null && createNewIfNotExists){
1059 result = SpecimenDescription.NewInstance(specimen);
1060 result.setImageGallery(isImageGallery);
1061 if (ref != null){
1062 result.addImportSource(null, null, ref, null);
1063 }
1064 }
1065 return result;
1066 }
1067
1068
1069 /**
1070 * Returns the textdata that holds general information about a feature for a taxon description.
1071 * This is mainly necessary for descriptions that have more than one description element for
1072 * a given feature such as 'distribution', 'description' or 'common name'. It may also hold
1073 * for hierarchical features where no description element exists for a higher hierarchy level.
1074 * Example: the description feature has subfeatures. But some information like authorship, figures,
1075 * sources need to be added to the description itself.
1076 * Currently a feature placeholder is marked by a marker of type 'feature placeholder'. Maybe in future
1077 * there will be a boolean marker in the TextData class itself.
1078 * @param state
1079 * @param feature
1080 * @param taxon
1081 * @param ref
1082 * @param createIfNotExists
1083 * @return
1084 */
1085 protected TextData getFeaturePlaceholder(STATE state, DescriptionBase<?> description, Feature feature, boolean createIfNotExists) {
1086 UUID featurePlaceholderUuid = MarkupTransformer.uuidFeaturePlaceholder;
1087 for (DescriptionElementBase element : description.getElements()){
1088 if (element.isInstanceOf(TextData.class)){
1089 TextData textData = CdmBase.deproxy(element, TextData.class);
1090 if (textData.getFeature() == null || ! textData.getFeature().equals(feature)){
1091 continue;
1092 }
1093 for (Marker marker : textData.getMarkers()){
1094 MarkerType markerType = marker.getMarkerType();
1095 if (markerType != null &&
1096 markerType.getUuid().equals(featurePlaceholderUuid) &&
1097 marker.getValue() == true){
1098 return textData;
1099 }
1100 }
1101 }
1102 }
1103 if (createIfNotExists){
1104 TextData newPlaceholder = TextData.NewInstance(feature);
1105 MarkerType placeholderMarkerType = getMarkerType(state, featurePlaceholderUuid, "Feature Placeholder", "Feature Placeholder", null);
1106 Marker marker = Marker.NewInstance(placeholderMarkerType, true);
1107 newPlaceholder.addMarker(marker);
1108 description.addElement(newPlaceholder);
1109 return newPlaceholder;
1110 }else{
1111 return null;
1112 }
1113 }
1114
1115
1116
1117 /**
1118 * Returns true, if this description has a source with a citation equal to the given reference.
1119 * Returns true if the given reference is null.
1120 * @param ref
1121 * @param description
1122 */
1123 private boolean hasCorrespondingSource(Reference<?> ref, DescriptionBase<?> description) {
1124 if (ref != null){
1125 for (IdentifiableSource source : description.getSources()){
1126 if (ref.equals(source.getCitation())){
1127 return true;
1128 }
1129 }
1130 return false;
1131 }
1132 return true;
1133
1134 }
1135
1136
1137 /**
1138 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
1139 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
1140 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
1141 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
1142 * same secundum reference is returned. If no such single taxon exists an
1143 * {@link IllegalStateException illegal state exception} is thrown.
1144 * @param taxonBase
1145 * @return
1146 */
1147 protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {
1148 if (taxonBase == null){
1149 return null;
1150 }else if(taxonBase.isInstanceOf(Taxon.class)){
1151 return CdmBase.deproxy(taxonBase, Taxon.class);
1152 }else if(taxonBase.isInstanceOf(Synonym.class)){
1153 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
1154 Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
1155 if (acceptedTaxa.size() == 0){
1156 return null;
1157 }else if (acceptedTaxa.size() == 1){
1158 return acceptedTaxa.iterator().next();
1159 }else{
1160 Reference<?> sec = synonym.getSec();
1161 if (sec != null){
1162 Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();
1163 for (Taxon taxon: acceptedTaxa){
1164 if (sec.equals(taxon.getSec())){
1165 taxaWithSameSec.add(taxon);
1166 }
1167 }
1168 if (taxaWithSameSec.size() == 1){
1169 return taxaWithSameSec.iterator().next();
1170 }
1171 }
1172 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
1173 }
1174 }else{
1175 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());
1176 }
1177 }
1178
1179
1180
1181 /**
1182 * Creates
1183 * @param uriString
1184 * @param readDataFromUrl
1185 * @see #READ_MEDIA_DATA
1186 * @return
1187 * @throws MalformedURLException
1188 */
1189 protected Media getImageMedia(String uriString, boolean readMediaData) throws MalformedURLException {
1190 if( uriString == null){
1191 return null;
1192 } else {
1193 ImageInfo imageInfo = null;
1194 URI uri;
1195 uriString = uriString.replace(" ", "%20"); //replace whitespace
1196 try {
1197 uri = new URI(uriString);
1198 try {
1199 if (readMediaData){
1200 logger.warn(uri);
1201 imageInfo = ImageInfo.NewInstance(uri, 0);
1202 }
1203 } catch (Exception e) {
1204 String message = "An error occurred when trying to read image meta data for " + uri.toString() + ": " + e.getMessage();
1205 logger.warn(message);
1206 fireWarningEvent(message, "unknown location", 2, 0);
1207 }
1208 ImageFile imageFile = ImageFile.NewInstance(uri, null, imageInfo);
1209 MediaRepresentation representation = MediaRepresentation.NewInstance();
1210 if(imageInfo != null){
1211 representation.setMimeType(imageInfo.getMimeType());
1212 representation.setSuffix(imageInfo.getSuffix());
1213 }
1214 representation.addRepresentationPart(imageFile);
1215 Media media = Media.NewInstance();
1216 media.addRepresentation(representation);
1217 return media;
1218 } catch (URISyntaxException e1) {
1219 String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + uriString;
1220 logger.warn(message);
1221 fireWarningEvent(message, "unknown location", 4, 0);
1222 return null;
1223 }
1224 }
1225 }
1226
1227
1228 /**
1229 * Retrieves an Integer value from a result set. If the value is NULL null is returned.
1230 * ResultSet.getInt() returns 0 therefore we need a special handling for this case.
1231 * @param rs
1232 * @param columnName
1233 * @return
1234 * @throws SQLException
1235 */
1236 protected Integer nullSafeInt(ResultSet rs, String columnName) throws SQLException {
1237 Object intObject = rs.getObject(columnName);
1238 if (intObject == null){
1239 return null;
1240 }else{
1241 return Integer.valueOf(intObject.toString());
1242 }
1243 }
1244
1245 protected Boolean nullSafeBoolean(ResultSet rs, String columnName) throws SQLException {
1246 Object bitObject = rs.getObject(columnName);
1247 if (bitObject == null){
1248 return null;
1249 }else{
1250 return Boolean.valueOf(bitObject.toString());
1251 }
1252 }
1253
1254 protected Double nullSafeDouble(ResultSet rs, String columnName) throws SQLException {
1255 Object doubleObject = rs.getObject(columnName);
1256 if (doubleObject == null){
1257 return null;
1258 }else{
1259 return Double.valueOf(doubleObject.toString());
1260 }
1261 }
1262
1263 protected Float nullSafeFloat(ResultSet rs, String columnName) throws SQLException {
1264 Object doubleObject = rs.getObject(columnName);
1265 if (doubleObject == null){
1266 return null;
1267 }else{
1268 return Float.valueOf(doubleObject.toString());
1269 }
1270 }
1271
1272
1273 /**
1274 * Returns <code>null</code> for all blank strings. Identity function otherwise.
1275 * @param str
1276 * @return
1277 */
1278 protected String NB(String str) {
1279 if (StringUtils.isBlank(str)){
1280 return null;
1281 }else{
1282 return str;
1283 }
1284 }
1285
1286
1287 }