hide term vocabulary constructors and create factory methods instead
[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.HashSet;
18 import java.util.Set;
19 import java.util.UUID;
20
21 import org.apache.log4j.Logger;
22
23 import eu.etaxonomy.cdm.common.CdmUtils;
24 import eu.etaxonomy.cdm.common.mediaMetaData.ImageMetaData;
25 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
26 import eu.etaxonomy.cdm.io.common.mapping.IInputTransformer;
27 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
28 import eu.etaxonomy.cdm.model.common.AnnotationType;
29 import eu.etaxonomy.cdm.model.common.CdmBase;
30 import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
31 import eu.etaxonomy.cdm.model.common.ExtensionType;
32 import eu.etaxonomy.cdm.model.common.IOriginalSource;
33 import eu.etaxonomy.cdm.model.common.ISourceable;
34 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
35 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
36 import eu.etaxonomy.cdm.model.common.Language;
37 import eu.etaxonomy.cdm.model.common.MarkerType;
38 import eu.etaxonomy.cdm.model.common.Representation;
39 import eu.etaxonomy.cdm.model.common.TermVocabulary;
40 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
41 import eu.etaxonomy.cdm.model.description.Feature;
42 import eu.etaxonomy.cdm.model.description.PresenceTerm;
43 import eu.etaxonomy.cdm.model.description.TaxonDescription;
44 import eu.etaxonomy.cdm.model.location.NamedArea;
45 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
46 import eu.etaxonomy.cdm.model.location.NamedAreaType;
47 import eu.etaxonomy.cdm.model.media.ImageFile;
48 import eu.etaxonomy.cdm.model.media.Media;
49 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
50 import eu.etaxonomy.cdm.model.name.NonViralName;
51 import eu.etaxonomy.cdm.model.name.Rank;
52 import eu.etaxonomy.cdm.model.reference.Reference;
53 import eu.etaxonomy.cdm.model.taxon.Classification;
54 import eu.etaxonomy.cdm.model.taxon.Synonym;
55 import eu.etaxonomy.cdm.model.taxon.Taxon;
56 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
57
58 /**
59 * @author a.mueller
60 * @created 01.07.2008
61 * @version 1.0
62 */
63 public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE extends ImportStateBase> extends CdmIoBase<STATE> implements ICdmImport<CONFIG, STATE>{
64 private static Logger logger = Logger.getLogger(CdmImportBase.class);
65
66 protected Classification makeTree(STATE state, Reference reference){
67 Reference ref = CdmBase.deproxy(reference, Reference.class);
68 String treeName = "Classification (Import)";
69 if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){
70 treeName = ref.getTitleCache();
71 }
72 Classification tree = Classification.NewInstance(treeName);
73 tree.setReference(ref);
74
75
76 // use defined uuid for first tree
77 CONFIG config = (CONFIG)state.getConfig();
78 if (state.countTrees() < 1 ){
79 tree.setUuid(config.getClassificationUuid());
80 }
81 getClassificationService().save(tree);
82 state.putTree(ref, tree);
83 return tree;
84 }
85
86
87 /**
88 * Alternative memory saving method variant of
89 * {@link #makeTree(STATE state, Reference ref)} which stores only the
90 * UUID instead of the full tree in the <code>ImportStateBase</code> by
91 * using <code>state.putTreeUuid(ref, tree);</code>
92 *
93 * @param state
94 * @param ref
95 * @return
96 */
97 protected Classification makeTreeMemSave(STATE state, Reference ref){
98 String treeName = "Classification (Import)";
99 if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){
100 treeName = ref.getTitleCache();
101 }
102 Classification tree = Classification.NewInstance(treeName);
103 tree.setReference(ref);
104
105
106 // use defined uuid for first tree
107 CONFIG config = (CONFIG)state.getConfig();
108 if (state.countTrees() < 1 ){
109 tree.setUuid(config.getClassificationUuid());
110 }
111 getClassificationService().save(tree);
112 state.putTreeUuid(ref, tree);
113 return tree;
114 }
115
116
117 protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
118 if (uuid == null){
119 uuid = UUID.randomUUID();
120 }
121 ExtensionType extensionType = state.getExtensionType(uuid);
122 if (extensionType == null){
123 extensionType = (ExtensionType)getTermService().find(uuid);
124 if (extensionType == null){
125 extensionType = ExtensionType.NewInstance(text, label, labelAbbrev);
126 extensionType.setUuid(uuid);
127 UUID uuidExtensionTypeVoc = UUID.fromString("117cc307-5bd4-4b10-9b2f-2e14051b3b20");
128 TermVocabulary voc = getVocabularyService().find(uuidExtensionTypeVoc);
129 voc.addTerm(extensionType);
130 getTermService().save(extensionType);
131 }
132 state.putExtensionType(extensionType);
133 }
134 return extensionType;
135 }
136
137
138 protected MarkerType getMarkerType(STATE state, String keyString) {
139 IInputTransformer transformer = state.getTransformer();
140 MarkerType markerType = null;
141 try {
142 markerType = transformer.getMarkerTypeByKey(keyString);
143 } catch (UndefinedTransformerMethodException e) {
144 logger.info("getMarkerTypeByKey not yet implemented for this import");
145 }
146 if (markerType == null ){
147 UUID uuid;
148 try {
149 uuid = transformer.getMarkerTypeUuid(keyString);
150 return getMarkerType(state, uuid, keyString, keyString, keyString);
151 } catch (UndefinedTransformerMethodException e) {
152 logger.warn("getMarkerTypeUuid not yet implemented for this import");
153 }
154 }
155 return null;
156 }
157
158 protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
159 if (uuid == null){
160 uuid = UUID.randomUUID();
161 }
162 MarkerType markerType = state.getMarkerType(uuid);
163 if (markerType == null){
164 markerType = (MarkerType)getTermService().find(uuid);
165 if (markerType == null){
166 markerType = MarkerType.NewInstance(label, text, labelAbbrev);
167 markerType.setUuid(uuid);
168 UUID uuidMarkerTypeVoc = UUID.fromString("19dffff7-e142-429c-a420-5d28e4ebe305");
169 TermVocabulary voc = getVocabularyService().find(uuidMarkerTypeVoc);
170 voc.addTerm(markerType);
171 getTermService().save(markerType);
172 }
173 state.putMarkerType(markerType);
174 }
175 return markerType;
176 }
177
178 protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev){
179 if (uuid == null){
180 uuid = UUID.randomUUID();
181 }
182 AnnotationType annotationType = state.getAnnotationType(uuid);
183 if (annotationType == null){
184 annotationType = (AnnotationType)getTermService().find(uuid);
185 if (annotationType == null){
186 annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
187 annotationType.setUuid(uuid);
188 UUID uuidAnnotationTypeVoc = UUID.fromString("ca04609b-1ba0-4d31-9c2e-aa8eb2f4e62d");
189 TermVocabulary voc = getVocabularyService().find(uuidAnnotationTypeVoc);
190 voc.addTerm(annotationType);
191 getTermService().save(annotationType);
192 }
193 state.putAnnotationType(annotationType);
194 }
195 return annotationType;
196 }
197
198 public static final UUID uuidUserDefinedNamedAreaVocabulary = UUID.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
199 /**
200 * Returns a named area for a given uuid by first . If the named area does not
201 * @param state
202 * @param uuid
203 * @param label
204 * @param text
205 * @param labelAbbrev
206 * @param areaType
207 * @param level
208 * @return
209 */
210 protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level){
211 return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, null);
212 }
213
214 protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc){
215 if (uuid == null){
216 uuid = UUID.randomUUID();
217 }
218 NamedArea namedArea = state.getNamedArea(uuid);
219 if (namedArea == null){
220 namedArea = (NamedArea)getTermService().find(uuid);
221 if (namedArea == null){
222 namedArea = NamedArea.NewInstance(text, label, labelAbbrev);
223 if (voc == null){
224 voc = getVocabulary(uuidUserDefinedNamedAreaVocabulary, "User defined vocabulary for named areas", "User Defined Named Areas", null);
225 }
226 voc.addTerm(namedArea);
227 namedArea.setType(areaType);
228 namedArea.setLevel(level);
229 namedArea.setUuid(uuid);
230 getTermService().save(namedArea);
231 }
232 state.putNamedArea(namedArea);
233 }
234 return namedArea;
235 }
236
237 /**
238 * Returns a feature for a given uuid by first ...
239 * @param state
240 * @param uuid
241 * @param label
242 * @param text
243 * @param labelAbbrev
244 * @return
245 */
246 protected Feature getFeature(STATE state, UUID uuid, String label, String text, String labelAbbrev){
247 if (uuid == null){
248 return null;
249 }
250 Feature feature = state.getFeature(uuid);
251 if (feature == null){
252 feature = (Feature)getTermService().find(uuid);
253 if (feature == null){
254 feature = Feature.NewInstance(text, label, labelAbbrev);
255 feature.setUuid(uuid);
256 feature.setSupportsTextData(true);
257 //set vocabulary ; FIXME use another user-defined vocabulary
258 UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8");
259 TermVocabulary<Feature> voc = getVocabularyService().find(uuidFeatureVoc);
260 voc.addTerm(feature);
261 getTermService().save(feature);
262 }
263 state.putFeature(feature);
264 }
265 return feature;
266 }
267
268 /**
269 * Returns a presence term for a given uuid by first ...
270 * @param state
271 * @param uuid
272 * @param label
273 * @param text
274 * @param labelAbbrev
275 * @return
276 */
277 protected PresenceTerm getPresenceTerm(STATE state, UUID uuid, String label, String text, String labelAbbrev){
278 if (uuid == null){
279 return null;
280 }
281 PresenceTerm presenceTerm = state.getPresenceTerm(uuid);
282 if (presenceTerm == null){
283 presenceTerm = (PresenceTerm)getTermService().find(uuid);
284 if (presenceTerm == null){
285 presenceTerm = PresenceTerm.NewInstance(text, label, labelAbbrev);
286 presenceTerm.setUuid(uuid);
287 //set vocabulary ; FIXME use another user-defined vocabulary
288 UUID uuidPresenceVoc = UUID.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05");
289 TermVocabulary<PresenceTerm> voc = getVocabularyService().find(uuidPresenceVoc);
290 voc.addTerm(presenceTerm);
291 getTermService().save(presenceTerm);
292 }
293 state.putPresenceTerm(presenceTerm);
294 }
295 return presenceTerm;
296 }
297
298 /**
299 * Returns a language for a given uuid by first ...
300 * @param state
301 * @param uuid
302 * @param label
303 * @param text
304 * @param labelAbbrev
305 * @return
306 */
307 protected Language getLanguage(STATE state, UUID uuid, String label, String text, String labelAbbrev){
308 if (uuid == null){
309 return null;
310 }
311 Language language = state.getLanguage(uuid);
312 if (language == null){
313 language = (Language)getTermService().find(uuid);
314 if (language == null){
315 language = Language.NewInstance(text, label, labelAbbrev);
316
317 language.setUuid(uuid);
318 //set vocabulary ; FIXME use another user-defined vocabulary
319 UUID uuidLanguageVoc = UUID.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de");
320 TermVocabulary<Language> voc = getVocabularyService().find(uuidLanguageVoc);
321 voc.addTerm(language);
322 getTermService().save(language);
323 }
324 state.putLanguage(language);
325 }
326 return language;
327 }
328
329
330 /**
331 * @param uuid
332 * @return
333 *
334 */
335 protected TermVocabulary getVocabulary(UUID uuid, String text, String label, String abbrev) {
336 TermVocabulary voc = getVocabularyService().find(uuid);
337 if (voc == null){
338 voc = TermVocabulary.NewInstance(text, label, abbrev, null);
339 voc.setUuid(uuid);
340 getVocabularyService().save(voc);
341 }
342 return voc;
343 }
344
345 /**
346 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
347 * If cdmBase is not sourceable nothing happens.
348 * TODO Move to DbImportBase once this exists.
349 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
350 * @param rs
351 * @param cdmBase
352 * @param dbIdAttribute
353 * @param namespace
354 * @param citation
355 * @throws SQLException
356 */
357 public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, Reference citation) {
358 if (cdmBase instanceof ISourceable ){
359 IOriginalSource source;
360 ISourceable sourceable = (ISourceable)cdmBase;
361 Object id = idAttributeValue;
362 String strId = String.valueOf(id);
363 String microCitation = null;
364 if (cdmBase instanceof IdentifiableEntity){
365 source = IdentifiableSource.NewInstance(strId, namespace, citation, microCitation);
366 }else if (cdmBase instanceof DescriptionElementBase){
367 source = DescriptionElementSource.NewInstance(strId, namespace, citation, microCitation);
368 }else{
369 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.");
370 return;
371 }
372 sourceable.addSource(source);
373 }else if (cdmBase != null){
374 logger.warn("Sourced object does not implement ISourceable: " + cdmBase.getClass() + "," + cdmBase.getUuid());
375 }else{
376 logger.warn("Sourced object is null");
377 }
378 }
379
380 /**
381 * @see #addOriginalSource(CdmBase, Object, String, Reference)
382 * @param rs
383 * @param cdmBase
384 * @param dbIdAttribute
385 * @param namespace
386 * @param citation
387 * @throws SQLException
388 */
389 public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, Reference citation) throws SQLException {
390 Object id = rs.getObject(dbIdAttribute);
391 addOriginalSource(cdmBase, id, namespace, citation);
392 }
393
394
395 /**
396 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
397 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
398 * If the name is an autonym and has no combination author/basionym author the authors are taken from
399 * the parent.
400 * @param parentTaxon
401 * @param childTaxon
402 */
403 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon, Taxon childTaxon) {
404 NonViralName parentName = HibernateProxyHelper.deproxy(parentTaxon.getName(), NonViralName.class);
405 NonViralName childName = HibernateProxyHelper.deproxy(childTaxon.getName(), NonViralName.class);
406 fillMissingEpithets(parentName, childName);
407 }
408
409 /**
410 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
411 * or <i>species</i> respectively the according epithets are taken from the parent name.
412 * If the name is an autonym and has no combination author/basionym author the authors are taken from
413 * the parent.
414 * @param parentTaxon
415 * @param childTaxon
416 */
417 protected void fillMissingEpithets(NonViralName parentName, NonViralName childName) {
418 if (CdmUtils.isEmpty(childName.getGenusOrUninomial()) && childName.getRank().isLower(Rank.GENUS()) ){
419 childName.setGenusOrUninomial(parentName.getGenusOrUninomial());
420 }
421
422 if (CdmUtils.isEmpty(childName.getSpecificEpithet()) && childName.getRank().isLower(Rank.SPECIES()) ){
423 childName.setSpecificEpithet(parentName.getSpecificEpithet());
424 }
425 if (childName.isAutonym() && childName.getCombinationAuthorTeam() == null && childName.getBasionymAuthorTeam() == null ){
426 childName.setCombinationAuthorTeam(parentName.getCombinationAuthorTeam());
427 childName.setBasionymAuthorTeam(parentName.getBasionymAuthorTeam());
428 }
429 }
430
431 /**
432 * Returns the image gallery for a taxon. If there are multiple taxon descriptions
433 * marked as image galleries an arbitrary one is chosen.
434 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
435 * is <code>true</code>.
436 * @param createNewIfNotExists
437 * @return
438 */
439 public TaxonDescription getTaxonDescription(Taxon taxon, boolean isImageGallery, boolean createNewIfNotExists) {
440 TaxonDescription result = null;
441 Set<TaxonDescription> descriptions= taxon.getDescriptions();
442 for (TaxonDescription description : descriptions){
443 if (description.isImageGallery() == isImageGallery){
444 result = description;
445 break;
446 }
447 }
448 if (result == null && createNewIfNotExists){
449 result = TaxonDescription.NewInstance(taxon);
450 result.setImageGallery(isImageGallery);
451 }
452 return result;
453 }
454
455
456 /**
457 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
458 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
459 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
460 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
461 * same secundum reference is returned. If no such single taxon exists an
462 * {@link IllegalStateException illegal state exception} is thrown.
463 * @param taxonBase
464 * @return
465 */
466 protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {
467 if (taxonBase == null){
468 return null;
469 }else if(taxonBase.isInstanceOf(Taxon.class)){
470 return CdmBase.deproxy(taxonBase, Taxon.class);
471 }else if(taxonBase.isInstanceOf(Synonym.class)){
472 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
473 Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
474 if (acceptedTaxa.size() == 0){
475 return null;
476 }else if (acceptedTaxa.size() == 1){
477 return acceptedTaxa.iterator().next();
478 }else{
479 Reference sec = synonym.getSec();
480 if (sec != null){
481 Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();
482 for (Taxon taxon: acceptedTaxa){
483 if (sec.equals(taxon.getSec())){
484 taxaWithSameSec.add(taxon);
485 }
486 }
487 if (taxaWithSameSec.size() == 1){
488 return taxaWithSameSec.iterator().next();
489 }
490 }
491 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
492 }
493 }else{
494 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());
495 }
496 }
497
498
499
500 /**
501 * @param derivedUnitFacade
502 * @param multimediaObject
503 * @throws MalformedURLException
504 */
505 protected Media getImageMedia(String multimediaObject, boolean readDataFromUrl) throws MalformedURLException {
506 if( multimediaObject == null){
507 return null;
508 } else {
509 ImageMetaData imd = ImageMetaData.newInstance();
510 URI uri;
511 try {
512 uri = new URI(multimediaObject);
513 try {
514 if (readDataFromUrl){
515 imd.readMetaData(uri, 0);
516 }
517 } catch (Exception e) {
518 String message = "An error occurred when trying to read image meta data: " + e.getMessage();
519 logger.warn(message);
520 }
521 ImageFile imf = ImageFile.NewInstance(uri, null, imd);
522 MediaRepresentation representation = MediaRepresentation.NewInstance();
523 representation.setMimeType(imd.getMimeType());
524 representation.addRepresentationPart(imf);
525 Media media = Media.NewInstance();
526 media.addRepresentation(representation);
527 return media;
528 } catch (URISyntaxException e1) {
529 String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + multimediaObject;
530 logger.warn(message);
531 return null;
532 }
533 }
534 }
535
536
537 }