changeset 96:895bf7494d17

first version of new import-merge.
author casties
date Thu, 27 Oct 2016 20:19:57 +0200
parents 12af756065b5
children 13b313ae1af8
files src/main/java/de/mpiwg/itgroup/ismi/entry/beans/SessionBean.java src/main/java/de/mpiwg/itgroup/ismi/merge/ImportMerge.java src/main/webapp/merge/importMerge.xhtml src/main/webapp/templates/main_template.xhtml
diffstat 4 files changed, 1201 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/SessionBean.java	Thu Oct 20 14:09:28 2016 +0200
+++ b/src/main/java/de/mpiwg/itgroup/ismi/entry/beans/SessionBean.java	Thu Oct 27 20:19:57 2016 +0200
@@ -27,6 +27,7 @@
 import de.mpiwg.itgroup.ismi.event.beans.StudyEvent;
 import de.mpiwg.itgroup.ismi.event.beans.TransferEvent;
 import de.mpiwg.itgroup.ismi.merge.GeneralMerge;
+import de.mpiwg.itgroup.ismi.merge.ImportMerge;
 import de.mpiwg.itgroup.ismi.merge.ReferenceMerge;
 import de.mpiwg.itgroup.ismi.publicView.DynamicPageEditor;
 import de.mpiwg.itgroup.ismi.publicView.PublicCodexBean;
@@ -51,7 +52,6 @@
 	
 	private EntityDetailsBean entDetailsForm = new EntityDetailsBean();
 	
-	
 	private DisplayAuthorBean displayAuthor = new DisplayAuthorBean();
 	private DisplayTitleBean displayTitle = new DisplayTitleBean();
 	
@@ -109,6 +109,7 @@
 
 	private GeneralMerge generalMerge;
 	private ReferenceMerge referenceMerge;
+    private ImportMerge importMerge;
 
 	//private String last_action;
 	//private Date time_of_lastAction;
@@ -242,6 +243,7 @@
 			this.setUser(user);
 			this.generalMerge = new GeneralMerge();
             this.referenceMerge = new ReferenceMerge();
+            this.importMerge = new ImportMerge();
 			this.defForm = new DefinitionForm();
 			// refresh the editor of Dirk
 			addSessionBean("CurrentWitness", new CurrentWitnessBean());
@@ -940,7 +942,21 @@
         this.referenceMerge = referenceMerge;
     }
 
