org.talend.repository.json.ui.wizards.extraction.JSONToXPathLinker.java Source code

Java tutorial

Introduction

Here is the source code for org.talend.repository.json.ui.wizards.extraction.JSONToXPathLinker.java

Source

// ============================================================================
//
// Copyright (C) 2006-2015 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.repository.json.ui.wizards.extraction;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.talend.commons.runtime.xml.XmlNodeRetriever;
import org.talend.commons.ui.runtime.exception.ExceptionHandler;
import org.talend.commons.ui.runtime.swt.tableviewer.selection.ILineSelectionListener;
import org.talend.commons.ui.runtime.swt.tableviewer.selection.LineSelectionEvent;
import org.talend.commons.ui.runtime.swt.tableviewer.selection.SelectionHelper;
import org.talend.commons.ui.runtime.utils.TableUtils;
import org.talend.commons.ui.runtime.ws.WindowSystem;
import org.talend.commons.ui.swt.dialogs.EventLoopProgressMonitor;
import org.talend.commons.ui.swt.dialogs.ProgressDialog;
import org.talend.commons.ui.swt.drawing.link.BezierHorizontalLink;
import org.talend.commons.ui.swt.drawing.link.ExtremityEastArrow;
import org.talend.commons.ui.swt.drawing.link.ExtremityLink;
import org.talend.commons.ui.swt.drawing.link.IExtremityLink;
import org.talend.commons.ui.swt.drawing.link.IStyleLink;
import org.talend.commons.ui.swt.drawing.link.LinkDescriptor;
import org.talend.commons.ui.swt.drawing.link.StyleLink;
import org.talend.commons.ui.swt.drawing.link.TreeExtremityDescriptor;
import org.talend.commons.ui.swt.extended.table.AbstractExtendedControlViewer.EVENT_TYPE;
import org.talend.commons.ui.swt.extended.table.ExtendedControlEvent;
import org.talend.commons.ui.swt.extended.table.IExtendedControlListener;
import org.talend.commons.ui.swt.linking.TreeToTablesLinker;
import org.talend.commons.ui.swt.proposal.TextCellEditorWithProposal;
import org.talend.commons.ui.swt.tableviewer.IModifiedBeanListener;
import org.talend.commons.ui.swt.tableviewer.ModifiedBeanEvent;
import org.talend.commons.utils.data.list.IListenableListListener;
import org.talend.commons.utils.data.list.ListenableListEvent;
import org.talend.commons.utils.data.list.ListenableListEvent.TYPE;
import org.talend.core.utils.TalendQuoteUtils;
import org.talend.designer.core.model.utils.emf.talendfile.ContextType;
import org.talend.metadata.managment.ui.utils.ConnectionContextHelper;
import org.talend.metadata.managment.ui.wizard.metadata.xml.XmlExtractorBgRefresher;
import org.talend.repository.json.ui.wizards.dnd.JSONToSchemaDragAndDropHandler;
import org.talend.repository.model.json.JSONXPathLoopDescriptor;
import org.talend.repository.model.json.SchemaTarget;
import org.talend.repository.ui.wizards.metadata.connection.files.json.AbstractTreePopulator;
import org.talend.repository.ui.wizards.metadata.connection.files.json.EJsonReadbyMode;
import org.w3c.dom.Node;

/**
 * DOC amaumont class global comment. Detailled comment <br/>
 * 
 * $Id$
 * 
 */
public class JSONToXPathLinker extends TreeToTablesLinker<Object, Object> {

    protected AbstractTreePopulator treePopulator;

    private ExtractionFieldsWithJSONXPathEditorView fieldsTableEditorView;

    private XmlNodeRetriever nodeRetriever;

    private ExtractionLoopWithJSONXPathEditorView loopTableEditorView;

    private StyleLink selectedLoopStyleLink;

    protected ArrayList<String> loopXpathNodes = new ArrayList<String>(0);

    private Comparator<LinkDescriptor<TreeItem, Object, Table, Object>> drawingLinksComparator;

    private ArrayList<Node> uniqueLoopNodes = new ArrayList<Node>();

    private ArrayList<Node> allLoopNodes = new ArrayList<Node>();

    private Color selectedLoopLinkColor;

    private Color selectedRelativeLinkColor;

    protected JSONToSchemaDragAndDropHandler jsonDndHandler;

    private XmlExtractorBgRefresher xmlExtractorBgRefresher;

    /**
     * DOC amaumont JSONToMetadataTableLinker constructor comment.
     * 
     * @param commonParent common main parent of tree and table, it and its children should have backgoundMode
     * configured with SWT.INHERIT_FORCE, same configuration for parents of tree and table.
     * @param tree
     * @param loopTableEditorView
     * @param table
     */
    public JSONToXPathLinker(Composite commonParent) {
        super(commonParent);
    }

