Project

General

Profile

Download (14.7 KB) Statistics
| Branch: | Tag: | 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 java.lang.reflect.Method;
13
import java.sql.ResultSet;
14
import java.sql.ResultSetMetaData;
15
import java.sql.SQLException;
16
import java.sql.Timestamp;
17
import java.util.HashMap;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import org.apache.log4j.Logger;
23
import org.joda.time.DateTime;
24

    
25
import eu.etaxonomy.cdm.common.CdmUtils;
26
import eu.etaxonomy.cdm.io.common.CdmImportBase;
27
import eu.etaxonomy.cdm.io.common.ICdmIO;
28
import eu.etaxonomy.cdm.io.common.IPartitionedIO;
29
import eu.etaxonomy.cdm.io.common.ImportHelper;
30
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
31
import eu.etaxonomy.cdm.io.common.Source;
32
import eu.etaxonomy.cdm.io.common.IImportConfigurator.EDITOR;
33
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
34
import eu.etaxonomy.cdm.model.common.Annotation;
35
import eu.etaxonomy.cdm.model.common.AnnotationType;
36
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
37
import eu.etaxonomy.cdm.model.common.Language;
38
import eu.etaxonomy.cdm.model.common.User;
39
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
40
import eu.etaxonomy.cdm.model.reference.Reference;
41

    
42
/**
43
 * @author a.mueller
44
 * @created 20.03.2008
45
 * @version 1.0
46
 */
