commit 02746e7f5a06fd106c517306644c0aae8dbc1406
Author: Patrick Plitzner <p.plitzner@bgbm.org>
Date:   Fri Jan 5 16:34:31 2018 +0100

    ref #7095 Fix session problems
    
     - load WS with property path to avoid multiple representation exception

diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/CharacterMatrix.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/CharacterMatrix.java
index ad6663509..72e0503d7 100644
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/CharacterMatrix.java
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/CharacterMatrix.java
@@ -13,9 +13,11 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -104,12 +106,14 @@ import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
 import eu.etaxonomy.cdm.api.service.IWorkingSetService;
 import eu.etaxonomy.cdm.model.common.TermVocabulary;
 import eu.etaxonomy.cdm.model.description.DescriptionBase;
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
 import eu.etaxonomy.cdm.model.description.Feature;
 import eu.etaxonomy.cdm.model.description.FeatureTree;
 import eu.etaxonomy.cdm.model.description.MeasurementUnit;
 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.description.State;
 import eu.etaxonomy.cdm.model.description.WorkingSet;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
 import eu.etaxonomy.taxeditor.editor.workingSet.matrix.categorical.CategoricalDataCellEditor;
 import eu.etaxonomy.taxeditor.editor.workingSet.matrix.categorical.CategoricalDataDisplayConverter;
@@ -120,6 +124,8 @@ import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
 import eu.etaxonomy.taxeditor.model.ImageResources;
 import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
+import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
 import eu.etaxonomy.taxeditor.store.CdmStore;
 import eu.etaxonomy.taxeditor.workbench.WorkbenchUtility;
 import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
@@ -129,7 +135,16 @@ import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
  * @since Nov 26, 2017
  *
  */