    public void init(Tree tree, ExtractionLoopWithJSONXPathEditorView loopTableEditorView,
            ExtractionFieldsWithJSONXPathEditorView fieldsTableEditorView, AbstractTreePopulator treePopulator) {
        xmlExtractorBgRefresher = new XmlExtractorBgRefresher(this);
        init(tree,
                new Table[] { loopTableEditorView.getExtendedTableViewer().getTableViewerCreator().getTable(),
                        fieldsTableEditorView.getExtendedTableViewer().getTableViewerCreator().getTable(), },
                xmlExtractorBgRefresher);
        this.treePopulator = treePopulator;
        this.loopTableEditorView = loopTableEditorView;
        this.fieldsTableEditorView = fieldsTableEditorView;
        this.nodeRetriever = getXmlNodeRetriever(treePopulator.getFilePath(), getCurrentLoopXPath());

        TextCellEditorWithProposal xPathCellEditor = loopTableEditorView.getXPathCellEditor();
        xPathCellEditor.setContentProposalProvider(getJSONXPathProposalProvider(this, false));
        xPathCellEditor = fieldsTableEditorView.getXPathCellEditor();
        xPathCellEditor.setContentProposalProvider(getJSONXPathProposalProvider(this, true));
        init();
    }

    public void init(AbstractTreePopulator treePopulator) {
        this.treePopulator = treePopulator;
        this.nodeRetriever = getXmlNodeRetriever(treePopulator.getFilePath(), getCurrentLoopXPath());
    }

    public String getAbsoluteXPath(TreeItem treeItem) {
        return treePopulator.getAbsoluteXPath(treeItem);
    }

    protected JSONXPathProposalProvider getJSONXPathProposalProvider(JSONToXPathLinker linker, boolean isRelative) {
        JSONXPathProposalProvider provider = new JSONXPathProposalProvider(linker, isRelative);
        provider.setReadbyMode(EJsonReadbyMode.XPATH.getValue());
        return provider;
    }

    protected XmlNodeRetriever getXmlNodeRetriever(String filePath, String loopXPath) {
        return new XmlNodeRetriever(filePath, loopXPath);
    }

    /**
     * DOC amaumont Comment method "init".
     * 
     * @param tree
     */
    private void init() {

        Display display = getBgDrawableComposite().getDisplay();

        initColors(display);

        StyleLink unselectedStyleLink = new StyleLink();
        unselectedStyleLink.setDrawableLink(new BezierHorizontalLink(unselectedStyleLink));
        unselectedStyleLink.setForegroundColor(display.getSystemColor(SWT.COLOR_GRAY));
        unselectedStyleLink.setLineWidth(2);

        int xOffset = WindowSystem.isGTK() ? 2 : -2;
        int yOffset = WindowSystem.isGTK() ? -1 : 0;
        unselectedStyleLink.setExtremity2(
                new ExtremityEastArrow(unselectedStyleLink, -ExtremityEastArrow.WIDTH_ARROW + xOffset, yOffset));
        setUnselectedStyleLink(unselectedStyleLink);

        getSelectedRelativeStyleLink();

        initListeners();
        createLinks();

    }

    /**
     * DOC amaumont Comment method "initColors".
     * 
     * @param display
     */
    private void initColors(Display display) {
        RGB selectedLoopLinkRGB = new RGB(255, 131, 0);
        RGB selectedRelativeLinkRGB = new RGB(110, 168, 255);
        ColorRegistry colorRegistry = JFaceResources.getColorRegistry();
        if (colorRegistry.get(selectedLoopLinkRGB.toString()) == null) {
            colorRegistry.put(selectedLoopLinkRGB.toString(), selectedLoopLinkRGB);
        }
        if (colorRegistry.get(selectedRelativeLinkRGB.toString()) == null) {
            colorRegistry.put(selectedRelativeLinkRGB.toString(), selectedRelativeLinkRGB);
        }
        selectedLoopLinkColor = colorRegistry.get(selectedLoopLinkRGB.toString());
        selectedRelativeLinkColor = colorRegistry.get(selectedRelativeLinkRGB.toString());

    }

    /**
     * DOC amaumont Comment method "initListeners".
     */
    protected void initListeners() {
        initLoopListeners();
        initFieldsListeners();
        jsonDndHandler = new JSONToSchemaDragAndDropHandler(this);
    }

    private void removeListeners() {
        removeLoopListeners();
        removeFieldsListeners();
        jsonDndHandler.dispose();
    }

