358421187fbed949ca852b0764854c30e365ce28
[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 = new TermVocabulary();
339 voc.setUuid(uuid);
340 Representation representation = Representation.NewInstance(text, label, abbrev, Language.DEFAULT());
341 voc.addRepresentation(representation);
342 getVocabularyService().save(voc);
343 }
344 return voc;
345 }
346
347 /**
348 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
349 * If cdmBase is not sourceable nothing happens.
350 * TODO Move to DbImportBase once this exists.
351 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
352 * @param rs
353 * @param cdmBase
354 * @param dbIdAttribute
355 * @param namespace
356 * @param citation
357 * @throws SQLException
358 */
359 public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, Reference citation) {
360 if (cdmBase instanceof ISourceable ){
361 IOriginalSource source;
362 ISourceable sourceable = (ISourceable)cdmBase;
363 Object id = idAttributeValue;
364 String strId = String.valueOf(id);
365 String microCitation = null;
366 if (cdmBase instanceof IdentifiableEntity){
367 source = IdentifiableSource.NewInstance(strId, namespace, citation, microCitation);
368 }else if (cdmBase instanceof DescriptionElementBase){
369 source = DescriptionElementSource.NewInstance(strId, namespace, citation, microCitation);
370 }else{
371 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.");
372 return;
373 }
374 sourceable.addSource(source);
375 }else if (cdmBase != null){
376 logger.warn("Sourced object does not implement ISourceable: " + cdmBase.getClass() + "," + cdmBase.getUuid());
377 }else{
378 logger.warn("Sourced object is null");
379 }
380 }
381
382 /**
383 * @see #addOriginalSource(CdmBase, Object, String, Reference)
384 * @param rs
385 * @param cdmBase
386 * @param dbIdAttribute
387 * @param namespace
388 * @param citation
389 * @throws SQLException
390 */
391 public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, Reference citation) throws SQLException {
392 Object id = rs.getObject(dbIdAttribute);
393 addOriginalSource(cdmBase, id, namespace, citation);
394 }
395
396
397 /**
398 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
399 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
400 * If the name is an autonym and has no combination author/basionym author the authors are taken from
401 * the parent.
402 * @param parentTaxon
403 * @param childTaxon
404 */
405 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon, Taxon childTaxon) {
406 NonViralName parentName = HibernateProxyHelper.deproxy(parentTaxon.getName(), NonViralName.class);
407 NonViralName childName = HibernateProxyHelper.deproxy(childTaxon.getName(), NonViralName.class);
408 fillMissingEpithets(parentName, childName);
409 }
410
411 /**
412 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
413 * or <i>species</i> respectively the according epithets are taken from the parent name.
414 * If the name is an autonym and has no combination author/basionym author the authors are taken from
415 * the parent.
416 * @param parentTaxon
417 * @param childTaxon
418 */
419 protected void fillMissingEpithets(NonViralName parentName, NonViralName childName) {
420 if (CdmUtils.isEmpty(childName.getGenusOrUninomial()) && childName.getRank().isLower(Rank.GENUS()) ){
421 childName.setGenusOrUninomial(parentName.getGenusOrUninomial());
422 }
423
424 if (CdmUtils.isEmpty(childName.getSpecificEpithet()) && childName.getRank().isLower(Rank.SPECIES()) ){
425 childName.setSpecificEpithet(parentName.getSpecificEpithet());
426 }
427 if (childName.isAutonym() && childName.getCombinationAuthorTeam() == null && childName.getBasionymAuthorTeam() == null ){
428 childName.setCombinationAuthorTeam(parentName.getCombinationAuthorTeam());
429 childName.setBasionymAuthorTeam(parentName.getBasionymAuthorTeam());
430 }
431 }
432
433 /**
434 * Returns the image gallery for a taxon. If there are multiple taxon descriptions
435 * marked as image galleries an arbitrary one is chosen.
436 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
437 * is <code>true</code>.
438 * @param createNewIfNotExists
439 * @return
440 */
441 public TaxonDescription getTaxonDescription(Taxon taxon, boolean isImageGallery, boolean createNewIfNotExists) {
442 TaxonDescription result = null;
443 Set<TaxonDescription> descriptions= taxon.getDescriptions();
444 for (TaxonDescription description : descriptions){
445 if (description.isImageGallery() == isImageGallery){
446 result = description;
447 break;
448 }
449 }
450 if (result == null && createNewIfNotExists){
451 result = TaxonDescription.NewInstance(taxon);
452 result.setImageGallery(isImageGallery);
453 }
454 return result;
455 }
456
457
458 /**
459 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
460 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
461 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
462 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
463 * same secundum reference is returned. If no such single taxon exists an
464 * {@link IllegalStateException illegal state exception} is thrown.
465 * @param taxonBase
466 * @return
467 */
468 protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {
469 if (taxonBase == null){
470 return null;
471 }else if(taxonBase.isInstanceOf(Taxon.class)){
472 return CdmBase.deproxy(taxonBase, Taxon.class);
473 }else if(taxonBase.isInstanceOf(Synonym.class)){
474 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
475 Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
476 if (acceptedTaxa.size() == 0){
477 return null;
478 }else if (acceptedTaxa.size() == 1){
479 return acceptedTaxa.iterator().next();
480 }else{
481 Reference sec = synonym.getSec();
482 if (sec != null){
483 Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();
484 for (Taxon taxon: acceptedTaxa){
485 if (sec.equals(taxon.getSec())){
486 taxaWithSameSec.add(taxon);
487 }
488 }
489 if (taxaWithSameSec.size() == 1){
490 return taxaWithSameSec.iterator().next();
491 }
492 }
493 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
494 }
495 }else{
496 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());
497 }
498 }
499
500
501
502 /**
503 * @param derivedUnitFacade
504 * @param multimediaObject
505 * @throws MalformedURLException
506 */
507 protected Media getImageMedia(String multimediaObject, boolean readDataFromUrl) throws MalformedURLException {
508 if( multimediaObject == null){
509 return null;
510 } else {
511 ImageMetaData imd = ImageMetaData.newInstance();
512 URI uri;
513 try {
514 uri = new URI(multimediaObject);
515 try {
516 if (readDataFromUrl){
517 imd.readMetaData(uri, 0);
518 }
519 } catch (Exception e) {
520 String message = "An error occurred when trying to read image meta data: " + e.getMessage();
521 logger.warn(message);
522 }
523 ImageFile imf = ImageFile.NewInstance(uri, null, imd);
524 MediaRepresentation representation = MediaRepresentation.NewInstance();
525 representation.setMimeType(imd.getMimeType());
526 representation.addRepresentationPart(imf);
527 Media media = Media.NewInstance();
528 media.addRepresentation(representation);
529 return media;
530 } catch (URISyntaxException e1) {
531 String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + multimediaObject;
532 logger.warn(message);
533 return null;
534 }
535 }
536 }
537
538
539 }