Project

General

Profile

Download (39 KB) Statistics
| Branch: | Revision:
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.globis;
11

    
12
import java.sql.ResultSet;
13
import java.sql.SQLException;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Set;
19
import java.util.UUID;
20
import java.util.regex.Matcher;
21
import java.util.regex.Pattern;
22

    
23
import org.apache.log4j.Logger;
24
import org.springframework.stereotype.Component;
25

    
26
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
27
import eu.etaxonomy.cdm.common.CdmUtils;
28
import eu.etaxonomy.cdm.io.common.IOValidator;
29
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
30
import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
31
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
32
import eu.etaxonomy.cdm.io.globis.validation.GlobisSpecTaxaImportValidator;
33
import eu.etaxonomy.cdm.model.agent.AgentBase;
34
import eu.etaxonomy.cdm.model.common.CdmBase;
35
import eu.etaxonomy.cdm.model.common.ExtensionType;
36
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
37
import eu.etaxonomy.cdm.model.common.Marker;
38
import eu.etaxonomy.cdm.model.common.MarkerType;
39
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
40
import eu.etaxonomy.cdm.model.description.Feature;
41
import eu.etaxonomy.cdm.model.location.NamedArea;
42
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
43
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
44
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
45
import eu.etaxonomy.cdm.model.name.Rank;
46
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
47
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
48
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
49
import eu.etaxonomy.cdm.model.name.ZoologicalName;
50
import eu.etaxonomy.cdm.model.occurrence.Collection;
51
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
52
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
53
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
54
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
55
import eu.etaxonomy.cdm.model.reference.Reference;
56
import eu.etaxonomy.cdm.model.taxon.Synonym;
57
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
58
import eu.etaxonomy.cdm.model.taxon.Taxon;
59
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
60
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
61

    
62

    
63
/**
64
 * @author a.mueller
65
 * @created 20.02.2010
66
 */
