com.amalto.workbench.compare.ResourceCompareInput.java Source code

Java tutorial

Introduction

Here is the source code for com.amalto.workbench.compare.ResourceCompareInput.java

Source

// ============================================================================
//
// Copyright (C) 2006-2017 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
//
// ============================================================================

/*******************************************************************************
 * Copyright (c) 2000, 2007 IBM Corporation and others. All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: IBM Corporation - initial API and implementation Matt McCutchen (hashproduct+eclipse@gmail.com) - Bug
 * 35390 Three-way compare cannot select (mis-selects) )ancestor resource
 *******************************************************************************/

package com.amalto.workbench.compare;

import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ZipFileStructureCreator;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.IDiffContainer;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.compare.structuremergeviewer.IStructureComparator;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

import com.amalto.workbench.i18n.Messages;
import com.amalto.workbench.utils.Util;
import com.amalto.workbench.utils.XmlUtil;
import com.amalto.workbench.webservices.WSDataClusterPK;
import com.amalto.workbench.webservices.WSDataModelPK;
import com.amalto.workbench.webservices.WSPutItem;

/**
 * A two-way or three-way compare for arbitrary IResources.
 */
public class ResourceCompareInput extends CompareEditorInput {

    private static Log log = LogFactory.getLog(ResourceCompareInput.class);

    private static final boolean NORMALIZE_CASE = true;

    private boolean fThreeWay = false;

    private Object fRoot;

    private IStructureComparator fAncestor;

    private IStructureComparator fLeft;

    private IStructureComparator fRight;

    private IResource fAncestorResource;

    private IResource fLeftResource;

    private IResource fRightResource;

    private DiffTreeViewer fDiffViewer;

    private IAction fOpenAction;

    private CompareHeadInfo compareHeadInfo;// if head info not equal null, then we need save changes

    class MyDiffNode extends DiffNode {

        private boolean fDirty = false;

        private ITypedElement fLastId;

        private String fLastName;

        public MyDiffNode(IDiffContainer parent, int description, ITypedElement ancestor, ITypedElement left,
                ITypedElement right) {
            super(parent, description, ancestor, left, right);
        }

        @Override
        public void fireChange() {
            super.fireChange();
            setDirty(true);
            fDirty = true;
            if (fDiffViewer != null) {
                fDiffViewer.refresh(this);
            }
        }

        void clearDirty() {
            fDirty = false;
        }

        @Override
        public String getName() {
            if (fLastName == null) {
                fLastName = super.getName();
            }
            if (fDirty) {
                return '<' + fLastName + '>';
            }
            return fLastName;
        }

        @Override
        public ITypedElement getId() {
            ITypedElement id = super.getId();
            if (id == null) {
                return fLastId;
            }
            fLastId = id;
            return id;
        }
    }

    static class FilteredBufferedResourceNode extends BufferedResourceNode {

        FilteredBufferedResourceNode(IResource resource) {
            super(resource);
        }

        @Override
        protected IStructureComparator createChild(IResource child) {
            String name = child.getName();
            // if (CompareUIPlugin.getDefault().filter(name, child instanceof IContainer, false))
            // return null;
            return new FilteredBufferedResourceNode(child);
        }
    }

    /*
     * Creates an compare editor input for the given selection.
     */
    ResourceCompareInput(CompareConfiguration config) {
        super(config);
    }

    @Override
    public Viewer createDiffViewer(Composite parent) {
        fDiffViewer = new DiffTreeViewer(parent, getCompareConfiguration()) {

            @Override
            protected void fillContextMenu(IMenuManager manager) {

                if (fOpenAction == null) {
                    fOpenAction = new Action() {

                        @Override
                        public void run() {
                            handleOpen(null);
                        }
                    };
                    Utilities.initAction(fOpenAction, getBundle(), "action.CompareContents."); //$NON-NLS-1$
                }

                boolean enable = false;
                ISelection selection = getSelection();
                if (selection instanceof IStructuredSelection) {
                    IStructuredSelection ss = (IStructuredSelection) selection;
                    if (ss.size() == 1) {
                        Object element = ss.getFirstElement();
                        if (element instanceof MyDiffNode) {
                            ITypedElement te = ((MyDiffNode) element).getId();
                            if (te != null) {
                                enable = !ITypedElement.FOLDER_TYPE.equals(te.getType());
                            }
                        } else {
                            enable = true;
                        }
                    }
                }
                fOpenAction.setEnabled(enable);

                manager.add(fOpenAction);

                super.fillContextMenu(manager);
            }
        };
        fDiffViewer.getControl();
        return fDiffViewer;
    }