47
public abstract class BerlinModelImportBase extends CdmImportBase<BerlinModelImportConfigurator, BerlinModelImportState> implements ICdmIO<BerlinModelImportState>, IPartitionedIO<BerlinModelImportState> {
48
	private static final Logger logger = Logger.getLogger(BerlinModelImportBase.class);
49
	
50
	public static final UUID ID_IN_SOURCE_EXT_UUID = UUID.fromString("23dac094-e793-40a4-bad9-649fc4fcfd44");
51
	
52
	public BerlinModelImportBase() {
53
		super();
54
	}
55
	
56
	protected void doInvoke(BerlinModelImportState state){
57
			//	String strTeamStore = ICdmIO.TEAM_STORE;
58
			BerlinModelImportConfigurator config = state.getConfig();
59
			Source source = config.getSource();
60
			boolean success = true ;
61
			
62
			logger.info("start make " + getPluralString() + " ...");
63

    
64
			String strIdQuery = getIdQuery();
65
			String strRecordQuery = getRecordQuery(config);
66

    
67
			int recordsPerTransaction = config.getRecordsPerTransaction();
68
			try{
69
				ResultSetPartitioner partitioner = ResultSetPartitioner.NewInstance(source, strIdQuery, strRecordQuery, recordsPerTransaction);
70
				while (partitioner.nextPartition()){
71
					try {
72
						partitioner.doPartition(this, state);
73
					} catch (Exception e) {
74
						e.printStackTrace();
75
						success = false;
76
					}
77
				}
78
			} catch (SQLException e) {
79
				logger.error("SQLException:" +  e);
80
				state.setUnsuccessfull();
81
			}
82
	
83
			logger.info("end make " + getPluralString() + " ... " + getSuccessString(success));
84
			if (success == false){
85
				state.setUnsuccessfull();
86
			}
87
			return;
88
	}
89

    
90
	
91
	/**
92
	 * @return
93
	 */
94
	protected abstract String getRecordQuery(BerlinModelImportConfigurator config);
95

    
96
	/**
97
	 * @return
98
	 */
99
	protected String getIdQuery(){
100
		String result = " SELECT " + getTableName() + "id FROM " + getTableName();
101
		return result;
102
	}
103
	
104
	/* (non-Javadoc)
105
	 * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#getPluralString()
106
	 */
107
	public abstract String getPluralString();
108

    
109
	/**
110
	 * @return
111
	 */
112
	protected abstract String getTableName();
113
	
114
	protected boolean doIdCreatedUpdatedNotes(BerlinModelImportState state, DescriptionElementBase descriptionElement, ResultSet rs, String id, String namespace) throws SQLException{
115
		boolean success = true;
116
		//id
117
		success &= ImportHelper.setOriginalSource(descriptionElement, state.getConfig().getSourceReference(), id, namespace);
118
		//createdUpdateNotes
119
		success &= doCreatedUpdatedNotes(state, descriptionElement, rs);
120
		return success;
121
	}
122
	
123
	protected boolean doIdCreatedUpdatedNotes(BerlinModelImportState state, IdentifiableEntity identifiableEntity, ResultSet rs, long id, String namespace)
124
			throws SQLException{
125
		boolean success = true;
126
		//id
127
		success &= ImportHelper.setOriginalSource(identifiableEntity, state.getConfig().getSourceReference(), id, namespace);
128
		//createdUpdateNotes
129
		success &= doCreatedUpdatedNotes(state, identifiableEntity, rs);
130
		return success;
131
	}
132
	
133
	
134
	protected boolean doCreatedUpdatedNotes(BerlinModelImportState state, AnnotatableEntity annotatableEntity, ResultSet rs)
135
			throws SQLException{
136

    
137
		BerlinModelImportConfigurator config = state.getConfig();
138
		Object createdWhen = rs.getObject("Created_When");
139
		String createdWho = rs.getString("Created_Who");
140
		createdWho = handleHieraciumPilosella(createdWho);
141
		Object updatedWhen = null;
142
		String updatedWho = null;
143
		try {
144
			updatedWhen = rs.getObject("Updated_When");
145
			updatedWho = rs.getString("Updated_who");
146
		} catch (SQLException e) {
147
			//Table "Name" has no updated when/who
148
		}
149
		String notes = rs.getString("notes");
150
		
151
		boolean success  = true;
152
		
153
		//Created When, Who, Updated When Who
154
		if (config.getEditor() == null || config.getEditor().equals(EDITOR.NO_EDITORS)){
155
			//do nothing
156
		}else if (config.getEditor().equals(EDITOR.EDITOR_AS_ANNOTATION)){
157
			String createdAnnotationString = "Berlin Model record was created By: " + String.valueOf(createdWho) + " (" + String.valueOf(createdWhen) + ") ";
158
			if (updatedWhen != null && updatedWho != null){
159
				createdAnnotationString += " and updated By: " + String.valueOf(updatedWho) + " (" + String.valueOf(updatedWhen) + ")";
160
			}
161
			Annotation annotation = Annotation.NewInstance(createdAnnotationString, Language.DEFAULT());
162
			annotation.setCommentator(config.getCommentator());
163
			annotation.setAnnotationType(AnnotationType.TECHNICAL());
164
			annotatableEntity.addAnnotation(annotation);
165
		}else if (config.getEditor().equals(EDITOR.EDITOR_AS_EDITOR)){
166
			User creator = getUser(createdWho, state);
167
			User updator = getUser(updatedWho, state);
168
			DateTime created = getDateTime(createdWhen);
169
			DateTime updated = getDateTime(updatedWhen);
170
			annotatableEntity.setCreatedBy(creator);
171
			annotatableEntity.setUpdatedBy(updator);
172
			annotatableEntity.setCreated(created);
173
			annotatableEntity.setUpdated(updated);
174
		}else {
175
			logger.warn("Editor type not yet implemented: " + config.getEditor());
176
		}
177
		
178
		
179
		//notes
180
		doNotes(annotatableEntity, notes);
181
		return success;
182
	}
183

    
184
	/**
185
	 * Adds a note to the annotatable entity.
186
	 * Nothing happens if annotatableEntity is <code>null</code> or notes is empty or <code>null</code>.
187
	 * @param annotatableEntity
188
	 * @param notes
189
	 */
190
	protected void doNotes(AnnotatableEntity annotatableEntity, String notes) {
191
		if (CdmUtils.isNotEmpty(notes) && annotatableEntity != null ){
192
			String notesString = String.valueOf(notes);
193
			if (notesString.length() > 65530 ){
194
				notesString = notesString.substring(0, 65530) + "...";
195
				logger.warn("Notes string is longer than 65530 and was truncated: " + annotatableEntity);
196
			}
197
			Annotation notesAnnotation = Annotation.NewInstance(notesString, Language.DEFAULT());
198
			//notesAnnotation.setAnnotationType(AnnotationType.EDITORIAL());
199
			//notes.setCommentator(bmiConfig.getCommentator());
200
			annotatableEntity.addAnnotation(notesAnnotation);
201
		}
202
	}
203
	
204
	/**
205
	 * Special usecase for EDITWP6 import where in the createdWho field the original ID is stored
206
	 * @param createdWho
207
	 * @return
208
	 */
209
	private String handleHieraciumPilosella(String createdWho) {
210
		String result = createdWho;
211
		if (result == null){
212
			return null;
213
		}else if (result.startsWith("Hieracium_Pilosella import from EM")){
214
			return "Hieracium_Pilosella import from EM";
215
		}else{
216
			return result;
217
		}
218
	}
219

    
220
	private User getUser(String userString, BerlinModelImportState state){
221
		if (CdmUtils.isEmpty(userString)){
222
			return null;
223
		}
224
		userString = userString.trim();
225
		
226
		User user = state.getUser(userString);
227
		if (user == null){
228
			user = getTransformedUser(userString,state);
229
		}
230
		if (user == null){
231
			user = makeNewUser(userString, state);
232
		}
233
		if (user == null){
234
			logger.warn("User is null");
235
		}
236
		return user;
237
	}
238
	
239
	private User getTransformedUser(String userString, BerlinModelImportState state){
240
		Method method = state.getConfig().getUserTransformationMethod();
241
		if (method == null){
242
			return null;
243
		}
244
		try {
245
			userString = (String)state.getConfig().getUserTransformationMethod().invoke(null, userString);
246
		} catch (Exception e) {
247
			logger.warn("Error when trying to transform userString " +  userString + ". No transformation done.");
248
		}
249
		User user = state.getUser(userString);
250
		return user;
251
	}
252

    
253
	private User makeNewUser(String userString, BerlinModelImportState state){
254
		String pwd = getPassword(); 
255
		User user = User.NewInstance(userString, pwd);
256
		state.putUser(userString, user);
257
		getUserService().save(user);
258
		logger.info("Added new user: " + userString);
259
		return user;
260
	}
261
	
262
	private String getPassword(){
263
		String result = UUID.randomUUID().toString();
264
		return result;
265
	}
266
	
267
	private DateTime getDateTime(Object timeString){
268
		if (timeString == null){
269
			return null;
270
		}
271
		DateTime dateTime = null;
272
		if (timeString instanceof Timestamp){
273
			Timestamp timestamp = (Timestamp)timeString;
274
			dateTime = new DateTime(timestamp);
275
		}else{
276
			logger.warn("time ("+timeString+") is not a timestamp. Datetime set to current date. ");
277
			dateTime = new DateTime();
278
		}
279
		return dateTime;
280
	}
281
	
282
	protected boolean resultSetHasColumn(ResultSet rs, String columnName){
283
		try {
284
			ResultSetMetaData metaData = rs.getMetaData();
285
			for (int i = 0; i < metaData.getColumnCount(); i++){
286
				if (metaData.getColumnName(i + 1).equalsIgnoreCase(columnName)){
287
					return true;
288
				}
289
			}
290
			return false;
291
		} catch (SQLException e) {
292
            logger.warn("Exception in resultSetHasColumn");
293
            return false;
294
		}
295
	}
296
	
297
	protected boolean checkSqlServerColumnExists(Source source, String tableName, String columnName){
298
		String strQuery = "SELECT  Count(t.id) as n " +
299
				" FROM sysobjects AS t " +
300
				" INNER JOIN syscolumns AS c ON t.id = c.id " +
301
				" WHERE (t.xtype = 'U') AND " + 
302
				" (t.name = '" + tableName + "') AND " + 
303
				" (c.name = '" + columnName + "')";
304
		ResultSet rs = source.getResultSet(strQuery) ;		
305
		int n;
306
		try {
307
			rs.next();
308
			n = rs.getInt("n");
309
			return n>0;
310
		} catch (SQLException e) {
311
			e.printStackTrace();
312
			return false;
313
		}
314
		
315
	}
316
	
317
	/**
318
	 * Returns a map that holds all values of a ResultSet. This is needed if a value needs to
319
	 * be accessed twice
320
	 * @param rs
321
	 * @return
322
	 * @throws SQLException
323
	 */
324
	protected Map<String, Object> getValueMap(ResultSet rs) throws SQLException{
325
		try{
326
			Map<String, Object> valueMap = new HashMap<String, Object>();
327
			int colCount = rs.getMetaData().getColumnCount();
328
			for (int c = 0; c < colCount ; c++){
329
				Object value = rs.getObject(c+1);
330
				String label = rs.getMetaData().getColumnLabel(c+1).toLowerCase();
331
				if (value != null && ! CdmUtils.Nz(value.toString()).trim().equals("")){
332
					valueMap.put(label, value);
333
				}
334
			}
335
			return valueMap;
336
		}catch(SQLException e){
337
			throw e;
338
		}
339
	}
340

    
341
	/**
342
	 * Reads a foreign key field from the result set and adds its value to the idSet.
343
	 * @param rs
344
	 * @param teamIdSet
345
	 * @throws SQLException
346
	 */
347
	protected void handleForeignKey(ResultSet rs, Set<String> idSet, String attributeName)
348
			throws SQLException {
349
		Object idObj = rs.getObject(attributeName);
350
		if (idObj != null){
351
			String id  = String.valueOf(idObj);
352
			idSet.add(id);
353
		}
354
	}
355
	
356
	/**
357
	 * Returns true if i is a multiple of recordsPerTransaction
358
	 * @param i
359
	 * @param recordsPerTransaction
360
	 * @return
361
	 */
362
	protected boolean loopNeedsHandling(int i, int recordsPerLoop) {
363
		startTransaction();
364
		return (i % recordsPerLoop) == 0;
365
		}
366
	
367
	protected void doLogPerLoop(int count, int recordsPerLog, String pluralString){
368
		if ((count % recordsPerLog ) == 0 && count!= 0 ){ logger.info(pluralString + " handled: " + (count));}
369
	}
370
	
371

    
372
	/**
373
	 * 	Searches first in the detail maps then in the ref maps for a reference.
374
	 *  Returns the reference as soon as it finds it in one of the map, according
375
	 *  to the order of the map.
376
	 *  If nomRefDetailFk is <code>null</code> no search on detail maps is performed.
377
	 *  If one of the maps is <code>null</code> no search on the according map is
378
	 *  performed. <BR>
379
	 *  You may define the order of search by the order you pass the maps but
380
	 *  make sure to always pass the detail maps first.
381
	 * @param firstDetailMap
382
	 * @param secondDetailMap
383
	 * @param firstRefMap
384
	 * @param secondRefMap
385
	 * @param nomRefDetailFk
386
	 * @param nomRefFk
387
	 * @return
388
	 */
389
	protected Reference getReferenceFromMaps(
390
			Map<String, Reference> firstDetailMap,
391
			Map<String, Reference> secondDetailMap, 
392
			Map<String, Reference> firstRefMap,
393
			Map<String, Reference> secondRefMap,
394
			String nomRefDetailFk,
395
			String nomRefFk) {
396
		Reference ref = null;
397
		ref = getReferenceDetailFromMaps(firstDetailMap, secondDetailMap, nomRefDetailFk);
398
		if (ref == null){
399
			ref = getReferenceOnlyFromMaps(firstRefMap, secondRefMap, nomRefFk);
400
		}
401
		return ref;
402
	}
403
	
404
	/**
405
	 * As getReferenceFromMaps but search is performed only on references, not on
406
	 * detail maps.
407
	 * @param firstRefMap
408
	 * @param secondRefMap
409
	 * @param nomRefFk
410
	 * @return
411
	 */
412
	protected Reference getReferenceOnlyFromMaps(
413
			Map<String, Reference> firstRefMap,
414
			Map<String, Reference> secondRefMap,
415
			String nomRefFk) {
416
		Reference ref = null;
417
		if (firstRefMap != null){
418
			ref = firstRefMap.get(nomRefFk);
419
		}else{
420
			logger.warn("First reference map does not exist");
421
		}
422
		if (ref == null){
423
			if (secondRefMap != null){
424
				ref = secondRefMap.get(nomRefFk);
425
			}else{
426
				logger.warn("Second reference map does not exist");		
427
			}
428
		}
429
		return ref;
430
	}
431

    
432
	/**
433
	 * Searches for a reference in the first detail map. If it does not exist it 
434
	 * searches in the second detail map. Returns null if it does not exist in any map.
435
	 * A map may be <code>null</code> to avoid search on this map.
436
	 * @param secondDetailMap 
437
	 * @param firstDetailMap 
438
	 * @param nomRefDetailFk 
439
	 * @return
440
	 */
441
	private Reference getReferenceDetailFromMaps(Map<String, Reference> firstDetailMap, Map<String, Reference> secondDetailMap, String nomRefDetailFk) {
442
		Reference result = null;
443
		if (nomRefDetailFk != null){
444
			//get ref
445
			if (firstDetailMap != null){
446
				result = firstDetailMap.get(nomRefDetailFk);
447
			}
448
			if (result == null && secondDetailMap != null){
449
				result = secondDetailMap.get(nomRefDetailFk);
450
			}
451
		}
452
		return result;
453
	}
454

    
455
	
456
}
(5-5/21)