67
@Component
68
public class GlobisSpecTaxImport  extends GlobisImportBase<Reference<?>> implements IMappingImport<Reference<?>, GlobisImportState>{
69
	private static final Logger logger = Logger.getLogger(GlobisSpecTaxImport.class);
70
	
71
	private int modCount = 10000;
72
	private static final String pluralString = "taxa";
73
	private static final String dbTableName = "specTax";
74
	private static final Class<?> cdmTargetClass = Reference.class;
75
	
76
	private static UUID uuidCitedTypeLocality = UUID.fromString("ca431e0a-84ec-4828-935f-df4c8f5cf880");
77
	private static UUID uuidCitedTypeMaterial = UUID.fromString("8395021a-e596-4a55-9794-8c03aaad9e16");
78

    
79
	public GlobisSpecTaxImport(){
80
		super(pluralString, dbTableName, cdmTargetClass);
81
	}
82

    
83
	@Override
84
	protected String getIdQuery() {
85
		String strRecordQuery = 
86
			" SELECT specTaxId " + 
87
			" FROM " + dbTableName; 
88
		return strRecordQuery;	
89
	}
90

    
91
	@Override
92
	protected String getRecordQuery(GlobisImportConfigurator config) {
93
		String strRecordQuery = 
94
			" SELECT t.*, t.DateCreated as Created_When, t.CreatedBy as Created_Who," +
95
			"        t.ModifiedBy as Updated_who, t.DateModified as Updated_When, t.SpecRemarks as Notes " + 
96
			" FROM " + getTableName() + " t " +
97
			" WHERE ( t.specTaxId IN (" + ID_LIST_TOKEN + ") )";
98
		return strRecordQuery;
99
	}
100
	
101

    
102
	@Override
103
	public boolean doPartition(ResultSetPartitioner partitioner, GlobisImportState state) {
104
		boolean success = true;
105
		
106
		Set<TaxonBase> objectsToSave = new HashSet<TaxonBase>();
107
		Set<TaxonNameBase> namesToSave = new HashSet<TaxonNameBase>();
108
		
109
		Map<String, Taxon> taxonMap = (Map<String, Taxon>) partitioner.getObjectMap(TAXON_NAMESPACE);
110
		Map<String, Reference> referenceMap = (Map<String, Reference>) partitioner.getObjectMap(REFERENCE_NAMESPACE);
111
		
112
		ResultSet rs = partitioner.getResultSet();
113
		
114
		try {
115
			
116
			int i = 0;
117

    
118
			//for each reference
119
            while (rs.next()){
120
                
121
        		if ((i++ % modCount) == 0 && i!= 1 ){ logger.info(pluralString + " handled: " + (i-1));}
122
				
123
        		Integer specTaxId = rs.getInt("SpecTaxId");
124
        		Integer acceptedTaxonId = nullSafeInt(rs, "SpecCurrspecID");
125
        		String specSystaxRank = rs.getString("SpecSystaxRank");
126
        		
127
        		//ignore: CountryDummy, currentSpecies, DepositoryDisplay, DepositoryDummy, ReferenceDisplay, 
128
        		//        SpecDescriptionImageFile, all *Valid*
129
        		
130
				try {
131
					
132
					//source ref
133
					Reference<?> sourceRef = state.getTransactionalSourceReference();
134
				
135
					Taxon acceptedTaxon =  taxonMap.get(String.valueOf(acceptedTaxonId));
136
					TaxonBase<?> thisTaxon = null;
137
					
138
					ZoologicalName name = null;
139
					if (isBlank(specSystaxRank) ){
140
						name = makeName(state, rs, specTaxId);
141
					}else if (specSystaxRank.equals("synonym")){
142
						Synonym synonym = getSynonym(state, rs, specTaxId);
143
						if (acceptedTaxon == null){
144
							if (acceptedTaxonId == null){
145
								logger.warn("Synonym has no accepted taxon defined. SpecTaxId: "+ specTaxId);
146
							}else{
147
								logger.warn("Accepted taxon (" + acceptedTaxonId + ") not found for synonym "+ specTaxId);
148
							}
149
						}else{
150
							acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.SYNONYM_OF());
151
							thisTaxon = synonym;
152
						}
153
					}else if (specSystaxRank.equals("species")){
154
						validateAcceptedTaxon(acceptedTaxon, rs, specTaxId, acceptedTaxonId);
155
						thisTaxon = acceptedTaxon;
156
					}else{
157
						logger.warn(String.format("Unhandled specSystaxRank %s in specTaxId %d", specSystaxRank, specTaxId));
158
						name = makeName(state, rs, specTaxId);
159
					}
160
					
161
					if (thisTaxon != null){
162
						name = CdmBase.deproxy(thisTaxon.getName(), ZoologicalName.class);
163
					}else{
164
						if (name == null){
165
							name = makeName(state, rs, specTaxId);
166
						}
167
						
168
						thisTaxon = Taxon.NewInstance(name, sourceRef);
169
						objectsToSave.add(thisTaxon);
170
					}
171
					if (name == null){
172
						throw new RuntimeException("Name is still null");
173
					}
174
					
175
					handleNomRef(state, referenceMap, rs, name, specTaxId);
176
				
177
					handleTypeInformation(state,rs, name, specTaxId);
178
				
179
				
180
//					this.doIdCreatedUpdatedNotes(state, ref, rs, refId, REFERENCE_NAMESPACE);
181
				
182
					if (acceptedTaxon != null){
183
						objectsToSave.add(acceptedTaxon); 
184
					}
185
					
186
					//makeMarker1(state, rs, name);   //ignore!
187
					
188
					//make not available
189
					makeNotAvailable(state, rs, name, specTaxId);
190
					
191
					//maken invalid
192
					//TODO 
193
					
194
					//SpecCitedTypeLocality
195
					String citedTypeLocality = rs.getString("SpecCitedTypeLocality");
196
					if (isNotBlank(citedTypeLocality)){
197
//						ExtensionType exTypeCitedTypeLoc = getExtensionType(state, uuidCitedTypeLocality, "Type locality as cited in original description", "Type locality as cited in original description", null, ExtensionType.DOI().getVocabulary());
198
//						name.addExtension(citedTypeLocality, exTypeCitedTypeLoc);
199
						addNameDescription(state, name, uuidCitedTypeLocality, citedTypeLocality, "Type locality as cited in original description");
200
					}
201

    
202
					//SpecCitedTypeMaterial
203
					String citedTypeMaterial = rs.getString("SpecCitedTypeMaterial");
204
					if (isNotBlank(citedTypeMaterial)){
205
						ExtensionType exTypeCitedTypeLoc = getExtensionType(state, uuidCitedTypeMaterial, "Type material as cited in original description", "Type material as cited in original description", null, ExtensionType.DOI().getVocabulary());
206
						name.addExtension(citedTypeLocality, exTypeCitedTypeLoc);
207
					}
208

    
209
					name.addSource(OriginalSourceType.Import, String.valueOf(specTaxId), SPEC_TAX_NAMESPACE, state.getTransactionalSourceReference(), null);
210
					
211
					namesToSave.add(name);
212
					
213

    
214
				} catch (Exception e) {
215
					logger.warn("Exception in specTax: SpecTaxId " + specTaxId + ". " + e.getMessage());
216
					e.printStackTrace();
217
				} 
218
                
219
            }
220
           
221
			logger.warn(pluralString + " to save: " + objectsToSave.size());
222
			getTaxonService().save(objectsToSave);	
223
			getNameService().save(namesToSave);
224
			
225
			return success;
226
		} catch (Exception e) {
227
			logger.error("Exception: " +  e);
228
			return false;
229
		}
230
	}
231

    
232

    
233
	private void makeNotAvailable(GlobisImportState state, ResultSet rs, ZoologicalName name, int id) throws SQLException {
234
		String notAvailableStr = rs.getString("SpecNotAvailable");
235
		String notAvailableReason = rs.getString("SpecNotAvailableReason");
236
		
237
		if (isNotBlank(notAvailableStr) && notAvailableStr.contains("not available")){
238
			if (isBlank(notAvailableReason)){
239
				logger.warn("Blank notAvailableReason has available: " + id);
240
			}
241
			NomenclaturalStatus nomStatus = getNomStatus(state, notAvailableReason, id);
242
			if (nomStatus != null){
243
				name.addStatus(nomStatus);
244
			}
245
		}else{
246
			if (isNotBlank(notAvailableReason)){
247
				logger.warn("Blank notAvailable has reason: " + id);
248
			}
249
			//Do nothing
250
		}
251

    
252

    
253
		//OLD
254
//				if (notAvailableStr.contains("not available") ){ 
255
//					UUID uuidNotAvailableMarkerType = state.getTransformer().getMarkerTypeUuid("not available");
256
//					
257
//					MarkerType markerType = getMarkerType(state, uuidNotAvailableMarkerType, "not available", "not available", null);
258
//					name.addMarker(Marker.NewInstance(markerType, true));
259
//				}
260
//		//Not available reason
261
//		String notAvailableReason = rs.getString("SpecNotAvailableReason");
262
//		if (isNotBlank(notAvailableReason)){
263
//			UUID uuidNotAvailableReason;
264
//			try {
265
//				uuidNotAvailableReason = state.getTransformer().getExtensionTypeUuid("not available reason");
266
//				ExtensionType notAvailableReasonExtType = getExtensionType(state, uuidNotAvailableReason, "Not available reason", "Not available reason", null, null);
267
//				name.addExtension(notAvailableReason, notAvailableReasonExtType);
268
//			} catch (UndefinedTransformerMethodException e) {
269
//				e.printStackTrace();
270
//			} 
271
//		}
272
		
273
	}