    class SelectAncestorDialog extends MessageDialog {

        private IResource[] theResources;

        IResource ancestorResource;

        IResource leftResource;

        IResource rightResource;

        private Button[] buttons;

        public SelectAncestorDialog(Shell parentShell, IResource[] theResources) {
            super(parentShell, "", null, "", MessageDialog.QUESTION, new String[] { IDialogConstants.OK_LABEL, //$NON-NLS-1$//$NON-NLS-2$
                    IDialogConstants.CANCEL_LABEL }, 0);
            this.theResources = theResources;
        }

        @Override
        protected Control createCustomArea(Composite parent) {
            Composite composite = new Composite(parent, SWT.NONE);
            composite.setLayout(new GridLayout());
            buttons = new Button[3];
            for (int i = 0; i < 3; i++) {
                buttons[i] = new Button(composite, SWT.RADIO);
                buttons[i].addSelectionListener(selectionListener);
                buttons[i].setText("custom");//$NON-NLS-1$
                buttons[i].setFont(parent.getFont());
                // set initial state
                buttons[i].setSelection(i == 0);
            }
            pickAncestor(0);
            return composite;
        }

        private void pickAncestor(int i) {
            ancestorResource = theResources[i];
            leftResource = theResources[i == 0 ? 1 : 0];
            rightResource = theResources[i == 2 ? 1 : 2];
        }

