eu.esdihumboldt.hale.io.haleconnect.ui.projects.HaleConnectTarget.java Source code

Java tutorial

Introduction

Here is the source code for eu.esdihumboldt.hale.io.haleconnect.ui.projects.HaleConnectTarget.java

Source

/*
 * Copyright (c) 2017 wetransform GmbH
 * 
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution. If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     wetransform GmbH <http://www.wetransform.to>
 */

package eu.esdihumboldt.hale.io.haleconnect.ui.projects;

import static eu.esdihumboldt.hale.io.haleconnect.HaleConnectService.PERMISSION_CREATE;
import static eu.esdihumboldt.hale.io.haleconnect.HaleConnectService.RESOURCE_TRANSFORMATION_PROJECT;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.PlatformUI;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;

import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.hale.common.core.io.Value;
import eu.esdihumboldt.hale.common.core.io.project.ProjectInfoService;
import eu.esdihumboldt.hale.common.core.io.project.impl.ArchiveProjectWriter;
import eu.esdihumboldt.hale.common.core.io.supplier.LocatableOutputSupplier;
import eu.esdihumboldt.hale.io.haleconnect.HaleConnectException;
import eu.esdihumboldt.hale.io.haleconnect.HaleConnectOrganisationInfo;
import eu.esdihumboldt.hale.io.haleconnect.HaleConnectProjectInfo;
import eu.esdihumboldt.hale.io.haleconnect.HaleConnectService;
import eu.esdihumboldt.hale.io.haleconnect.HaleConnectUrnBuilder;
import eu.esdihumboldt.hale.io.haleconnect.Owner;
import eu.esdihumboldt.hale.io.haleconnect.OwnerType;
import eu.esdihumboldt.hale.io.haleconnect.project.HaleConnectProjectReader;
import eu.esdihumboldt.hale.io.haleconnect.project.HaleConnectProjectWriter;
import eu.esdihumboldt.hale.io.haleconnect.ui.HaleConnectLoginDialog;
import eu.esdihumboldt.hale.io.haleconnect.ui.HaleConnectLoginHandler;
import eu.esdihumboldt.hale.ui.HaleUI;
import eu.esdihumboldt.hale.ui.io.target.AbstractTarget;

/**
 * hale connect export target
 * 
 * @author Florian Esser
 */
public class HaleConnectTarget extends AbstractTarget<HaleConnectProjectWriter> {

    private static final ALogger log = ALoggerFactory.getLogger(HaleConnectTarget.class);

    private final HaleConnectService haleConnect;

    private Label loginStatusLabel;
    private Button loginButton;
    private Button enableVersioning;
    private Button publicAccess;
    private Composite ownershipGroup;
    private Button ownerUser;
    private Button ownerOrg;
    private ComboViewer orgSelector;
    private Button includeWebResources;
    private Button excludeData;
    private Button excludeCachedResources;
    private Group updateOrNewGroup;
    private Button newProject;
    private Button updateProject;
    private Composite controlsStack;
    private StackLayout controlsStackLayout;
    private Composite newProjectControls;
    private Composite updateProjectControls;
    private StringFieldEditor projectName;
    private Button selectProjectButton;
    private Label upstreamModifiedWarning;

    private boolean createNewProject;
    private HaleConnectProjectConfig targetProject;

    /**
     * Default constructor
     */
    public HaleConnectTarget() {
        haleConnect = HaleUI.getServiceProvider().getService(HaleConnectService.class);
    }