274

    
275

    
276

    
277

    
278
	
279
	private NomenclaturalStatus getNomStatus(GlobisImportState state, String notAvailableReason, int id) {
280
		NomenclaturalStatus status = NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ZOO_NOT_AVAILABLE());
281
		status.setRuleConsidered(notAvailableReason);
282
		if (notAvailableReason.equalsIgnoreCase("hybrid")){
283
			logger.warn("Check hybrid for correctnes. Is there a better status?");
284
		}else if (notAvailableReason.equalsIgnoreCase("infrasubspecific name") || notAvailableReason.equalsIgnoreCase("infrasubspeciic name")){
285
			logger.warn("Check infrasubspecific name for correctnes. Is there a better status?");
286
		}else if (notAvailableReason.equalsIgnoreCase("by ruling of the Commission")){
287
			logger.warn("Check by ruling of the Commission for correctnes. Is there a better status?");
288
		}else{
289
			logger.warn("Unknown non available reason. ");
290
		}
291
		return status;
292
	}
293

    
294
	/**
295
	 * This method is not used anymore as according to Alexander Marker1 should be ignored.
296
	 * @param state
297
	 * @param rs
298
	 * @param name
299
	 * @throws SQLException
300
	 */
301
	@SuppressWarnings("unused")
302
	private void makeMarker1(GlobisImportState state, ResultSet rs, ZoologicalName name) throws SQLException {
303
		String marker1Str = rs.getString("Marker1");
304
		try {
305
			if (isNotBlank(marker1Str)){
306
				marker1Str = marker1Str.trim();
307
				if (marker1Str.contains("checked") || marker1Str.contains("berpr") ){ //überprüft
308
					UUID uuidCheckedMarkerType;
309
						uuidCheckedMarkerType = state.getTransformer().getMarkerTypeUuid("checked");
310
					
311
					MarkerType markerType = getMarkerType(state, uuidCheckedMarkerType, "checked", "checked", null);
312
					name.addMarker(Marker.NewInstance(markerType, true));
313
				}
314
				if (marker1Str.contains("old record") || marker1Str.contains("alte Angabe") ){
315
					UUID uuidOldRecordMarkerType = state.getTransformer().getMarkerTypeUuid("old record");
316
					MarkerType markerType = getMarkerType(state, uuidOldRecordMarkerType, "checked", "checked", null);
317
					name.addMarker(Marker.NewInstance(markerType, true));
318
				}
319
			}
320
		} catch (UndefinedTransformerMethodException e) {
321
			e.printStackTrace();
322
		}
323
		
324
	}
325

    
326

    
327
	private void addNameDescription(GlobisImportState state, ZoologicalName name, UUID featureUuid,
328
			String citedTypeLocality, String featureLabel) {
329
		Feature feature = getFeature(state, featureUuid,featureLabel,featureLabel, null, null);
330
		getTaxonNameDescription(name, false, true);
331
		
332
	}
333

    
334

    
335
	private Pattern patternAll = Pattern.compile("(.+,\\s.+)(\\(.+\\))");
336
	
337

    
338
	private void handleTypeInformation(GlobisImportState state, ResultSet rs, ZoologicalName name, Integer specTaxId) throws SQLException {
339
		if (! hasTypeInformation(rs)){
340
			return;
341
		}
342
		
343
		FieldUnit fieldObservation = makeTypeFieldObservation(state, rs);
344
		
345
		//typeDepository
346
		String specTypeDepositoriesStr = rs.getString("SpecTypeDepository");
347
		String[] specTypeDepositories; 
348
		if (isNotBlank(specTypeDepositoriesStr) ){
349
			specTypeDepositories = specTypeDepositoriesStr.trim().split(";");
350
		}else{
351
			specTypeDepositories = new String[0];
352
		}
353
		
354
		//TODO several issues
355
		if (specTypeDepositories.length == 0){
356
			DerivedUnit specimen = makeSingleTypeSpecimen(fieldObservation);
357
			makeTypeDesignation(name, rs, specimen, specTaxId);
358
			makeTypeIdInSource(state, specimen, "null", specTaxId);
359
		}else{
360
			for (String specTypeDepositoryStr : specTypeDepositories){
361
				specTypeDepositoryStr = specTypeDepositoryStr.trim();
362
				
363
				//Specimen
364
				DerivedUnit specimen = makeSingleTypeSpecimen(fieldObservation);
365
	
366
				if (specTypeDepositoryStr.equals("??")){
367
					//unknown
368
					//TODO marker unknown ?
369
					specimen.setTitleCache("??", true);
370
					makeTypeIdInSource(state, specimen, "??", specTaxId);
371
				}else if (specTypeDepositoryStr.equals("[lost]")){
372
					//lost
373
					//TODO marker lost ?
374
					specimen.setTitleCache("lost", true);
375
					makeTypeIdInSource(state, specimen, "[lost]", specTaxId);
376
				}else{
377
					specTypeDepositoryStr = makeAdditionalSpecimenInformation(
378
							specTypeDepositoryStr, specimen, specTaxId);
379
					
380
					Collection collection = makeCollection(state, specTypeDepositoryStr, specimen, specTaxId);
381
					String collectionCode = collection.getCode();
382
					if (isBlank(collectionCode)){
383
						collectionCode = collection.getName();
384
					}
385
					if (isBlank(collectionCode)){
386
						logger.warn("Collection has empty representation: " + specTypeDepositoryStr + ", specTaxId" +  specTaxId);
387
					}
388
					makeTypeIdInSource(state, specimen, collectionCode , specTaxId);	
389
				}
390
				
391
				//type Designation
392
				makeTypeDesignation(name, rs, specimen, specTaxId);
393
			}
394
		}
395

    
396
		
397
	}