-public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails, IConversationEnabled, IDirtyMarkable{
+public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails, IConversationEnabled, IDirtyMarkable,
+        ICdmEntitySessionEnabled{
+
+    private static final List<String> WS_PROPERTY_PATH = Arrays.asList(new String[] {
+            "descriptions", //$NON-NLS-1$
+            "descriptions.descriptionElements", //$NON-NLS-1$
+            "descriptions.descriptionElements.inDescription", //$NON-NLS-1$
+            "descriptions.descriptionElements.inDescription.descriptionElements", //$NON-NLS-1$
+            "descriptions.descriptionElements.feature", //$NON-NLS-1$
+    });
 
     private static final String CHARACTER_MATRIX_STATE_PROPERTIES = "characterMatrixState.properties";
 
@@ -145,6 +160,8 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
 
     private ConversationHolder conversation;
 
+    private ICdmEntitySession cdmEntitySession;
+
     @Inject
     private ESelectionService selService;
 
@@ -169,6 +186,9 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
         if(CdmStore.isActive() && conversation==null){
             conversation = CdmStore.createConversation();
         }
+        if(cdmEntitySession == null){
+            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
+        }
         else{
             return;
         }
@@ -178,7 +198,7 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
 
 
     public void init(UUID workingSetUuid) {
-        this.workingSet = CdmStore.getService(IWorkingSetService.class).load(workingSetUuid);
+        this.workingSet = CdmStore.getService(IWorkingSetService.class).load(workingSetUuid, WS_PROPERTY_PATH);
         thisPart.setLabel(workingSet.getLabel());
 
         Composite toolbarComposite = new Composite(parent, SWT.NONE);
@@ -518,13 +538,14 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
         btnAddDescription.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
-                DescriptionSelectionDialog dialog = new DescriptionSelectionDialog(natTable.getShell(), workingSet);
+                SpecimenSelectionDialog dialog = new SpecimenSelectionDialog(natTable.getShell(), workingSet);
                 if(dialog.open()==Window.OK){
-                    Collection<DescriptionBase> selectedDescriptions = dialog.getDescriptions();
+                    Collection<SpecimenOrObservationBase> specimens = dialog.getSpecimen();
                     boolean hasAdded = false;
-                    for (DescriptionBase description : selectedDescriptions) {
+                    for (SpecimenOrObservationBase specimen : specimens) {
+                        SpecimenDescription description = getDescriptionForWorkingSet(specimen);
                         if(!workingSet.getDescriptions().contains(description)){
-                            CharacterMatrix.this.descriptions.add(new RowWrapper((SpecimenDescription) description));
+                            CharacterMatrix.this.descriptions.add(new RowWrapper(description));
                             workingSet.addDescription(description);
                             hasAdded = true;
                         }
@@ -535,10 +556,31 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
                 }
             }
         });
-
         parent.layout();
     }
 
+    private SpecimenDescription getDescriptionForWorkingSet(SpecimenOrObservationBase specimen){
+        Set<SpecimenDescription> descriptions = specimen.getDescriptions();
+        if(descriptions!=null){
+            Set<Feature> features = workingSet.getDescriptiveSystem().getDistinctFeatures();
+            for (SpecimenDescription specimenDescription : descriptions) {
+                Set<Feature> specimenDescriptionFeatures = new HashSet<>();
+                for (DescriptionElementBase descriptionElementBase : specimenDescription.getElements()) {
+                    specimenDescriptionFeatures.add(descriptionElementBase.getFeature());
+                }
+                if(specimenDescriptionFeatures.containsAll(features)){
+                    return specimenDescription;
+                }
+            }
+        }
+        //Create new specimen description if no match was found
+        setDirty();
+        SpecimenDescription newDesription = SpecimenDescription.NewInstance(specimen);
+        newDesription.setTitleCache("WorkingSet "+workingSet.getLabel()+" "+newDesription.generateTitle(), true);
+        return newDesription;
+
+    }
+
     private void initLabels(final ColumnOverrideLabelAccumulator columnLabelAccumulator,
             int index, Feature feature) {
 
@@ -657,28 +699,36 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
         if(conversation!=null){
             conversation.bind();
         }
+        if(cdmEntitySession != null) {
+            cdmEntitySession.bind();
+        }
     }
 
     @PreDestroy
     public void dispose(){
-        if(conversation!=null){
+        if (conversation != null) {
             conversation.close();
             conversation = null;
         }
-        try (FileOutputStream tableStateStream =
-                new FileOutputStream(getStatePropertiesFile())) {
-            natTableState.store(tableStateStream, null);
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
+        if(cdmEntitySession != null) {
+            cdmEntitySession.dispose();
+            cdmEntitySession = null;
+        }
+        dirty.setDirty(false);
+        if(natTableState!=null){
+            try (FileOutputStream tableStateStream =
+                    new FileOutputStream(getStatePropertiesFile())) {
+                natTableState.store(tableStateStream, null);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            }
         }
     }
 
-
     private File getStatePropertiesFile() {
         return new File(WorkbenchUtility.getBaseLocation(), CHARACTER_MATRIX_STATE_PROPERTIES);
     }
 
-
     /**
      * {@inheritDoc}
      */
@@ -686,7 +736,6 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
     public void update(CdmDataChangeMap arg0) {
     }
 
-
     /**
      * {@inheritDoc}
      */
@@ -695,23 +744,50 @@ public class CharacterMatrix implements IE4SavablePart, IPartContentHasDetails,
         return conversation;
     }
 
-
     /**
      * {@inheritDoc}
      */
     @Override
     public void changed(Object element) {
-        dirty.setDirty(true);
+        setDirty();
         natTable.refresh();
     }
 
-
     /**
      * {@inheritDoc}
      */
     @Override
     public void forceDirty() {
-        dirty.setDirty(true);
+        setDirty();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ICdmEntitySession getCdmEntitySession() {
+        return cdmEntitySession;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Collection<WorkingSet> getRootEntities() {
+        return Collections.singleton(this.workingSet);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Map<Object, List<String>> getPropertyPathsMap() {
+        Map<Object, List<String>> propertyMap = new HashMap<>();
+        propertyMap.put(SpecimenOrObservationBase.class,WS_PROPERTY_PATH);
+        return propertyMap;
     }
 
 }
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/DescriptionSelectionDialog.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/DescriptionSelectionDialog.java
deleted file mode 100644
index 5a9f60d50..000000000
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/DescriptionSelectionDialog.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
-* Copyright (C) 2018 EDIT
-* European Distributed Institute of Taxonomy
-* http://www.e-taxonomy.eu
-*
-* The contents of this file are subject to the Mozilla Public License Version 1.1
-* See LICENSE.TXT at the top of this package for the full license terms.
-*/
-package eu.etaxonomy.taxeditor.editor.workingSet.matrix;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Shell;
-
-import eu.etaxonomy.cdm.api.service.IOccurrenceService;
-import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
-import eu.etaxonomy.cdm.model.description.DescriptionBase;
-import eu.etaxonomy.cdm.model.description.SpecimenDescription;
-import eu.etaxonomy.cdm.model.description.WorkingSet;
-import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
-import eu.etaxonomy.cdm.model.taxon.Taxon;
-import eu.etaxonomy.cdm.model.taxon.TaxonNode;
-import eu.etaxonomy.taxeditor.model.ImageResources;
-import eu.etaxonomy.taxeditor.store.CdmStore;
-
-/**
- * @author pplitzner
- * @since Jan 3, 2018
- *
- */
-public class DescriptionSelectionDialog extends Dialog {
-
-    private TableViewer list;
-
-    private WorkingSet workingSet;
-
-    Collection<DescriptionBase> selectedDescriptions = new ArrayList<>();
-
-    protected DescriptionSelectionDialog(Shell parentShell, WorkingSet workingSet) {
-        super(parentShell);
-        this.workingSet = workingSet;
-    }
-
-    @Override
-    protected Control createDialogArea(Composite parent) {
-        Composite composite = (Composite) super.createDialogArea(parent);
-        list = new TableViewer(composite);
-        list.setContentProvider(new ArrayContentProvider());
-        list.setLabelProvider(new DescriptionLabelProvider());
-
-        //gather descriptions
-        Set<TaxonNode> taxonNodes = workingSet.getTaxonSubtreeFilter();
-        Set<SpecimenDescription> specimenDescriptions = new HashSet<>();
-        for (TaxonNode node : taxonNodes) {
-            specimenDescriptions.addAll(addDescriptionsRecursively(node));
-        }
-        list.setInput(specimenDescriptions);
-        return composite;
-    }
-
-    private Set<SpecimenDescription> addDescriptionsRecursively(TaxonNode node){
-        Set<SpecimenDescription> descriptions = new HashSet<>();
-        if(node.getTaxon()!=null){
-            Taxon taxon = HibernateProxyHelper.deproxy(node.getTaxon(), Taxon.class);
-            Collection<SpecimenOrObservationBase> specimens = CdmStore.getService(IOccurrenceService.class).listByAssociatedTaxon(SpecimenOrObservationBase.class, null, taxon, null, null, null, null, null);
-            for (SpecimenOrObservationBase specimen : specimens) {
-                Set<SpecimenDescription> specimenDescriptions = specimen.getSpecimenDescriptions();
-                for (SpecimenDescription specimenDescription : specimenDescriptions) {
-                    descriptions.add(specimenDescription);
-                }
-            }
-        }
-        List<TaxonNode> childNodes = node.getChildNodes();
-        for (TaxonNode childNode : childNodes) {
-            descriptions.addAll(addDescriptionsRecursively(childNode));
-        }
-        return descriptions;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void okPressed() {
-        selectedDescriptions = ((IStructuredSelection)list.getSelection()).toList();
-        super.okPressed();
-    }
-    public Collection<DescriptionBase> getDescriptions(){
-        return selectedDescriptions;
-    }
-
-    private class DescriptionLabelProvider extends LabelProvider{
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Image getImage(Object element) {
-            if(workingSet.getDescriptions().contains(element)){
-                return ImageResources.getImage(ImageResources.SYNCED);
-            }
-            return null;
-        }
-    }
-}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/SpecimenSelectionDialog.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/SpecimenSelectionDialog.java
new file mode 100644
index 000000000..64c53b51f
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/workingSet/matrix/SpecimenSelectionDialog.java
@@ -0,0 +1,109 @@
+/**
+* Copyright (C) 2018 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.editor.workingSet.matrix;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+import eu.etaxonomy.cdm.api.service.IOccurrenceService;
+import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
+import eu.etaxonomy.cdm.model.description.WorkingSet;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;
+import eu.etaxonomy.taxeditor.model.ImageResources;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+
+/**
+ * @author pplitzner
+ * @since Jan 3, 2018
+ *
+ */
+public class SpecimenSelectionDialog extends Dialog {
+
+    private TableViewer list;
+
+    private WorkingSet workingSet;
+
+    Collection<SpecimenOrObservationBase> selectedSpecimens = new ArrayList<>();
+
+    protected SpecimenSelectionDialog(Shell parentShell, WorkingSet workingSet) {
+        super(parentShell);
+        this.workingSet = workingSet;
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+        list = new TableViewer(composite);
+        list.setContentProvider(new ArrayContentProvider());
+        list.setLabelProvider(new DescriptionLabelProvider());
+
+        //gather descriptions
+        Set<TaxonNode> taxonNodes = workingSet.getTaxonSubtreeFilter();
+        Set<SpecimenOrObservationBase> specimens = new HashSet<>();
+        for (TaxonNode node : taxonNodes) {
+            specimens.addAll(addDescriptionsRecursively(node));
+        }
+        list.setInput(specimens);
+        return composite;
+    }
+
+    private Collection<SpecimenOrObservationBase> addDescriptionsRecursively(TaxonNode node){
+        Collection<SpecimenOrObservationBase> specimens = new HashSet<>();
+        if(node.getTaxon()!=null){
+            Taxon taxon = HibernateProxyHelper.deproxy(node.getTaxon(), Taxon.class);
+            specimens = CdmStore.getService(IOccurrenceService.class).listByAssociatedTaxon(SpecimenOrObservationBase.class, null, taxon, null, null, null, null, null);
+        }
+        List<TaxonNode> childNodes = node.getChildNodes();
+        for (TaxonNode childNode : childNodes) {
+            specimens.addAll(addDescriptionsRecursively(childNode));
+        }
+        return specimens;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void okPressed() {
+        selectedSpecimens = ((IStructuredSelection)list.getSelection()).toList();
+        super.okPressed();
+    }
+
+    public Collection<SpecimenOrObservationBase> getSpecimen(){
+        return selectedSpecimens;
+    }
+
+    private class DescriptionLabelProvider extends LabelProvider{
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Image getImage(Object element) {
+            if(workingSet.getDescriptions().contains(element)){
+                return ImageResources.getImage(ImageResources.SYNCED);
+            }
+            return null;
+        }
+    }
+}
