cleanup and generics for ICdmEntitySessionEnabled
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / e4 / TaxonEditorInputE4.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.taxeditor.editor.e4;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.eclipse.core.commands.ExecutionException;
23 import org.eclipse.core.commands.operations.IOperationHistory;
24 import org.eclipse.core.runtime.IAdaptable;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.NullProgressMonitor;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.e4.ui.di.UISynchronize;
29 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
30
31 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
32 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
33 import eu.etaxonomy.cdm.api.service.IClassificationService;
34 import eu.etaxonomy.cdm.api.service.INameService;
35 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
36 import eu.etaxonomy.cdm.api.service.ITaxonService;
37 import eu.etaxonomy.cdm.api.service.config.SynonymDeletionConfigurator;
38 import eu.etaxonomy.cdm.api.service.config.TaxonBaseDeletionConfigurator;
39 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
40 import eu.etaxonomy.cdm.model.common.CdmBase;
41 import eu.etaxonomy.cdm.model.name.HybridRelationship;
42 import eu.etaxonomy.cdm.model.name.TaxonName;
43 import eu.etaxonomy.cdm.model.taxon.ITaxonTreeNode;
44 import eu.etaxonomy.cdm.model.taxon.Synonym;
45 import eu.etaxonomy.cdm.model.taxon.Taxon;
46 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
47 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
48 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
49 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
50 import eu.etaxonomy.taxeditor.editor.CdmEntitySessionInput;
51 import eu.etaxonomy.taxeditor.editor.ChooseFromMultipleAcceptedTaxaDialog;
52 import eu.etaxonomy.taxeditor.editor.ChooseFromMultipleTaxonNodesDialog;
53 import eu.etaxonomy.taxeditor.editor.l10n.Messages;
54 import eu.etaxonomy.taxeditor.model.AbstractUtility;
55 import eu.etaxonomy.taxeditor.model.DataChangeBridge;
56 import eu.etaxonomy.taxeditor.model.MessagingUtils;
57 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
58 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
59 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
60 import eu.etaxonomy.taxeditor.store.CdmStore;
61 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
62
63 /**
64 * @author pplitzner
65 * @date Aug 24, 2017
66 */
67 public class TaxonEditorInputE4 extends CdmEntitySessionInput<TaxonNode>
68 implements IConversationEnabled {
69
70 private static final String INCORRECT_STATE = Messages.TaxonEditorInput_INCORRECT_STATE;
71
72 private final ConversationHolder conversation;
73
74 private TaxonNode taxonNode;
75
76 private Map<TaxonBase, TaxonBaseDeletionConfigurator> toDeletes = new HashMap<>();
77 private Set<Synonym> toSaveNewSynonyms = new HashSet<>();
78 private List<TaxonBase> toSaveNewConcepts = new ArrayList<>();
79 private List<TaxonName> toSaveNewNames = new ArrayList<>();
80
81
82 private Set<AbstractPostOperation> operations = new HashSet<>();
83
84 private TaxonEditorInputDataChangeBehaviourE4 dataChangeBehavior;
85
86 private TaxonBase<?> initiallySelectedTaxonBase;
87
88 private UISynchronize sync;
89
90
91 public void setSync(UISynchronize sync) {
92 this.sync = sync;
93 }
94
95 private enum CdmType {
96 TAXON_NODE,
97 TAXON_BASE,
98 PARENT_TAXON_NODE
99 }
100
101 private TaxonEditorInputE4(UUID uuid, CdmType type) {
102 super(true);
103 this.conversation = CdmStore.createConversation();
104 switch(type) {
105 case PARENT_TAXON_NODE:
106 initForParentTaxonNode(uuid);
107 break;
108 case TAXON_BASE:
109 initForTaxonBase(uuid);
110 break;
111 case TAXON_NODE:
112 initForTaxonNode(uuid);
113 break;
114 }
115 }
116
117 private void init(TaxonNode taxonNode) {
118 this.taxonNode = taxonNode;
119 }
120
121 private void initForTaxonNode(UUID taxonNodeUuid) {
122 this.getCdmEntitySession().bind();
123 TaxonNode taxonNode = CdmStore.getService(ITaxonNodeService.class).load(taxonNodeUuid, getTaxonNodePropertyPaths());
124 // TaxonNode taxonNode = getCdmEntitySession().remoteLoad(CdmStore.getService(ITaxonNodeService.class), taxonNodeUuid, getTaxonNodePropertyPaths());
125 if(taxonNode == null){
126 MessagingUtils.warningDialog(Messages.TaxonEditorInput_NOT_IMPLEMENTED, TaxonEditorInputE4.class, Messages.TaxonEditorInput_NOT_IMPLEMENTED_MESSAGE);
127 }
128 init(taxonNode);
129 setInitiallySelectedTaxonBase(getTaxon());
130
131 }
132
133 private void initForTaxonBase(UUID taxonBaseUuid) {
134 this.getCdmEntitySession().bind();
135 // TaxonBase taxonBase = CdmStore.getService(ITaxonService.class).load(taxonBaseUuid, getTaxonBasePropertyPaths());
136 TaxonBase<?> taxonBase = getCdmEntitySession().remoteLoad(CdmStore.getService(ITaxonService.class), taxonBaseUuid, getTaxonBasePropertyPaths());
137 if (taxonBase != null){
138 if(taxonBase.isInstanceOf(Taxon.class)){
139 Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
140 setInitiallySelectedTaxonBase(taxon);
141
142 if ( taxon.isMisapplication() || taxon.isProparteSynonym()){
143 // TODO get accepted taxon
144 MessagingUtils.info(Messages.TaxonEditorInput_OPEN_MISSAPPLIED_NAME);
145
146 Set<Taxon> acceptedTaxa = new HashSet<Taxon>();
147 Set<TaxonRelationship> relations = taxon.getRelationsFromThisTaxon();
148 for(TaxonRelationship relation : relations){
149 if(relation.getType().isAnyMisappliedName() || relation.getType().isAnySynonym()){
150 acceptedTaxa.add(relation.getToTaxon());
151 }
152 }
153 if (taxon.getTaxonNodes().size() > 0){
154 acceptedTaxa.add(taxon);
155 }
156 setInputForRelatedTaxa(conversation, acceptedTaxa);
157
158 }else{
159 setInputForMultipleNodes(conversation, taxon.getTaxonNodes());
160 }
161 }else if(taxonBase instanceof Synonym){
162 Synonym synonym = (Synonym) taxonBase;
163
164 Set<Taxon> taxa = new HashSet<>();
165 Taxon taxon = synonym.getAcceptedTaxon();
166 if (taxon != null){
167 taxa.add(taxon);
168 }
169 setInputForMultipleTaxa(conversation, taxa);
170 setInitiallySelectedTaxonBase(synonym);
171 }
172 }
173 }
174
175
176 private void initForParentTaxonNode(UUID parentNodeUuid){
177 this.getCdmEntitySession().bind();
178 TaxonName name = PreferencesUtil.getPreferredNomenclaturalCode().getNewTaxonNameInstance(null);
179 ITaxonTreeNode parentNode = CdmStore.getService(IClassificationService.class).getTreeNodeByUuid(parentNodeUuid);
180
181 Taxon newTaxon = Taxon.NewInstance(name, parentNode.getReference());
182 TaxonNode newTaxonNode = parentNode.addChildTaxon(newTaxon, parentNode.getReference(), parentNode.getMicroReference());
183
184 // add the new taxon to the editors persistence context
185 UUID newTaxonNodeUuid = CdmStore.getService(ITaxonNodeService.class).save(newTaxonNode).getUuid();
186
187 initForTaxonNode(newTaxonNodeUuid);
188 }
189
190 private void setInputForMultipleNodes(ConversationHolder conversation, Set<TaxonNode> taxonNodes){
191 if(taxonNodes.size() == 1){
192 TaxonNode taxonNode = taxonNodes.iterator().next();
193 taxonNode = getCdmEntitySession().remoteLoad(CdmStore.getService(ITaxonNodeService.class), taxonNode.getUuid(), getTaxonNodePropertyPaths());
194 init(taxonNode);
195 }else if(taxonNodes.size() > 1){
196
197 TaxonNode taxonNode = ChooseFromMultipleTaxonNodesDialog.choose(taxonNodes);
198 if(taxonNode != null){
199 taxonNode = CdmStore.getService(ITaxonNodeService.class).load(taxonNode.getUuid(), getTaxonNodePropertyPaths());
200 }
201 if(taxonNode != null){
202 init(taxonNode);
203 }
204 } else if (taxonNodes.size() == 0) {
205 // this is an undesired state
206 MessagingUtils.warningDialog(INCORRECT_STATE,TaxonEditorInputE4.class,Messages.TaxonEditorInput_TAXON_NOT_IN_CLASSIFICATION);
207 }
208 }
209
210 private void setInputForMultipleTaxa(ConversationHolder conversation, Set<Taxon> taxa){
211 if(taxa.size() == 1){
212 Taxon taxon = taxa.iterator().next();
213 Set<TaxonNode> nodes = taxon.getTaxonNodes();
214 setInputForMultipleNodes(conversation, nodes);
215 }else if(taxa.size() > 1){
216 Set<TaxonNode> taxonNodes = new HashSet<TaxonNode>();
217 for ( Taxon taxon : taxa ){
218 taxonNodes.addAll(taxon.getTaxonNodes());
219 }
220 setInputForMultipleNodes(conversation, taxonNodes);
221 }else if(taxa.size() == 0){
222 // this is an undesired state
223 MessagingUtils.warningDialog(INCORRECT_STATE, TaxonEditorInputE4.class, Messages.TaxonEditorInput_NO_ACCEPTED_TAXON_PRESENT);
224 }
225 }
226
227 private void setInputForRelatedTaxa(ConversationHolder conversation, Set<Taxon> taxa){
228 if(taxa.size() == 1){
229 Taxon taxon = taxa.iterator().next();
230 Set<TaxonNode> nodes = taxon.getTaxonNodes();
231 TaxonNode taxonNode = null;
232 if (nodes.size()>1){
233 taxonNode = ChooseFromMultipleTaxonNodesDialog.choose(nodes);
234 }else if (nodes.size()==1){
235 taxonNode = nodes.iterator().next();
236 }else{
237 MessagingUtils.warningDialog(INCORRECT_STATE,TaxonEditorInputE4.class,Messages.TaxonEditorInput_TAXON_NOT_IN_CLASSIFICATION);
238 }
239 init(taxonNode);
240 }else if(taxa.size() > 1){
241 Iterator<Taxon> taxonIterator = taxa.iterator();
242 Set<TaxonNode> nodes = new HashSet<>();
243 while (taxonIterator.hasNext()){
244
245 nodes.addAll(taxonIterator.next().getTaxonNodes());
246 }
247 TaxonNode taxonNode = ChooseFromMultipleAcceptedTaxaDialog.choose(nodes);
248 if(taxonNode != null){
249 taxonNode = CdmStore.getService(ITaxonNodeService.class).load(taxonNode.getUuid(), getTaxonNodePropertyPaths());
250 }
251 if(taxonNode != null){
252 init(taxonNode);
253 }
254 } else if (taxa.size() == 0) {
255 // this is an undesired state
256 MessagingUtils.warningDialog(INCORRECT_STATE,TaxonEditorInputE4.class,Messages.TaxonEditorInput_TAXON_NOT_IN_CLASSIFICATION);
257 }
258 }
259
260 public static TaxonEditorInputE4 NewInstance(UUID taxonNodeUuid) {
261 return new TaxonEditorInputE4(taxonNodeUuid, CdmType.TAXON_NODE);
262
263 }
264
265 public static TaxonEditorInputE4 NewInstanceFromTaxonBase(UUID taxonBaseUuid){
266 return new TaxonEditorInputE4(taxonBaseUuid, CdmType.TAXON_BASE);
267 }
268
269
270 public static TaxonEditorInputE4 NewEmptyInstance(UUID parentNodeUuid){
271 return new TaxonEditorInputE4(parentNodeUuid, CdmType.PARENT_TAXON_NODE);
272 }
273
274 public Object getAdapter(Class adapter) {
275
276 if (adapter == Taxon.class) {
277 return getTaxon();
278 }
279
280 if (adapter == TaxonNode.class) {
281 return taxonNode;
282 }
283
284 return null;
285 }
286
287 /**
288 * {@inheritDoc}
289 *
290 * Overrides equals to ensure that a taxon can only be edited by
291 * one editor at a time.
292 */
293 @Override
294 public boolean equals(Object obj) {
295 if (TaxonEditorInputE4.class.equals(obj.getClass())
296 && getTaxon() != null
297 && getTaxon().equals(((TaxonEditorInputE4) obj).getTaxon())) {
298 if (((TaxonEditorInputE4) obj).getInitiallySelectedTaxonBase() != null){
299 setInitiallySelectedTaxonBase(((TaxonEditorInputE4) obj).getInitiallySelectedTaxonBase());
300 }
301 return true;
302 }
303 return false;
304 }
305
306 public Taxon getTaxon(){
307 if(taxonNode!=null){
308 Taxon taxon = CdmBase.deproxy(taxonNode.getTaxon(), Taxon.class);
309 return taxon;
310 }
311 return null;
312 }
313
314 public TaxonNode getTaxonNode() {
315 return taxonNode;
316 }
317
318 @Override
319 public ConversationHolder getConversationHolder() {
320 return conversation;
321 }
322
323 @Override
324 public void update(CdmDataChangeMap events) {
325 if(dataChangeBehavior == null){
326 dataChangeBehavior = new TaxonEditorInputDataChangeBehaviourE4(this);
327 }
328
329 DataChangeBridge.handleDataChange(events, dataChangeBehavior);
330 }
331
332 public void setInitiallySelectedTaxonBase(TaxonBase taxonBase) {
333 this.initiallySelectedTaxonBase = taxonBase;
334 }
335
336 public TaxonBase getInitiallySelectedTaxonBase() {
337 return initiallySelectedTaxonBase;
338 }
339
340 public void addOperation(AbstractPostOperation operation) {
341 this.operations.add(operation);
342 }
343
344 public void addToSaveNewSynonym(Synonym toSaveNew) {
345 this.toSaveNewSynonyms.add(toSaveNew);
346 }
347 public void addToSaveNewConcept(Taxon toSaveNew) {
348 this.toSaveNewConcepts.add(toSaveNew);
349
350 }
351
352 @Override
353 public List<TaxonNode> getRootEntities() {
354 return Arrays.asList(taxonNode);
355 }
356
357 @Override
358 public void merge() {
359 if (!this.getCdmEntitySession().isActive()){
360 this.getCdmEntitySession().bind();
361 }
362 for(Entry<TaxonBase, TaxonBaseDeletionConfigurator> entry:toDeletes.entrySet()){
363 delete(entry.getKey(), entry.getValue());
364 }
365 toDeletes.clear();
366 for(AbstractPostOperation<?> entry:operations){
367 IStatus status = Status.CANCEL_STATUS;
368 final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
369 .getUIInfoAdapter(AbstractUtility.getShell());
370 String operationlabel = entry.getLabel();
371 try {
372 entry.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
373 status = entry.execute(new NullProgressMonitor(), uiInfoAdapter);
374 } catch (ExecutionException e) {
375
376 MessagingUtils.operationDialog(AbstractUtility.class, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
377
378 }
379
380 String statusString = status.equals(Status.OK_STATUS) ? "completed"
381 : "cancelled";
382
383 IPostOperationEnabled postOperationEnabled = entry
384 .getPostOperationEnabled();
385 if (postOperationEnabled != null) {
386 postOperationEnabled.onComplete();
387 }
388
389
390 //AbstractUtility.executeOperation(entry,sync);
391 }
392
393 operations.clear();
394 for (Synonym syn: toSaveNewSynonyms){
395 for (HybridRelationship rel : syn.getName().getHybridChildRelations()){
396 // if (!rel.getParentName().isPersited()) {
397 toSaveNewNames.add(rel.getParentName());
398 // }
399 // if (!rel.getHybridName().isPersited()) {
400 toSaveNewNames.add(rel.getHybridName());
401 // }
402
403 }
404 }
405
406 for (TaxonBase<?> concept: toSaveNewConcepts){
407 for (HybridRelationship rel : concept.getName().getHybridChildRelations()){
408 // if (!rel.getParentName().isPersited()) {
409 toSaveNewNames.add(rel.getParentName());
410 // }
411 // if (!rel.getHybridName().isPersited()) {
412 toSaveNewNames.add(rel.getHybridName());
413 // }
414
415 }
416 }
417 if (!toSaveNewNames.isEmpty()){
418 CdmStore.getService(INameService.class).merge(toSaveNewNames, true);
419 }
420 if (!toSaveNewConcepts.isEmpty()){
421 CdmStore.getService(ITaxonService.class).merge(toSaveNewConcepts, true);
422 }
423
424 toSaveNewNames.clear();
425 toSaveNewConcepts.clear();
426
427 CdmStore.getService(ITaxonNodeService.class).merge(taxonNode, true);
428
429
430 }
431
432 private void delete(TaxonBase key, TaxonBaseDeletionConfigurator value) {
433 if (key instanceof Synonym){
434 CdmStore.getService(ITaxonService.class).deleteSynonym(((Synonym)key).getUuid(), (SynonymDeletionConfigurator) value);
435 }else{
436 CdmStore.getService(ITaxonService.class).deleteTaxon(((Taxon)key).getUuid(), (TaxonDeletionConfigurator) value, null);
437 }
438 }
439
440 @Override
441 public Map<Object, List<String>> getPropertyPathsMap() {
442 return null;
443 }
444
445 private List<String> getTaxonNodePropertyPaths() {
446 List<String> taxonNodePropertyPaths = new ArrayList<String>();
447 for(String propertyPath : getTaxonBasePropertyPaths()) {
448 taxonNodePropertyPaths.add("taxon." + propertyPath); //$NON-NLS-1$
449 }
450 return taxonNodePropertyPaths;
451 }
452
453 private List<String> getTaxonBasePropertyPaths() {
454 List<String> taxonBasePropertyPaths = Arrays.asList(new String[] {
455 "sec", //$NON-NLS-1$
456 "createdBy", //$NON-NLS-1$
457 "updatedBy", //$NON-NLS-1$
458 "annotations", //$NON-NLS-1$
459 "markers", //$NON-NLS-1$
460 "credits", //$NON-NLS-1$
461 "extensions", //$NON-NLS-1$
462 "rights", //$NON-NLS-1$
463 "sources", //$NON-NLS-1$
464 "identifiers",
465 "descriptions", //$NON-NLS-1$
466 "taxonNodes", //$NON-NLS-1$
467 "descriptions.descriptionElements.feature", //$NON-NLS-1$
468 "descriptions.descriptionElements.area", //$NON-NLS-1$
469 "descriptions.descriptionElements.status", //$NON-NLS-1$
470 "descriptions.markers", //$NON-NLS-1$
471 "name.descriptions", //$NON-NLS-1$
472 "name.typeDesignations.typeSpecimen.derivedFrom.originals", //$NON-NLS-1$
473 "name.status", //$NON-NLS-1$
474 "name.nomenclaturalReference.inReference", //$NON-NLS-1$
475 "name.taxonBases.taxonNodes", //$NON-NLS-1$
476 "name.relationsFromThisName", //$NON-NLS-1$
477 "name.relationsToThisName", //$NON-NLS-1$
478 "name.homotypicalGroup.typifiedNames.taxonBases.synonyms.synonym.name.status", //$NON-NLS-1$
479 "name.homotypicalGroup.typifiedNames.relationsToThisName.fromName", //$NON-NLS-1$
480 "synonyms.name.status.type", //$NON-NLS-1$
481 "synonyms.name.relationsToThisName.fromName", //$NON-NLS-1$
482 "synonyms.name.nomenclaturalReference.inReference.authorship", //$NON-NLS-1$
483 "synonyms.name.nomenclaturalReference.authorship", //$NON-NLS-1$
484 "synonyms.name.homotypicalGroup.typifiedNames.taxonBases.synonyms" //$NON-NLS-1$
485 });
486
487 return taxonBasePropertyPaths;
488 }
489
490 public void addTaxonBaseToDelete(TaxonBase selectedElement, TaxonBaseDeletionConfigurator deleteConfig) {
491 this.toDeletes.put(selectedElement, deleteConfig);
492
493 }
494
495 public void addToSaveNewName(TaxonName newName) {
496 this.toSaveNewNames.add(newName);
497 }
498 }