398

    
399

    
400
	private void makeTypeIdInSource(GlobisImportState state, DerivedUnit specimen, String collectionCode, Integer specTaxId) {
401
		String namespace = TYPE_NAMESPACE;
402
		String id = getTypeId(specTaxId, collectionCode);
403
		IdentifiableSource source = IdentifiableSource.NewInstance(OriginalSourceType.Import, id, namespace, state.getTransactionalSourceReference(), null);
404
		specimen.addSource(source);
405
	}
406

    
407

    
408

    
409

    
410
	public static String getTypeId(Integer specTaxId, String collectionCode) {
411
		String result = String.valueOf(specTaxId) + "@" + collectionCode;
412
		return result;
413
	}
414

    
415

    
416

    
417

    
418
	private boolean hasTypeInformation(ResultSet rs) throws SQLException {
419
		String specTypeDepositoriesStr = rs.getString("SpecTypeDepository");
420
		String countryString = rs.getString("SpecTypeCountry");
421
		String specType = rs.getString("SpecType");
422
		boolean result = false;
423
		result |= isNotBlank(specTypeDepositoriesStr) || isNotBlank(countryString)
424
			|| isNotBlank(specType);
425
		return result;
426
	}
427

    
428

    
429

    
430
	/**
431
	 * @param state 
432
	 * @param specTypeDepositoryStr
433
	 * @param specimen
434
	 * @param specTaxId 
435
	 */
436
	protected Collection makeCollection(GlobisImportState state, String specTypeDepositoryStr, DerivedUnit specimen, Integer specTaxId) {
437
		
438
		//Collection
439
		specTypeDepositoryStr = specTypeDepositoryStr.replace("Washington, D.C.", "Washington@ D.C.")
440
				.replace("St.-Raymond, Quebec", "St.-Raymond@ Quebec")
441
				.replace("St.Petersburg", "St. Petersburg");
442
		
443
		
444
		Collection collection = handleSpecialCase(specTypeDepositoryStr, state, specimen);
445
		if (collection == null){
446
			String[] split = specTypeDepositoryStr.split(",");
447
			if (split.length != 2){
448
				if (split.length == 1 && (split[0].startsWith("coll.")|| split[0].startsWith("Coll.") )){
449
					collection = state.getRelatedObject(COLLECTION_NAMESPACE, split[0], Collection.class);
450
					if (collection == null){
451
						collection = Collection.NewInstance();
452
						collection.setName(split[0]);
453
						state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
454
					}
455
					specimen.setCollection(collection);
456
				}else{
457
					logger.warn("Split size in SpecTypeDepository is not 2: " + specTypeDepositoryStr + " (specTaxID:" + specTaxId + ")");
458
					collection = Collection.NewInstance();
459
					collection.setCode("??");
460
					//TODO deduplicate ??
461
				}
462
				
463
			}else{
464
				String collectionStr = split[0];
465
				String location = split[1].replace("@", ",").trim();
466
				
467
				collection = state.getRelatedObject(COLLECTION_NAMESPACE, collectionStr, Collection.class);
468
				if (collection == null){
469
					collection = Collection.NewInstance();
470
					if (collectionStr != null && collectionStr.startsWith("coll.")){
471
						collection.setName(collectionStr);
472
					}else{
473
						collection.setCode(collectionStr);
474
					}
475
					collection.setTownOrLocation(location);
476
					state.addRelatedObject(COLLECTION_NAMESPACE, collection.getCode(), collection);
477
						
478
				}else if (! CdmUtils.nullSafeEqual(location, collection.getTownOrLocation())){
479
					if (! normalizeTownOrLocation(location, collection)){
480
						String message = "Location (%s) is not equal to location (%s) of existing collection, specTaxId: " + specTaxId;
481
						logger.warn(String.format(message, location, collection.getTownOrLocation(), collection.getCode()));
482
					}
483
					
484
				}
485
				
486
				specimen.setCollection(collection);
487
			}
488
		}
489
		return collection;
490
	}