    @Override
    public void createControls(Composite parent) {
        getPage().setDescription("Please select a destination file for the export");

        parent.setLayout(new GridLayout(4, false));

        Composite loginGroup = new Composite(parent, SWT.BORDER);
        loginGroup.setLayout(new GridLayout(4, false));
        GridData loginGroupLayout = new GridData(SWT.LEAD, SWT.LEAD, false, false, 4, 1);
        loginGroupLayout.widthHint = 550;
        loginGroup.setLayoutData(loginGroupLayout);

        /*
         * Login status label
         */
        loginStatusLabel = new Label(loginGroup, SWT.NONE);
        loginStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));

        loginButton = new Button(loginGroup, SWT.PUSH);
        loginButton.setText("Login");
        loginButton.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false, 1, 1));
        loginButton.addSelectionListener(new SelectionAdapter() {

            /**
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                HaleConnectLoginDialog loginDialog = HaleConnectLoginHandler
                        .createLoginDialog(Display.getCurrent().getActiveShell());
                if (loginDialog != null && loginDialog.open() == Dialog.OK) {
                    HaleConnectLoginHandler.performLogin(loginDialog);
                    updateState();
                    prefillTargetProject();
                }
            }

        });

        updateOrNewGroup = new Group(parent, SWT.NONE);
        updateOrNewGroup.setText("Please choose whether you would like to...");
        updateOrNewGroup.setLayout(new GridLayout(4, false));
        updateOrNewGroup.setLayoutData(new GridData(SWT.LEAD, SWT.LEAD, false, false, 4, 1));

        newProject = new Button(updateOrNewGroup, SWT.RADIO);
        newProject.setText("create a new project on hale connect");
        newProject.setSelection(true);
        newProject.addSelectionListener(new SelectionAdapter() {

            /**
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateState();
            }

        });

        updateProject = new Button(updateOrNewGroup, SWT.RADIO);
        updateProject.setText("update an existing project");
        updateProject.addSelectionListener(new SelectionAdapter() {

            /**
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateState();
            }

        });

        controlsStackLayout = new StackLayout();
        controlsStack = new Composite(parent, SWT.NONE);
        controlsStack.setLayout(controlsStackLayout);

        newProjectControls = new Composite(controlsStack, SWT.NONE);
        newProjectControls.setLayout(new GridLayout(4, true));
        GridData grid = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1);
        newProjectControls.setLayoutData(grid);

        ownershipGroup = new Composite(newProjectControls, SWT.NONE);
        ownershipGroup.setLayout(new GridLayout(4, false));
        ownershipGroup.setLayoutData(new GridData(SWT.LEAD, SWT.LEAD, false, false, 4, 1));

        Label ownerLabel = new Label(ownershipGroup, SWT.NONE);
        ownerLabel.setText("Who should own the uploaded project?");

        ownerUser = new Button(ownershipGroup, SWT.RADIO);
        ownerUser.setText("You");

        ownerOrg = new Button(ownershipGroup, SWT.RADIO);
        ownerOrg.setText("Your organisation");

        orgSelector = new ComboViewer(ownershipGroup);
        GridData orgSelectorGrid = new GridData(SWT.LEAD, SWT.LEAD, false, false);
        orgSelectorGrid.widthHint = 175;
        orgSelector.getCombo().setLayoutData(orgSelectorGrid);
        orgSelector.setContentProvider(ArrayContentProvider.getInstance());
        orgSelector.setLabelProvider(new LabelProvider() {

            @Override
            public String getText(Object element) {
                if (element instanceof HaleConnectOrganisationInfo) {
                    return ((HaleConnectOrganisationInfo) element).getName();
                }

                return super.getText(element);
            }

        });

        Composite bucketOptions = new Composite(parent, SWT.NONE);
        bucketOptions.setLayout(new RowLayout());
        bucketOptions.setLayoutData(new GridData(SWT.LEAD, SWT.LEAD, true, true, 4, 1));

        enableVersioning = new Button(bucketOptions, SWT.CHECK);
        enableVersioning.setText("Enable versioning?");

        publicAccess = new Button(bucketOptions, SWT.CHECK);
        publicAccess.setText("Allow public access?");

        updateProjectControls = new Composite(controlsStack, SWT.NONE);
        updateProjectControls.setVisible(false);
        updateProjectControls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));

        /*
         * Project name text field
         */
        projectName = new StringFieldEditor("project", "Project to update", updateProjectControls) {

            // the following methods are overridden so the button
            // may appear on the same line

            @Override
            public int getNumberOfControls() {
                return super.getNumberOfControls() + 1;
            }

            @Override
            protected void doFillIntoGrid(Composite parent, int numColumns) {
                super.doFillIntoGrid(parent, numColumns - 1);
            }
        };
        projectName.setEmptyStringAllowed(false);
        projectName.setErrorMessage("Please select a project before continuing.");
        projectName.setPage(getPage());
        projectName.getTextControl(updateProjectControls).setEditable(false);
        projectName.getTextControl(updateProjectControls).addMouseListener(new MouseAdapter() {

            @Override
            public void mouseDown(MouseEvent e) {
                selectProject();
            }

        });

        projectName.setPropertyChangeListener(new IPropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent event) {
                if (event.getProperty().equals(FieldEditor.IS_VALID)) {
                    getPage().setMessage(null);
                    updateState();
                } else if (event.getProperty().equals(FieldEditor.VALUE)) {
                    getPage().setMessage(null);
                    updateState();
                }
            }
        });

        /*
         * Select project button
         */
        selectProjectButton = new Button(updateProjectControls, SWT.PUSH);
        selectProjectButton.setText("Select");
        selectProjectButton.setToolTipText("Select project");
        selectProjectButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
        selectProjectButton.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                selectProject();
            }
        });

        FontData currentFont = loginStatusLabel.getFont().getFontData()[0];

        upstreamModifiedWarning = new Label(updateProjectControls, SWT.WRAP);
        upstreamModifiedWarning.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false, 4, 1));
        upstreamModifiedWarning.setFont(new Font(upstreamModifiedWarning.getDisplay(),
                new FontData(currentFont.getName(), currentFont.getHeight(), SWT.BOLD)));
        upstreamModifiedWarning.setVisible(false);

        Composite writerOptions = new Composite(parent, SWT.NONE);
        writerOptions.setLayout(new RowLayout());
        writerOptions.setLayoutData(new GridData(SWT.LEAD, SWT.LEAD, true, true, 4, 2));

        includeWebResources = new Button(writerOptions, SWT.CHECK);
        includeWebResources.setText("Include web resources?");

        excludeData = new Button(writerOptions, SWT.CHECK);
        excludeData.setText("Exclude source data?");
        excludeData.setSelection(true);

        excludeCachedResources = new Button(writerOptions, SWT.CHECK);
        excludeCachedResources
                .setText("Use cached internal schema representation (required for big schema files)?");
        excludeCachedResources.setSelection(true);

        prefillTargetProject();

        updateState();
    }

    /**
     * 
     */
    private void prefillTargetProject() {
        if (!haleConnect.isLoggedIn()) {
            return;
        }

        ProjectInfoService pis = HaleUI.getServiceProvider().getService(ProjectInfoService.class);
        String projectUrnProperty = pis.getProperty(HaleConnectProjectReader.HALECONNECT_URN_PROPERTY)
                .getStringRepresentation();

        if (projectUrnProperty != null) {
            // If project was loaded from hale connect, prefill project name

            URI projectUrn = URI.create(projectUrnProperty);
            if (HaleConnectUrnBuilder.isValidProjectUrn(projectUrn)) {
                String projectId = HaleConnectUrnBuilder.extractProjectId(projectUrn);
                Owner owner = HaleConnectUrnBuilder.extractProjectOwner(projectUrn);

                try {
                    if (!haleConnect.testProjectPermission(HaleConnectService.PERMISSION_EDIT, owner, projectId)) {
                        return;
                    }

                    HaleConnectProjectInfo projectInfo = haleConnect.getProject(owner, projectId);
                    if (projectInfo != null) {
                        targetProject = new HaleConnectProjectConfig();
                        targetProject.setOwner(owner);
                        targetProject.setProjectId(projectId);
                        targetProject.setProjectName(projectInfo.getName());
                        targetProject.setLastModified(projectInfo.getLastModified());
                        newProject.setSelection(false);
                        updateProject.setSelection(true);
                        projectName.setStringValue(projectInfo.getName());
                    }
                } catch (Throwable t) {
                    // Non-fatal
                    log.warn(MessageFormat.format("Unable to prefill target project: {0}", t.getMessage()), t);
                }
            }
        }

    }

    /**
     * Update the page state.
     */
    protected void updateState() {
        updateLoginStatus();
        updateOverwriteWarning();

        setValid(haleConnect.isLoggedIn() && (ownerUser.isEnabled() || ownerOrg.isEnabled())
                && (newProject.getSelection() || targetProject != null));
        if (newProject.getSelection()) {
            controlsStackLayout.topControl = newProjectControls;
            createNewProject = true;
        } else {
            controlsStackLayout.topControl = updateProjectControls;
            createNewProject = false;
        }
        controlsStack.layout();
    }

    @Override
    public void onShowPage(boolean firstShow) {
        super.onShowPage(firstShow);
        updateState();
    }

    @Override
    public boolean updateConfiguration(HaleConnectProjectWriter provider) {
        provider.setParameter(HaleConnectProjectWriter.ENABLE_VERSIONING,
                Value.of(enableVersioning.getSelection()));
        provider.setParameter(HaleConnectProjectWriter.SHARING_PUBLIC, Value.of(publicAccess.getSelection()));
        Value ownerValue = Value.of(
                ownerUser.getSelection() ? OwnerType.USER.getJsonValue() : OwnerType.ORGANISATION.getJsonValue());
        provider.setParameter(HaleConnectProjectWriter.OWNER_TYPE, ownerValue);
        provider.setParameter(ArchiveProjectWriter.EXLUDE_DATA_FILES, Value.of(excludeData.getSelection()));
        provider.setParameter(ArchiveProjectWriter.INCLUDE_WEB_RESOURCES,
                Value.of(includeWebResources.getSelection()));
        provider.setParameter(ArchiveProjectWriter.EXCLUDE_CACHED_RESOURCES,
                Value.of(excludeCachedResources.getSelection()));

        // organisation selection
        ISelection sel = orgSelector.getSelection();
        if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
            Object selected = ((IStructuredSelection) sel).getFirstElement();
            if (selected instanceof HaleConnectOrganisationInfo) {
                String orgId = ((HaleConnectOrganisationInfo) selected).getId();
                provider.setParameter(HaleConnectProjectWriter.ORGANISATION_ID, Value.of(orgId));
            }
        }

        provider.setTarget(new LocatableOutputSupplier<OutputStream>() {

            @Override
            public OutputStream getOutput() throws IOException {
                return null;
            }

            @Override
            public URI getLocation() {
                if (createNewProject) {
                    // Returning null will advise HaleConnectProjectWriter to
                    // create a new hale connect transformation project
                    return null;
                } else if (targetProject != null) {
                    return HaleConnectUrnBuilder.buildProjectUrn(targetProject.getOwner(),
                            targetProject.getProjectId());
                } else {
                    throw new IllegalStateException("No target project selected.");
                }
            }

        });
        return true;
    }

    private void updateLoginStatus() {
        HaleConnectService hcs = HaleUI.getServiceProvider().getService(HaleConnectService.class);
        boolean loggedIn = hcs.isLoggedIn();
        ownershipGroup.setEnabled(loggedIn);
        enableVersioning.setEnabled(loggedIn);
        publicAccess.setEnabled(loggedIn);
        ownerUser.setEnabled(loggedIn);
        includeWebResources.setEnabled(loggedIn);
        excludeData.setEnabled(loggedIn);
        excludeCachedResources.setEnabled(loggedIn);
        selectProjectButton.setEnabled(loggedIn);
        newProject.setEnabled(loggedIn);
        updateProject.setEnabled(loggedIn);

        if (loggedIn) {
            loginStatusLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN));
            loginStatusLabel.setText(MessageFormat.format("Logged in as {0}", hcs.getSession().getUsername()));

            boolean orgAllowed;
            if (hcs.getSession().getOrganisationIds().isEmpty()) {
                orgAllowed = false;
            } else {
                try {
                    orgAllowed = hcs.testUserPermission(RESOURCE_TRANSFORMATION_PROJECT,
                            hcs.getSession().getOrganisationIds().iterator().next(), PERMISSION_CREATE);
                } catch (Throwable t) {
                    log.userError("A problem occurred while contacting hale connect. Functionality may be limited.",
                            t);
                    orgAllowed = false;
                }
            }

            ownerOrg.setEnabled(false);
            orgSelector.getCombo().setEnabled(false);
            if (orgAllowed) {
                final SettableFuture<List<HaleConnectOrganisationInfo>> orgsFuture = SettableFuture.create();
                Futures.addCallback(orgsFuture, new FutureCallback<List<HaleConnectOrganisationInfo>>() {

                    @Override
                    public void onSuccess(List<HaleConnectOrganisationInfo> result) {
                        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

                            @Override
                            public void run() {
                                ownerOrg.setEnabled(true);
                                orgSelector.getCombo().setEnabled(true);
                                orgSelector.setInput(result);
                                if (!result.isEmpty()) {
                                    orgSelector.setSelection(new StructuredSelection(result.get(0)));
                                }
                            }
                        });
                    }

                    @Override
                    public void onFailure(Throwable t) {
                        log.userError(
                                "A problem occurred while contacting hale connect. Functionality may be limited.",
                                t);
                    }
                });

                Thread fetchOrgInfoThread = new Thread(new Runnable() {

                    @Override
                    public void run() {
                        boolean hadException = false;

                        List<HaleConnectOrganisationInfo> organisations = new ArrayList<>();
                        List<HaleConnectException> exceptions = new ArrayList<>();
                        for (String orgId : hcs.getSession().getOrganisationIds()) {
                            try {
                                HaleConnectOrganisationInfo orgInfo = hcs.getOrganisationInfo(orgId);
                                if (orgInfo != null) {
                                    organisations.add(orgInfo);
                                }
                            } catch (HaleConnectException e) {
                                hadException = true;
                                log.error("Error fetching organization details from hale connect.", e);
                                exceptions.add(e);

                                // As a fallback, display dummy value that
                                // contains the orgId
                                organisations.add(new HaleConnectOrganisationInfo(orgId,
                                        MessageFormat.format("<Organisation {0}>", orgId)));
                            }
                        }

                        orgsFuture.set(organisations);

                        if (hadException) {
                            PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

                                @Override
                                public void run() {
                                    log.userError(
                                            "A problem occurred while contacting hale connect. Functionality may be limited.");
                                }
                            });
                        }
                    }
                });

                fetchOrgInfoThread.start();
            }

            boolean userAllowed;
            try {
                userAllowed = hcs.testUserPermission(RESOURCE_TRANSFORMATION_PROJECT, OwnerType.USER.getJsonValue(),
                        PERMISSION_CREATE);
            } catch (Throwable t) {
                log.userError("A problem occurred while contacting hale connect. Functionality may be limited.", t);
                userAllowed = false;
            }
            ownerUser.setEnabled(userAllowed);

            ownerUser.setSelection(userAllowed);
            if (!userAllowed || !orgAllowed) {
                ownerOrg.setSelection(orgAllowed);
            }

            if (!userAllowed && !orgAllowed) {
                loginStatusLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
                loginStatusLabel.setText(
                        "You do not have sufficient permissions to upload transformation projects to hale connect.");
            }
        } else {
            loginStatusLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
            loginStatusLabel
                    .setText("You are not logged in to hale connect. Please login before sharing a project.");

            ownerOrg.setEnabled(false);
        }
    }

    private void selectProject() {
        targetProject = ChooseHaleConnectProjectWizard.openSelectProject();
        if (targetProject != null) {
            projectName.setStringValue(targetProject.getProjectName());
            updateOverwriteWarning();
        }
    }

    private void updateOverwriteWarning() {
        if (createNewProject || targetProject == null) {
            upstreamModifiedWarning.setVisible(false);
            return;
        }

        ProjectInfoService pis = HaleUI.getServiceProvider().getService(ProjectInfoService.class);

        String lastModifiedProperty = pis.getProperty(HaleConnectProjectReader.HALECONNECT_LAST_MODIFIED_PROPERTY)
                .getStringRepresentation();
        if (lastModifiedProperty != null && targetProject != null && targetProject.getLastModified() != null) {
            Long lastModified = Long.parseLong(lastModifiedProperty);
            boolean hasNewerVersion = lastModified < targetProject.getLastModified();
            if (hasNewerVersion) {
                upstreamModifiedWarning.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
                upstreamModifiedWarning.setText(
                        "The project on hale connect has been updated since it was last imported.\nChanges may be lost if you continue with this export.");
                upstreamModifiedWarning.setVisible(true);
            } else {
                upstreamModifiedWarning.setVisible(false);
            }
        } else {
            upstreamModifiedWarning.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED));
            upstreamModifiedWarning.setText(
                    "The current project to be exported was not originally imported from hale connect.\nThe project to update on hale connect will be replaced by this project if you continue with this export.");
            upstreamModifiedWarning.setVisible(true);
        }

        updateProjectControls.layout();
    }
}