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