491

    
492

    
493
	private boolean normalizeTownOrLocation(String location, Collection collection) {
494
		boolean result = false;
495
		if (location != null){
496
			if ("coll. C. G. Treadaway".equals(collection.getName())){
497
				if (! "Frankfurt am Main".equals(collection.getTownOrLocation())){
498
					collection.setTownOrLocation("Frankfurt am Main");
499
					getCollectionService().saveOrUpdate(collection);
500
				}
501
				return true;
502
			}	else if ("coll. K. Rose".equals(collection.getName())){
503
				if (! "Mainz-Bretzenheim".equals(collection.getTownOrLocation())){
504
					collection.setTownOrLocation("Mainz-Bretzenheim");
505
					getCollectionService().saveOrUpdate(collection);
506
				}
507
				return true;
508
			} else if ("NMPN".equals(collection.getCode())){
509
				if (! "Prague".equals(collection.getTownOrLocation())){
510
					collection.setTownOrLocation("Prague");
511
					getCollectionService().saveOrUpdate(collection);
512
				}
513
				return true;
514
			} else if ("USNM".equals(collection.getCode())){
515
				if (! "Washington, D.C.".equals(collection.getTownOrLocation())){
516
					collection.setTownOrLocation("Washington, D.C.");
517
					getCollectionService().saveOrUpdate(collection);
518
				}
519
				return true;
520
			} else if ("coll. S. Kocman".equals(collection.getName())){
521
				if (! "Ostrava-Zabreh".equals(collection.getTownOrLocation())){
522
					collection.setTownOrLocation("Ostrava-Zabreh");
523
					getCollectionService().saveOrUpdate(collection);
524
				}
525
				return true;
526
			} else if ("ZSSM".equals(collection.getCode())){
527
				if (! "Munich".equals(collection.getTownOrLocation())){
528
					collection.setTownOrLocation("Munich");
529
					getCollectionService().saveOrUpdate(collection);
530
				}
531
				return true;
532
			} else if ("coll. R. H. Anken".equals(collection.getName())){
533
				if (! "Stuttgart".equals(collection.getTownOrLocation())){
534
					collection.setTownOrLocation("Stuttgart");
535
					getCollectionService().saveOrUpdate(collection);
536
				}
537
				return true;
538
			} else if ("coll. S.-I. Murayama".equals(collection.getName())){
539
				if (! "Aichi-Gakuin".equals(collection.getTownOrLocation())){
540
					collection.setTownOrLocation("Aichi-Gakuin");
541
					getCollectionService().saveOrUpdate(collection);
542
				}
543
				return true;
544
			} else if ("coll. Y. Sorimachi".equals(collection.getName())){
545
				if (! "Saitama".equals(collection.getTownOrLocation())){
546
					collection.setTownOrLocation("Saitama");
547
					getCollectionService().saveOrUpdate(collection);
548
				}
549
				return true;
550
			} else if ("coll. K. Yoshino".equals(collection.getName())){
551
				if (! "Saitama".equals(collection.getTownOrLocation())){
552
					collection.setTownOrLocation("Saitama");
553
					getCollectionService().saveOrUpdate(collection);
554
				}
555
				return true;
556
			} else if ("coll. U. Eitschberger".equals(collection.getName())){
557
				if (! "Marktleuthen".equals(collection.getTownOrLocation())){
558
					collection.setTownOrLocation("Marktleuthen");
559
					getCollectionService().saveOrUpdate(collection);
560
				}
561
				return true;
562
			} else if ("coll. G. Sala".equals(collection.getName())){
563
				if (! "Sal\u00f2".equals(collection.getTownOrLocation())){
564
					collection.setTownOrLocation("Sal\u00f2");  //LATIN SMALL LETTER O WITH GRAVE
565
					getCollectionService().saveOrUpdate(collection);
566
				}
567
				return true;
568
			} else if ("coll. Dantchenko".equals(collection.getName())){
569
				if (! "Moscow".equals(collection.getTownOrLocation())){
570
					collection.setTownOrLocation("Moscow");  
571
					getCollectionService().saveOrUpdate(collection);
572
				}
573
				return true;
574
			} else if ("coll. S. Nakano".equals(collection.getName())){
575
				if (! "Tokyo".equals(collection.getTownOrLocation())){
576
					collection.setTownOrLocation("Tokyo");  
577
					getCollectionService().saveOrUpdate(collection);
578
				}
579
				return true;
580
			} else if ("coll. A. Yagishita".equals(collection.getName())){
581
				if (! "Toride Ibaraki".equals(collection.getTownOrLocation())){
582
					collection.setTownOrLocation("Toride Ibaraki");  
583
					getCollectionService().saveOrUpdate(collection);
584
				}
585
				return true;
586
			} else if ("coll. H. Sugiyama".equals(collection.getName())){
587
				if (! "Gifu".equals(collection.getTownOrLocation())){
588
					collection.setTownOrLocation("Gifu");  
589
					getCollectionService().saveOrUpdate(collection);
590
				}
591
				return true;
592
			} else if ("MDMO".equals(collection.getCode())){
593
				if (! "Moscow".equals(collection.getTownOrLocation())){
594
					collection.setTownOrLocation("Moscow");  
595
					getCollectionService().saveOrUpdate(collection);
596
				}
597
				return true;
598
			} else if ("coll. W. Eckweiler".equals(collection.getName())){
599
				if (! "Frankfurt am Main".equals(collection.getTownOrLocation())){
600
					collection.setTownOrLocation("Frankfurt am Main");  
601
					getCollectionService().saveOrUpdate(collection);
602
				}
603
				return true;
604
			} else if ("coll. T. Frankenbach".equals(collection.getName())){
605
				if (! "Wangen".equals(collection.getTownOrLocation())){
606
					collection.setTownOrLocation("Wangen");  
607
					getCollectionService().saveOrUpdate(collection);
608
				}
609
				return true;
610
			}
611
		}
612
		
613
		return result;
614
	}
