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