es.uah.aut.srg.micobs.ui.handlers.UpdateRemoteFilesHandler.java Source code

Java tutorial

Introduction

Here is the source code for es.uah.aut.srg.micobs.ui.handlers.UpdateRemoteFilesHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2013-2015 UAH Space Research Group.
 * 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:
 *     MICOBS SRG Team - Initial API and implementation
 ******************************************************************************/
package es.uah.aut.srg.micobs.ui.handlers;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.dialogs.DiagnosticDialog;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.tigris.subversion.subclipse.core.ISVNRepositoryLocation;
import org.tigris.subversion.subclipse.core.SVNProviderPlugin;
import org.tigris.subversion.subclipse.core.resources.RemoteFile;
import org.tigris.subversion.svnclientadapter.SVNRevision;
import org.tigris.subversion.svnclientadapter.SVNUrl;

import es.uah.aut.srg.micobs.plugin.MICOBSPlugin;
import es.uah.aut.srg.micobs.util.impl.MICOBSUtilProvider;
import es.uah.aut.srg.modeling.util.file.FileHelper;
import es.uah.aut.srg.modeling.util.plugin.ModelingUtilPlugin;

/**
 * Class used to implement a handler that updates a certain set of files
 * from a remote SVN repository. The handler will first check the file that
 * triggers the generation, then will ask the user to confirm the operation,
 * then will erase a set of resources that will depend on the generation
 * process, and then will update the remote files.
 * 
 * The classes that implement this will have to provide the following:
 * 
 * <ul>
 *       <li>The root class of the triggering model file.</li>
 *       <li>The item provider adapter factory corresponding to the model file.</li>
 *       <li>The message for the user confirmation dialog.</li>
 *       <li>The error message in case the checking of the triggering model
 *          fails.</li>
 *       <li>The list of resources to erase after the confirmation.</li>
 *       <li>The list of remote files to be updated and the final local
 *          location in which they will be stored.</li>
 * </ul>
 *
 * All the updating process is executed synchronously by the GUI thread.
 *
 */
public abstract class UpdateRemoteFilesHandler extends AbstractHandler {

    /**
     * Returns the message of the user confirmation dialog.
     * @return the message of the user confirmation dialog.
     */
    protected abstract String getConfirmDialogMessage();

    /**
     * Returns the message string of the error that is generated if the
     * name of the folder that contains the triggering model file does not
     * match with the standard name.
     * @return the message string of the error.
     */
    protected String getModelFolderErrorMessage() {
        return MICOBSPlugin.INSTANCE.getString("_UI_Handlers_ModelFolderError_message");
    }

    /**
     * Returns the message string of the error that is generated if the root
     * class of the triggering model file is not the expected one.
     * @return the message string of the error.
     */
    protected abstract String getModelClassErrorMessage();

    /**
     * Returns the list of workspace resources to erase.
     * 
     * The method will throw a {@link CoreException} if an error occurs when
     * obtaining the list of resources to erase.
     * 
     * @param rootFolder the root folder of the project that contains the triggering
     *                   model file.
     * @param model the root object of the triggering model file.
     * @return the list of workspace resources to erase.
     */
    protected abstract List<IResource> getResourcesToErase(IContainer rootFolder, EObject model)
            throws CoreException;

    /**
     * Returns the list of remote files to update. The members of this list are
     * {@link RemoteFileToCopy} objects that store the remote URL of the file
     * and the local destination in which it will be copied.
     * 
     * @param model the root object of the triggering model file.
     * @param rootFolder the root folder of the project that contains the triggering
     *                   model file.
     * @param monitor the progress monitor that will be shown during the generation
     *                process.
     * @return the list of remote files to update.
     */
    protected abstract List<RemoteFileToCopy> getRemoteFilesToCopy(EObject model, IContainer rootFolder,
            IProgressMonitor monitor);

    /**
     * Returns the standard MICOBS models folder name.
     * @param model the root object of the triggering model file.
     * @return the standard MICOBS models folder name.
     */
    protected String getModelFolderName(EObject model) {
        return MICOBSPlugin.INSTANCE.getString("_MICOBSProject_models_foldername");
    }