    /**
     * DOC amaumont Comment method "createLinks".
     */
    public void createLinks() {

        removeAllLinks();
        getBackgroundRefresher().refreshBackground();

        ProgressDialog progressDialog = new ProgressDialog(getTree().getShell(), 1000) {

            private IProgressMonitor monitorWrap;

            @Override
            public void run(IProgressMonitor monitor) {

                TableItem[] loopTableItems = loopTableEditorView.getTable().getItems();
                TableItem[] fieldsTableItems = fieldsTableEditorView.getTable().getItems();

                monitorWrap = new EventLoopProgressMonitor(monitor);

                String taskName = "Loop links creation ...";
                int totalWork = loopTableItems.length + fieldsTableItems.length;

                monitorWrap.beginTask(taskName, totalWork);

                List<JSONXPathLoopDescriptor> xpathLoopDescriptorList = loopTableEditorView.getModel()
                        .getBeansList();
                for (int i = 0; i < loopTableItems.length; i++) {

                    if (monitorWrap.isCanceled()) {
                        return;
                    }

                    TableItem tableItem = loopTableItems[i];
                    JSONXPathLoopDescriptor xpathLoopDescriptor = xpathLoopDescriptorList.get(i);
                    String originalValue = xpathLoopDescriptor.getAbsoluteXPathQuery();
                    if (xpathLoopDescriptor.getConnection() != null) {
                        ContextType contextType = ConnectionContextHelper.getContextTypeForContextMode(
                                xpathLoopDescriptor.getConnection(),
                                xpathLoopDescriptor.getConnection().getContextName());
                        if (contextType != null) {
                            originalValue = ConnectionContextHelper.getOriginalValue(contextType,
                                    xpathLoopDescriptor.getAbsoluteXPathQuery());
                            originalValue = TalendQuoteUtils.removeQuotes(originalValue);
                        }
                    }

                    if (originalValue != null) {
                        createLoopLinks(originalValue, tableItem, monitorWrap);
                    }

                    monitorWrap.worked(1);
                }

                List<SchemaTarget> schemaTargetList = fieldsTableEditorView.getModel().getBeansList();

                createFieldsLinkWithProgressMonitor(monitorWrap, schemaTargetList.size() + loopTableItems.length,
                        schemaTargetList, 0, fieldsTableItems.length);

                monitorWrap.done();

            }

        };

        try {
            progressDialog.executeProcess();
        } catch (InvocationTargetException e) {
            ExceptionHandler.process(e);
        } catch (InterruptedException e) {
            // Nothing to do
        }

    }

    /**
     * DOC amaumont Comment method "createFieldsLinkWithProgressDialog".
     * 
     * @param monitorWrap
     * @param fieldsTableItems
     * @param totalWork
     * @param schemaTargetList
     */
    private void createFieldsLinkWithProgressMonitor(IProgressMonitor monitorWrap, int totalWork,
            List<SchemaTarget> schemaTargetList, int startTableItem, int tableItemLength) {
        monitorWrap.beginTask("Fields links creation ...", totalWork);

        TableItem[] fieldsTableItems = fieldsTableEditorView.getTable().getItems();
        for (int i = startTableItem, indexShemaTarget = 0; i < startTableItem
                + tableItemLength; i++, indexShemaTarget++) {

            if (monitorWrap.isCanceled()) {
                for (int j = startTableItem + tableItemLength - 2; j >= 0; j--) {
                    // fieldsTableEditorView.getTable().remove(j);
                    fieldsTableEditorView.getTable().redraw();
                    JSONExtractorFieldModel schemaModel = this.fieldsTableEditorView.getModel();
                    schemaModel.remove(j);
                }
                return;
            }

            TableItem tableItem = fieldsTableItems[i];
            SchemaTarget schemaTarget = schemaTargetList.get(indexShemaTarget);
            String relativeXpathQuery = schemaTarget.getRelativeXPathQuery();
            createFieldLinks(relativeXpathQuery, tableItem, monitorWrap, schemaTarget);
            monitorWrap.worked(1);
        }
        getLinksManager().sortLinks(getDrawingLinksComparator());
        getBackgroundRefresher().refreshBackground();
    }

    private IModifiedBeanListener loopModelModifiedBeanListener;

    private IExtendedControlListener loopTableExtendedControlListener;

    private ILineSelectionListener afterLineSelectionListener;

    /**
     * DOC amaumont Comment method "initListeners".
     */
    private void initLoopListeners() {

        JSONExtractorLoopModel loopModel = this.loopTableEditorView.getModel();

        final Table loopTable = this.loopTableEditorView.getTableViewerCreator().getTable();
        loopModelModifiedBeanListener = new IModifiedBeanListener<JSONXPathLoopDescriptor>() {

            @Override
            public void handleEvent(ModifiedBeanEvent<JSONXPathLoopDescriptor> event) {
                handleModifiedBeanEvent(event);
            }

            private void handleModifiedBeanEvent(ModifiedBeanEvent<JSONXPathLoopDescriptor> event) {
                if (event.column == loopTableEditorView.getXPathColumn()) {
                    onXPathValueChanged(loopTable, (String) event.newValue, event.index);
                }

            }

        };
        loopModel.addModifiedBeanListener(loopModelModifiedBeanListener);

        loopTableExtendedControlListener = new IExtendedControlListener() {

            @Override
            public void handleEvent(ExtendedControlEvent event) {
                if (event.getType() == EVENT_TYPE.MODEL_CHANGED) {
                    nodeRetriever.setCurrentLoopXPath(getCurrentLoopXPath());
                }
            }

        };
        this.loopTableEditorView.getExtendedTableViewer().addListener(loopTableExtendedControlListener);

        SelectionHelper selectionHelper = this.loopTableEditorView.getTableViewerCreator().getSelectionHelper();
        afterLineSelectionListener = new ILineSelectionListener() {

            @Override
            public void handle(LineSelectionEvent e) {
                updateLinksStyleAndControlsSelection(e.source.getTable(), true);
            }
        };
        selectionHelper.addAfterSelectionListener(afterLineSelectionListener);
    }