615

    
616
	private Collection handleSpecialCase(String specTypeDepositoryStr, GlobisImportState state, DerivedUnit specimen) {
617
		Collection collection;
618
		if (specTypeDepositoryStr.equals("BMNH, London and/or MNHN, Paris")){
619
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
620
			if (collection == null){
621
				collection = Collection.NewInstance();
622
				collection.setName(specTypeDepositoryStr);
623
				collection.setTownOrLocation("London or Paris");
624
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
625
			}
626
			specimen.setCollection(collection);
627
		}else if (specTypeDepositoryStr.equals("ZISP, St. Petersburg, and/or BMNH, London ?")){
628
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
629
			if (collection == null){
630
				collection = Collection.NewInstance();
631
				collection.setName(specTypeDepositoryStr);
632
				collection.setTownOrLocation("St. Petersburg or London");
633
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
634
			}
635
			specimen.setCollection(collection);
636
		}else if (specTypeDepositoryStr.equals("MFNB, Berlin or SMTD, Dresden")){
637
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
638
			if (collection == null){
639
				collection = Collection.NewInstance();
640
				collection.setName(specTypeDepositoryStr);
641
				collection.setTownOrLocation("Berlin or Dresden");
642
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
643
			}
644
			specimen.setCollection(collection);
645
		}else if (specTypeDepositoryStr.equals("coll. S. Ianoka, Yamanashi, coll. A. Shinkai, Tokyo or coll. S. Morita")){
646
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
647
			if (collection == null){
648
				collection = Collection.NewInstance();
649
				collection.setName(specTypeDepositoryStr);
650
				collection.setTownOrLocation("Yamanashi or Tokyo or ?");
651
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
652
			}
653
			specimen.setCollection(collection);
654
		}else if (specTypeDepositoryStr.equals("coll. S. Inaoka, Yamanashi, coll. A. Shinkai, Tokyo, coll. H. Mikami, coll. S. Koiwaya, coll S. Morita or coll. Y. Nose")){
655
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
656
			if (collection == null){
657
				collection = Collection.NewInstance();
658
				collection.setName(specTypeDepositoryStr);
659
				collection.setTownOrLocation("Yamanashi or Tokyo or ?");
660
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
661
			}
662
			specimen.setCollection(collection);
663
		}else if (specTypeDepositoryStr.equals("S. Morita, Tokyo or coll. Y. Sorimachi, Saitama")){
664
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, specTypeDepositoryStr, Collection.class);
665
			if (collection == null){
666
				collection = Collection.NewInstance();
667
				collection.setName(specTypeDepositoryStr);
668
				collection.setTownOrLocation("Tokyo or Saitama");
669
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
670
			}
671
			specimen.setCollection(collection);
672
			
673
		}else if (specTypeDepositoryStr.equals("coll. L. V. Kaabak, A .V. Sotshivko & V. V. Titov, Moscow")){
674
			String colName = "coll. L. V. Kaabak, A .V. Sotshivko & V. V. Titov";
675
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, colName, Collection.class);
676
			if (collection == null){
677
				collection = Collection.NewInstance();
678
				collection.setName(colName);
679
				collection.setTownOrLocation("Moscow");
680
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
681
			}
682
			specimen.setCollection(collection);
683
		}else if (specTypeDepositoryStr.matches("coll. R. E. Parrott?, Port Hope, Ontario")){
684
			String colName = "coll. R. E. Parrott";
685
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, colName, Collection.class);
686
			if (collection == null){
687
				collection = Collection.NewInstance();
688
				collection.setName(colName);
689
				collection.setTownOrLocation("Port Hope, Ontario");
690
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
691
			}
692
			specimen.setCollection(collection);
693
		}else if (specTypeDepositoryStr.matches("coll. O. Slaby, Plzen, Tschechei")){
694
			String colName = "coll. O. Slaby";
695
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, colName, Collection.class);
696
			if (collection == null){
697
				collection = Collection.NewInstance();
698
				collection.setName(colName);
699
				collection.setTownOrLocation("Plzen, Tschechei");
700
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
701
			}
702
			specimen.setCollection(collection);
703
		}else if (specTypeDepositoryStr.matches("coll. K. Okubo")){
704
			String colName = "coll. K. Okubo";
705
			collection = state.getRelatedObject(COLLECTION_NAMESPACE, colName, Collection.class);
706
			if (collection == null){
707
				collection = Collection.NewInstance();
708
				collection.setName(colName);
709
				collection.setTownOrLocation("Nichinomiya city, Hyogo");
710
				state.addRelatedObject(COLLECTION_NAMESPACE, collection.getName(), collection);
711
			}
712
			specimen.setCollection(collection);
713
		}else{
714
			collection = null;
715
		}
716
		
717
		
718
		return collection;
719
	}
720

    
721
	/**
722
	 * @param specTypeDepositoriesStr
723
	 * @param specTypeDepositoryStr
724
	 * @param specimen
725
	 * @param specTaxId 
726
	 * @return
727
	 */
728
	protected String makeAdditionalSpecimenInformation( String specTypeDepositoryStr, DerivedUnit specimen, Integer specTaxId) {
729
		//doubful
730
		if (specTypeDepositoryStr.endsWith("?")){
731
			Marker.NewInstance(specimen, true, MarkerType.IS_DOUBTFUL());
732
			specTypeDepositoryStr = specTypeDepositoryStr.substring(0, specTypeDepositoryStr.length() -1).trim();
733
		}
734
		
735
		//brackets
736
		Matcher matcher = patternAll.matcher(specTypeDepositoryStr);
737
		if (matcher.find()){
738
			//has brackets
739
			String brackets = matcher.group(2);
740
			brackets = brackets.substring(1, brackets.length()-1);
741
			
742
			//TODO this is unwanted according to Alexander
743
			brackets = brackets.replace("[mm]", "\u2642\u2642");
744
			brackets = brackets.replace("[m]", "\u2642");
745
			brackets = brackets.replace("[ff]", "\u2640\u2640");
746
			brackets = brackets.replace("[f]", "\u2640");
747
			brackets = brackets.replace("[m/f]", "\u26a5");
748
			
749
			if (brackets.contains("[") || brackets.contains("]")){
750
				logger.warn ("There are still '[', ']' in the bracket part: " + brackets + "; specTaxId: " + specTaxId);
751
			}
752
			
753
			//TODO replace mm/ff by Unicode male 
754
			specimen.setTitleCache(brackets, true);
755
			specTypeDepositoryStr = matcher.group(1).trim();
756
		}
757
		return specTypeDepositoryStr;
758
	}
759

    
760

    
761

    
762

    
763
	/**
764
	 * @param fieldObservation
765
	 * @return
766
	 */