        private SelectionListener selectionListener = new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                Button selectedButton = (Button) e.widget;
                if (!selectedButton.getSelection()) {
                    return;
                }
                for (int i = 0; i < 3; i++) {
                    if (selectedButton == buttons[i]) {
                        pickAncestor(i);
                    }
                }
            }
        };
    }

    public CompareHeadInfo getCompareHeadInfo() {
        return compareHeadInfo;
    }

    public void setCompareHeadInfo(CompareHeadInfo compareHeadInfo) {
        this.compareHeadInfo = compareHeadInfo;
    }

    // If the compare is three-way, this method asks the user which resource
    // to use as the ancestor. Returns false if the user cancels the prompt,
    // true otherwise.
    public boolean setSelection(ISelection s, Shell shell) {

        IResource[] selection = Utilities.getResources(s);

        fThreeWay = selection.length == 3;

        if (fThreeWay) {
            SelectAncestorDialog dialog = new SelectAncestorDialog(shell, selection);
            int code = dialog.open();
            if (code == Window.CANCEL) {
                return false;
            }

            fAncestorResource = dialog.ancestorResource;
            fAncestor = getStructure(fAncestorResource);
            fLeftResource = dialog.leftResource;
            fRightResource = dialog.rightResource;
        } else {
            fAncestorResource = null;
            fAncestor = null;
            fLeftResource = selection[0];
            fRightResource = selection[1];
        }

        fLeft = getStructure(fLeftResource);
        fRight = getStructure(fRightResource);
        return true;
    }

    /*
     * Returns true if compare can be executed for the given selection.
     */
    public boolean isEnabled(ISelection s) {

        IResource[] selection = Utilities.getResources(s);
        if (selection.length < 2 || selection.length > 3) {
            return false;
        }

        boolean threeWay = selection.length == 3;

        if (threeWay) {
            // It only makes sense if they're all mutually comparable.
            // If not, the user should compare two of them.
            return comparable(selection[0], selection[1]) && comparable(selection[0], selection[2])
                    && comparable(selection[1], selection[2]);
        }

        return comparable(selection[0], selection[1]);
    }

    /**
     * Initializes the images in the compare configuration.
     */
    void initializeCompareConfiguration() {
        CompareConfiguration cc = getCompareConfiguration();
        if (fLeftResource != null) {
            cc.setLeftLabel(buildLabel(fLeftResource));
            // cc.setLeftImage(CompareUIPlugin.getImage(fLeftResource));
        }
        if (fRightResource != null) {
            cc.setRightLabel(buildLabel(fRightResource));
            // cc.setRightImage(CompareUIPlugin.getImage(fRightResource));
        }
        if (fThreeWay && fAncestorResource != null) {
            cc.setAncestorLabel(buildLabel(fAncestorResource));
            // cc.setAncestorImage(CompareUIPlugin.getImage(fAncestorResource));
        }
    }

    /*
     * Returns true if both resources are either structured or unstructured.
     */
    private boolean comparable(IResource c1, IResource c2) {
        return hasStructure(c1) == hasStructure(c2);
    }

    /*
     * Returns true if the given argument has a structure.
     */
    private boolean hasStructure(IResource input) {

        if (input instanceof IContainer) {
            return true;
        }

        if (input instanceof IFile) {
            IFile file = (IFile) input;
            String type = file.getFileExtension();
            if (type != null) {
                type = normalizeCase(type);
                return "JAR".equals(type) || "ZIP".equals(type); //$NON-NLS-2$ //$NON-NLS-1$
            }
        }

        return false;
    }

    /*
     * Creates a <code>IStructureComparator</code> for the given input. Returns <code>null</code> if no
     * <code>IStructureComparator</code> can be found for the <code>IResource</code>.
     */
    private IStructureComparator getStructure(IResource input) {

        if (input instanceof IContainer) {
            return new FilteredBufferedResourceNode(input);
        }

        if (input instanceof IFile) {
            IStructureComparator rn = new FilteredBufferedResourceNode(input);
            IFile file = (IFile) input;
            String type = normalizeCase(file.getFileExtension());
            if ("JAR".equals(type) || "ZIP".equals(type)) {
                return new ZipFileStructureCreator().getStructure(rn);
            }
            return rn;
        }
        return null;
    }

    /*
     * Performs a two-way or three-way diff on the current selection.
     */
    @Override
    public Object prepareInput(IProgressMonitor pm) throws InvocationTargetException {

        try {
            // fix for PR 1GFMLFB: ITPUI:WIN2000 - files that are out of sync with the file system appear as empty
            fLeftResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
            fRightResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
            if (fThreeWay && fAncestorResource != null) {
                fAncestorResource.refreshLocal(IResource.DEPTH_INFINITE, pm);
                // end fix
            }

            //pm.beginTask(Utilities.getString("ResourceCompare.taskName"), IProgressMonitor.UNKNOWN); //$NON-NLS-1$

            String leftLabel = fLeftResource.getName();
            String rightLabel = fRightResource.getName();

            String title;
            // if (fThreeWay) {
            //            String format= Utilities.getString("ResourceCompare.threeWay.title"); //$NON-NLS-1$
            // String ancestorLabel= fAncestorResource.getName();
            // title= MessageFormat.format(format, new String[] {ancestorLabel, leftLabel, rightLabel});
            // } else {
            //            String format= Utilities.getString("ResourceCompare.twoWay.title"); //$NON-NLS-1$
            // title= MessageFormat.format(format, new String[] {leftLabel, rightLabel});
            // }
            // setTitle(title);

            Differencer d = new Differencer() {

                @Override
                protected Object visit(Object parent, int description, Object ancestor, Object left, Object right) {
                    return new MyDiffNode((IDiffContainer) parent, description, (ITypedElement) ancestor,
                            (ITypedElement) left, (ITypedElement) right);
                }
            };

            fRoot = d.findDifferences(fThreeWay, pm, null, fAncestor, fLeft, fRight);
            return fRoot;

        } catch (CoreException ex) {
            throw new InvocationTargetException(ex);
        } finally {
            pm.done();
        }
    }

    @Override
    public String getToolTipText() {
        // if (fLeftResource != null && fRightResource != null) {
        // String leftLabel= fLeftResource.getFullPath().makeRelative().toString();
        // String rightLabel= fRightResource.getFullPath().makeRelative().toString();
        // if (fThreeWay) {
        //            String format= Utilities.getString("ResourceCompare.threeWay.tooltip"); //$NON-NLS-1$
        // String ancestorLabel= fAncestorResource.getFullPath().makeRelative().toString();
        // return MessageFormat.format(format, new String[] {ancestorLabel, leftLabel, rightLabel});
        // }
        //         String format= Utilities.getString("ResourceCompare.twoWay.tooltip"); //$NON-NLS-1$
        // return MessageFormat.format(format, new String[] {leftLabel, rightLabel});
        // }
        // fall back
        return super.getToolTipText();
    }

    private String buildLabel(IResource r) {
        String n = r.getFullPath().toString();
        if (n.charAt(0) == IPath.SEPARATOR) {
            return n.substring(1);
        }
        return n;
    }

    @Override
    public boolean isSaveNeeded() {
        if (compareHeadInfo == null) {
            return false;
        }
        if (fRoot instanceof MyDiffNode) {
            return ((MyDiffNode) fRoot).fDirty;
        }
        return false;
    }

    @Override
    public void saveChanges(IProgressMonitor pm) throws CoreException {
        super.saveChanges(pm);
        if (fRoot instanceof DiffNode) {
            try {
                commit(pm, (DiffNode) fRoot);
            } finally {
                if (fDiffViewer != null) {
                    fDiffViewer.refresh();
                }
                setDirty(false);
                if (fRoot instanceof MyDiffNode) {
                    ((MyDiffNode) fRoot).fDirty = false;
                }
            }
        }
    }

    /*
     * Recursively walks the diff tree and commits all changes.
     */
    private void commit(IProgressMonitor pm, DiffNode node) throws CoreException {

        if (node instanceof MyDiffNode) {
            ((MyDiffNode) node).clearDirty();
        }

        ITypedElement left = node.getLeft();
        if (left instanceof BufferedResourceNode) {
            ((BufferedResourceNode) left).commit(pm);
        }

        ITypedElement right = node.getRight();
        if (right instanceof BufferedResourceNode) {
            ((BufferedResourceNode) right).commit(pm);
        }

        IDiffElement[] children = node.getChildren();
        if (children != null) {
            for (IDiffElement element : children) {
                if (element instanceof DiffNode) {
                    commit(pm, (DiffNode) element);
                }
            }
        }

        if (this.compareHeadInfo != null) {
            commitToDB();
        }
    }

    private void commitToDB() {

        try {
            String toCommitContent = CompareManager.getInstance().getLeftContent();
            toCommitContent = XmlUtil.formatCompact(toCommitContent, "UTF-8");//$NON-NLS-1$
            if (this.compareHeadInfo.isItem()) {
                Util.getMDMService(compareHeadInfo.getXobject())
                        .putItem(new WSPutItem(false, (WSDataClusterPK) compareHeadInfo.getXobject().getWsKey(), ""//$NON-NLS-1$
                                .equals(compareHeadInfo.getDataModelName()) ? null
                                        : new WSDataModelPK(compareHeadInfo.getDataModelName()),
                                toCommitContent));
            } else {
                // TODO add support for Object(s)

            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            if (!Util.handleConnectionException((Shell) null, e, null)) {
                MessageDialog.openError(null, Messages._Error,
                        Messages.bind(Messages.ResourceCompareInput_ErrorMsg, e.getLocalizedMessage()));
            }
        }

    }

    /*
     * (non Javadoc) see IAdaptable.getAdapter
     */
    @Override
    public Object getAdapter(Class adapter) {
        if (IFile.class.equals(adapter)) {
            IProgressMonitor pm = new NullProgressMonitor();
            // flush changes in any dirty viewer
            flushViewers(pm);
            IFile[] files = (IFile[]) getAdapter(IFile[].class);
            if (files != null && files.length > 0) {
                return files[0]; // can only return one: limitation on IDE.saveAllEditors; see #64617
            }
            return null;
        }
        if (IFile[].class.equals(adapter)) {
            HashSet collector = new HashSet();
            collectDirtyResources(fRoot, collector);
            return collector.toArray(new IFile[collector.size()]);
        }
        return super.getAdapter(adapter);
    }

    private void collectDirtyResources(Object o, Set collector) {
        if (o instanceof DiffNode) {
            DiffNode node = (DiffNode) o;

            ITypedElement left = node.getLeft();
            if (left instanceof BufferedResourceNode) {
                BufferedResourceNode bn = (BufferedResourceNode) left;
                if (bn.isDirty()) {
                    IResource resource = bn.getResource();
                    if (resource instanceof IFile) {
                        collector.add(resource);
                    }
                }
            }

            ITypedElement right = node.getRight();
            if (right instanceof BufferedResourceNode) {
                BufferedResourceNode bn = (BufferedResourceNode) right;
                if (bn.isDirty()) {
                    IResource resource = bn.getResource();
                    if (resource instanceof IFile) {
                        collector.add(resource);
                    }
                }
            }

            IDiffElement[] children = node.getChildren();
            if (children != null) {
                for (IDiffElement element : children) {
                    if (element instanceof DiffNode) {
                        collectDirtyResources(element, collector);
                    }
                }
            }
        }
    }

    private static String normalizeCase(String s) {
        if (NORMALIZE_CASE && s != null) {
            return s.toUpperCase();
        }
        return s;
    }

    @Override
    public boolean canRunAsJob() {
        return true;
    }
}