    private void removeLoopListeners() {
        JSONExtractorLoopModel loopModel = this.loopTableEditorView.getModel();
        loopModel.removeModifiedBeanListener(loopModelModifiedBeanListener);
        this.loopTableEditorView.getExtendedTableViewer().removeListener(loopTableExtendedControlListener);
        SelectionHelper selectionHelper = this.loopTableEditorView.getTableViewerCreator().getSelectionHelper();
        selectionHelper.removeAfterSelectionListener(afterLineSelectionListener);
    }

    private IModifiedBeanListener schemaModelModifiedBeanListener;

    private IListenableListListener schemaModelBeforeListenableListListener;

    private IListenableListListener schemaModelAfterListenableListListener;

    private ILineSelectionListener fieldsTableLineSelectionListener;

    /**
     * DOC amaumont Comment method "initListeners".
     */
    private void initFieldsListeners() {

        JSONExtractorFieldModel schemaModel = this.fieldsTableEditorView.getModel();

        final Table fieldsTable = this.fieldsTableEditorView.getTable();

        schemaModelModifiedBeanListener = new IModifiedBeanListener<SchemaTarget>() {

            @Override
            public void handleEvent(ModifiedBeanEvent<SchemaTarget> event) {
                handleModifiedBeanEvent(event);
            }

            private void handleModifiedBeanEvent(ModifiedBeanEvent<SchemaTarget> event) {
                if (event.column == fieldsTableEditorView.getXPathColumn()) {
                    onXPathValueChanged(fieldsTable, (String) event.newValue, event.index);
                }

            }

        };
        schemaModel.addModifiedBeanListener(schemaModelModifiedBeanListener);

        schemaModelBeforeListenableListListener = new IListenableListListener<SchemaTarget>() {

            @Override
            public void handleEvent(ListenableListEvent<SchemaTarget> event) {
                handleListenableListBeforeTableViewerRefreshedEvent(event);
            }

        };
        schemaModel.addBeforeOperationListListener(-50, schemaModelBeforeListenableListListener);

        schemaModelAfterListenableListListener = new IListenableListListener<SchemaTarget>() {

            @Override
            public void handleEvent(ListenableListEvent<SchemaTarget> event) {
                handleListenableListAfterTableViewerRefreshedEvent(event);
            }

        };
        schemaModel.addAfterOperationListListener(schemaModelAfterListenableListListener);

        SelectionHelper selectionHelper = this.fieldsTableEditorView.getTableViewerCreator().getSelectionHelper();
        fieldsTableLineSelectionListener = new ILineSelectionListener() {

            @Override
            public void handle(LineSelectionEvent e) {
                updateLinksStyleAndControlsSelection(e.source.getTable(), true);
            }
        };
        selectionHelper.addAfterSelectionListener(fieldsTableLineSelectionListener);

    }