767
	protected DerivedUnit makeSingleTypeSpecimen(FieldUnit fieldObservation) {
768
		DerivationEvent derivEvent = DerivationEvent.NewInstance();
769
//			derivEvent.setType(DerivationEventType.ACCESSIONING());
770
		fieldObservation.addDerivationEvent(derivEvent);
771
		DerivedUnit specimen = DerivedUnit.NewPreservedSpecimenInstance();
772
		specimen.setDerivedFrom(derivEvent);
773
		return specimen;
774
	}
775

    
776

    
777

    
778

    
779
	/**
780
	 * @param state
781
	 * @return
782
	 * @throws SQLException
783
	 */
784
	protected FieldUnit makeTypeFieldObservation(GlobisImportState state, 
785
			ResultSet rs) throws SQLException {
786
		
787
		String countryString = rs.getString("SpecTypeCountry");
788
		
789
		SpecimenOrObservationType unitType = SpecimenOrObservationType.PreservedSpecimen;
790
		DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(unitType);
791
		
792
		NamedArea typeCountry = getCountry(state, countryString);
793
		facade.setCountry(typeCountry);
794
		FieldUnit fieldObservation = facade.innerFieldUnit();
795
		return fieldObservation;
796
	}
797

    
798

    
799

    
800

    
801
	/**
802
	 * @param name
803
	 * @param rs 
804
	 * @param status
805
	 * @param specimen
806
	 * @param specTaxId 
807
	 * @throws SQLException 
808
	 */
809
	protected void makeTypeDesignation(ZoologicalName name, ResultSet rs, DerivedUnit specimen, Integer specTaxId) throws SQLException {
810
		//type
811
		String specType = rs.getString("SpecType");
812
		SpecimenTypeDesignationStatus status = getTypeDesigType(specType, specTaxId);
813

    
814
		SpecimenTypeDesignation typeDesignation = SpecimenTypeDesignation.NewInstance();
815
		typeDesignation.setTypeStatus(status);
816
		typeDesignation.setTypeSpecimen(specimen);
817
		
818
		name.addTypeDesignation(typeDesignation, true);
819
	}
820

    
821

    
822

    
823

    
824
	private SpecimenTypeDesignationStatus getTypeDesigType(String specType, Integer specTaxId) {
825
		if (isBlank(specType) ){
826
			return null;
827
		}else if (specType.matches("Holotype(\r*\n*Holotypus)?")){
828
			return SpecimenTypeDesignationStatus.HOLOTYPE();
829
		}else if (specType.matches("Neotype")){
830
			return SpecimenTypeDesignationStatus.NEOTYPE();
831
		}else if (specType.matches("Syntype(\\(s\\))?") || specType.matches("Syntype.*Syntype\\(s\\)\\s*") ){
832
			return SpecimenTypeDesignationStatus.SYNTYPE();
833
		}else if (specType.matches("Syntype\r*\n*Syntype.*") ){
834
			return SpecimenTypeDesignationStatus.SYNTYPE();
835
		}else if (specType.matches("Lectotype")){
836
			return SpecimenTypeDesignationStatus.LECTOTYPE();
837
		}else{
838
			logger.warn("SpecimenTypeDesignationStatus does not match: " + specType + " in specTaxId "  + specTaxId);
839
			return null;
840
		}
841
	}
842

    
843

    
844

    
845

    
846
	/**
847
	 * @param state
848
	 * @param referenceMap
849
	 * @param rs
850
	 * @param name
851
	 * @param specTaxId 
852
	 * @return
853
	 * @throws SQLException
854
	 */
855
	private Reference<?> handleNomRef(GlobisImportState state, Map<String, Reference> referenceMap, ResultSet rs,
856
			ZoologicalName name, Integer specTaxId) throws SQLException {
857
		//ref
858
		Integer refId = nullSafeInt(rs, "fiSpecRefID");
859
		Reference<?> nomRef = null;
860
		if (refId != null){
861
			nomRef = referenceMap.get(String.valueOf(refId));
862
			if (nomRef == null && state.getConfig().getDoReferences().equals(state.getConfig().getDoReferences().ALL)){
863
				logger.warn("Reference " + refId + " could not be found. SpecTaxId: " + specTaxId);
864
			}else if (nomRef != null){
865
				name.setNomenclaturalReference(nomRef);
866
			}
867
		}
868
		
869
		//refDetail
870
		String refDetail = rs.getString("SpecPage");
871
		if (isNotBlank(refDetail)){
872
			name.setNomenclaturalMicroReference(refDetail);
873
		}
874
		return nomRef;
875
	}
876

    
877

    
878

    
879
	
880
	private void validateAcceptedTaxon(Taxon acceptedTaxon, ResultSet rs, Integer specTaxId, Integer acceptedTaxonId) throws SQLException {
881
		if (acceptedTaxon == null){
882
			logger.warn("Accepted taxon is null for taxon taxon to validate. SpecTaxId " + specTaxId + ", accTaxonId: " + acceptedTaxonId);
883
			return;
884
		}
885
		
886
		//TODO 
887
		ZoologicalName name = CdmBase.deproxy(acceptedTaxon.getName(), ZoologicalName.class);
888
		
889
		String specName = rs.getString("SpecName");
890
		if (! name.getSpecificEpithet().equals(specName)){
891
			logger.warn(String.format("Species epithet is not equal for accepted taxon: %s - %s. SpecTaxId: %d", name.getSpecificEpithet(), specName, specTaxId));
892
		}
893
		//TODO
894
	}
895

    
896

    
897

    
898

    
899
	private Synonym getSynonym(GlobisImportState state, ResultSet rs, Integer specTaxId) throws SQLException {
900
		ZoologicalName name = makeName(state, rs, specTaxId);
901
				
902
		Synonym synonym = Synonym.NewInstance(name, state.getTransactionalSourceReference());
903
		
904
		return synonym;
905
	}
