Project

General

Profile

Download (11.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
package eu.etaxonomy.taxeditor.bulkeditor.input;
10

    
11
import java.util.ArrayList;
12
import java.util.Comparator;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Map.Entry;
18
import java.util.Set;
19
import java.util.UUID;
20

    
21
import org.eclipse.core.runtime.ICoreRunnable;
22
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
23
import org.eclipse.core.runtime.jobs.Job;
24
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
25
import org.eclipse.jface.viewers.IStructuredSelection;
26

    
27
import ca.odell.glazedlists.BasicEventList;
28
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
29
import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
30
import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
31
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
32
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
35
import eu.etaxonomy.cdm.model.common.MarkerType;
36
import eu.etaxonomy.cdm.strategy.merge.IMergable;
37
import eu.etaxonomy.cdm.strategy.merge.MergeException;
38
import eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator;
39
import eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityPersistenceService;
40
import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorQuery;
41
import eu.etaxonomy.taxeditor.bulkeditor.IBulkEditorSortProvider;
42
import eu.etaxonomy.taxeditor.bulkeditor.input.sortprovider.CdmBaseSortProvider;
43
import eu.etaxonomy.taxeditor.bulkeditor.input.sortprovider.TitleCacheComparator;
44
import eu.etaxonomy.taxeditor.bulkeditor.internal.TaxeditorBulkeditorPlugin;
45
import eu.etaxonomy.taxeditor.editor.CdmEntitySessionInput;
46
import eu.etaxonomy.taxeditor.event.EventUtility;
47
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
48
import eu.etaxonomy.taxeditor.l10n.Messages;
49
import eu.etaxonomy.taxeditor.model.MessagingUtils;
50
import eu.etaxonomy.taxeditor.store.CdmStore;
51

    
52
/**
53
 * @author p.ciardelli
54
 * @created 25.06.2009
55
 * @version 1.0
56
 * @param <T>
57
 */
58
public abstract class AbstractBulkEditorInput<T extends CdmBase> extends CdmEntitySessionInput implements
59
    IEntityPersistenceService<T> {
60

    
61
	private UUID entityUuid;
62

    
63
	private BasicEventList<T> model = new BasicEventList<>();
64

    
65
	private Map<T, DeleteConfiguratorBase> toDelete = new HashMap<>();
66
	private Set<T> saveCandidates = new HashSet<>();
67

    
68

    
69
	private Set<T> markedMergeCandidates = new HashSet<>();
70
	private T markedMergeTarget = null;
71

    
72
	private HashMap<T, Set<T>> mergedEntities = new HashMap<>();
73

    
74
	private IEntityCreator<T> entityCreator;
75
	private final ConversationHolder conversation;
76

    
77
    private Job searchJob;
78

    
79
    private volatile boolean hasSearchFinished;
80

    
81
	public AbstractBulkEditorInput() {
82
	    super(true);
83
	    this.conversation = CdmStore.createConversation();
84
	}
85

    
86
	static public AbstractBulkEditorInput NewInstance(BulkEditorInputType inputType) {
87

    
88
		return BulkEditorInputType.getInput(inputType);
89
	}
90

    
91
	public static AbstractBulkEditorInput NewInstance(IdentifiableEntity entity) {
92

    
93
		BulkEditorInputType inputType = BulkEditorInputType.getByType(entity.getClass());
94

    
95
		AbstractBulkEditorInput editorInput = NewInstance(inputType);
96

    
97
		editorInput.setEntityUuid(entity.getUuid());
98

    
99
		return editorInput;
100
	}
101

    
102
    public abstract String getName();
103

    
104
    public String getEditorName(){
105
        return getName();
106
    }
107

    
108
    protected int getPageSize(){
109
        return 100;
110
    }
111

    
112
	protected abstract List<T> listEntities(IIdentifiableEntityServiceConfigurator configurator);
113

    
114
	protected abstract long countEntities(IIdentifiableEntityServiceConfigurator configurator);
115

    
116
	protected abstract T loadEntity(UUID entityUuid);
117

    
118
	public Comparator<T> getTitleComparator(){
119
	    return new TitleCacheComparator();
120
	}
121

    
122
	public void setMergeTarget(T t){
123
	    markedMergeTarget = t;
124
	}
125

    
126
    public Set<T> getMergeCandidates() {
127
        return markedMergeCandidates;
128
    }
129

    
130
    public T getMergeTarget() {
131
        return markedMergeTarget;
132
    }
133

    
134
	public void removeMergeTarget(){
135
	    markedMergeTarget = null;
136
	}
137

    
138
	public void addMergeCandidate(T t){
139
	    markedMergeCandidates.add(t);
140
	}
141

    
142
	public void removeMergeCandidate(T t){
143
		markedMergeCandidates.remove(t);
144
	}
145

    
146
    public void addToDelete(T t, DeleteConfiguratorBase config) {
147
        toDelete.put(t, config);
148
    }
149
    public void addSaveCandidate(T t){
150
        saveCandidates.add(t);
151
    }
152
	private void setEntityUuid(UUID entityUuid){
153
		this.entityUuid = entityUuid;
154
	}
155

    
156
	public UUID getEntityUuid() {
157
		return entityUuid;
158
	}
159

    
160
	public void performSearch(final BulkEditorQuery bulkEditorQuery, IStructuredSelection selection) {
161
	    //cancel previous search job
162
	    if(searchJob!=null && searchJob.getState()!=Job.NONE){
163
	        searchJob.cancel();
164
	        while(!hasSearchFinished){
165
	            //wait for search to finish
166
	            try {
167
	                Thread.sleep(100);
168
	            } catch (InterruptedException e) {
169
	                e.printStackTrace();
170
	            }
171
	        }
172
	        searchJob = null;
173
	    }
174
	    model.clear();
175

    
176
		if(getEntityUuid() != null){
177

    
178
			T entity = loadEntity(getEntityUuid());
179
			model.add(entity);
180
		}
181
		else if(bulkEditorQuery != null){
182
            IIdentifiableEntityServiceConfigurator configurator = bulkEditorQuery.getSearchConfigurator();
183

    
184
            // check for UUID search
185
            String titleSearchString = configurator.getTitleSearchString();
186
            try {
187
                UUID uuid = UUID.fromString(titleSearchString);
188
                T entity = loadEntity(uuid);
189
                //UUID search found -> add entity to list and return
190
                model.add(entity);
191
                return;
192
            } catch (IllegalArgumentException e) {
193
                // search string was no UUID
194
            }
195
            //-> continue with standard search
196

    
197
            int pageSize = configurator.getPageSize()!=null?configurator.getPageSize():getPageSize();
198
            configurator.setPageSize(pageSize);
199
			long count = countEntities(configurator);
200
			int totalWork = count>Integer.MAX_VALUE?Integer.MAX_VALUE:(int)count;
201
			String jobLabel = String.format(Messages.AbstractBulkEditorInput_LOADING, getName(), bulkEditorQuery.getSearchString());
202
	        searchJob = Job.create(jobLabel, (ICoreRunnable) monitor -> {
203
	            monitor.beginTask(jobLabel, totalWork);
204
	            int pageNumber = 0;
205
	            List<T> entities;
206
                do {
207
                    if (monitor.isCanceled()) {
208
                        break;
209
                    }
210

    
211
                    configurator.setPageNumber(pageNumber);
212
                    entities = listEntities(configurator);
213
                    model.addAll(entities);
214
                    //select if entity is loaded
215
                    if(selection!=null && model.containsAll(selection.toList())){
216
                        EventUtility.postAsyncEvent(WorkbenchEventConstants.BULK_EDITOR_SEARCH_FINISHED, selection);
217
                    }
218
                    pageNumber++;
219
                    monitor.worked(pageSize);
220
                    long workedLong = pageSize*pageNumber;
221
                    int loadedCount =  workedLong>Integer.MAX_VALUE?Integer.MAX_VALUE:(int)workedLong;
222
                    monitor.setTaskName(String.format(Messages.AbstractBulkEditorInput_LOADED, loadedCount, totalWork, getName()));
223
                } while (!entities.isEmpty());
224
	            monitor.done();
225
	            EventUtility.postAsyncEvent(WorkbenchEventConstants.BULK_EDITOR_SEARCH_FINISHED, selection);
226
	        });
227
	        searchJob.addJobChangeListener(new JobChangeAdapter(){
228
	            @Override
229
	            public void done(IJobChangeEvent event) {
230
	                hasSearchFinished = true;
231
	            }
232
	        });
233
	        hasSearchFinished = false;
234
	        searchJob.schedule();
235
		}
236
	}
237

    
238
	public boolean isMergingEnabled() {
239
		return false;
240
	}
241

    
242
	public boolean isConvertingEnabled() {
243
		return false;
244
	}
245

    
246
	public boolean isMarkerTypeEditingEnabled(MarkerType markerType) {
247
		return false;
248
	}
249

    
250

    
251
	/** {@inheritDoc} */
252
	@Override
253
    public boolean merge(T entity, T mergeTarget) {
254
		if (entity instanceof IMergable) {
255
			try {
256
				CdmStore.getCommonService().merge(mergeTarget.getUuid(), entity.getUuid(), (Class<? extends CdmBase>)entity.getClass());
257
			} catch (MergeException e) {
258
				MessagingUtils.errorDialog(Messages.AbstractBulkEditorInput_MERGE_ERROR_TITLE,
259
						this,
260
						String.format(Messages.AbstractBulkEditorInput_MERGE_ERROR_MESSAGE, entity.getClass().getName()),
261
						TaxeditorBulkeditorPlugin.PLUGIN_ID,
262
						e,
263
						true);
264
			}
265
		}
266
		return true;
267
	}
268

    
269
	public void saveModel(){
270
	    saveModel(true);
271
	}
272

    
273
	public void saveModel(boolean resetMerge){
274
	    //delete entities
275
	    for(Entry<T, DeleteConfiguratorBase> entry:toDelete.entrySet()){
276
	        try {
277
                delete(entry.getKey(), entry.getValue());
278
            } catch (ReferencedObjectUndeletableException e) {
279
                e.printStackTrace();
280
            }
281
	    }
282
	    if (!saveCandidates.isEmpty()){
283
	        CdmStore.getService(saveCandidates.iterator().next()).merge(new ArrayList<>(saveCandidates), true);
284
        }
285
	    if(resetMerge){
286
	        //merge entities
287
	        for(T mergeTarget:mergedEntities.keySet()){
288
	            for (T mergeCandidate: mergedEntities.get(mergeTarget)){
289
	                merge(mergeCandidate, mergeTarget);
290
	            }
291
	        }
292
	    }
293
	    toDelete.clear();
294
	    saveCandidates.clear();
295
	    mergedEntities.clear();
296
	}
297

    
298

    
299
	/** {@inheritDoc} */
300
	@Override
301
    public T create(T entity) {
302
		return save(entity);
303
	}
304

    
305
	public IEntityCreator<T> getEntityCreator(){
306
		if(entityCreator == null){
307
			entityCreator = createEntityCreator();
308
		}
309
		return entityCreator;
310
	}
311

    
312
	protected abstract IEntityCreator<T> createEntityCreator();
313

    
314
	/**
315
	 * The default implementation returns an empty list of sort providers.
316
	 * @return
317
	 */
318
	public List<IBulkEditorSortProvider<T>> getSortProviders(){
319
		List<IBulkEditorSortProvider<T>> sortProviders = new ArrayList<IBulkEditorSortProvider<T>>();
320

    
321
		sortProviders.add(new CdmBaseSortProvider<T>());
322

    
323
		return sortProviders;
324
	}
325

    
326
	/**
327
	 * Returns a textual representation given object. The default implementation
328
	 * in the abstract base class returns the simple name of the class, this may
329
	 * be overwritten to something more specific in subclasses.
330
	 *
331
	 * @param entity
332
	 * @return a textual representation given object.
333
	 */
334
	public String getTypeText(Object entity){
335
		return entity.getClass().getSimpleName();
336
	}
337

    
338
	public String getText(T entity) {
339
		if(entity instanceof IdentifiableEntity){
340
			IdentifiableEntity identifiableEntity = (IdentifiableEntity) HibernateProxyHelper.deproxy(entity);
341
			String text = identifiableEntity.getTitleCache();
342
			return text;
343
		}
344

    
345
		return "No text. Implement in subclass"; //$NON-NLS-1$
346
	}
347

    
348
	public BasicEventList<T> getModel() {
349
		return model;
350
	}
351

    
352
	public boolean replaceInModel(T entity) {
353
	    int index = model.indexOf(entity);
354
	    if(index >= 0) {
355
	        model.set(index, entity);
356
	        return true;
357
	    } else {
358
	        return false;
359
	    }
360
	}
361

    
362
    @Override
363
    public List<T> getRootEntities() {
364
        return getModel();
365
    }
366

    
367

    
368
    @Override
369
    public Map<Object, List<String>> getPropertyPathsMap() {
370
        // TODO Auto-generated method stub
371
        return null;
372
    }
373

    
374
	public ConversationHolder getConversation() {
375
		return conversation;
376
	}
377

    
378
	public Set<T> getSaveCandidates() {
379
        return saveCandidates;
380
    }
381

    
382
    public HashMap<T, Set<T>> getMergedEntities() {
383
        return mergedEntities;
384
    }
385

    
386
    public void setMergedEntities(HashMap<T, Set<T>> mergedEntities) {
387
        this.mergedEntities = mergedEntities;
388
    }
389
}
(1-1/11)