    private void removeFieldsListeners() {
        JSONExtractorFieldModel schemaModel = this.fieldsTableEditorView.getModel();
        schemaModel.removeModifiedBeanListener(schemaModelModifiedBeanListener);
        schemaModel.removeModifiedListListener(schemaModelBeforeListenableListListener);
        schemaModel.removeModifiedListListener(schemaModelAfterListenableListListener);
        SelectionHelper selectionHelper = this.fieldsTableEditorView.getTableViewerCreator().getSelectionHelper();
        selectionHelper.removeAfterSelectionListener(fieldsTableLineSelectionListener);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.talend.commons.ui.swt.linking.TreeToTableLinker#drawBackground(org.eclipse.swt.graphics.GC)
     */
    @Override
    public void drawBackground(GC gc) {

        Rectangle clipBounds = getTree().getBounds();

        List<Table> tables = getTables();

        if (tables == null || tables.size() == 0) {
            throw new IllegalStateException();
        }
        Table table = tables.get(0);

        Rectangle tableBounds = table.getDisplay().map(table, getBgDrawableComposite(), table.getBounds());
        // System.out.println(tableBounds);

        // System.out.println(getBgDrawableComposite());

        int offset = WindowSystem.isGTK() ? 0 : 20;

        clipBounds.width = tableBounds.x;
        clipBounds.height += offset - 4;
        clipBounds.x = 0;
        clipBounds.y = offset;

        gc.setClipping(clipBounds);

        super.drawBackground(gc);

        gc.setClipping((Rectangle) null);
    }

    @Override
    protected TreeItem getTreeItem(Tree tree, Object dataOfTreeItem, Object dataOfTableItem) {
        String path = null;
        if (dataOfTableItem instanceof SchemaTarget) {
            SchemaTarget target = (SchemaTarget) dataOfTableItem;
            path = target.getRelativeXPathQuery();
        } else if (dataOfTableItem instanceof JSONXPathLoopDescriptor) {
            JSONXPathLoopDescriptor target = (JSONXPathLoopDescriptor) dataOfTableItem;
            path = target.getAbsoluteXPathQuery();
        }
        if (path == null) {
            return super.getTreeItem(tree, dataOfTreeItem, dataOfTableItem);
        }

        boolean expressionIsAbsolute = false;
        if (path.trim().startsWith("/")) { //$NON-NLS-1$
            expressionIsAbsolute = true;
        }

        String fullPath = ""; //$NON-NLS-1$
        if (!expressionIsAbsolute) {
            if (loopXpathNodes.size() > 0) {
                fullPath = loopXpathNodes.get(0) + "/"; //$NON-NLS-1$
            }
            // adapt relative path
            String[] relatedSplitedPaths = path.split("\\.\\./"); //$NON-NLS-1$
            if (relatedSplitedPaths.length > 1) {
                int pathsToRemove = relatedSplitedPaths.length - 1;
                String[] fullPathSplited = fullPath.split("/"); //$NON-NLS-1$
                fullPath = ""; //$NON-NLS-1$
                for (int j = 1; j < (fullPathSplited.length - pathsToRemove); j++) {
                    fullPath += "/" + fullPathSplited[j]; //$NON-NLS-1$
                }
                fullPath += "/" + relatedSplitedPaths[pathsToRemove]; //$NON-NLS-1$
            } else {
                fullPath += path;
            }
        } else {
            fullPath = path;
        }
        TreeItem treeItem = treePopulator.getTreeItem(fullPath);
        if (treeItem != null) {
            return treeItem;
        } else {
            return super.getTreeItem(tree, dataOfTreeItem, dataOfTableItem);
        }
    }

    private void handleListenableListBeforeTableViewerRefreshedEvent(ListenableListEvent<SchemaTarget> event) {
        if (event.type == TYPE.REMOVED) {
            Collection<SchemaTarget> removedObjects = event.removedObjects;
            for (SchemaTarget target : removedObjects) {
                linksManager.removeLinksFromDataItem2(target);
            }
        }

    }

    public void handleListenableListAfterTableViewerRefreshedEvent(final ListenableListEvent<SchemaTarget> event) {
        if (event.type == ListenableListEvent.TYPE.ADDED) {

            ProgressDialog progressDialog = new ProgressDialog(getTree().getShell(), 1000) {

                private IProgressMonitor monitorWrap;

                @Override
                public void run(IProgressMonitor monitor) {

                    monitorWrap = new EventLoopProgressMonitor(monitor);

                    List<SchemaTarget> addedObjects = new ArrayList<SchemaTarget>(event.addedObjects);

                    JSONToXPathLinker.this.createFieldsLinkWithProgressMonitor(monitorWrap, addedObjects.size(),
                            addedObjects, event.index, addedObjects.size());

                    monitorWrap.done();

                }

            };

            try {
                progressDialog.executeProcess();
            } catch (InvocationTargetException e) {
                ExceptionHandler.process(e);
            } catch (InterruptedException e) {
                // Nothing to do
            }

            getBackgroundRefresher().refreshBackground();
        } else if (event.type == ListenableListEvent.TYPE.SWAPED) {
            getBackgroundRefresher().refreshBackground();
        } else if (event.type == TYPE.REMOVED) {
            getBackgroundRefresher().refreshBackground();
        }

    }

    /**
     * DOC amaumont Comment method "addLink".
     * 
     * @param treeItem
     * @param dataItem1
     * @param table
     * @param dataItem2
     */
    public void addLoopLink(TreeItem treeItem, Object dataItem1, Table table, JSONXPathLoopDescriptor dataItem2) {
        LinkDescriptor<TreeItem, Object, Table, Object> link = addLink(treeItem, dataItem1, table, dataItem2, true);
        link.setStyleLink(getSelectedLoopStyleLink());
    }

    /**
     * DOC amaumont Comment method "addLink".
     * 
     * @param treeItem
     * @param dataItem1
     * @param table
     * @param dataItem2
     */
    private LinkDescriptor<TreeItem, Object, Table, Object> addLink(TreeItem treeItem, Object dataItem1,
            Table table, Object dataItem2, Boolean flag) {
        LinkDescriptor<TreeItem, Object, Table, Object> link = new LinkDescriptor<TreeItem, Object, Table, Object>(
                new TreeExtremityDescriptor(treeItem, dataItem1),
                new ExtremityLink<Table, Object>(table, dataItem2));

        link.setStyleLink(getUnselectedStyleLink());
        getLinksManager().addLink(link);
        updateLinksStyleAndControlsSelection(table, flag);
        return link;
    }

    /**
     * DOC amaumont Comment method "addLink".
     * 
     * @param treeItem
     * @param dataItem1
     * @param table
     * @param dataItem2
     */
    public void addFieldLink(TreeItem treeItem, Object dataItem1, Table table, SchemaTarget dataItem2) {
        LinkDescriptor<TreeItem, Object, Table, Object> link = addLink(treeItem, dataItem1, table, dataItem2,
                false);
        // link.setStyleLink(getSelectedStyleLink());
    }

    /**
     * DOC amaumont Comment method "removeAllLinks".
     */
    public void removeAllLinks() {
        getLinksManager().clearLinks();
    }

    public boolean removeLinksFromTableEntry(SchemaTarget schemaTarget) {
        return getLinksManager().removeLinksFromDataItem2(schemaTarget);
    }

    /**
     * DOC amaumont Comment method "onXPathValueChanged".
     * 
     * @param table
     * @param newValue
     * @param itemIndex
     */
    public void onXPathValueChanged(Table table, String newValue, int itemIndex) {
        if (isLoopTable(table)) {
            nodeRetriever.setCurrentLoopXPath(newValue);
        }
        TableItem tableItem = table.getItem(itemIndex);
        linksManager.removeLinksFromDataItem2(tableItem.getData());
        if (isLoopTable(table)) {
            createLinks();
        } else {
            createFieldLinks(newValue, tableItem, null, null);
        }
        getBackgroundRefresher().refreshBackground();

    }

    /**
     * DOC amaumont Comment method "isLoopTable".
     * 
     * @param table
     * @return
     */
    public boolean isLoopTable(Table table) {
        return loopTableEditorView.getTableViewerCreator().getTable() == table;
    }

    /**
     * DOC amaumont Comment method "createLoopLinks".
     * 
     * @param monitorWrap
     * 
     * @param pathQuery
     * @param tableItem
     */
    private void createLoopLinks(String xPathExpression, TableItem tableItemTarget, IProgressMonitor monitorWrap) {

        if (xPathExpression == null || xPathExpression.trim().length() == 0) {
            loopXpathNodes.clear();
            uniqueLoopNodes.clear();
            allLoopNodes.clear();
            return;
        }

        Set<String> alreadyProcessedXPath = new HashSet<String>();
        List<Node> nodeList = null;

        loopXpathNodes = new ArrayList<String>();
        uniqueLoopNodes = new ArrayList<Node>();
        allLoopNodes = new ArrayList<Node>();
        if (!alreadyProcessedXPath.contains(xPathExpression)) {
            loopXpathNodes.add(xPathExpression);
            TreeItem treeItemFromAbsoluteXPath = treePopulator.getTreeItem(xPathExpression);
            if (treeItemFromAbsoluteXPath != null) {
                addLoopLink(treeItemFromAbsoluteXPath, treeItemFromAbsoluteXPath.getData(),
                        tableItemTarget.getParent(), (JSONXPathLoopDescriptor) tableItemTarget.getData());
                alreadyProcessedXPath.add(xPathExpression);
            }
        }
    }

    /**
     * DOC amaumont Comment method "addLinks".
     * 
     * @param relativeXpath
     * @param tableItemTarget
     * @param progressMonitor
     * @throws XPathExpressionException
     */
    protected void createFieldLinks(final String relativeXpathPrm, final TableItem tableItemTarget,
            IProgressMonitor progressMonitor, SchemaTarget schemaTarget) {

        if (relativeXpathPrm == null || relativeXpathPrm.trim().length() == 0) {
            return;
        }

        boolean expressionIsAbsolute = false;
        if (relativeXpathPrm.trim().startsWith("/")) { //$NON-NLS-1$
            expressionIsAbsolute = true;
        }

        String relativeXpath = relativeXpathPrm;
        // TDI-19173
        if (relativeXpath != null && relativeXpath.endsWith("]")) {
            relativeXpath = relativeXpath.substring(0, relativeXpath.lastIndexOf("["));
        }
        Set<String> alreadyProcessedXPath = new HashSet<String>();

        String fullPath = ""; //$NON-NLS-1$
        if (!expressionIsAbsolute) {
            if (loopXpathNodes.size() > 0) {
                fullPath = loopXpathNodes.get(0) + "/"; //$NON-NLS-1$
            }
            // adapt relative path
            String[] relatedSplitedPaths = relativeXpath.split("\\.\\./"); //$NON-NLS-1$
            if (relatedSplitedPaths.length > 1) {
                int pathsToRemove = relatedSplitedPaths.length - 1;
                String[] fullPathSplited = fullPath.split("/"); //$NON-NLS-1$
                fullPath = ""; //$NON-NLS-1$
                for (int i = 1; i < (fullPathSplited.length - pathsToRemove); i++) {
                    fullPath += "/" + fullPathSplited[i]; //$NON-NLS-1$
                }
                fullPath += "/" + relatedSplitedPaths[pathsToRemove]; //$NON-NLS-1$
            } else {
                fullPath += relativeXpath;
            }
        } else {
            fullPath = relativeXpath;
        }
        TreeItem treeItemFromAbsoluteXPath = treePopulator.getTreeItem(fullPath);
        if (treeItemFromAbsoluteXPath != null && !alreadyProcessedXPath.contains(fullPath)) {
            addFieldLink(treeItemFromAbsoluteXPath, treeItemFromAbsoluteXPath.getData(),
                    tableItemTarget.getParent(), (SchemaTarget) tableItemTarget.getData());
            alreadyProcessedXPath.add(fullPath);
        }

    }

    public SchemaTarget getNewSchemaTargetEntry(String relativeXPathValue) {

        JSONExtractorFieldModel xpathNodeSchemaModel = fieldsTableEditorView.getModel();
        SchemaTarget schemaTarget = xpathNodeSchemaModel.createNewSchemaTarget();
        schemaTarget.setRelativeXPathQuery(relativeXPathValue);

        return schemaTarget;
    }

    /**
     * Getter for tableEditorView.
     * 
     * @return the tableEditorView
     */
    public ExtractionFieldsWithJSONXPathEditorView getFieldsTableEditorView() {
        return this.fieldsTableEditorView;
    }

    /**
     * Getter for loopTableEditorView.
     * 
     * @return the loopTableEditorView
     */
    public ExtractionLoopWithJSONXPathEditorView getLoopTableEditorView() {
        return this.loopTableEditorView;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void updateLinksStyleAndControlsSelection(Control currentControl, Boolean flag) {

        boolean selectedControlIsTable = false;
        if (currentControl instanceof Table) {
            selectedControlIsTable = true;
        } else if (currentControl instanceof Tree) {
            selectedControlIsTable = false;
        } else {
            throw new IllegalArgumentException("This type of currentControl is unsupported");
        }

        HashSet selectedItems = new HashSet();
        Map itemsToSelect = new HashMap();

        if (selectedControlIsTable) {
            for (Table table : getTables()) {
                if (table != currentControl) {
                    table.deselectAll();
                    if (isFieldsTable(table)) {
                        fieldsTableEditorView.getExtendedToolbar().updateEnabledStateOfButtons();
                    }
                }
            }

            TableItem[] selection = ((Table) currentControl).getSelection();
            for (TableItem tableItem : selection) {
                selectedItems.add(tableItem.getData());
            }

        } else {

            TreeItem[] selection = getTree().getSelection();
            for (TreeItem treeItem : selection) {
                selectedItems.add(treeItem.getData());
            }

        }

        List<LinkDescriptor<TreeItem, Object, Table, Object>> links = linksManager.getLinks();
        for (LinkDescriptor<TreeItem, Object, Table, Object> link : links) {
            IStyleLink styleLink = null;
            IExtremityLink extremity = null;
            IExtremityLink otherExtremity = null;
            if (selectedControlIsTable) {
                extremity = link.getExtremity2();
                otherExtremity = link.getExtremity1();
            } else {
                extremity = link.getExtremity1();
                otherExtremity = link.getExtremity2();
            }
            boolean currentItemIsSelected = selectedItems.contains(extremity.getDataItem());

            if (extremity.getGraphicalObject() == loopTableEditorView.getTableViewerCreator().getTable()
                    || otherExtremity.getGraphicalObject() == loopTableEditorView.getTableViewerCreator()
                            .getTable()) {
                styleLink = getSelectedLoopStyleLink();
            } else {

                if (currentItemIsSelected) {
                    styleLink = getSelectedStyleLink();
                    if (selectedControlIsTable) {

                        itemsToSelect.put(otherExtremity.getGraphicalObject(), null);

                    } else {

                        Table currentTable = (Table) otherExtremity.getGraphicalObject();
                        List<TableItem> tableItemsToSelect = (List<TableItem>) itemsToSelect.get(currentTable);

                        if (tableItemsToSelect == null) {
                            tableItemsToSelect = new ArrayList<TableItem>();
                            itemsToSelect.put(currentTable, tableItemsToSelect);
                        }
                        TableItem tableItem = TableUtils.getTableItem(currentTable, otherExtremity.getDataItem());
                        tableItemsToSelect.add(tableItem);
                    }
                } else {
                    styleLink = getUnselectedStyleLink();
                }
            }
            if (styleLink == null) {
                styleLink = getDefaultStyleLink();
            }
            link.setStyleLink(styleLink);

        }

        if (selectedControlIsTable) {
            TreeItem[] treeItems = (TreeItem[]) itemsToSelect.keySet().toArray(new TreeItem[0]);
            if (treeItems.length > 0) {
                if (!treeItems[0].isDisposed()) {
                    (getTree()).setSelection(treeItems);
                }
            }
        } else {
            Set<Table> set = itemsToSelect.keySet();
            if (set.size() > 0) {
                for (Table table : set) {
                    ArrayList<TableItem> tableItemsToSelect = (ArrayList<TableItem>) itemsToSelect.get(table);
                    table.deselectAll();
                    TableItem[] tableItems = tableItemsToSelect.toArray(new TableItem[0]);
                    table.setSelection(tableItems);
                }
            } else {
                loopTableEditorView.getTable().deselectAll();
                fieldsTableEditorView.getTable().deselectAll();
            }
            fieldsTableEditorView.getExtendedToolbar().updateEnabledStateOfButtons();
        }
        if (flag) {
            getLinksManager().sortLinks(getDrawingLinksComparator());
            getBackgroundRefresher().refreshBackground();
        }
    }

    /**
     * DOC amaumont Comment method "isFieldsTable".
     * 
     * @param table
     * @return
     */
    public boolean isFieldsTable(Table table) {
        return fieldsTableEditorView.getTableViewerCreator().getTable() == table;
    }

    public StyleLink getSelectedLoopStyleLink() {
        if (this.selectedLoopStyleLink == null) {
            StyleLink styleLink = new StyleLink();
            styleLink.setDrawableLink(new BezierHorizontalLink(styleLink));
            styleLink.setForegroundColor(selectedLoopLinkColor);
            styleLink.setLineWidth(2);
            int xOffset = WindowSystem.isGTK() ? 2 : -2;
            int yOffset = WindowSystem.isGTK() ? -1 : 0;
            styleLink.setExtremity2(
                    new ExtremityEastArrow(styleLink, -ExtremityEastArrow.WIDTH_ARROW + xOffset, yOffset));
            this.selectedLoopStyleLink = styleLink;
        }
        return this.selectedLoopStyleLink;
    }

    /**
     * DOC amaumont Comment method "getSelectedRelativeStyleLink".
     * 
     * @param selectedLoopLinkColor
     */
    private void getSelectedRelativeStyleLink() {

        StyleLink selectedStyleLink = new StyleLink();
        selectedStyleLink.setDrawableLink(new BezierHorizontalLink(selectedStyleLink));
        selectedStyleLink.setForegroundColor(selectedRelativeLinkColor);
        selectedStyleLink.setLineWidth(2);
        int xOffset = WindowSystem.isGTK() ? 2 : -2;
        int yOffset = WindowSystem.isGTK() ? -1 : 0;
        selectedStyleLink.setExtremity2(
                new ExtremityEastArrow(selectedStyleLink, -ExtremityEastArrow.WIDTH_ARROW + xOffset, yOffset));
        setSelectedStyleLink(selectedStyleLink);
    }

    public String getCurrentLoopXPath() {
        return loopTableEditorView.getExtendedTableModel().getBeansList().get(0).getAbsoluteXPathQuery();
    }

    public void parseAllFieldsXPathExpressions() {

        List<SchemaTarget> beansList = fieldsTableEditorView.getExtendedTableModel().getBeansList();

        int lstSize = beansList.size();
        for (int i = 0; i < lstSize; i++) {
            SchemaTarget schemaTarget = beansList.get(i);
            onXPathValueChanged(fieldsTableEditorView.getTable(), schemaTarget.getRelativeXPathQuery(), i);
        }

    }

    /**
     * Getter for loopXpathNodes.
     * 
     * @return the loopXpathNodes
     */
    public ArrayList<String> getLoopXpathNodes() {
        return this.loopXpathNodes;
    }

    /**
     * DOC amaumont Comment method "validateXPathExpression".
     * 
     * @param newValue
     * @return null if expression is valid, else return the error message.
     */
    public String validateXPathExpression(String xpathExpression) {
        if (xpathExpression == null || xpathExpression.trim().length() == 0) {
            return null;
        }
        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();
        try {
            xpath.compile(xpathExpression);
        } catch (Exception e) {
            return "The current XPath expression is invalid";
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.talend.commons.ui.swt.linking.TreeToTablesLinker#getDrawingLinksComparator()
     */
    @Override
    protected Comparator<LinkDescriptor<TreeItem, Object, Table, Object>> getDrawingLinksComparator() {
        if (this.drawingLinksComparator == null) {
            this.drawingLinksComparator = new Comparator<LinkDescriptor<TreeItem, Object, Table, Object>>() {

                @Override
                public int compare(LinkDescriptor<TreeItem, Object, Table, Object> link1,
                        LinkDescriptor<TreeItem, Object, Table, Object> link2) {
                    IStyleLink link1StyleLink = link1.getStyleLink();
                    IStyleLink link2StyleLink = link2.getStyleLink();
                    if (link1StyleLink == link2StyleLink) {
                        return 0;
                    }
                    if (link1StyleLink == getSelectedLoopStyleLink()) {
                        return 1;
                    }
                    if (link2StyleLink == getSelectedLoopStyleLink()) {
                        return -1;
                    }
                    if (link1StyleLink == getUnselectedStyleLink()) {
                        return -1;
                    }
                    return 1;
                }

            };
        }
        return this.drawingLinksComparator;
    }

    /**
     * Getter for allLoopNodes.
     * 
     * @return the allLoopNodes
     */
    public ArrayList<Node> getAllLoopNodes() {
        return this.allLoopNodes;
    }

    /**
     * Getter for uniqueLoopNodes.
     * 
     * @return the uniqueLoopNodes
     */
    public ArrayList<Node> getUniqueLoopNodes() {
        return this.uniqueLoopNodes;
    }

    /**
     * Getter for nodeRetriever.
     * 
     * @return the nodeRetriever
     */
    public XmlNodeRetriever getNodeRetriever() {
        return this.nodeRetriever;
    }

    public String getFieldSeperator() {
        return "/"; //$NON-NLS-1$
    }

    public String getRootSeperator() {
        return "/"; //$NON-NLS-1$
    }

    public AbstractTreePopulator getTreePopulator() {
        return this.treePopulator;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.talend.commons.ui.swt.linking.TreeToTablesLinker#dispose()
     */
    @Override
    public void dispose() {
        super.dispose();
        removeListeners();
        xmlExtractorBgRefresher.dispose();
    }

}