Project

General

Profile

Download (54.1 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.berlinModel.in;
11

    
12
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_ARTICLE;
13
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_BOOK;
14
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_CONFERENCE_PROCEEDINGS;
15
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_DATABASE;
16
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_INFORMAL;
17
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_JOURNAL;
18
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_JOURNAL_VOLUME;
19
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_PART_OF_OTHER_TITLE;
20
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_PRINT_SERIES;
21
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_UNKNOWN;
22
import static eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer.REF_WEBSITE;
23
import static eu.etaxonomy.cdm.io.common.ImportHelper.NO_OVERWRITE;
24
import static eu.etaxonomy.cdm.io.common.ImportHelper.OBLIGATORY;
25
import static eu.etaxonomy.cdm.io.common.ImportHelper.OVERWRITE;
26

    
27
import java.net.URI;
28
import java.net.URISyntaxException;
29
import java.sql.ResultSet;
30
import java.sql.SQLException;
31
import java.util.ArrayList;
32
import java.util.Arrays;
33
import java.util.HashMap;
34
import java.util.HashSet;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.Set;
38
import java.util.UUID;
39
import java.util.regex.Matcher;
40
import java.util.regex.Pattern;
41

    
42
import org.apache.log4j.Logger;
43
import org.springframework.stereotype.Component;
44

    
45
import eu.etaxonomy.cdm.common.CdmUtils;
46
import eu.etaxonomy.cdm.common.DOI;
47
import eu.etaxonomy.cdm.io.berlinModel.in.validation.BerlinModelReferenceImportValidator;
48
import eu.etaxonomy.cdm.io.common.ICdmImport;
49
import eu.etaxonomy.cdm.io.common.IImportConfigurator;
50
import eu.etaxonomy.cdm.io.common.ImportHelper;
51
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
52
import eu.etaxonomy.cdm.io.common.Source;
53
import eu.etaxonomy.cdm.io.common.mapping.CdmAttributeMapperBase;
54
import eu.etaxonomy.cdm.io.common.mapping.CdmIoMapping;
55
import eu.etaxonomy.cdm.io.common.mapping.CdmSingleAttributeMapperBase;
56
import eu.etaxonomy.cdm.io.common.mapping.DbImportExtensionMapper;
57
import eu.etaxonomy.cdm.io.common.mapping.DbImportMarkerMapper;
58
import eu.etaxonomy.cdm.io.common.mapping.DbSingleAttributeImportMapperBase;
59
import eu.etaxonomy.cdm.io.common.mapping.berlinModel.CdmOneToManyMapper;
60
import eu.etaxonomy.cdm.io.common.mapping.berlinModel.CdmStringMapper;
61
import eu.etaxonomy.cdm.io.common.mapping.berlinModel.CdmUriMapper;
62
import eu.etaxonomy.cdm.io.common.utils.ImportDeduplicationHelper;
63
import eu.etaxonomy.cdm.model.agent.Person;
64
import eu.etaxonomy.cdm.model.agent.Team;
65
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
66
import eu.etaxonomy.cdm.model.common.CdmBase;
67
import eu.etaxonomy.cdm.model.common.ExtensionType;
68
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
69
import eu.etaxonomy.cdm.model.common.Marker;
70
import eu.etaxonomy.cdm.model.common.MarkerType;
71
import eu.etaxonomy.cdm.model.reference.IArticle;
72
import eu.etaxonomy.cdm.model.reference.IBookSection;
73
import eu.etaxonomy.cdm.model.reference.IPrintSeries;
74
import eu.etaxonomy.cdm.model.reference.Reference;
75
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
76
import eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy;
77
import eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy;
78

    
79
/**
80
 * @author a.mueller
81
 * @since 20.03.2008
82
 */
83
@Component
84
public class BerlinModelReferenceImport extends BerlinModelImportBase {
85
    private static final long serialVersionUID = -3667566958769967591L;
86

    
87
    private static final Logger logger = Logger.getLogger(BerlinModelReferenceImport.class);
88

    
89
	public static final String REFERENCE_NAMESPACE = "Reference";
90
	private static final String REF_AUTHOR_NAMESPACE = "Reference.refAuthorString";
91

    
92

    
93
	public static final UUID REF_DEPOSITED_AT_UUID = UUID.fromString("23ca88c7-ce73-41b2-8ca3-2cb22f013beb");
94
	public static final UUID REF_SOURCE_UUID = UUID.fromString("d6432582-2216-4b08-b0db-76f6c1013141");
95
	public static final UUID DATE_STRING_UUID = UUID.fromString("e4130eae-606e-4b0c-be4f-e93dc161be7d");
96
	public static final UUID IS_PAPER_UUID = UUID.fromString("8a326129-d0d0-4f9d-bbdf-8d86b037c65e");
97

    
98
	private static ImportDeduplicationHelper<BerlinModelImportState> deduplicationHelper;
99

    
100
	private final int modCount = 1000;
101
	private static final String pluralString = "references";
102
	private static final String dbTableName = "reference";
103

    
104

    
105
	public BerlinModelReferenceImport(){
106
		super(dbTableName, pluralString);
107
	}
108

    
109
	protected void initializeMappers(BerlinModelImportState state){
110
		for (CdmAttributeMapperBase mapper: classMappers){
111
			if (mapper instanceof DbSingleAttributeImportMapperBase){
112
				@SuppressWarnings("unchecked")
113
                DbSingleAttributeImportMapperBase<BerlinModelImportState,Reference> singleMapper =
114
				        (DbSingleAttributeImportMapperBase<BerlinModelImportState,Reference>)mapper;
115
				singleMapper.initialize(state, Reference.class);
116
			}
117
		}
118
		return;
119
	}
120

    
121
	private Set<Integer> commonNameRefSet = null;
122
	private void initializeCommonNameRefMap(BerlinModelImportState state) throws SQLException{
123
	    if (state.getConfig().isEuroMed()){
124
	        commonNameRefSet = new HashSet<>();
125
	        String queryStr = "SELECT DISTINCT RefFk "
126
	                + " FROM emCommonName ";
127
	        ResultSet rs = state.getConfig().getSource().getResultSet(queryStr);
128
	        while (rs.next()){
129
	            commonNameRefSet.add(rs.getInt("RefFk"));
130
	        }
131
	    }
132
	}
133

    
134
	protected static CdmAttributeMapperBase[] classMappers = new CdmAttributeMapperBase[]{
135
		new CdmStringMapper("edition", "edition"),
136
		new CdmStringMapper("volume", "volume"),
137
		new CdmStringMapper("publisher", "publisher"),
138
		new CdmStringMapper("publicationTown", "placePublished"),
139
		new CdmStringMapper("isbn", "isbn"),
140
		new CdmStringMapper("isbn", "isbn"),
141
		new CdmStringMapper("pageString", "pages"),
142
		new CdmStringMapper("series", "seriesPart"),
143
		new CdmStringMapper("issn", "issn"),
144
		new CdmUriMapper("url", "uri"),
145
		DbImportExtensionMapper.NewInstance("NomStandard", ExtensionType.NOMENCLATURAL_STANDARD()),
146
		DbImportExtensionMapper.NewInstance("DateString", DATE_STRING_UUID, "Date String", "Date String", "dates"),
147
		DbImportExtensionMapper.NewInstance("RefDepositedAt", REF_DEPOSITED_AT_UUID, "Ref. deposited at", "Reference is deposited at", "at"),
148
		DbImportExtensionMapper.NewInstance("RefSource", REF_SOURCE_UUID, "RefSource", "Reference Source", "source"),
149
		DbImportMarkerMapper.NewInstance("isPaper", IS_PAPER_UUID, "is paper", "is paper", "paper", false)
150
	};
151

    
152

    
153
	protected static String[] operationalAttributes = new String[]{
154
		"refId", "refCache", "nomRefCache", "preliminaryFlag", "inRefFk", "title", "nomTitleAbbrev",
155
		"refAuthorString", "nomAuthorTeamFk",
156
		"refCategoryFk", "thesisFlag", "informalRefCategory", "idInSource"
157
	};
158

    
159
	protected static String[] createdAndNotesAttributes = new String[]{
160
			"created_When", "updated_When", "created_Who", "updated_Who", "notes"
161
	};
162

    
163
	protected static String[] unclearMappers = new String[]{
164
			/*"isPaper",*/ "exportDate",
165
	};
166

    
167
	//TODO isPaper
168
	//
169

    
170

    
171

    
172
	//type to count the references nomReferences that have been created and saved
173
	private class RefCounter{
174
		RefCounter() {refCount = 0;}
175
		int refCount;
176
		int dedupCount;
177

    
178
		@Override
179
        public String toString(){return String.valueOf(refCount) + "/" + String.valueOf(dedupCount) ;}
180
	}
181

    
182
	@Override
183
	protected String getRecordQuery(BerlinModelImportConfigurator config) {
184
		return null;  //not needed
185
	}
186

    
187
	@Override
188
	protected void doInvoke(BerlinModelImportState state){
189
		logger.info("start make " + getPluralString() + " ...");
190
		deduplicationHelper = ImportDeduplicationHelper.NewInstance(this, state);
191

    
192
		boolean success = true;
193
		initializeMappers(state);
194
		try {
195
            initializeCommonNameRefMap(state);
196
        } catch (SQLException e1) {
197
            e1.printStackTrace();
198
            logger.error("Error in initializeCommonNameRefMap in BerlinModelReferenceimport");
199
        }
200
		BerlinModelImportConfigurator config = state.getConfig();
201
		Source source = config.getSource();
202

    
203
		String strSelectId = " SELECT Reference.RefId as refId ";
204
		String strSelectFull =
205
			" SELECT Reference.* ,InReference.RefCategoryFk as InRefCategoryFk, RefSource.RefSource " ;
206
		String strFrom =
207
		        " FROM %s  " +
208
		    	    " LEFT OUTER JOIN Reference as InReference ON InReference.refId = Reference.inRefFk " +
209
		    	    " LEFT OUTER JOIN RefSource ON Reference.RefSourceFk = RefSource.RefSourceId " +
210
		    	" WHERE (1=1) ";
211
		String strOrderBy = " ORDER BY InReference.inRefFk, Reference.inRefFk "; //to make in-references available in first run
212
		String strWherePartitioned = " AND (Reference.refId IN ("+ ID_LIST_TOKEN + ") ) ";
213

    
214
		String referenceTable = CdmUtils.Nz(state.getConfig().getReferenceIdTable());
215
		referenceTable = referenceTable.isEmpty() ? " Reference"  : referenceTable + " as Reference ";
216
		String strIdFrom = String.format(strFrom, referenceTable );
217

    
218
		String referenceFilter = CdmUtils.Nz(state.getConfig().getReferenceIdTable());
219
		if (! referenceFilter.isEmpty()){
220
			referenceFilter = " AND " + referenceFilter + " ";
221
		}
222
		referenceFilter = "";  //don't use it for now, in E+M the tabelle is directly used
223

    
224
		String strIdQueryFirstPath = strSelectId + strIdFrom + strOrderBy ;
225
		String strIdQuerySecondPath = strSelectId + strIdFrom + " AND (Reference.InRefFk is NOT NULL) ";
226

    
227
//		if (config.getDoReferences() == CONCEPT_REFERENCES){
228
//			strIdQueryNoInRef += " AND ( Reference.refId IN ( SELECT ptRefFk FROM PTaxon) ) " + referenceFilter;
229
//		}
230

    
231
		String strRecordQuery = strSelectFull + String.format(strFrom, " Reference ") + strWherePartitioned + strOrderBy;
232

    
233
		int recordsPerTransaction = config.getRecordsPerTransaction();
234
		try{
235
			//firstPath
236
			ResultSetPartitioner<BerlinModelImportState> partitioner =
237
			        ResultSetPartitioner.NewInstance(source, strIdQueryFirstPath, strRecordQuery, recordsPerTransaction);
238
			while (partitioner.nextPartition()){
239
				partitioner.doPartition(this, state);
240
			}
241
			logger.info("end make references without in-references ... " + getSuccessString(success));
242
			state.setReferenceSecondPath(true);
243

    
244
			//secondPath
245
//			partitioner = ResultSetPartitioner.NewInstance(source, strIdQuerySecondPath, strRecordQuery, recordsPerTransaction);
246
//			while (partitioner.nextPartition()){
247
//			    //currently not used as inRef assignment fully works through sorting of idQuery now, at least in E+M
248
//				partitioner.doPartition(this, state);
249
//			}
250
//			logger.info("end make references with no 1 in-reference ... " + getSuccessString(success));
251
			state.setReferenceSecondPath(false);
252

    
253
		} catch (SQLException e) {
254
			logger.error("SQLException:" +  e);
255
			state.setUnsuccessfull();
256
			return;
257
		}
258
		logger.info("end make " + getPluralString() + " ... " + getSuccessString(success));
259
		if (! success){
260
			state.setUnsuccessfull();
261
		}
262
	    deduplicationHelper = null;
263
		return;
264
	}
265

    
266
	@Override
267
	public boolean doPartition(@SuppressWarnings("rawtypes") ResultSetPartitioner partitioner, BerlinModelImportState state) {
268
        deduplicationHelper.restartSession();
269

    
270
	    if (state.isReferenceSecondPath()){
271
			return doPartitionSecondPath(partitioner, state);
272
		}
273
		boolean success = true;
274

    
275
		Map<Integer, Reference> refToSave = new HashMap<>();
276

    
277
//		@SuppressWarnings("unchecked")
278
//        Map<String, Reference> relatedReferences = partitioner.getObjectMap(REFERENCE_NAMESPACE);
279

    
280
		BerlinModelImportConfigurator config = state.getConfig();
281

    
282
		try {
283

    
284
			int i = 0;
285
			RefCounter refCounter  = new RefCounter();
286
			ResultSet rs = partitioner.getResultSet();
287

    
288
			//for each resultset
289
			while (rs.next()){
290
				if ((i++ % modCount) == 0 && i!= 1 ){ logger.info("References handled: " + (i-1) + " in round -" );}
291

    
292
				success &= makeSingleReferenceRecord(rs, state, partitioner, refToSave, refCounter);
293
			} // end resultSet
294

    
295
			//for the concept reference a fixed uuid may be needed -> change uuid
296
			Integer sourceSecId = (Integer)config.getSourceSecId();
297
			Reference sec = refToSave.get(sourceSecId);
298

    
299
			if (sec != null){
300
				sec.setUuid(config.getSecUuid());
301
				logger.info("SecUuid changed to: " + config.getSecUuid());
302
			}
303

    
304
			//save and store in map
305
			logger.warn("Save references (" + refCounter.toString() + ")");  //set preliminary to warn for printing dedup count
306

    
307
			getReferenceService().saveOrUpdate(refToSave.values());
308

    
309
//			logger.info("end makeReferences ..." + getSuccessString(success));;
310
			return success;
311
		} catch (SQLException e) {
312
			logger.error("SQLException:" +  e);
313
			return false;
314
		}
315
	}
316

    
317

    
318

    
319
	/**
320
	 * Adds the inReference to the according references.
321
	 * @param partitioner
322
	 * @param state
323
	 * @return
324
	 */
325
	private boolean doPartitionSecondPath(@SuppressWarnings("rawtypes") ResultSetPartitioner partitioner, BerlinModelImportState state) {
326
		boolean success = true;
327

    
328
		Map<Integer, Reference> refToSave = new HashMap<>();
329

    
330
		@SuppressWarnings("unchecked")
331
        Map<String, Reference> relatedReferencesMap = partitioner.getObjectMap(REFERENCE_NAMESPACE);
332

    
333
		try {
334
				int i = 0;
335
				RefCounter refCounter  = new RefCounter();
336

    
337
				ResultSet rs = partitioner.getResultSet();
338
				//for each resultset
339
				while (rs.next()){
340
					if ((i++ % modCount) == 0 && i!= 1 ){ logger.info("References handled: " + (i-1) + " in round -" );}
341

    
342
					Integer refId = rs.getInt("refId");
343
					Integer inRefFk = nullSafeInt(rs, "inRefFk");
344

    
345
					if (inRefFk != null){
346

    
347
						Reference thisRef = relatedReferencesMap.get(String.valueOf(refId));
348

    
349
						Reference inRef = relatedReferencesMap.get(String.valueOf(inRefFk));
350

    
351
						if (thisRef != null){
352
							if (inRef == null){
353
								logger.warn("No InRef found for nomRef: " + thisRef.getTitleCache() + "; RefId: " +  refId + "; inRefFK: " +  inRefFk);
354
							}
355
							thisRef.setInReference(inRef);
356
							refToSave.put(refId, thisRef);
357
							if(!thisRef.isProtectedTitleCache()){
358
							    thisRef.setTitleCache(null);
359
							    thisRef.getTitleCache();
360
							}
361
						}else{
362
						    logger.warn("Reference which has an inReference not found in DB. RefId: " + refId);
363
						}
364
						if(inRefFk.equals(0)){
365
						    logger.warn("InRefFk is 0 for refId "+ refId);
366
						}
367
					}
368

    
369
				} // end resultSet
370

    
371
				//save and store in map
372
				logger.info("Save in references (" + refCounter.toString() + ")");
373
				getReferenceService().saveOrUpdate(refToSave.values());
374

    
375
//			}//end resultSetList
376

    
377
//			logger.info("end makeReferences ..." + getSuccessString(success));;
378
			return success;
379
		} catch (SQLException e) {
380
			logger.error("SQLException:" +  e);
381
			return false;
382
		}
383
	}
384

    
385

    
386
	@Override
387
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, BerlinModelImportState state) {
388
		String nameSpace;
389
		Class<?> cdmClass;
390
		Set<String> idSet;
391

    
392
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<>();
393

    
394
		try{
395
			Set<String> teamIdSet = new HashSet<>();
396
			Set<String> referenceIdSet = new HashSet<>();
397
			Set<String> teamStringSet = new HashSet<>();
398

    
399
			while (rs.next()){
400
				handleForeignKey(rs, teamIdSet, "NomAuthorTeamFk");
401
				handleForeignKey(rs, referenceIdSet, "InRefFk");
402
				handleForeignKey(rs, teamStringSet, "refAuthorString");
403
				//TODO only needed in second path but state not available here to check if state is second path
404
				handleForeignKey(rs, referenceIdSet, "refId");
405
			}
406

    
407
			Set<String> teamStringSet2 = new HashSet<>();
408
			for (String teamString : teamStringSet){
409
			    teamStringSet2.add(teamString.replace("'", "´"));
410
			}
411

    
412
			//team map
413
			nameSpace = BerlinModelAuthorTeamImport.NAMESPACE;
414
			cdmClass = TeamOrPersonBase.class;
415
			idSet = teamIdSet;
416
			@SuppressWarnings("unchecked")
417
            Map<String, Team> teamMap = (Map<String, Team>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
418
			result.put(nameSpace, teamMap);
419

    
420
            //refAuthor map
421
            nameSpace = REF_AUTHOR_NAMESPACE;
422
            cdmClass = TeamOrPersonBase.class;
423
            idSet = teamStringSet2;
424
            @SuppressWarnings("unchecked")
425
            Map<String, Team> refAuthorMap = (Map<String, Team>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
426
            result.put(nameSpace, refAuthorMap);
427

    
428
			//reference map
429
			nameSpace = BerlinModelReferenceImport.REFERENCE_NAMESPACE;
430
			cdmClass = Reference.class;
431
			idSet = referenceIdSet;
432
			Map<String, Reference> referenceMap = (Map<String, Reference>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
433
			result.put(nameSpace, referenceMap);
434

    
435
		} catch (SQLException e) {
436
			throw new RuntimeException(e);
437
		}
438
		return result;
439
	}
440

    
441

    
442
	/**
443
	 * Handles a single reference record
444
	 * @param rs
445
	 * @param state
446
	 * @param biblioRefToSave
447
	 * @param nomRefToSave
448
	 * @param relatedBiblioReferences
449
	 * @param relatedNomReferences
450
	 * @param refCounter
451
	 * @return
452
	 */
453
	private boolean makeSingleReferenceRecord(
454
				ResultSet rs,
455
				BerlinModelImportState state,
456
				ResultSetPartitioner<BerlinModelImportState> partitioner,
457
				Map<Integer, Reference> refToSave,
458
				RefCounter refCounter){
459

    
460
	    boolean success = true;
461

    
462
		Integer refId = null;
463
		try {
464
			Map<String, Object> valueMap = getValueMap(rs);
465

    
466
			Integer categoryFk = (Integer)valueMap.get("refCategoryFk".toLowerCase());
467
			refId = (Integer)valueMap.get("refId".toLowerCase());
468
			Boolean thesisFlag = (Boolean)valueMap.get("thesisFlag".toLowerCase());
469

    
470

    
471
			Reference reference;
472
			logger.debug("RefCategoryFk: " + categoryFk);
473

    
474
			if (thesisFlag){
475
				reference = makeThesis(valueMap);
476
			}else if (categoryFk == REF_JOURNAL){
477
				reference = makeJournal(valueMap);
478
			}else if(categoryFk == REF_BOOK){
479
				reference = makeBook(valueMap);
480
			}else if(categoryFk == REF_DATABASE){
481
				reference = makeDatabase(valueMap);
482
			}else if(categoryFk == REF_INFORMAL){
483
				reference = makeInformal(valueMap);
484
			}else if(categoryFk == REF_WEBSITE){
485
				reference = makeWebSite(valueMap);
486
			}else if(categoryFk == REF_UNKNOWN){
487
				reference = makeUnknown(valueMap);
488
			}else if(categoryFk == REF_PRINT_SERIES){
489
				reference = makePrintSeries(valueMap);
490
			}else if(categoryFk == REF_CONFERENCE_PROCEEDINGS){
491
				reference = makeProceedings(valueMap);
492
			}else if(categoryFk == REF_ARTICLE){
493
				reference = makeArticle(valueMap);
494
			}else if(categoryFk == REF_JOURNAL_VOLUME){
495
				reference = makeJournalVolume(valueMap);
496
			}else if(categoryFk == REF_PART_OF_OTHER_TITLE){
497
				reference = makePartOfOtherTitle(valueMap);
498
			}else{
499
				logger.warn("Unknown categoryFk (" + categoryFk + "). Create 'Generic instead'");
500
				reference = ReferenceFactory.newGeneric();
501
				success = false;
502
			}
503

    
504
			//refYear
505
			String refYear = (String)valueMap.get("refYear".toLowerCase());
506
			reference.setDatePublished(ImportHelper.getDatePublished(refYear));
507

    
508
			//created, updated, notes
509
			doCreatedUpdatedNotes(state, reference, rs);
510

    
511
			//idInSource (import from older source to berlin model)
512
			//TODO do we want this being imported? Maybe as alternatvie identifier?
513
			String idInSource = (String)valueMap.get("IdInSource".toLowerCase());
514
			if (isNotBlank(idInSource)){
515
				IdentifiableSource source = IdentifiableSource.NewDataImportInstance(idInSource);
516
				source.setIdNamespace("import to Berlin Model");
517
				reference.addSource(source);
518
			}
519

    
520
			//nom&BiblioReference  - must be last because a clone is created
521
			success &= makeNomAndBiblioReference(rs, state, partitioner, refId, reference, refCounter, refToSave);
522

    
523

    
524
		} catch (Exception e) {
525
			logger.warn("Reference with BM refId '" + CdmUtils.Nz(refId) +  "' threw Exception and could not be saved");
526
			e.printStackTrace();
527
			success = false;
528
		}
529
		return success;
530
	}
531

    
532

    
533
	/**
534
	 * Creates and saves a nom. reference and a biblio. reference after checking necessity
535
	 * @param rs
536
	 * @param refId
537
	 * @param ref
538
	 * @param refCounter
539
	 * @param biblioRefToSave
540
	 * @param nomRefToSave
541
	 * @param teamMap
542
	 * @param stores
543
	 * @return
544
	 * @throws SQLException
545
	 */
546
	private boolean makeNomAndBiblioReference(
547
				ResultSet rs,
548
				BerlinModelImportState state,
549
				@SuppressWarnings("rawtypes") ResultSetPartitioner partitioner,
550
				int refId,
551
				Reference ref,
552
				RefCounter refCounter,
553
				Map<Integer, Reference> refToSave
554
			) throws SQLException{
555

    
556
		@SuppressWarnings("unchecked")
557
        Map<String, Team> teamMap = partitioner.getObjectMap(BerlinModelAuthorTeamImport.NAMESPACE);
558

    
559
		String refCache = trim(rs.getString("refCache"));
560
		String nomRefCache = trim(rs.getString("nomRefCache"));
561
		String title = trim(rs.getString("title"));
562
		String nomTitleAbbrev = trim(rs.getString("nomTitleAbbrev"));
563
		boolean isPreliminary = rs.getBoolean("PreliminaryFlag");
564
		String refAuthorString = trim(rs.getString("refAuthorString"));
565
		Integer nomAuthorTeamFk = nullSafeInt(rs, "NomAuthorTeamFk");
566
		Integer inRefFk = nullSafeInt(rs, "inRefFk");
567

    
568

    
569
		TeamOrPersonBase<?> nomAuthor = null;
570
		if (nomAuthorTeamFk != null){
571
		    String strNomAuthorTeamFk = String.valueOf(nomAuthorTeamFk);
572
		    nomAuthor = teamMap.get(strNomAuthorTeamFk);
573
		    if (nomAuthor == null){
574
		        logger.warn("NomAuthor ("+strNomAuthorTeamFk+") not found in teamMap (but it should exist) for " + refId);
575
		    }
576
		}
577

    
578
		Reference sourceReference = state.getTransactionalSourceReference();
579

    
580
		//preliminary
581
		if (isPreliminary){
582
			ref.setAbbrevTitleCache(nomRefCache, true);
583
			ref.setTitleCache(refCache, true);
584
		}
585

    
586
		//title/abbrevTitle
587
		if (isNotBlank(nomTitleAbbrev)){
588
			ref.setAbbrevTitle(nomTitleAbbrev);
589
		}
590
		if (isNotBlank(title)){
591
			ref.setTitle(title);
592
		}
593

    
594
		//author
595
		TeamOrPersonBase<?> author = getAuthorship(state, refAuthorString, nomAuthor, refId);
596
		ref.setAuthorship(author);
597

    
598
		//inRef
599
		Reference inRef = null;
600
		if (inRefFk != null){
601
		    @SuppressWarnings({"unchecked" })
602
		    Map<String, Reference>  relatedReferences = partitioner.getObjectMap(REFERENCE_NAMESPACE);
603
		    inRef = relatedReferences.get(String.valueOf(inRefFk));
604
		    if (inRef == null){
605
		        inRef = refToSave.get(inRefFk);
606
		    }
607
		    if (inRef == null){
608
		        logger.warn("InRef not (yet) found. RefId: " + refId + "; InRef: "+ inRefFk);
609
		    }else{
610
		        ref.setInReference(inRef);
611
		    }
612
		}
613

    
614
		Reference result = deduplicateReference(state, ref);
615
		if(ref != result){
616
		    //dedup not possible at this point because inRef exists but is not yet defined
617
		    if (inRefFk != null && inRef == null){
618
		        result = ref;
619
		        logger.warn("Ref has deduplication candidate but inRef is still missing. " + inRef);
620
		    }else{
621
		        logger.debug("Reference was deduplicated. RefId: " + refId);
622
		        //FIXME also check annotations etc. for deduplication
623
		        refCounter.dedupCount++;
624
		    }
625
		}else{
626
		    refCounter.refCount++;
627
		}
628

    
629
		//save
630
		if (! refToSave.containsKey(refId)){
631
			refToSave.put(refId, result);
632
		}else{
633
		    //should not happen
634
			logger.warn("Duplicate refId in Berlin Model database. Second reference was not imported !!");
635
		}
636

    
637

    
638
		//refId
639
		ImportHelper.setOriginalSource(result, sourceReference, refId, REFERENCE_NAMESPACE);
640

    
641
		if (commonNameRefSet != null && commonNameRefSet.contains(refId)){
642
		    result.addMarker(Marker.NewInstance(MarkerType.COMMON_NAME_REFERENCE(), true));
643
        }
644

    
645
		return true;
646
	}
647

    
648
	/**
649
     * @param string
650
     * @return
651
     */
652
    private String trim(String string) {
653
        if (string == null){
654
            return null;
655
        }else{
656
            return string.trim();
657
        }
658
    }
659

    
660
    /**
661
	 * Copies the created and updated information from the nomReference to the cloned bibliographic reference
662
	 * @param referenceBase
663
	 * @param nomReference
664
	 */
665
	private void copyCreatedUpdated(Reference biblioReference, Reference nomReference) {
666
		biblioReference.setCreatedBy(nomReference.getCreatedBy());
667
		biblioReference.setCreated(nomReference.getCreated());
668
		biblioReference.setUpdatedBy(nomReference.getUpdatedBy());
669
		biblioReference.setUpdated(nomReference.getUpdated());
670

    
671
	}
672

    
673
	private Reference makeArticle (Map<String, Object> valueMap){
674

    
675
		IArticle article = ReferenceFactory.newArticle();
676
		Object inRefFk = valueMap.get("inRefFk".toLowerCase());
677
		Integer inRefCategoryFk = (Integer)valueMap.get("inRefCategoryFk".toLowerCase());
678
		Integer refId = (Integer)valueMap.get("refId".toLowerCase());
679

    
680
		if (inRefFk != null){
681
			if (inRefCategoryFk != REF_JOURNAL){
682
				logger.warn("Wrong inrefCategory for Article (refID = " + refId +"). Type must be 'Journal' but was not (RefCategoryFk=" + inRefCategoryFk + "))." +
683
					" InReference was added anyway! ");
684
			}
685
		}else{
686
			logger.warn ("Article has no inreference: " + refId);
687
		}
688
		makeStandardMapper(valueMap, (Reference)article); //url, pages, series, volume
689
		String url = (String)valueMap.get("url");
690
		if (url != null && url.contains("dx.doi.org")){
691
		    article.setDoi(DOI.fromString(url));
692
		    article.setUri(null);
693
		}
694
		return (Reference)article;
695
	}
696

    
697
	private Reference makePartOfOtherTitle (Map<String, Object> valueMap){
698

    
699
		Reference result;
700
		Object inRefFk = valueMap.get("inRefFk".toLowerCase());
701
		Integer inRefCategoryFk = (Integer)valueMap.get("inRefCategoryFk".toLowerCase());
702
		Integer refId = (Integer)valueMap.get("refId".toLowerCase());
703

    
704
		if (inRefCategoryFk == null){
705
			//null -> error
706
			logger.warn("Part-Of-Other-Title has no inRefCategoryFk! RefId = " + refId + ". ReferenceType set to Generic.");
707
			result = makeUnknown(valueMap);
708
		}else if (inRefFk == null){
709
			//TODO is this correct ??
710
			logger.warn("Part-Of-Other-Title has no in reference: " + refId);
711
			result = makeUnknown(valueMap);
712
		}else if (inRefCategoryFk == REF_BOOK){
713
			//BookSection
714
			IBookSection bookSection = ReferenceFactory.newBookSection();
715
			result = (Reference)bookSection;
716
		}else if (inRefCategoryFk == REF_ARTICLE){
717
			//Article
718
			logger.info("Reference (refId = " + refId + ") of type 'part_of_other_title' is part of 'article'." +
719
					" We use the section reference type for such in references now.") ;
720
			result = ReferenceFactory.newSection();
721
		}else if (inRefCategoryFk == REF_JOURNAL){
722
			//TODO
723
			logger.warn("Reference (refId = " + refId + ") of type 'part_of_other_title' has inReference of type 'journal'." +
724
					" This is not allowed! Generic reference created instead") ;
725
			result = ReferenceFactory.newGeneric();
726
			result.addMarker(Marker.NewInstance(MarkerType.TO_BE_CHECKED(), true));
727
		}else if (inRefCategoryFk == REF_PART_OF_OTHER_TITLE){
728
			logger.info("Reference (refId = " + refId + ") of type 'part_of_other_title' has inReference 'part of other title'." +
729
					" This is allowed, but may be true only for specific cases (e.g. parts of book chapters). You may want to check if this is correct") ;
730
			result = ReferenceFactory.newSection();
731
		}else{
732
			logger.warn("InReference type (catFk = " + inRefCategoryFk + ") of part-of-reference not recognized for refId " + refId + "." +
733
				" Create 'Generic' reference instead");
734
			result = ReferenceFactory.newGeneric();
735
		}
736
		makeStandardMapper(valueMap, result); //url, pages
737
		return result;
738
	}
739

    
740

    
741
	/**
742
	 * @param inRefFkInt
743
	 * @param biblioRefToSave
744
	 * @param nomRefToSave
745
	 * @param relatedBiblioReferences
746
	 * @param relatedNomReferences
747
	 * @return
748
	 */
749
	private boolean existsInMapOrToSave(Integer inRefFkInt, Map<Integer, Reference> refToSave, Map<String, Reference> relatedReferences) {
750
		boolean result = false;
751
		if (inRefFkInt == null){
752
			return false;
753
		}
754
		result |= refToSave.containsKey(inRefFkInt);
755
		result |= relatedReferences.containsKey(String.valueOf(inRefFkInt));
756
		return result;
757
	}
758

    
759
	private Reference makeWebSite(Map<String, Object> valueMap){
760
		if (logger.isDebugEnabled()){logger.debug("RefType 'Website'");}
761
		Reference webPage = ReferenceFactory.newWebPage();
762
		makeStandardMapper(valueMap, webPage); //placePublished, publisher
763
		return webPage;
764
	}
765

    
766
	private Reference makeUnknown(Map<String, Object> valueMap){
767
		if (logger.isDebugEnabled()){logger.debug("RefType 'Unknown'");}
768
		Reference generic = ReferenceFactory.newGeneric();
769
//		generic.setSeries(series);
770
		makeStandardMapper(valueMap, generic); //pages, placePublished, publisher, series, volume
771
		return generic;
772
	}
773

    
774
	private Reference makeInformal(Map<String, Object> valueMap){
775
		if (logger.isDebugEnabled()){logger.debug("RefType 'Informal'");}
776
		Reference generic = ReferenceFactory.newGeneric();
777
//		informal.setSeries(series);
778
		makeStandardMapper(valueMap, generic);//editor, pages, placePublished, publisher, series, volume
779
		String informal = (String)valueMap.get("InformalRefCategory".toLowerCase());
780
		if (isNotBlank(informal) ){
781
			generic.addExtension(informal, ExtensionType.INFORMAL_CATEGORY());
782
		}
783
		return generic;
784
	}
785

    
786
	private Reference makeDatabase(Map<String, Object> valueMap){
787
		if (logger.isDebugEnabled()){logger.debug("RefType 'Database'");}
788
		Reference database =  ReferenceFactory.newDatabase();
789
		makeStandardMapper(valueMap, database); //?
790
		return database;
791
	}
792

    
793
	private Reference makeJournal(Map<String, Object> valueMap){
794
		if (logger.isDebugEnabled()){logger.debug("RefType 'Journal'");}
795
		Reference journal = ReferenceFactory.newJournal();
796

    
797
		Set<String> omitAttributes = new HashSet<>();
798
		String series = "series";
799
//		omitAttributes.add(series);
800

    
801
		makeStandardMapper(valueMap, journal, omitAttributes); //issn,placePublished,publisher
802
//		if (valueMap.get(series) != null){
803
//			logger.warn("Series not yet implemented for journal!");
804
//		}
805
		return journal;
806
	}
807

    
808
	private Reference makeBook(
809
				Map<String, Object> valueMap){
810

    
811
		if (logger.isDebugEnabled()){logger.debug("RefType 'Book'");}
812
		Reference book = ReferenceFactory.newBook();
813
		Integer refId = (Integer)valueMap.get("refId".toLowerCase());
814

    
815
		//Set bookAttributes = new String[]{"edition", "isbn", "pages","publicationTown","publisher","volume"};
816

    
817
		Set<String> omitAttributes = new HashSet<>();
818
		String attrSeries = "series";
819
//		omitAttributes.add(attrSeries);
820

    
821
		makeStandardMapper(valueMap, book, omitAttributes);
822

    
823
		//Series (as String)
824
		IPrintSeries printSeries = null;
825
		if (valueMap.get(attrSeries) != null){
826
			String series = (String)valueMap.get("title".toLowerCase());
827
			if (series == null){
828
				String nomTitle = (String)valueMap.get("nomTitleAbbrev".toLowerCase());
829
				series = nomTitle;
830
			}
831
			printSeries = ReferenceFactory.newPrintSeries(series);
832
			logger.info("Implementation of printSeries is preliminary");
833
		}
834
		//Series (as Reference)
835
		if (book.getInSeries() != null && printSeries != null){
836
			logger.warn("Book has series string and inSeries reference. Can not take both. Series string neglected");
837
		}else{
838
			book.setInSeries(printSeries);
839
		}
840
		book.setEditor(null);
841
		return book;
842

    
843
	}
844

    
845
	/**
846
	 * Returns the requested object if it exists in one of both maps. Prefers the refToSaveMap in ambigious cases.
847
	 * @param inRefFkInt
848
	 * @param nomRefToSave
849
	 * @param relatedNomReferences
850
	 * @return
851
	 */
852
	private Reference getReferenceFromMaps(
853
			int inRefFkInt,
854
			Map<Integer, Reference> refToSaveMap,
855
			Map<String, Reference> relatedRefMap) {
856
		Reference result = null;
857
		result = refToSaveMap.get(inRefFkInt);
858
		if (result == null){
859
			result = relatedRefMap.get(String.valueOf(inRefFkInt));
860
		}
861
		return result;
862
	}
863

    
864
	private Reference makePrintSeries(Map<String, Object> valueMap){
865
		if (logger.isDebugEnabled()){logger.debug("RefType 'PrintSeries'");}
866
		Reference printSeries = ReferenceFactory.newPrintSeries();
867
		makeStandardMapper(valueMap, printSeries, null);
868
		return printSeries;
869
	}
870

    
871
	private Reference makeProceedings(Map<String, Object> valueMap){
872
		if (logger.isDebugEnabled()){logger.debug("RefType 'Proceedings'");}
873
		Reference proceedings = ReferenceFactory.newProceedings();
874
		makeStandardMapper(valueMap, proceedings, null);
875
		return proceedings;
876
	}
877

    
878
	private Reference makeThesis(Map<String, Object> valueMap){
879
		if (logger.isDebugEnabled()){logger.debug("RefType 'Thesis'");}
880
		Reference thesis = ReferenceFactory.newThesis();
881
		makeStandardMapper(valueMap, thesis, null);
882
		return thesis;
883
	}
884

    
885

    
886
	private Reference makeJournalVolume(Map<String, Object> valueMap){
887
		if (logger.isDebugEnabled()){logger.debug("RefType 'JournalVolume'");}
888
		//Proceedings proceedings = Proceedings.NewInstance();
889
		Reference journalVolume = ReferenceFactory.newGeneric();
890
		makeStandardMapper(valueMap, journalVolume, null);
891
		logger.warn("Journal volumes not yet implemented. Generic created instead but with errors");
892
		return journalVolume;
893
	}
894

    
895
	private boolean makeStandardMapper(Map<String, Object> valueMap, Reference ref){
896
		return makeStandardMapper(valueMap, ref, null);
897
	}
898

    
899

    
900
	private boolean makeStandardMapper(Map<String, Object> valueMap, CdmBase cdmBase, Set<String> omitAttributes){
901
		boolean result = true;
902
		for (CdmAttributeMapperBase mapper : classMappers){
903
			if (mapper instanceof CdmSingleAttributeMapperBase){
904
				result &= makeStandardSingleMapper(valueMap, cdmBase, (CdmSingleAttributeMapperBase)mapper, omitAttributes);
905
			}else if (mapper instanceof CdmOneToManyMapper){
906
				result &= makeMultipleValueAddMapper(valueMap, cdmBase, (CdmOneToManyMapper)mapper, omitAttributes);
907
			}else{
908
				logger.error("Unknown mapper type");
909
				result = false;
910
			}
911
		}
912
		return result;
913
	}
914

    
915
	private boolean makeStandardSingleMapper(Map<String, Object> valueMap, CdmBase cdmBase, CdmSingleAttributeMapperBase mapper, Set<String> omitAttributes){
916
		boolean result = true;
917
		if (omitAttributes == null){
918
			omitAttributes = new HashSet<>();
919
		}
920
		if (mapper instanceof DbImportExtensionMapper){
921
			result &= ((DbImportExtensionMapper)mapper).invoke(valueMap, cdmBase);
922
		}else if (mapper instanceof DbImportMarkerMapper){
923
			result &= ((DbImportMarkerMapper)mapper).invoke(valueMap, cdmBase);
924
		}else{
925
			String sourceAttribute = mapper.getSourceAttributeList().get(0).toLowerCase();
926
			Object value = valueMap.get(sourceAttribute);
927
			if (mapper instanceof CdmUriMapper && value != null){
928
				try {
929
					value = new URI (value.toString());
930
				} catch (URISyntaxException e) {
931
					logger.error("URI syntax exception: " + value.toString());
932
					value = null;
933
				}
934
			}
935
			if (value != null){
936
				String destinationAttribute = mapper.getDestinationAttribute();
937
				if (! omitAttributes.contains(destinationAttribute)){
938
					result &= ImportHelper.addValue(value, cdmBase, destinationAttribute, mapper.getTypeClass(), OVERWRITE, OBLIGATORY);
939
				}
940
			}
941
		}
942
		return result;
943
	}
944

    
945

    
946
	private boolean makeMultipleValueAddMapper(Map<String, Object> valueMap, CdmBase cdmBase, CdmOneToManyMapper<CdmBase, CdmBase, CdmSingleAttributeMapperBase> mapper, Set<String> omitAttributes){
947
		if (omitAttributes == null){
948
			omitAttributes = new HashSet<>();
949
		}
950
		boolean result = true;
951
		String destinationAttribute = mapper.getSingleAttributeName();
952
		List<Object> sourceValues = new ArrayList<>();
953
		List<Class> classes = new ArrayList<>();
954
		for (CdmSingleAttributeMapperBase singleMapper : mapper.getSingleMappers()){
955
			String sourceAttribute = singleMapper.getSourceAttribute();
956
			Object value = valueMap.get(sourceAttribute);
957
			sourceValues.add(value);
958
			Class<?> clazz = singleMapper.getTypeClass();
959
			classes.add(clazz);
960
		}
961

    
962
		result &= ImportHelper.addMultipleValues(sourceValues, cdmBase, destinationAttribute, classes, NO_OVERWRITE, OBLIGATORY);
963
		return result;
964
	}
965

    
966

    
967
	private TeamOrPersonBase<?> getAuthorship(BerlinModelImportState state, String refAuthorString,
968
	        TeamOrPersonBase<?> nomAuthor, Integer refId){
969

    
970
	    TeamOrPersonBase<?> result;
971
		if (nomAuthor != null){
972
			result = nomAuthor;
973
			if (isNotBlank(refAuthorString) && !nomAuthor.getTitleCache().equals(refAuthorString)){
974
			    boolean isSimilar = handleSimilarAuthors(state, refAuthorString, nomAuthor, refId);
975
			    if (! isSimilar){
976
			        String message = "refAuthorString differs from nomAuthor.titleCache: " + refAuthorString
977
                            + " <-> " + nomAuthor.getTitleCache() + "; RefId: " + refId;
978
			        logger.warn(message);
979
			    }
980
			}
981
		} else if (isNotBlank(refAuthorString)){//only RefAuthorString exists
982
		    refAuthorString = refAuthorString.trim();
983
			//TODO match with existing Persons/Teams
984
		    TeamOrPersonBase<?> author = state.getRelatedObject(REF_AUTHOR_NAMESPACE, refAuthorString, TeamOrPersonBase.class);
985
			if (author == null){
986
			    if (!BerlinModelAuthorTeamImport.hasTeamSeparator(refAuthorString)){
987
			        author = makePerson(refAuthorString, false, refId);
988
			    }else{
989
			        author = makeTeam(state, refAuthorString, refId);
990
			    }
991
			    state.addRelatedObject(REF_AUTHOR_NAMESPACE, refAuthorString, author);
992
			    result = deduplicatePersonOrTeam(state, author);
993

    
994
			    if (result != author){
995
                    logger.debug("RefAuthorString author deduplicated " + author);
996
                }else{
997
                    if (!importSourceExists(author, refAuthorString, REF_AUTHOR_NAMESPACE, state.getTransactionalSourceReference() )){
998
                        author.addImportSource(refAuthorString, REF_AUTHOR_NAMESPACE, state.getTransactionalSourceReference(), null);
999
                    }
1000
                }
1001
			}else{
1002
			    logger.debug("RefAuthor loaded from map");
1003
			}
1004
			result = author;
1005
		}else{
1006
			result = null;
1007
		}
1008

    
1009
		return result;
1010
	}
1011

    
1012

    
1013
    /**
1014
     * @param state
1015
     * @param refAuthorString
1016
     * @param refId
1017
     * @return
1018
     */
1019
    private TeamOrPersonBase<?> makeTeam(BerlinModelImportState state, String refAuthorString, Integer refId) {
1020
        Team team = Team.NewInstance();
1021
        boolean hasDedupMember = false;
1022
        if (containsEdOrColon(refAuthorString)){
1023
            team.setTitleCache(refAuthorString, true);
1024
        }else{
1025
            String[] refAuthorTeams = BerlinModelAuthorTeamImport.splitTeam(refAuthorString);
1026
            boolean lastWasInitials = false;
1027
            for (int i = 0; i< refAuthorTeams.length ;i++){
1028
                if (lastWasInitials){
1029
                    lastWasInitials = false;
1030
                    continue;
1031
                }
1032
                String fullTeam = refAuthorTeams[i].trim();
1033
                String initials = null;
1034
                if (refAuthorTeams.length > i+1){
1035
                    String nextSplit = refAuthorTeams[i+1].trim();
1036
                    if (isInitial(nextSplit)){
1037
                        lastWasInitials = true;
1038
                        initials = nextSplit;
1039
                    }
1040
                }
1041
                Person member = makePerson(fullTeam, isNotBlank(initials), refId);
1042

    
1043
                if (initials != null){
1044
                    if (member.getInitials() != null){
1045
                        logger.warn("Initials already set: " + refId);
1046
                    }else if (!member.isProtectedTitleCache()){
1047
                        member.setInitials(initials);
1048
                    }else {
1049
                        member.setTitleCache(member.getTitleCache() + ", " + initials, true);
1050
                    }
1051
                }
1052

    
1053
                if (i == refAuthorTeams.length -1 && BerlinModelAuthorTeamImport.isEtAl(member)){
1054
                    team.setHasMoreMembers(true);
1055
                }else{
1056
                    Person dedupMember = deduplicatePersonOrTeam(state, member);
1057
                    if (dedupMember != member){
1058
                        hasDedupMember = true;
1059
                    }else{
1060
                        if (!importSourceExists(member, refAuthorString, REF_AUTHOR_NAMESPACE, state.getTransactionalSourceReference())){
1061
                            member.addImportSource(refAuthorString, REF_AUTHOR_NAMESPACE, state.getTransactionalSourceReference(), null);
1062
                        }
1063
                    }
1064

    
1065
                    team.addTeamMember(dedupMember);
1066
                }
1067
            }
1068
        }
1069

    
1070
        TeamOrPersonBase<?> result = team;
1071
        if (team.getTeamMembers().size() == 1 && !team.isHasMoreMembers()){
1072
            Person person = team.getTeamMembers().get(0);
1073
            checkPerson(person, refAuthorString, hasDedupMember, refId);
1074
            result = person;
1075
        }else{
1076
            checkTeam(team, refAuthorString, refId);
1077
            result = team;
1078
        }
1079

    
1080
        return result;
1081
    }
1082

    
1083
    /**
1084
     * @param team
1085
     * @param refAuthorString
1086
     * @param refId
1087
     */
1088
    private static void checkTeam(Team team, String refAuthorString, Integer refId) {
1089
        TeamDefaultCacheStrategy formatter = (TeamDefaultCacheStrategy) team.getCacheStrategy();
1090
        formatter.setEtAlPosition(100);
1091
        if (formatter.getTitleCache(team).equals(refAuthorString)){
1092
            team.setProtectedTitleCache(false);
1093
        }else if(formatter.getTitleCache(team).replace(" & ", ", ").equals(refAuthorString.replace(" & ", ", ").replace(" ,", ","))){
1094
            //also accept teams with ', ' as final member separator as not protected
1095
            team.setProtectedTitleCache(false);
1096
        }else if(formatter.getFullTitle(team).replace(" & ", ", ").equals(refAuthorString.replace(" & ", ", "))){
1097
            //.. or teams with initials first
1098
            team.setProtectedTitleCache(false);
1099
        }else if (containsEdOrColon(refAuthorString)){
1100
            //nothing to do, it is expected to be protected
1101

    
1102
        }else{
1103
            team.setTitleCache(refAuthorString, true);
1104
            logger.warn("Creation of titleCache for team with members did not (fully) work: " + refAuthorString + " <-> " + formatter.getTitleCache(team)+ " : " + refId);
1105
        }
1106

    
1107
    }
1108

    
1109
    /**
1110
     * @param hasDedupMember
1111
     * @param result
1112
     * @return
1113
     */
1114
    private static void checkPerson(Person person, String refAuthorString, boolean hasDedupMember, Integer refId) {
1115
        PersonDefaultCacheStrategy formatter = (PersonDefaultCacheStrategy) person.getCacheStrategy();
1116

    
1117
        String oldTitleCache = person.getTitleCache();
1118
        boolean oldTitleCacheProtected = person.isProtectedTitleCache();
1119

    
1120
        if (! oldTitleCache.equals(refAuthorString)){
1121
            logger.error("Old titleCache does not equal refAuthorString this should not happen. "+ oldTitleCache + " <-> " + refAuthorString + "; refId = " + refId);
1122
        }
1123

    
1124
        boolean protect = true;
1125
        person.setProtectedTitleCache(false);
1126
        if (refAuthorString.equals(formatter.getTitleCache(person))){
1127
            protect = false;
1128
        }else if(formatter.getFullTitle(person).equals(refAuthorString)){
1129
            //.. or teams with initials first
1130
            protect = false;
1131
        }else{
1132
            //keep protected, see below
1133
        }
1134

    
1135
        if (hasDedupMember){
1136
            //restore
1137
            //TODO maybe even do not use dedup for testing
1138
            person.setTitleCache(oldTitleCache, oldTitleCacheProtected);
1139
            if (protect != oldTitleCacheProtected){
1140
                logger.warn("Deduplicated person protection requirement unclear for "+refAuthorString+". New:"+protect+"/Old:"+oldTitleCacheProtected+"; RefId: " + refId);
1141
            }
1142
        }else{
1143
            if (protect){
1144
                logger.warn("Creation of titleCache for person (converted from team) with members did not (fully) work: " + refAuthorString + " <-> " + formatter.getTitleCache(person)+ " : " + refId);
1145
                person.setTitleCache(refAuthorString, protect);
1146
            }else{
1147
                //keep unprotected
1148
            }
1149
        }
1150
    }
1151

    
1152
    /**
1153
     * @param refAuthorString
1154
     * @return
1155
     */
1156
    private static boolean containsEdOrColon(String str) {
1157
        if (str.contains(" ed.") || str.contains(" Ed.") || str.contains("(ed.")
1158
                || str.contains("[ed.") || str.contains("(Eds)") || str.contains("(Eds.)") ||
1159
                str.contains("(eds.)") || str.contains(":")|| str.contains(";") || str.contains("Publ. & Inform. Directorate")
1160
                || str.contains("Anonymous [Department of Botany, Faculty of Science, FER-ZPR, University of Zagreb]")
1161
                || str.contains("Davis, P. H. (Güner, A. & al.)")){
1162
            return true;
1163
        }else{
1164
            return false;
1165
        }
1166
    }
1167

    
1168
    /**
1169
     * @param nextSplit
1170
     * @return
1171
     */
1172
    private static boolean isInitial(String str) {
1173
        if (str == null){
1174
            return false;
1175
        }
1176
        boolean matches = str.trim().matches("(\\p{javaUpperCase}|Yu|Ya|Th|Ch|Lj|Sz|Dz|Sh|Ju|R. M. da S)\\.?"
1177
                + "(\\s*[-\\s]\\s*(\\p{javaUpperCase}|Yu|Ja|Kh|Tz|Ya|Th|Ju)\\.?)*(\\s+(van|von|de|de la|del|da|van der))?");
1178
        return matches;
1179
    }
1180

    
1181
    private <T extends TeamOrPersonBase<?>> T deduplicatePersonOrTeam(BerlinModelImportState state,T author) {
1182
        T result = deduplicationHelper.getExistingAuthor(state, author);
1183
        return result;
1184
    }
1185

    
1186
    private Reference deduplicateReference(BerlinModelImportState state,Reference ref) {
1187
        Reference result = deduplicationHelper.getExistingReference(state, ref);
1188
        return result;
1189
    }
1190

    
1191
    private static Person makePerson(String full, boolean followedByInitial, Integer refId) {
1192
        Person person = Person.NewInstance();
1193
        person.setTitleCache(full, true);
1194
        if (!full.matches(".*[\\s\\.].*")){
1195
            person.setFamilyName(full);
1196
            person.setProtectedTitleCache(false);
1197
        }else{
1198
            parsePerson(person, full, true, followedByInitial);
1199
        }
1200

    
1201
        if ((full.length() <= 2 && !full.matches("(Li|Bo|Em|Ay|Ma)")) || (full.length() == 3 && full.endsWith(".") && !full.equals("al.")) ){
1202
            logger.warn("Unexpected short nom author name part: " + full + "; " + refId);
1203
        }
1204

    
1205
        return person;
1206
    }
1207

    
1208
    private static void parsePerson(Person person, String str, boolean preliminary, boolean followedByInitial) {
1209
        String capWord = "\\p{javaUpperCase}\\p{javaLowerCase}{2,}";
1210
        String famStart = "(Le |D'|'t |Mc|Mac|Des |d'|Du |De |Al-)";
1211
        String regEx = "((\\p{javaUpperCase}|Ya|Th|Ju|Kh|An)\\.([\\s-]\\p{javaUpperCase}\\.)*(\\s(de|del|da|von|van|van der|v.|af|zu|von M. Und L.))?\\s)("
1212
                + famStart + "?" + capWord + "((-| y | i | é | de | de la )" + capWord + ")?)";
1213
        Matcher matcher = Pattern.compile(regEx).matcher(str);
1214
        if (matcher.matches()){
1215
            person.setProtectedTitleCache(false);
1216
            String familyName = matcher.group(6).trim();
1217
            person.setFamilyName(familyName);
1218
            person.setInitials(matcher.group(1).trim());
1219
        }else{
1220
            String regEx2 = "("+ capWord + "\\s" + capWord + "|Le Sueur|Beck von Mannagetta|Di Martino|Galán de Mera|Van Der Maesen|Farga i Arquimbau|Perez de Paz|Borzatti de Loewenstern|Lo Giudice|Perez de Paz)";
1221
            Matcher matcher2 = Pattern.compile(regEx2).matcher(str);
1222
            if (followedByInitial && matcher2.matches()){
1223
                person.setFamilyName(str);
1224
                person.setProtectedTitleCache(false);
1225
            }else{
1226
                person.setTitleCache(str, preliminary);
1227
            }
1228
        }
1229
    }
1230

    
1231
    /**
1232
     * @param state
1233
     * @param refAuthorString
1234
     * @param nomAuthor
1235
     * @return
1236
     */
1237
    private static boolean handleSimilarAuthors(BerlinModelImportState state, String refAuthorString,
1238
            TeamOrPersonBase<?> nomAuthor, int refId) {
1239
        String nomTitle = nomAuthor.getTitleCache();
1240

    
1241
        if (refAuthorString.equals(nomAuthor.getNomenclaturalTitle())){
1242
            //nomTitle equal
1243
            return true;
1244
        }else{
1245
            if (refAuthorString.replace(" & ", ", ").equals(nomTitle.replace(" & ", ", "))){
1246
                //nomTitle equal except for "&"
1247
                return true;
1248
            }
1249
            String nomFullTitle = nomAuthor.getFullTitle();
1250
            if (refAuthorString.replace(" & ", ", ").equals(nomFullTitle.replace(" & ", ", "))){
1251
                return true;
1252
            }
1253

    
1254
            if (nomAuthor.isInstanceOf(Person.class)){
1255
                Person person = CdmBase.deproxy(nomAuthor, Person.class);
1256

    
1257
                //refAuthor has initials behind, nom Author in front // the other way round is handled in firstIsFullNameOfInitialName
1258
                if (refAuthorString.contains(",") && !nomTitle.contains(",") ){
1259
                    String[] splits = refAuthorString.split(",");
1260
                    if (splits.length == 2){
1261
                        String newMatch = splits[1].trim() + " " + splits[0].trim();
1262
                        if (newMatch.equals(nomTitle)){
1263
                            if (isBlank(person.getFamilyName())){
1264
                                person.setFamilyName(splits[0].trim());
1265
                            }
1266
                            if (isBlank(person.getInitials())){
1267
                                person.setInitials(splits[1].trim());
1268
                            }
1269
                            return true;
1270
                        }
1271
                    }
1272
                }
1273

    
1274
                if (refAuthorIsFamilyAuthorOfNomAuthor(state, refAuthorString, person)){
1275
                    return true;
1276
                }
1277

    
1278
                if (firstIsFullNameOfInitialName(state, refAuthorString, person, refId)){
1279
                    return true;
1280
                }
1281
            }
1282

    
1283
        }
1284
        return false;
1285
    }
1286

    
1287
    /**
1288
     * @param state
1289
     * @param refAuthorString
1290
     * @param person
1291
     * @return
1292
     */
1293
    private static boolean refAuthorIsFamilyAuthorOfNomAuthor(BerlinModelImportState state, String refAuthorString,
1294
            Person person) {
1295
        if (refAuthorString.equals(person.getFamilyName())){
1296
            return true;
1297
        }else{
1298
            return false;
1299
        }
1300
    }
1301

    
1302
    /**
1303
     * @param state
1304
     * @param refAuthorString
1305
     * @param nomAuthor
1306
     * @return
1307
     */
1308
    private static boolean firstIsFullNameOfInitialName(BerlinModelImportState state, String fullName,
1309
            Person initialAuthor, int refId) {
1310
        String initialName = initialAuthor.getTitleCache();
1311

    
1312
        String[] fullSplits = fullName.split(",");
1313
        String[] initialSplits = initialName.split(",");
1314

    
1315
        if (fullSplits.length == 2 && initialSplits.length == 2){
1316
            String[] fullGivenName = fullSplits[1].trim().split(" ");
1317
            String[] initialsGivenName = initialSplits[1].trim().split(" ");
1318
            boolean result = compareFamilyAndInitials(fullSplits[0], initialSplits[0], fullGivenName, initialsGivenName);
1319
            if (result){
1320
                setGivenName(state, fullSplits[1], initialAuthor, refId);
1321
            }
1322
            return result;
1323
        }else if (fullSplits.length == 1 && initialSplits.length == 2){
1324
            String[] fullSingleSplits = fullName.split(" ");
1325
            String fullFamily = fullSingleSplits[fullSingleSplits.length-1];
1326
            String[] fullGivenName = Arrays.copyOfRange(fullSingleSplits, 0, fullSingleSplits.length-1);
1327
            String[] initialsGivenName = initialSplits[1].trim().split(" ");
1328
            boolean result =  compareFamilyAndInitials(fullFamily, initialSplits[0], fullGivenName, initialsGivenName);
1329
            if (result){
1330
                if(hasAtLeastOneFullName(fullGivenName)){
1331
                    setGivenName(state, CdmUtils.concat(" ", fullGivenName), initialAuthor, refId);
1332
                }
1333
            }
1334
            return result;
1335
        }else if (fullSplits.length == 1 && initialAuthor.getInitials() == null){
1336
            //don't if this will be implemented, initialAuthors with only nomencl.Author set
1337
        }
1338

    
1339
        return false;
1340
    }
1341

    
1342
    /**
1343
     * @param fullGivenName
1344
     * @return
1345
     */
1346
    private static boolean hasAtLeastOneFullName(String[] fullGivenName) {
1347
        for (String singleName : fullGivenName){
1348
            if (!singleName.endsWith(".") && singleName.length() > 2 && !singleName.matches("(von|van)") ){
1349
                return true;
1350
            }
1351
        }
1352
        return false;
1353
    }
1354

    
1355
    /**
1356
     * @param state
1357
     * @param string
1358
     * @param initialAuthor
1359
     */
1360
    private static void setGivenName(BerlinModelImportState state, String givenName, Person person, int refId) {
1361
        givenName = givenName.trim();
1362
        if(person.getGivenName() == null || person.getGivenName().equals(givenName)){
1363
            person.setGivenName(givenName);
1364
        }else{
1365
            logger.warn("RefAuthor given name and existing given name differ: " + givenName + " <-> " + person.getGivenName() + "; RefId + " + refId);
1366
        }
1367
    }
1368

    
1369
    /**
1370
     * @param fullGivenName
1371
     * @param initialsGivenName
1372
     */
1373
    protected static boolean compareFamilyAndInitials(String fullFamilyName, String initialsFamilyName,
1374
            String[] fullGivenName, String[] initialsGivenName) {
1375
        if (!fullFamilyName.equals(initialsFamilyName)){
1376
            return false;
1377
        }
1378
        if (fullGivenName.length == initialsGivenName.length){
1379
            for (int i =0; i< fullGivenName.length ; i++){
1380
                if (fullGivenName[i].length() == 0  //comma ending not allowed
1381
                        || initialsGivenName[i].length() != 2 //only K. or similar allowed
1382
                        || fullGivenName[i].length() < initialsGivenName[i].length()  //fullFirstName must be longer than abbrev Name
1383
                        || !initialsGivenName[i].endsWith(".") //initials must end with "."
1384
                        || !fullGivenName[i].startsWith(initialsGivenName[i].replace(".", ""))){ //start with same letter
1385
                    if (fullGivenName[i].matches("(von|van|de|zu)") && fullGivenName[i].equals(initialsGivenName[i])){
1386
                        continue;
1387
                    }else{
1388
                        return false;
1389
                    }
1390
                }
1391
            }
1392
            return true;
1393
        }else{
1394
            return false;
1395
        }
1396
    }
1397

    
1398
    /**
1399
	 * @param lowerCase
1400
	 * @param config
1401
	 * @return
1402
	 */
1403
	public Set<String> getObligatoryAttributes(boolean lowerCase, BerlinModelImportConfigurator config){
1404
		Set<String> result = new HashSet<>();
1405
		Class<ICdmImport>[] ioClassList = config.getIoClassList();
1406
		logger.warn("getObligatoryAttributes has been commented because it still needs to be adapted to the new package structure");
1407
		result.addAll(Arrays.asList(unclearMappers));
1408
		result.addAll(Arrays.asList(createdAndNotesAttributes));
1409
		result.addAll(Arrays.asList(operationalAttributes));
1410
		CdmIoMapping mapping = new CdmIoMapping();
1411
		for (CdmAttributeMapperBase mapper : classMappers){
1412
			mapping.addMapper(mapper);
1413
		}
1414
		result.addAll(mapping.getSourceAttributes());
1415
		if (lowerCase){
1416
			Set<String> lowerCaseResult = new HashSet<>();
1417
			for (String str : result){
1418
				if (str != null){lowerCaseResult.add(str.toLowerCase());}
1419
			}
1420
			result = lowerCaseResult;
1421
		}
1422
		return result;
1423
	}
1424

    
1425
	@Override
1426
	protected boolean doCheck(BerlinModelImportState state){
1427
		BerlinModelReferenceImportValidator validator = new BerlinModelReferenceImportValidator();
1428
		return validator.validate(state, this);
1429
	}
1430

    
1431
	@Override
1432
	protected boolean isIgnore(BerlinModelImportState state){
1433
		return (state.getConfig().getDoReferences() == IImportConfigurator.DO_REFERENCES.NONE);
1434
	}
1435

    
1436
}
(14-14/22)