    /**
     * Returns the {@link EClass} object corresponding to the root class of the
     * triggering model file.
     * @return the {@link EClass} object.
     */
    protected abstract EClass getModelEClass();

    /**
     * Returns the item provider adapter factory of the triggering model file.
     * @return the item provider adapter factory of the triggering model file.
     */
    protected abstract AdapterFactory getItemProviderAdapterFactory();

    protected Shell shell;

    /**
     * Class that represents a remote file to copy and the corresponding
     * local destination in which it will be copied.
     *
     */
    protected class RemoteFileToCopy {

        IContainer destination;
        String url;

        /**
         * Constructor.
         * 
         * @param destination the local destination of the file.
         * @param url the URL of the remote file.
         */
        public RemoteFileToCopy(IContainer destination, String url) {
            this.destination = destination;
            this.url = url;
        }

        /**
         * Returns the local destination of the file.
         * @return the local destination of the file.
         */
        public IContainer getDestination() {
            return destination;
        }

        /**
         * Returns the remote URL of the file.
         * @return the remote URL of the file.
         */
        public String getUrl() {
            return url;
        }

    }

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {

        ISelection selection = HandlerUtil.getCurrentSelection(event);

        if (selection instanceof IStructuredSelection) {
            final Object object = ((IStructuredSelection) selection).getFirstElement();
            if (object instanceof IResource) {
                shell = HandlerUtil.getActiveShell(event);
                final IRunnableContext context = new ProgressMonitorDialog(shell);
                final Exception except[] = new Exception[1];

                // First we obtain the model folder
                final IContainer modelFolder = ((IResource) object).getParent();

                final IContainer rootFolder = modelFolder.getParent();

                ResourceSet resourceSet = new ResourceSetImpl();
                Resource resource = resourceSet.getResource(
                        URI.createPlatformResourceURI(((IResource) object).getFullPath().toString(), true), true);

                final EObject model = resource.getContents().get(0);

                if (model.eClass() != getModelEClass()) {
                    MessageDialog.openError(shell,
                            MICOBSPlugin.INSTANCE
                                    .getString("_UI_GenerateFileHandler_ModelClassMismatch_dialogTitle"),
                            getModelClassErrorMessage());
                    return null;
                }

                Diagnostic diagnostic = MICOBSUtilProvider.getMICOBSUtil().validateResource(resource,
                        getItemProviderAdapterFactory());

                if (diagnostic.getSeverity() != Diagnostic.OK) {
                    handleDiagnostic(diagnostic);
                    return null;
                }

                if (getModelFolderName(model) != null && !modelFolder.getName().equals(getModelFolderName(model))) {
                    MessageDialog.openError(shell,
                            MICOBSPlugin.INSTANCE
                                    .getString("_UI_GenerateFileHandler_ModelFolderNameMismatch_dialogTitle"),
                            getModelFolderErrorMessage());
                    return null;
                }

                if (!MessageDialog.openQuestion(shell,
                        MICOBSPlugin.INSTANCE.getString("_UI_GenerateFileHandler_ConfirmOperation_dialogTitle"),
                        getConfirmDialogMessage())) {
                    return null;
                }

                shell.getDisplay().syncExec(new Runnable() {

                    @Override
                    public void run() {

                        try {
                            context.run(false, false, new IRunnableWithProgress() {

                                @Override
                                public void run(IProgressMonitor monitor)
                                        throws InvocationTargetException, InterruptedException {

                                    monitor.beginTask(MICOBSPlugin.INSTANCE
                                            .getString("_UI_GenerateFileHandler_ErasingTask_message"), 100);

                                    try {
                                        List<IResource> resources = getResourcesToErase(rootFolder, model);

                                        for (Iterator<IResource> res = resources.iterator(); res.hasNext();) {
                                            IResource resource = res.next();

                                            if (resource.exists()) {
                                                res.remove();
                                                resource.delete(true, new NullProgressMonitor());
                                            }
                                        }

                                    } catch (CoreException e) {
                                        throw new InvocationTargetException(e);
                                    }

                                    monitor.done();

                                }
                            });
                        } catch (InvocationTargetException e) {
                            except[0] = e;
                        } catch (InterruptedException e) {
                            except[0] = e;
                        }
                    }
                });

                if (except[0] != null) {
                    except[0].printStackTrace();
                    return null;
                }

                // Now we have to link the new stuff and update

                shell.getDisplay().syncExec(new Runnable() {

                    @Override
                    public void run() {

                        try {
                            context.run(false, false, new IRunnableWithProgress() {
                                public void run(IProgressMonitor monitor)
                                        throws InvocationTargetException, InterruptedException {

                                    monitor.beginTask(MICOBSPlugin.INSTANCE
                                            .getString("_UI_GenerateFileHandler_FileGeneration_message"), 100);

                                    List<RemoteFileToCopy> remoteFiles = getRemoteFilesToCopy(model, rootFolder,
                                            monitor);

                                    for (RemoteFileToCopy remoteFileToCopy : remoteFiles) {
                                        if (remoteFileToCopy.getDestination() == null
                                                || remoteFileToCopy.getUrl() == null) {
                                            continue;
                                        }
                                        IContainer destination = remoteFileToCopy.getDestination();
                                        String url = remoteFileToCopy.getUrl();
                                        String remoteFilename = "";

                                        for (int i = 0; i < url.length(); i++) {
                                            String partialPath = url.substring(0, i + 1);
                                            if (partialPath.endsWith("/")) {
                                                remoteFilename = url.substring(i + 1, url.length());
                                            }
                                        }
                                        if (remoteFilename.length() == 0) {
                                            continue;
                                        }
                                        IFile localFile = destination.getFile(new Path(remoteFilename));

                                        try {
                                            ISVNRepositoryLocation location = SVNProviderPlugin.getPlugin()
                                                    .getRepository(url);
                                            RemoteFile remoteFile = null;

                                            remoteFile = new RemoteFile(location, new SVNUrl(url),
                                                    SVNRevision.HEAD);
                                            remoteFile.fetchContents(new NullProgressMonitor());
                                            InputStream remoteFileIS = remoteFile
                                                    .getStorage(new NullProgressMonitor()).getContents();

                                            if (localFile.exists() == true) {
                                                if (FileHelper.compare(localFile.getContents(),
                                                        remoteFileIS) == false) {
                                                    localFile.setContents(remoteFileIS, true, true, monitor);
                                                }
                                            } else {
                                                localFile.create(remoteFileIS, true, monitor);
                                            }
                                        } catch (CoreException e) {
                                            e.printStackTrace();
                                            throw new InvocationTargetException(e);
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                            throw new InvocationTargetException(e);
                                        }
                                    }

                                    monitor.done();

                                }
                            });
                        } catch (InvocationTargetException e) {
                            except[0] = e;
                        } catch (InterruptedException e) {
                            except[0] = e;
                        }
                    }
                });

                if (except[0] != null) {
                    except[0].printStackTrace();
                    return null;
                }

                try {
                    ((IResource) object).getProject().refreshLocal(IProject.DEPTH_INFINITE,
                            new NullProgressMonitor());
                } catch (CoreException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    /**
     * Handles the diagnostic of the triggering model file in case an error
     * is detected when triggering the transformation. This function will
     * display a diagnostic dialog in case an error or a warning is
     * encountered.
     * @param diagnostic the resulting diagnostic of the triggering model
     *                 check.
     */
    protected void handleDiagnostic(Diagnostic diagnostic) {
        int severity = diagnostic.getSeverity();
        String title = null;
        String message = null;

        if (severity == Diagnostic.ERROR || severity == Diagnostic.WARNING) {
            title = ModelingUtilPlugin.getString("_UI_ValidationProblems_title");
            message = ModelingUtilPlugin.getString("_UI_ValidationProblems_message");
        } else {
            title = ModelingUtilPlugin.getString("_UI_ValidationResults_title");
            message = ModelingUtilPlugin.getString(
                    severity == Diagnostic.OK ? "_UI_ValidationOK_message" : "_UI_ValidationResults_message");
        }

        if (diagnostic.getSeverity() == Diagnostic.OK) {
            MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title,
                    message);
        } else {
            DiagnosticDialog.open(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, message,
                    diagnostic);
        }
    }

}