906

    
907

    
908

    
909

    
910
	/**
911
	 * @param state
912
	 * @param rs
913
	 * @param specTaxId 
914
	 * @return
915
	 * @throws SQLException
916
	 */
917
	protected ZoologicalName makeName(GlobisImportState state, ResultSet rs, Integer specTaxId)
918
			throws SQLException {
919
		//rank
920
		String rankStr = rs.getString("SpecRank");
921
		Rank rank = null;
922
		if (isNotBlank(rankStr)){
923
			try {
924
				rank = Rank.getRankByNameOrIdInVoc(rankStr, NomenclaturalCode.ICZN, true);
925
			} catch (UnknownCdmTypeException e) {
926
				e.printStackTrace();
927
			}
928
		}
929
		
930
		//name
931
		ZoologicalName name = ZoologicalName.NewInstance(rank);
932
		makeNamePartsAndCache(state, rs, rankStr, name);
933
		
934

    
935
//		name.setGenusOrUninomial(genusOrUninomial);
936
		String authorStr = rs.getString("SpecAuthor");
937
		String yearStr = rs.getString("SpecYear");
938
		String authorAndYearStr = CdmUtils.concat(", ", authorStr, yearStr);
939
		handleAuthorAndYear(authorAndYearStr, name, specTaxId, state);
940
		
941
		return name;
942
	}
943

    
944

    
945

    
946

    
947
	private void makeNamePartsAndCache(GlobisImportState state, ResultSet rs, String rank, ZoologicalName name) throws SQLException {
948
		String citedFamily = rs.getString("SpecCitedFamily");
949
		String citedGenus = rs.getString("SpecCitedGenus");
950
		String citedSpecies = rs.getString("SpecCitedSpecies");
951
		String citedSubspecies = rs.getString("SpecCitedSubspecies");
952
		String lastEpithet = rs.getString("SpecName");
953
		
954
		
955
		String cache = CdmUtils.concat(" ", new String[]{citedFamily, citedGenus, citedSpecies, citedSubspecies, rank, lastEpithet});
956
		name.setGenusOrUninomial(citedGenus);
957
		//TODO separate authors
958
		if (isBlank(citedSpecies)){
959
			name.setSpecificEpithet(lastEpithet);
960
		}else{
961
			name.setSpecificEpithet(citedSpecies);
962
			if (isBlank(citedSubspecies)){
963
				name.setInfraSpecificEpithet(lastEpithet);
964
			}
965
		}
966
		
967
		//TODO check if cache needs protection
968
		name.setNameCache(cache, true);
969
	}
970

    
971
	@Override
972
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, GlobisImportState state) {
973
		String nameSpace;
974
		Class<?> cdmClass;
975
		Set<String> idSet;
976
		
977
		Set<AgentBase> agents = state.getAgents();
978
		getAgentService().saveOrUpdate(agents);
979
		
980
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
981
		try{
982
			Set<String> taxonIdSet = new HashSet<String>();
983
			Set<String> referenceIdSet = new HashSet<String>();
984
			
985
			while (rs.next()){
986
				handleForeignKey(rs, taxonIdSet, "SpecCurrspecID");
987
				handleForeignKey(rs, referenceIdSet, "fiSpecRefID");
988
			}
989
			
990
			//taxon map
991
			nameSpace = TAXON_NAMESPACE;
992
			cdmClass = Taxon.class;
993
			idSet = taxonIdSet;
994
			Map<String, Taxon> objectMap = (Map<String, Taxon>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
995
			result.put(nameSpace, objectMap);
996

    
997
			//reference map
998
			nameSpace = REFERENCE_NAMESPACE;
999
			cdmClass = Reference.class;
1000
			idSet = referenceIdSet;
1001
			Map<String, Reference> referenceMap = (Map<String, Reference>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
1002
			result.put(nameSpace, referenceMap);
1003
			
1004
			//collection map
1005
			nameSpace = COLLECTION_NAMESPACE;
1006
			List<Collection> listCollection = getCollectionService().list(Collection.class, null, null, null, null);
1007
			Map<String, Collection> collectionMap = new HashMap<String, Collection>();
1008
			for (Collection collection : listCollection){
1009
				if (isNotBlank(collection.getCode())){
1010
					collectionMap.put(collection.getCode(), collection);
1011
				}else if (isNotBlank(collection.getName())){
1012
					collectionMap.put(collection.getName(), collection);
1013
				}else{
1014
					logger.warn("Collection code and name are blank: " + collection);
1015
				}
1016
			}
1017
			result.put(nameSpace, collectionMap);
1018
			
1019
		} catch (SQLException e) {
1020
			throw new RuntimeException(e);
1021
		}
1022
		return result;
1023
	}
1024
	
1025
	/* (non-Javadoc)
1026
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IImportConfigurator)
1027
	 */
1028
	@Override
1029
	protected boolean doCheck(GlobisImportState state){
1030
		IOValidator<GlobisImportState> validator = new GlobisSpecTaxaImportValidator();
1031
		return validator.validate(state);
1032
	}
1033
	
1034
	
1035
	/* (non-Javadoc)
1036
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
1037
	 */
1038
	protected boolean isIgnore(GlobisImportState state){
1039
		return ! state.getConfig().isDoSpecTaxa();
1040
	}
1041

    
1042

    
1043

    
1044

    
1045
	@Override
1046
	public Reference<?> createObject(ResultSet rs, GlobisImportState state)
1047
			throws SQLException {
1048
		// not needed
1049
		return null;
1050
	}
1051

    
1052
}
(9-9/10)