org.eclipse.emf.compare.ide.ui.internal.logical.LogicalModelResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.ide.ui.internal.logical.LogicalModelResolver.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Obeo.
 * 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:
 *     Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.logical;

import com.google.common.collect.Sets;

import java.util.Collections;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.compare.ide.internal.utils.SyncResourceSet;
import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIMessages;
import org.eclipse.emf.compare.ide.ui.logical.AbstractModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.IModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor;
import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor.DiffSide;
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
import org.eclipse.emf.compare.ide.utils.StorageTraversal;
import org.eclipse.emf.compare.ide.utils.StorageURIConverter;

/**
 * This will be used as a default implementation of an {@link IModelResolver} by the comparison scope builder.
 * It is a "top-down" implementation : loading a given resource as a starting point, it will resolve all of
 * the containment tree to discover other resources composing the model.
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
public class LogicalModelResolver extends AbstractModelResolver {
    /**
     * {@inheritDoc}
     * 
     * @see org.eclipse.emf.compare.ide.ui.logical.IModelResolver#resolveLocalModels(org.eclipse.core.resources.IResource,
     *      org.eclipse.core.resources.IResource, org.eclipse.core.resources.IResource,
     *      org.eclipse.core.runtime.IProgressMonitor)
     */
    public SynchronizationModel resolveLocalModels(IResource left, IResource right, IResource origin,
            IProgressMonitor monitor) {
        SubMonitor subMonitor = SubMonitor.convert(monitor, 3);

        final StorageTraversal leftTraversal = resolveLocalModel(left, subMonitor.newChild(1));
        final StorageTraversal rightTraversal = resolveLocalModel(right, subMonitor.newChild(1));

        final StorageTraversal originTraversal;
        if (origin != null) {
            originTraversal = resolveLocalModel(origin, subMonitor.newChild(1));
        } else {
            subMonitor.setWorkRemaining(2);
            originTraversal = new StorageTraversal(Sets.<IStorage>newLinkedHashSet());
        }

        return new SynchronizationModel(leftTraversal, rightTraversal, originTraversal);
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.eclipse.emf.compare.ide.ui.logical.IModelResolver#resolveLocalModel(org.eclipse.core.resources.IResource,
     *      org.eclipse.core.runtime.IProgressMonitor)
     */
    public StorageTraversal resolveLocalModel(IResource start, IProgressMonitor monitor) {
        SubMonitor subMonitor = SubMonitor.convert(monitor, 100);

        if (!(start instanceof IFile)) {
            subMonitor.setWorkRemaining(0);
            return new StorageTraversal(Sets.<IStorage>newLinkedHashSet());
        }

        final SyncResourceSet resourceSet = new SyncResourceSet();
        final StorageURIConverter converter = new StorageURIConverter(resourceSet.getURIConverter());
        resourceSet.setURIConverter(converter);

        if (resourceSet.resolveAll((IFile) start, subMonitor.newChild(95))) {
            final Set<IStorage> storages = Sets.newLinkedHashSet(
                    Sets.union(Collections.singleton((IFile) start), converter.getLoadedRevisions()));
            subMonitor.worked(5);
            return new StorageTraversal(storages);
        } else {
            subMonitor.setWorkRemaining(5);
            // We failed to load the starting point. simply return an empty traversal.
        }

        subMonitor.worked(5);

        return new StorageTraversal(Collections.singleton((IFile) start));
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.eclipse.emf.compare.ide.ui.logical.IModelResolver#resolveModels(org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor,
     *      org.eclipse.core.resources.IStorage, org.eclipse.core.resources.IStorage,
     *      org.eclipse.core.resources.IStorage, org.eclipse.core.runtime.IProgressMonitor)
     */
    public SynchronizationModel resolveModels(IStorageProviderAccessor storageAccessor, IStorage left,
            IStorage right, IStorage origin, IProgressMonitor monitor) {
        SubMonitor progress = SubMonitor.convert(monitor,
                EMFCompareIDEUIMessages.getString("EMFSynchronizationModel.resolving"), 3); //$NON-NLS-1$
        SynchronizationModel syncModel;

        StorageTraversal leftTraversal = resolveTraversal(storageAccessor, left, DiffSide.SOURCE,
                progress.newChild(1));
        StorageTraversal rightTraversal = resolveTraversal(storageAccessor, right, DiffSide.REMOTE,
                progress.newChild(1));

        StorageTraversal originTraversal = null;
        if (origin != null) {
            originTraversal = resolveTraversal(storageAccessor, origin, DiffSide.ORIGIN, progress.newChild(1));
        }
        progress.setWorkRemaining(0);

        syncModel = new SynchronizationModel(leftTraversal, rightTraversal, originTraversal);

        return syncModel;
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.eclipse.emf.compare.ide.ui.logical.IModelResolver#canResolve(org.eclipse.core.resources.IStorage)
     */
    public boolean canResolve(IStorage sourceStorage) {
        // This is our default resolver. It should be able to handle any case.
        return true;
    }

    /**
     * Checks whether the given set already contains the given storage. We can't rely on contains() since the
     * storages override neither hash code nor equals.
     * 
     * @param storages
     *            The set of existing storages.
     * @param storage
     *            The candidate for addition in the storages set.
     * @return <code>true</code> if the given set already contains the given storage.
     */
    protected boolean contains(Set<IStorage> storages, IStorage storage) {
        final IPath candidateFullPath = storage.getFullPath();
        for (IStorage existing : storages) {
            if (candidateFullPath.equals(existing.getFullPath())) {
                return true;
            }
        }
        return false;
    }

    /**
     * This will be called by EMF Compare in order to resolve the whole logical model containing the given
     * storage. Since this may be either a local or remote model, all I/O should go through the given storage
     * accessor.
     * 
     * @param storageAccessor
     *            Provides access to the resources, local or remote, that can be found in this context.
     * @param start
     *            The storage that will be considered as the "starting point" of the traversal to resolve.
     * @param side
     *            Side of this particular model. Should be used in conjunction with the
     *            {@code storageAccessor} to retrieve resource contents.
     * @param monitor
     *            Monitor on which to report progress to the user.
     * @return A traversal corresponding to all resources composing the given storage's logical model.
     */
    private StorageTraversal resolveTraversal(IStorageProviderAccessor storageAccessor, IStorage start,
            DiffSide side, IProgressMonitor monitor) {
        SubMonitor progress = SubMonitor.convert(monitor, 100);

        StorageTraversal traversal = new StorageTraversal(Sets.<IStorage>newLinkedHashSet());
        if (start == null) {
            return traversal;
        }

        final SyncResourceSet resourceSet = new SyncResourceSet();
        final StorageURIConverter converter = new RevisionedURIConverter(resourceSet.getURIConverter(),
                storageAccessor, side);
        resourceSet.setURIConverter(converter);

        if (resourceSet.resolveAll(start, progress.newChild(95))) {
            final Set<IStorage> storages = Sets.newLinkedHashSet();
            for (IStorage loaded : converter.getLoadedRevisions()) {
                if (!contains(storages, loaded)) {
                    storages.add(loaded);
                }
            }
            traversal = new StorageTraversal(storages);
        } else {
            progress.setWorkRemaining(5);
            // We failed to load the starting point. simply return an empty traversal.
        }

        progress.worked(5);

        return traversal;
    }
}