-	public DefinitionForm getDefForm() {
+	/**
+     * @return the importMerge
+     */
+    public ImportMerge getImportMerge() {
+        return importMerge;
+    }
+
+    /**
+     * @param importMerge the importMerge to set
+     */
+    public void setImportMerge(ImportMerge importMerge) {
+        this.importMerge = importMerge;
+    }
+
+    public DefinitionForm getDefForm() {
 		return defForm;
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/mpiwg/itgroup/ismi/merge/ImportMerge.java	Thu Oct 27 20:19:57 2016 +0200
@@ -0,0 +1,787 @@
+package de.mpiwg.itgroup.ismi.merge;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.event.ActionEvent;
+import javax.faces.model.SelectItem;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.mpi.openmind.repository.bo.Attribute;
+import org.mpi.openmind.repository.bo.Entity;
+import org.mpi.openmind.repository.bo.Node;
+import org.mpi.openmind.repository.bo.Relation;
+import org.mpi.openmind.repository.utils.CsvNodeListReader;
+
+import de.mpiwg.itgroup.ismi.entry.beans.AbstractISMIBean;
+
+public class ImportMerge extends AbstractISMIBean implements Serializable {
+
+    private static Logger logger = Logger.getLogger(ImportMerge.class);
+
+    private static final long serialVersionUID = 1L;
+
+    private String importFilename = "/var/tmp/ismi-import.csv";
+    private String importFileMsg = null;
+
+    private List<Node> importNodeList;
+    private int importNodeIdx;
+    private int importNodeListLength = 0;
+    private Node importNode;
+    private String importNodeMsg;
+
+    public static String FIRST_VALUE = "old value";
+    public static String SECOND_VALUE = "new value";
+    public static String IGNORE = "ignore";
+    public static String TAKE = "take";
+
+    private boolean showAttributeMapping = false;
+    private boolean showSrcRelationMapping = false;
+    private boolean showTarRelationMapping = false;
+
+    private boolean entitiesLoaded = false;
+
+    private Map<String, String> firstAttMap = new HashMap<String, String>();
+    private Map<String, String> secondAttMap = new HashMap<String, String>();
+
+    private Entity firstEntity;
+    private Entity secondEntity;
+
+    private String firstId;
+    private String secondId;
+
+    private Entity entResult;
+    private List<Attribute> resultAtts;
+    private List<Relation> resultSrcRels;
+    private List<Relation> resultTarRels;
+
+    private List<String> attLabels;
+    private Map<String, String> selectedAtts;
+
+    Map<Long, String> selectedFirstSrcRelations;
+    Map<Long, String> selectedSecondSrcRelations;
+    Map<Long, String> selectedFirstTarRelations;
+    Map<Long, String> selectedSecondTarRelations;
+
+
+    public ImportMerge() {
+    }
+
+    public void loadImportFile(ActionEvent event) {
+        reset();
+        try {
+            File importFile = new File(this.importFilename);
+            if (!importFile.canRead()) {
+                this.importFileMsg = "File missing!";
+                return;
+            }
+            Reader importReader = new InputStreamReader(new FileInputStream(importFile), "UTF-8");
+            importNodeList = CsvNodeListReader.readCsv(importReader);
+            
+            this.importNodeListLength = importNodeList.size();
+            this.importFileMsg = importNodeListLength + " Nodes";
+            this.importNodeIdx = 0;
+            loadImportNode(null);
+            //this.reset();
+            //this.firstEntity = (Entity) importNodeList.get(importNodeIdx);
+            
+        } catch (Exception e) {
+            addErrorMsg("The import file could no be loaded.");
+            addErrorMsg("Error: "+e);
+        }
+    }
+
+    public void loadImportNode(ActionEvent event) {
+        reset();
+        try {
+            importNode = importNodeList.get(importNodeIdx);
+            importNodeMsg = null;
+            firstEntity = null;
+            secondEntity = null;
+
+            if (importNode.getNodeType().equals("ATTRIBUTE")) {
+                Attribute att = (Attribute) importNode;
+                String attName = att.getName();
+                if (attName == null) {
+                    importNodeMsg = "Attribute has no name!";
+                    return;
+                }
+                Long source_id = att.getSourceId();
+                if (source_id == null) {
+                    importNodeMsg = "Attribute has no source_id to attach to!";
+                    return;
+                } else {
+                    Entity systemEnt = getWrapper().getEntityById(source_id);
+                    if (systemEnt != null) {
+                        if (systemEnt.isLightweight()) {
+                            systemEnt = getWrapper().getEntityContent(systemEnt);
+                        }
+                        Attribute systemAtt = systemEnt.getAttributeByName(attName);
+                        if ((systemAtt != null) && (systemAtt.getOwnValue().equals(att.getOwnValue()))) {
+                            importNodeMsg = "Same attribute exists already!";
+                            return;
+                        }
+                        // create new Entity with this Attribute
+                        Entity newEnt = (Entity) systemEnt.clone();
+                        newEnt.addAttribute(att);
+                        this.secondEntity = newEnt;
+                        // compare with old version 
+                        this.firstEntity = systemEnt;
+                    } else {
+                        importNodeMsg = "Entity for Attribute does not exist!";
+                        return;
+                    }
+                }
+            } else if (importNode.getNodeType().equals("ENTITY")) {
+                Entity ent = (Entity) importNode;
+                Long id = ent.getId();
+                if (id == null) {
+                    // new Entity
+                    this.secondEntity = ent;
+                    // what to use to compare?
+                    this.firstEntity = new Entity();
+                    deployDifferences();
+                    
+                } else {
+                    // entity exists
+                    Entity systemEnt = getWrapper().getEntityById(id);
+                    if (systemEnt != null) {
+                        if (systemEnt.isLightweight()) {
+                            systemEnt = getWrapper().getEntityContent(systemEnt);
+                        }
+                        importNodeMsg = "Entity exists (but may be different).";
+                        // TODO: does it make sense to check for equality?
+                        this.secondEntity = ent;
+                        // compare with old version 
+                        this.firstEntity = systemEnt;
+                    } else {
+                        importNodeMsg = "Entity does no longer exist!";
+                        // TODO: try to undelete?
+                        this.firstEntity = new Entity();
+                        this.secondEntity = ent;
+                    }
+                }
+            } else if (importNode.getNodeType().equals("RELATION")) {
+                Relation rel = (Relation) importNode;
+                String relName = rel.getObjectClass();
+                if (relName == null) {
+                    importNodeMsg = "Relation has no name!";
+                    return;
+                }
+                Long source_id = rel.getSourceId();
+                Long target_id = rel.getTargetId();
+                if (source_id == null) {
+                    importNodeMsg = "Relation has no source_id!";
+                    return;
+                } else if (target_id == null) {
+                    importNodeMsg = "Relation has no target_id!";
+                    return;
+                } else {
+                    Entity sourceEnt = getWrapper().getEntityById(source_id);
+                    Entity targetEnt = getWrapper().getEntityById(target_id);
+                    if (sourceEnt == null) {
+                        importNodeMsg = "Relation source does not exist!";
+                    } else if (targetEnt == null) {
+                        importNodeMsg = "Relation target does not exist!";
+                    } else {
+                        if (sourceEnt.isLightweight()) {
+                            sourceEnt = getWrapper().getEntityContent(sourceEnt);
+                        }
+                        Relation systemRel = sourceEnt.getSourceRelation(relName, target_id);
+                        if ((systemRel != null) && (systemRel.getObjectClass().equals(rel.getObjectClass()))) {
+                            // TODO: also check Relation attributes
+                            importNodeMsg = "Same Relation exists already!";
+                            return;
+                        }
+                        // create new Entity with this Relation
+                        Entity newEnt = (Entity) sourceEnt.clone();
+                        newEnt.addSourceRelation(rel);
+                        this.secondEntity = newEnt;
+                        // compare with old version 
+                        this.firstEntity = sourceEnt;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            addErrorMsg("The import Node could no be loaded.");
+        }
+    }
+
+    public void skipCurrentNode(ActionEvent event) {
+        importNodeIdx += 1;
+        if (importNodeIdx >= importNodeList.size()) {
+            importNodeIdx = importNodeList.size() - 1;
+        }
+        if (importNodeIdx < 0) {
+            importNodeIdx = 0;
+        }
+        loadImportNode(null);
+    }
+    
+    public void loadFirstEntity(ActionEvent event) {
+        reset();
+        try {
+            if (firstEntity != null && secondEntity != null) {
+                deployDifferences();
+            } else {
+                if (importNodeMsg != null) {
+                    addErrorMsg(importNodeMsg);
+                }
+            }
+        } catch (Exception e) {
+            addErrorMsg("The first entity could no be loaded.");
+        }
+    }
+
+    @Override
+    public void reset() {
+        this.attLabels = new ArrayList<String>();
+        this.selectedAtts = new HashMap<String, String>();
+        this.selectedFirstSrcRelations = new HashMap<Long, String>();
+        this.selectedSecondSrcRelations = new HashMap<Long, String>();
+        this.selectedFirstTarRelations = new HashMap<Long, String>();
+        this.selectedSecondTarRelations = new HashMap<Long, String>();
+        this.entResult = null;
+
+        this.entitiesLoaded = false;
+        this.showAttributeMapping = false;
+        this.showSrcRelationMapping = false;
+        this.showTarRelationMapping = false;
+    }
+
+    public void listenerExecuteMerge() {
+        this.executeMerge();
+        getAppBean().getSimpleSearchCache().setMapDirty(true);
+    }
+
+    private void deployDifferences() {
+        this.showAttributeMapping = true;
+        this.showSrcRelationMapping = true;
+        this.showTarRelationMapping = true;
+        this.entitiesLoaded = true;
+        if (this.firstEntity != null && this.secondEntity != null) {
+            /* 
+            if (firstEntity.isLightweight()) {
+                this.firstEntity = getWrapper().getEntityContent(this.firstEntity);
+            }
+            if (secondEntity.isLightweight()) {
+                this.secondEntity = getWrapper().getEntityContent(this.secondEntity);
+            }
+
+            this.firstEntity = (Entity) firstEntity.clone();
+            this.secondEntity = (Entity) secondEntity.clone();
+            */
+            
+            // attributes
+            this.attLabels = new ArrayList<String>();
+            this.selectedAtts = new HashMap<String, String>();
+            this.firstAttMap = new HashMap<String, String>();
+            this.secondAttMap = new HashMap<String, String>();
+
+            for (Attribute att : this.firstEntity.getAttributes()) {
+                firstAttMap.put(att.getName(), att.getValue());
+                if (!attLabels.contains(att.getName())) {
+                    attLabels.add(att.getName());
+                    selectedAtts.put(att.getName(), FIRST_VALUE);
+                }
+            }
+
+            for (Attribute att : this.secondEntity.getAttributes()) {
+                secondAttMap.put(att.getName(), att.getValue());
+                if (!attLabels.contains(att.getName())) {
+                    attLabels.add(att.getName());
+                    selectedAtts.put(att.getName(), FIRST_VALUE);
+                }
+            }
+
+            // source relations
+            this.selectedFirstSrcRelations = new HashMap<Long, String>();
+            this.selectedSecondSrcRelations = new HashMap<Long, String>();
+
+            for (Relation rel : this.firstEntity.getSourceRelations()) {
+                rel.setTarget(getWrapper().getEntityById(rel.getTargetId()));
+                selectedFirstSrcRelations.put(rel.getId(), TAKE);
+            }
+
+            for (Relation rel : this.secondEntity.getSourceRelations()) {
+                rel.setTarget(getWrapper().getEntityById(rel.getTargetId()));
+                selectedSecondSrcRelations.put(rel.getId(), TAKE);
+            }
+
+            // target relations
+            this.selectedFirstTarRelations = new HashMap<Long, String>();
+            this.selectedSecondTarRelations = new HashMap<Long, String>();
+
+            for (Relation rel : this.firstEntity.getTargetRelations()) {
+                rel.setSource(getWrapper().getEntityById(rel.getSourceId()));
+                selectedFirstTarRelations.put(rel.getId(), TAKE);
+            }
+
+            for (Relation rel : this.secondEntity.getTargetRelations()) {
+                rel.setSource(getWrapper().getEntityById(rel.getSourceId()));
+                selectedSecondTarRelations.put(rel.getId(), TAKE);
+            }
+
+        }
+    }
+
+    public void preview(ActionEvent event) {
+        this.generateResultEntity();
+    }
+
+    private void executeMerge() {
+
+        logger.info("Starting merge execution " + firstEntity.getObjectClass() + " [" + getUserName() + "]"
+                + "[firstEntity=" + firstEntity.getId() + ", secondEntity=" + secondEntity.getId() + "]");
+
+        try {
+            this.generateResultEntity();
+            if (this.entResult != null) {
+
+                this.printMergeInfo(entResult);
+
+                this.getWrapper().saveEntity(this.entResult, getSessionUser().getEmail() + "_merge");
+
+                this.getWrapper().removeCurrentVersionEntity(this.firstEntity);
+                this.getWrapper().removeCurrentVersionEntity(this.secondEntity);
+
+                // the old relations should be removed, before...
+                this.updateRelatedOW(this.entResult, getSessionUser().getEmail() + "_merge");
+
+                this.printMergeInfo(entResult);
+
+                logger.info("Merge execution 'successful' " + firstEntity.getObjectClass() + " [" + getUserName() + "]"
+                        + "[firstEntity=" + firstEntity.getId() + ", secondEntity=" + secondEntity.getId()
+                        + ", generatedEntity=" + entResult.getId() + "]");
+
+                this.firstEntity = null;
+                this.secondEntity = null;
+
+                addGeneralMsg("The entities were merged successfully");
+                addGeneralMsg("The new entity has the id " + this.entResult.getId());
+                this.reset();
+            }
+        } catch (Exception e) {
+            printInternalError(e);
+            logger.error("[" + getUserName() + "] " + e.getMessage(), e);
+        }
+    }
+
+    private void printMergeInfo(Entity ent) {
+        StringBuilder sb = new StringBuilder("\n\n");
+
+        sb.append("-------------------------------------------");
+        sb.append("-----------------------------------------\n");
+        sb.append("Merging result [" + getUserName() + "]\n");
+        sb.append(ent.toString() + "\n");
+        sb.append("Attributes:\n");
+        for (Attribute att : ent.getAttributes()) {
+            sb.append("\t" + att.toString() + "\n");
+        }
+
+        sb.append("Src Relations:\n");
+        for (Relation src : ent.getSourceRelations()) {
+            sb.append("\t" + src.toString() + "\n");
+        }
+
+        sb.append("Tar Relations:\n");
+        for (Relation tar : ent.getTargetRelations()) {
+            sb.append("\t" + tar.toString() + "\n");
+        }
+
+        sb.append("-------------------------------------------");
+        sb.append("-----------------------------------------\n");
+        logger.info(sb.toString());
+    }
+
+    public void actionShowTarRelationMapping(ActionEvent event) {
+        this.showTarRelationMapping = true;
+    }
+
+    public void actionHideTarRelationMapping(ActionEvent event) {
+        this.showTarRelationMapping = false;
+    }
+
+    public void actionShowSrcRelationMapping(ActionEvent event) {
+        this.showSrcRelationMapping = true;
+    }
+
+    public void actionHideSrcRelationMapping(ActionEvent event) {
+        this.showSrcRelationMapping = false;
+    }
+
+    public void actionShowAttributeMapping(ActionEvent event) {
+        this.showAttributeMapping = true;
+    }
+
+    public void actionHideAttributeMapping(ActionEvent event) {
+        this.showAttributeMapping = false;
+    }
+
+    private void generateResultEntity() {
+        this.entResult = new Entity();
+        this.entResult.setLightweight(false);
+        this.entResult.setObjectClass(this.firstEntity.getObjectClass());
+
+        // generating attributes
+        try {
+            for (String attName : this.selectedAtts.keySet()) {
+                String selected = this.selectedAtts.get(attName);
+                String value = "";
+                if (selected.equals(FIRST_VALUE)) {
+                    value = (firstEntity.getAttributeByName(attName) == null) ? ""
+                            : firstEntity.getAttributeByName(attName).getOwnValue();
+                } else if (selected.equals(SECOND_VALUE)) {
+                    value = (secondEntity.getAttributeByName(attName) == null) ? ""
+                            : secondEntity.getAttributeByName(attName).getOwnValue();
+                }
+                this.entResult.addAttribute(new Attribute(attName, "text", value));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            addErrorMsg("Please inform support of this exception: " + e.getMessage());
+        }
+
+        // generating source relations
+        for (Relation rel : firstEntity.getSourceRelations()) {
+            String selectedValue = this.selectedFirstSrcRelations.get(rel.getId());
+            if (StringUtils.isNotEmpty(selectedValue) && selectedValue.equals(TAKE)) {
+                if (!this.entResult.containsSourceRelation(rel.getOwnValue(), rel.getTargetId())) {
+                    this.entResult.addSourceRelation(generateSrcRelation(rel));
+                }
+            }
+        }
+
+        for (Relation rel : secondEntity.getSourceRelations()) {
+            String selectedValue = this.selectedSecondSrcRelations.get(rel.getId());
+            if (StringUtils.isNotEmpty(selectedValue) && selectedValue.equals(TAKE)) {
+                if (!this.entResult.containsSourceRelation(rel.getOwnValue(), rel.getTargetId())) {
+                    this.entResult.addSourceRelation(generateSrcRelation(rel));
+                }
+            }
+        }
+
+        // generating target relations
+        for (Relation rel : firstEntity.getTargetRelations()) {
+            String selectedValue = this.selectedFirstTarRelations.get(rel.getId());
+            if (StringUtils.isNotEmpty(selectedValue) && selectedValue.equals(TAKE)) {
+                // ensuring that there is no two equals relations.
+                if (!this.entResult.containsTargetRelation(rel.getOwnValue(), rel.getSourceId())) {
+                    this.entResult.addTargetRelation(generateTarRelation(rel));
+                }
+            }
+        }
+
+        for (Relation rel : secondEntity.getTargetRelations()) {
+            String selectedValue = this.selectedSecondTarRelations.get(rel.getId());
+            if (StringUtils.isNotEmpty(selectedValue) && selectedValue.equals(TAKE)) {
+                if (!this.entResult.containsTargetRelation(rel.getOwnValue(), rel.getSourceId())) {
+                    this.entResult.addTargetRelation(generateTarRelation(rel));
+                }
+            }
+        }
+    }
+
+    private Relation generateSrcRelation(Relation rel) {
+
+        Relation newRel = new Relation();
+        newRel.setOwnValue(rel.getOwnValue());
+        newRel.setTarget(getWrapper().getEntityById(rel.getTargetId()));
+
+        return newRel;
+    }
+
+    private Relation generateTarRelation(Relation rel) {
+        Relation newRel = new Relation();
+        newRel.setOwnValue(rel.getOwnValue());
+        newRel.setSource(getWrapper().getEntityById(rel.getSourceId()));
+        return newRel;
+    }
+
+    public List<SelectItem> getAttSelectItems() {
+        List<SelectItem> items = new ArrayList<SelectItem>();
+        items.add(new SelectItem(FIRST_VALUE));
+        items.add(new SelectItem(SECOND_VALUE));
+        items.add(new SelectItem(IGNORE));
+        return items;
+    }
+
+    public List<SelectItem> getRelSelectItems() {
+        List<SelectItem> items = new ArrayList<SelectItem>();
+        items.add(new SelectItem(TAKE));
+        items.add(new SelectItem(IGNORE));
+        return items;
+    }
+
+    public Entity getEntResult() {
+        return entResult;
+    }
+
+    public void setEntResult(Entity entResult) {
+        this.entResult = entResult;
+    }
+
+    public List<Attribute> getResultAtts() {
+        return resultAtts;
+    }
+
+    public void setResultAtts(List<Attribute> resultAtts) {
+        this.resultAtts = resultAtts;
+    }
+
+    public List<Relation> getResultSrcRels() {
+        return resultSrcRels;
+    }
+
+    public void setResultSrcRels(List<Relation> resultSrcRels) {
+        this.resultSrcRels = resultSrcRels;
+    }
+
+    public List<Relation> getResultTarRels() {
+        return resultTarRels;
+    }
+
+    public void setResultTarRels(List<Relation> resultTarRels) {
+        this.resultTarRels = resultTarRels;
+    }
+
+    public Entity getFirstEntity() {
+        return firstEntity;
+    }
+
+    public void setFirstEntity(Entity firstEntity) {
+        this.firstEntity = firstEntity;
+    }
+
+    public Entity getSecondEntity() {
+        return secondEntity;
+    }
+
+    public void setSecondEntity(Entity secondEntity) {
+        this.secondEntity = secondEntity;
+    }
+
+    public String getFirstId() {
+        return firstId;
+    }
+
+    public void setFirstId(String firstId) {
+        this.firstId = firstId;
+    }
+
+    public String getSecondId() {
+        return secondId;
+    }
+
+    public void setSecondId(String secondId) {
+        this.secondId = secondId;
+    }
+
+    public List<String> getAttLabels() {
+        return attLabels;
+    }
+
+    public void setAttLabels(List<String> attLabels) {
+        this.attLabels = attLabels;
+    }
+
+    public Map<String, String> getFirstAttMap() {
+        return firstAttMap;
+    }
+
+    public void setFirstAttMap(Map<String, String> firstAttMap) {
+        this.firstAttMap = firstAttMap;
+    }
+
+    public Map<String, String> getSecondAttMap() {
+        return secondAttMap;
+    }
+
+    public void setSecondAttMap(Map<String, String> secondAttMap) {
+        this.secondAttMap = secondAttMap;
+    }
+
+    public Map<String, String> getSelectedAtts() {
+        return selectedAtts;
+    }
+
+    public void setSelectedAtts(Map<String, String> selectedAtts) {
+        this.selectedAtts = selectedAtts;
+    }
+
+    public boolean isShowAttributeMapping() {
+        return showAttributeMapping;
+    }
+
+    public void setShowAttributeMapping(boolean showAttributeMapping) {
+        this.showAttributeMapping = showAttributeMapping;
+    }
+
+    public boolean isEntitiesLoaded() {
+        return entitiesLoaded;
+    }
+
+    public void setEntitiesLoaded(boolean entitiesLoaded) {
+        this.entitiesLoaded = entitiesLoaded;
+    }
+
+    public Map<Long, String> getSelectedFirstSrcRelations() {
+        return selectedFirstSrcRelations;
+    }
+
+    public void setSelectedFirstSrcRelations(Map<Long, String> selectedFirstSrcRelations) {
+        this.selectedFirstSrcRelations = selectedFirstSrcRelations;
+    }
+
+    public Map<Long, String> getSelectedSecondSrcRelations() {
+        return selectedSecondSrcRelations;
+    }
+
+    public void setSelectedSecondSrcRelations(Map<Long, String> selectedSecondSrcRelations) {
+        this.selectedSecondSrcRelations = selectedSecondSrcRelations;
+    }
+
+    public boolean isShowSrcRelationMapping() {
+        return showSrcRelationMapping;
+    }
+
+    public void setShowSrcRelationMapping(boolean showSrcRelationMapping) {
+        this.showSrcRelationMapping = showSrcRelationMapping;
+    }
+
+    public boolean isShowTarRelationMapping() {
+        return showTarRelationMapping;
+    }
+
+    public void setShowTarRelationMapping(boolean showTarRelationMapping) {
+        this.showTarRelationMapping = showTarRelationMapping;
+    }
+
+    public Map<Long, String> getSelectedFirstTarRelations() {
+        return selectedFirstTarRelations;
+    }
+
+    public void setSelectedFirstTarRelations(Map<Long, String> selectedFirstTarRelations) {
+        this.selectedFirstTarRelations = selectedFirstTarRelations;
+    }
+
+    public Map<Long, String> getSelectedSecondTarRelations() {
+        return selectedSecondTarRelations;
+    }
+
+    public void setSelectedSecondTarRelations(Map<Long, String> selectedSecondTarRelations) {
+        this.selectedSecondTarRelations = selectedSecondTarRelations;
+    }
+
+    /**
+     * @return the importFilename
+     */
+    public String getImportFilename() {
+        return importFilename;
+    }
+
+    /**
+     * @param importFilename
+     *            the importFilename to set
+     */
+    public void setImportFilename(String importFilename) {
+        this.importFilename = importFilename;
+    }
+
+    /**
+     * @return the importFileMsg
+     */
+    public String getImportFileMsg() {
+        return importFileMsg;
+    }
+
+    /**
+     * @param importFileMsg
+     *            the importFileMsg to set
+     */
+    public void setImportFileMsg(String importFileMsg) {
+        this.importFileMsg = importFileMsg;
+    }
+
+    /**
+     * @return the importNode
+     */
+    public Node getImportNode() {
+        return importNode;
+    }
+    
+    public String getImportNodeAsText() {
+        String s = "";
+        try {
+            String nt = importNode.getNodeType();
+            if (nt.equals("ATTRIBUTE")) {
+                Attribute att = (Attribute) importNode;
+                s = "ATTRIBUTE " + att.getName() + " [on " + att.getSourceObjectClass() + " " + att.getSourceId() + "] = " + att.getOwnValue();
+            } else if (nt.equals("ENTITY")) {
+                Entity ent = (Entity) importNode;
+                s = "ENTITY " + ent.getObjectClass() + " [" + ent.getId() + "] = " + ent.getOwnValue();
+            } else if (nt.equals("RELATION")) {
+                Relation rel = (Relation) importNode;
+                s = "RELATION " + rel.getObjectClass() + " [" + rel.getId() + "] "
+                    + "source=[" + rel.getSourceObjectClass() + " " + rel.getSourceId() + "] "
+                    + "target=[" + rel.getTargetObjectClass() + " " + rel.getTargetId() + "]";
+            } else {
+                s = importNode.toString();
+            }
+        } catch (Exception e) {
+            logger.error(e);
+        }
+        return s;
+    }
+
+    /**
+     * @param importNode the importNode to set
+     */
+    public void setImportNode(Node importNode) {
+        this.importNode = importNode;
+    }
+
+    /**
+     * @return the importNodeListLength
+     */
+    public int getImportNodeListLength() {
+        return importNodeListLength;
+    }
+
+    /**
+     * @return the importNodeIdx
+     */
+    public int getImportNodeIdx() {
+        return importNodeIdx;
+    }
+
+    /**
+     * @param importNodeIdx the importNodeIdx to set
+     */
+    public void setImportNodeIdx(int importNodeIdx) {
+        this.importNodeIdx = importNodeIdx;
+    }
+
+    /**
+     * @return the importNodeMsg
+     */
+    public String getImportNodeMsg() {
+        return importNodeMsg;
+    }
+
+    /**
+     * @param importNodeMsg the importNodeMsg to set
+     */
+    public void setImportNodeMsg(String importNodeMsg) {
+        this.importNodeMsg = importNodeMsg;
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/merge/importMerge.xhtml	Thu Oct 27 20:19:57 2016 +0200
@@ -0,0 +1,378 @@
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:f="http://java.sun.com/jsf/core"
+	xmlns:ui="http://java.sun.com/jsf/facelets"
+	xmlns:a4j="http://richfaces.org/a4j"
+	xmlns:rich="http://richfaces.org/rich">
+
+<body>
+	<ui:composition template="/templates/privateTemplate.xhtml">
+
+		<ui:define name="privateContent">
+			
+			<div id="pageTitle">
+				<h:outputText value="Merge Import List" />
+			</div>
+			
+			<h:panelGrid rendered="#{Session.user != null}"
+				styleClass="mainPanel" columns="1">
+			
+				
+
+                <h:panelGrid columns="2" styleClass="createPanel"
+                    columnClasses="createPanelFirstColumn" id="loadListPanel">
+                    
+                    <h:outputText value="Import File" />
+
+                    <h:panelGrid columns="3">
+                        <h:outputText value="#{Session.importMerge.importFilename}" />
+                    
+                        <a4j:commandButton value="Load"
+                            actionListener="#{Session.importMerge.loadImportFile}"
+                            render="loadListPanel,loadingPanel" />
+                            
+                        <h:outputText
+                                value="#{Session.importMerge.importFileMsg}"
+                                rendered="#{!empty Session.importMerge.importFileMsg}" 
+                                styleClass="textBack"/>
+                    </h:panelGrid>
+                </h:panelGrid>
+
+				<h:panelGrid columns="2" styleClass="createPanel"
+					columnClasses="createPanelFirstColumn" id="loadingPanel" 
+					rendered="#{Session.importMerge.importNodeListLength > 0}">
+
+					<h:outputText value="Import Nodes" />
+
+					<h:panelGrid columns="3">
+
+						<h:outputText value="Node #{Session.importMerge.importNodeIdx + 1} / #{Session.importMerge.importNodeListLength}" 
+							styleClass="textBack"/>
+                        <a4j:commandButton value="Skip"
+                            actionListener="#{Session.importMerge.skipCurrentNode}"
+                            render="loadingPanel,mergingPanel" />
+						<h:column>
+							<h:outputText
+								value="#{Session.importMerge.importNodeAsText}"
+								rendered="#{Session.importMerge.importNode != null}" 
+								styleClass="textBack"/>
+						</h:column>
+
+                        <h:outputText/>
+                        <a4j:commandButton value="Load"
+                            actionListener="#{Session.importMerge.loadFirstEntity}"
+                            render="loadingPanel,mergingPanel" />
+                        <h:outputText
+                                value="#{Session.importMerge.importNodeMsg}"
+                                rendered="#{! empty Session.importMerge.importNodeMsg}" 
+                                styleClass="textBack"/>
+					</h:panelGrid>
+
+				</h:panelGrid>
+
+				<h:panelGrid columns="1" id="mergingPanel">
+
+					<h:outputText value="Merge Mapping"
+						rendered="#{Session.importMerge.entitiesLoaded}"
+						styleClass="titlePanel"/>
+
+					<h:panelGrid columns="2" styleClass="createPanel"
+						columnClasses="createPanelFirstColumn,createPanelColumn02,createPanelColumn02"
+						rendered="#{Session.importMerge.entitiesLoaded}">
+
+
+						<h:outputText value="Attributes" />
+						<rich:dataTable var="attName"
+							value="#{Session.importMerge.attLabels}"
+							rendered="#{!empty Session.importMerge.attLabels}">
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Attribute Name" />
+								</f:facet>
+								<h:outputText value="#{attName}" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Value Old Entity" />
+								</f:facet>
+								<h:outputText
+									value="#{Session.importMerge.firstAttMap[attName]}" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Value New Entity" />
+								</f:facet>
+								<h:outputText
+									value="#{Session.importMerge.secondAttMap[attName]}" />
+							</h:column>
+							<h:column style="width:300px;">
+								<f:facet name="header">
+									<h:outputText value="Select Value" />
+								</f:facet>
+								<h:selectOneRadio
+									value="#{Session.importMerge.selectedAtts[attName]}">
+									<f:selectItems value="#{Session.importMerge.attSelectItems}" />
+								</h:selectOneRadio>
+							</h:column>
+						</rich:dataTable>
+
+                    </h:panelGrid>
+
+                    <h:panelGrid columns="3" styleClass="createPanel"
+                        columnClasses="createPanelFirstColumn,createPanelColumn02,createPanelColumn02"
+                        rendered="#{Session.importMerge.entitiesLoaded}">
+
+
+						<h:outputText value="Source Relations" />
+
+						<h:panelGrid columns="1">
+							<rich:dataTable var="srcRelation"
+								rendered="#{!empty Session.importMerge.firstEntity.sourceRelations}"
+								value="#{Session.importMerge.firstEntity.sourceRelations}">
+
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="Relation Name" />
+									</f:facet>
+									<h:outputText value="#{srcRelation.ownValue}" />
+								</h:column>
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="linked to this" />
+									</f:facet>
+									<h:outputText
+										value="#{srcRelation.target.ownValue} [#{srcRelation.target.objectClass}-#{srcRelation.targetId}]" />
+								</h:column>
+
+								<h:column>
+									<h:selectOneRadio
+										value="#{Session.importMerge.selectedFirstSrcRelations[srcRelation.id]}">
+										<f:selectItems value="#{Session.importMerge.relSelectItems}" />
+									</h:selectOneRadio>
+								</h:column>
+
+							</rich:dataTable>
+
+							<h:outputText
+								value="The old entity does not have source relations"
+								rendered="#{empty Session.importMerge.firstEntity.sourceRelations}" />
+						</h:panelGrid>
+
+						<h:panelGrid columns="1">
+
+							<rich:dataTable var="srcRelation"
+								rendered="#{!empty Session.importMerge.secondEntity.sourceRelations}"
+								value="#{Session.importMerge.secondEntity.sourceRelations}">
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="Relation Name" />
+									</f:facet>
+									<h:outputText value="#{srcRelation.ownValue}" />
+								</h:column>
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="linked to this" />
+									</f:facet>
+									<h:outputText
+										value="#{srcRelation.target.ownValue} [#{srcRelation.target.objectClass}-#{srcRelation.targetId}]" />
+								</h:column>
+								<h:column>
+									<h:selectOneRadio
+										value="#{Session.importMerge.selectedSecondSrcRelations[srcRelation.id]}">
+										<f:selectItems value="#{Session.importMerge.relSelectItems}" />
+									</h:selectOneRadio>
+								</h:column>
+							</rich:dataTable>
+							
+							<h:outputText
+								value="The new entity does not have source relations"
+								rendered="#{empty Session.importMerge.secondEntity.sourceRelations}" />
+
+						</h:panelGrid>
+
+
+						<h:outputText value="Target Relations" />
+
+						<h:panelGrid columns="1">
+							<rich:dataTable var="tarRelation"
+								rendered="#{!empty Session.importMerge.firstEntity.targetRelations}"
+								value="#{Session.importMerge.firstEntity.targetRelations}"
+								style="width:60%;">
+
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="linked from this" />
+									</f:facet>
+									<h:outputText
+										value="#{tarRelation.source.ownValue} [#{tarRelation.source.objectClass}-#{tarRelation.sourceId}]" />
+								</h:column>
+
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="Relation Name" />
+									</f:facet>
+									<h:outputText value="#{tarRelation.ownValue}" />
+								</h:column>
+
+								<h:column>
+									<h:selectOneRadio
+										value="#{Session.importMerge.selectedFirstTarRelations[tarRelation.id]}">
+										<f:selectItems value="#{Session.importMerge.relSelectItems}" />
+									</h:selectOneRadio>
+								</h:column>
+							</rich:dataTable>
+							<h:outputText
+								value="The old entity does not have target relations."
+								rendered="#{empty Session.importMerge.firstEntity.targetRelations}" />
+						</h:panelGrid>
+
+						<h:panelGrid columns="1">
+
+							<rich:dataTable var="tarRelation"
+								rendered="#{!empty Session.importMerge.secondEntity.targetRelations}"
+								value="#{Session.importMerge.secondEntity.targetRelations}"
+								style="width:60%;">
+
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="linked from this" />
+									</f:facet>
+									<h:outputText
+										value="#{tarRelation.source.ownValue} [#{tarRelation.source.objectClass}-#{tarRelation.sourceId}]" />
+								</h:column>
+
+								<h:column>
+									<f:facet name="header">
+										<h:outputText value="Relation Name" />
+									</f:facet>
+									<h:outputText value="#{tarRelation.ownValue}" />
+								</h:column>
+
+								<h:column>
+									<h:selectOneRadio
+										value="#{Session.importMerge.selectedSecondTarRelations[tarRelation.id]}">
+										<f:selectItems value="#{Session.importMerge.relSelectItems}" />
+									</h:selectOneRadio>
+								</h:column>
+
+							</rich:dataTable>
+
+							<h:outputText
+								value="The new entity does not have target relations"
+								rendered="#{empty Session.importMerge.secondEntity.targetRelations}" />
+
+						</h:panelGrid>
+					</h:panelGrid>
+
+					<h:panelGrid columns="2" styleClass="controlPanel"
+						rendered="#{Session.importMerge.entitiesLoaded}">
+
+						<a4j:commandButton value="Preview"
+							actionListener="#{Session.importMerge.preview}"
+							rendered="#{Session.importMerge.entitiesLoaded}"
+							render="mergingPanel" />
+
+						<a4j:commandButton value="Execute Merge"
+							actionListener="#{Session.importMerge.listenerExecuteMerge }"
+							rendered="#{Session.importMerge.entitiesLoaded}"
+							onclick="#{ApplicationBean1.JSConfirmationMerge}"
+							render="mergingPanel" />
+
+					</h:panelGrid>
+
+
+					<h:outputText value="Entity Preview"
+						rendered="#{!empty Session.importMerge.entResult}"
+						styleClass="titlePanel"/>
+					<h:panelGrid columns="2" styleClass="createPanel"
+						columnClasses="createPanelFirstColumn"
+						rendered="#{!empty Session.importMerge.entResult}">
+
+
+						<h:outputText value="Attributes" />
+						<rich:dataTable
+							value="#{Session.importMerge.entResult.attributes}"
+							var="attribute" border="1">
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Name" />
+								</f:facet>
+								<h:outputText value="#{attribute.objectClass}" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Value" />
+								</f:facet>
+								<h:outputText value="#{attribute.ownValue}" />
+							</h:column>
+						</rich:dataTable>
+
+
+						<h:outputText value="Source Relations" />
+						<rich:dataTable
+							value="#{Session.importMerge.entResult.sourceRelations}"
+							var="srcRelation" border="1">
+
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="linked from this" />
+								</f:facet>
+								<h:outputText value="#{'x'}" />
+							</h:column>
+
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Relation Name" />
+								</f:facet>
+								<h:outputText value="#{srcRelation.ownValue}" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="linked to this" />
+								</f:facet>
+								<h:outputText
+									value="#{srcRelation.target.ownValue} [#{srcRelation.target.objectClass}]" />
+							</h:column>
+						</rich:dataTable>
+
+						<h:outputText value="Target Relations" />
+						<rich:dataTable
+							value="#{Session.importMerge.entResult.targetRelations}"
+							var="tarRelation" border="1">
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="linked from this" />
+								</f:facet>
+								<h:outputText
+									value="#{tarRelation.source.ownValue} [#{tarRelation.source.objectClass}]" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="Relation Name" />
+								</f:facet>
+								<h:outputText value="#{tarRelation.ownValue}" />
+							</h:column>
+							<h:column>
+								<f:facet name="header">
+									<h:outputText value="linked to this" />
+								</f:facet>
+								<h:outputText value="#{'x'}" />
+							</h:column>
+						</rich:dataTable>
+
+
+					</h:panelGrid>
+
+
+
+				</h:panelGrid>
+
+
+
+			</h:panelGrid>
+		</ui:define>
+	</ui:composition>
+</body>
+</html>
\ No newline at end of file
--- a/src/main/webapp/templates/main_template.xhtml	Thu Oct 20 14:09:28 2016 +0200
+++ b/src/main/webapp/templates/main_template.xhtml	Thu Oct 27 20:19:57 2016 +0200
@@ -147,11 +147,25 @@
 				</rich:menuItem>
 			</rich:dropDownMenu>
 
-			<h:outputLink rendered="#{Session.canMerge}"
-				value="#{ApplicationBean1.root}/merge/generalMerge.xhtml">Merge</h:outputLink>
+            <rich:dropDownMenu mode="ajax" rendered="#{Session.canMerge}">
+                <f:facet name="label">
+                    <h:panelGroup>
+                        <h:outputText value="Merge" />
+                    </h:panelGroup>
+                </f:facet>
 
-            <h:outputLink rendered="#{Session.canMerge}"
-                value="#{ApplicationBean1.root}/merge/referenceMerge.xhtml">Join References</h:outputLink>
+                <rich:menuItem label="Merge Entities"
+                    onclick="document.location.href='#{ApplicationBean1.root}/merge/generalMerge.xhtml'">
+                </rich:menuItem>
+
+                <rich:menuItem label="Join References"
+                    onclick="document.location.href='#{ApplicationBean1.root}/merge/referenceMerge.xhtml'">
+                </rich:menuItem>
+
+                <rich:menuItem label="Merge Import List"
+                    onclick="document.location.href='#{ApplicationBean1.root}/merge/importMerge.xhtml'">
+                </rich:menuItem>
+            </rich:dropDownMenu>
 
 			<h:outputLink  rendered="#{Session.canCreate}"
 				value="#{ApplicationBean1.root}/browse/entityRepository.xhtml">Browse Repository</h:outputLink>