de.uniluebeck.itm.spyglass.gui.wizard.WisebedPacketReaderConfigurationWizard.java Source code

Java tutorial

Introduction

Here is the source code for de.uniluebeck.itm.spyglass.gui.wizard.WisebedPacketReaderConfigurationWizard.java

Source

/*----------------------------------------------------------------------------------------
 * This file is part of the
 * WSN visualization framework SpyGlass. Copyright (C) 2004-2007 by the SwarmNet (www.swarmnet.de)
 * project SpyGlass is free software; you can redistribute it and/or modify it under the terms of
 * the BSD License. Refer to spyglass-licence.txt file in the root of the SpyGlass source tree for
 * further details.
 * ---------------------------------------------------------------------------------------
 */

package de.uniluebeck.itm.spyglass.gui.wizard;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import de.uniluebeck.itm.spyglass.SpyglassApp;
import de.uniluebeck.itm.spyglass.io.wisebed.WisebedPacketReader;
import de.uniluebeck.itm.spyglass.io.wisebed.WisebedPacketReaderXMLConfig;
import de.uniluebeck.itm.tr.util.UrlUtils;
import de.uniluebeck.itm.wisebed.cmdlineclient.BeanShellHelper;
import eu.wisebed.api.common.KeyValuePair;
import eu.wisebed.api.rs.*;
import eu.wisebed.api.sm.SecretReservationKey;
import eu.wisebed.api.sm.SessionManagement;
import eu.wisebed.api.snaa.AuthenticationTriple;
import eu.wisebed.api.snaa.SNAA;
import eu.wisebed.api.snaa.SecretAuthenticationKey;
import eu.wisebed.testbed.api.rs.RSServiceHelper;
import eu.wisebed.testbed.api.snaa.helpers.SNAAServiceHelper;
import eu.wisebed.testbed.api.wsn.WSNServiceHelper;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.ws.Holder;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import static com.google.common.collect.Lists.newArrayList;

/**
 * Wizard for creating a PacketReader instance connected to WISEBED testbeds.
 *
 * @author Jens Kluttig, Daniel Bimschas
 */
public class WisebedPacketReaderConfigurationWizard extends Wizard {

    private static final Logger log = LoggerFactory.getLogger(WisebedPacketReaderConfigurationWizard.class);

    private static final DatatypeFactory datatypeFactory;

    static {
        try {
            datatypeFactory = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    private class SessionManagementEndpointUrlPage extends WizardPage implements IExtendedWizardPage {

        private Text sessionManagementText;

        protected SessionManagementEndpointUrlPage(String pageName) {
            super(pageName);
            setMessage("Please enter the endpoint URL of the Session Management service of the testbed you want to "
                    + "connect to.");
        }

        @Override
        public void createControl(Composite composite) {

            final GridLayout gridLayout = new GridLayout();
            gridLayout.makeColumnsEqualWidth = true;
            gridLayout.numColumns = 2;

            final Composite area = new Composite(composite, SWT.NONE);
            area.setLayout(gridLayout);

            final Label smLabel = new Label(area, SWT.NONE);
            smLabel.setText("Session Management Service Endpoint URL");

            sessionManagementText = new Text(area, SWT.BORDER);
            sessionManagementText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            setControl(area);

            final DataBindingContext context = new DataBindingContext(
                    SWTObservables.getRealm(composite.getDisplay()));

            IObservableValue smUrlObservable = PojoObservables.observeValue(
                    SWTObservables.getRealm(composite.getDisplay()),
                    WisebedPacketReaderConfigurationWizard.this.config,
                    WisebedPacketReaderXMLConfig.PROPERTYNAME_SM_ENDPOINT_URL);

            context.bindValue(SWTObservables.observeText(sessionManagementText, SWT.Modify), smUrlObservable,
                    new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE),
                    new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE));
        }

        @Override
        public void nextPressed() {
            StringBuilder builder = new StringBuilder();
            if (StringUtils.isBlank(sessionManagementText.getText())) {
                builder.append("URN of Session Management Service is missing!").append("\n");
            }
            if (StringUtils.isNotBlank(builder.toString())) {
                MessageDialog.openWarning(getShell(), "Warning", builder.toString());
            }
            fetchSnaaAndRsEndpointUrls();
        }

        @Override
        public boolean isComplete() {
            boolean notBlank = StringUtils.isNotBlank(sessionManagementText.getText());
            if (notBlank) {
                String smEndpointUrl = sessionManagementText.getText();
                try {
                    new URL(smEndpointUrl);
                } catch (MalformedURLException e) {
                    return false;
                }
                return true;
            } else {
                return false;
            }
        }

        private void fetchSnaaAndRsEndpointUrls() {

            SessionManagement sessionManagement = WSNServiceHelper
                    .getSessionManagementService(sessionManagementText.getText());

            final Holder<String> rsEndpointUrl = new Holder<String>();
            final Holder<String> snaaEndpointUrl = new Holder<String>();
            final Holder<List<KeyValuePair>> configurationOptions = new Holder<List<KeyValuePair>>();

            sessionManagement.getConfiguration(rsEndpointUrl, snaaEndpointUrl, configurationOptions);

            WisebedPacketReaderConfigurationWizard.this.config.setRsEndpointUrl(rsEndpointUrl.value);
            WisebedPacketReaderConfigurationWizard.this.config.setSnaaEndpointUrl(snaaEndpointUrl.value);
        }

    }

    private class AuthenticationPage extends WizardPage implements IExtendedWizardPage {

        protected AuthenticationPage(String pageName) {
            super(pageName);
            setMessage("Please provide your authentication credentials.");
        }

        @Override
        public void createControl(Composite composite) {
            final Composite area = new Composite(composite, SWT.NONE);
            final GridLayout gridLayout = new GridLayout();
            gridLayout.makeColumnsEqualWidth = true;
            gridLayout.numColumns = 1;
            area.setLayout(gridLayout);
            final Composite upperArea = new Composite(area, SWT.NONE);
            final GridLayout upperLayout = new GridLayout();
            upperLayout.makeColumnsEqualWidth = true;
            upperLayout.numColumns = 3;
            upperArea.setLayout(upperLayout);
            upperArea.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            final Label urnLabel = new Label(upperArea, SWT.NONE);
            urnLabel.setText("URN-Prefix");
            final Label userLabel = new Label(upperArea, SWT.NONE);
            userLabel.setText("Username");
            final Label pwLabel = new Label(upperArea, SWT.NONE);
            pwLabel.setText("Password");
            final Text urnText = new Text(upperArea, SWT.BORDER);
            urnText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            urnText.setText(config.getUrnPrefix() == null ? "" : config.getUrnPrefix());
            final Text userText = new Text(upperArea, SWT.BORDER);
            userText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            userText.setText(config.getUsername() == null ? "" : config.getUsername());
            final Text pwText = new Text(upperArea, SWT.BORDER);
            pwText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            pwText.setText(config.getPassword() == null ? "" : config.getPassword());
            pwText.setEchoChar('*');
            Label none1 = new Label(upperArea, SWT.NONE);
            Label none2 = new Label(upperArea, SWT.NONE);
            final Button loginButton = new Button(upperArea, SWT.NONE);
            loginButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true, 1, 1));
            loginButton.setText("add to Authentication Data");

            final Group lowerArea = new Group(area, SWT.NONE);
            lowerArea.setLayout(gridLayout);
            lowerArea.setText("Authentication Data");
            lowerArea.setLayoutData(new GridData(GridData.FILL_BOTH));
            final Table rsList = new Table(lowerArea, SWT.NONE);
            rsList.setHeaderVisible(true);
            rsList.setLayoutData(new GridData(GridData.FILL_BOTH));
            final TableColumn[] columns = new TableColumn[2];
            TableColumn urnColumn = new TableColumn(rsList, SWT.NONE);
            urnColumn.setText("URN-Prefix");
            columns[0] = urnColumn;
            TableColumn usrColumn = new TableColumn(rsList, SWT.NONE);
            usrColumn.setText("Username");
            columns[1] = usrColumn;

            setControl(area);

            loginButton.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event event) {
                    AuthenticationTriple triple = new AuthenticationTriple();
                    triple.setPassword(pwText.getText());
                    triple.setUrnPrefix(urnText.getText());
                    triple.setUsername(userText.getText());
                    for (AuthenticationTriple at : authMap.keySet()) {
                        if (at.getUrnPrefix().equalsIgnoreCase(triple.getUrnPrefix())
                                && at.getUsername().equalsIgnoreCase(triple.getUsername())) {
                            MessageDialog.openInformation(getShell(), "Information",
                                    "User already added to Authentication Data");
                            return;
                        }
                    }
                    if (authenticate(triple)) {
                        TableItem item = new TableItem(rsList, SWT.NONE);
                        item.setText(new String[] { urnText.getText(), userText.getText() });
                        for (int i = 0, n = columns.length; i < n; i++) {
                            columns[i].pack();
                        }

                        config.setUrnPrefix(urnText.getText());
                        urnText.setText("");

                        config.setUsername(userText.getText());
                        userText.setText("");

                        config.setPassword(pwText.getText());
                        pwText.setText("");
                    } else {
                        MessageDialog.openWarning(getShell(), "Fehler", "Authentication Error");
                    }

                }
            }

            );
        }

        @Override
        public void nextPressed() {
            fillReservations();
        }

        @Override
        public boolean isComplete() {
            return !authMap.isEmpty();
        }

    }

    private class SelectReservationPage extends WizardPage implements IExtendedWizardPage {

        private static final int RESERVATION_TABLE_COLUMN_FROM = 0;

        private static final int RESERVATION_TABLE_COLUMN_TO = 1;

        private static final int RESERVATION_TABLE_COLUMN_NODE_URNS = 2;

        private Table reservationsTable;

        private TableColumn[] columns;

        private java.util.List<ConfidentialReservationData> reservationList = Lists.newArrayList();

        protected SelectReservationPage(String pageName) {
            super(pageName);
            setMessage(
                    "Please choose the experiment reservation you want to connect to.\nDisplaying all reservations of the next 24 hours.");
        }

        @Override
        public void createControl(Composite composite) {

            Composite contentComposite = new Composite(composite, SWT.FILL);
            contentComposite.setLayout(new GridLayout(1, false));
            GridData contentCompositeLayoutData = new GridData(SWT.FILL);
            contentCompositeLayoutData.grabExcessHorizontalSpace = true;
            contentComposite.setData(contentCompositeLayoutData);

            GridData reservationsTableLayoutData = new GridData(GridData.FILL);
            reservationsTableLayoutData.grabExcessHorizontalSpace = true;
            reservationsTableLayoutData.grabExcessVerticalSpace = true;
            reservationsTableLayoutData.horizontalAlignment = GridData.FILL;
            reservationsTableLayoutData.verticalAlignment = GridData.FILL;

            reservationsTable = new Table(contentComposite, SWT.SINGLE);
            reservationsTable.setLayoutData(reservationsTableLayoutData);
            reservationsTable.setHeaderVisible(true);
            reservationsTable.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent selectionEvent) {
                    setPageComplete(reservationsTable.getSelectionCount() == 1);
                }
            });

            TableColumn fromColumn = new TableColumn(reservationsTable, SWT.NONE);
            fromColumn.setText("From");

            TableColumn toColumn = new TableColumn(reservationsTable, SWT.NONE);
            toColumn.setText("To");

            TableColumn nodeUrnsColumn = new TableColumn(reservationsTable, SWT.NONE);
            nodeUrnsColumn.setText("Node URNs");

            columns = new TableColumn[3];
            columns[RESERVATION_TABLE_COLUMN_FROM] = fromColumn;
            columns[RESERVATION_TABLE_COLUMN_TO] = toColumn;
            columns[RESERVATION_TABLE_COLUMN_NODE_URNS] = nodeUrnsColumn;

            Button refreshButton = new Button(contentComposite, SWT.NORMAL);
            refreshButton.setText("Refresh");
            refreshButton.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent selectionEvent) {
                    clearReservations();
                    fillReservations();
                }
            });
            GridData refreshButtonLayoutData = new GridData();
            refreshButtonLayoutData.horizontalAlignment = GridData.END;
            refreshButton.setData(refreshButtonLayoutData);

            setControl(contentComposite);
        }

        public void clearReservations() {
            reservationsTable.removeAll();
            reservationsTable.clearAll();
            reservationList.clear();
        }

        public ConfidentialReservationData getSelectedReservation() {
            if (reservationsTable.getSelectionIndex() >= 0) {
                return reservationList.get(reservationsTable.getSelectionIndex());
            } else {
                return null;
            }
        }

        public void addReservation(ConfidentialReservationData data) {

            String from = new DateTime(data.getFrom().toGregorianCalendar()).toString("dd.MM.yyyy HH:mm");
            String to = new DateTime(data.getTo().toGregorianCalendar()).toString("dd.MM.yyyy HH:mm");
            String nodeUrns = Joiner.on(",").join(data.getNodeURNs());

            TableItem item = new TableItem(reservationsTable, SWT.NONE);
            item.setText(new String[] { from, to, nodeUrns });

            for (int i = 0, n = columns.length; i < n; i++) {
                columns[i].pack();
            }

            reservationList.add(data);
        }

        @Override
        public void nextPressed() {
        }

        @Override
        public boolean isComplete() {
            return getSelectedReservation() != null;
        }

    }

    private final Map<AuthenticationTriple, SecretAuthenticationKey> authMap = Maps.newHashMap();

    private WisebedPacketReaderXMLConfig config;

    private SelectReservationPage selectReservationPage;

    private AuthenticationPage authenticationPage;

    private SessionManagementEndpointUrlPage sessionManagementEndpointUrlPage;

    public WisebedPacketReaderConfigurationWizard() {
        super();

        config = SpyglassApp.spyglass.getConfigStore().getSpyglassConfig().getWisebedPacketReaderSettings();

        setWindowTitle("Wisebed Testbed Packet Source Configuration");

        sessionManagementEndpointUrlPage = new SessionManagementEndpointUrlPage("Testbed URLs");
        authenticationPage = new AuthenticationPage("Authorization");
        selectReservationPage = new SelectReservationPage("Reservation");

        addPage(sessionManagementEndpointUrlPage);
        addPage(authenticationPage);
        addPage(selectReservationPage);
    }

    @Override
    public boolean performFinish() {

        if (!sessionManagementEndpointUrlPage.isComplete()) {
            MessageDialog.openWarning(getShell(), "Warning",
                    "Please fill in the Session Management service endpoint URL.");
            return false;
        }

        if (!selectReservationPage.isComplete()) {
            MessageDialog.openWarning(getShell(), "Warning", "Please select a reservation.");
            return false;
        }

        String localControllerEndpointUrl = tryToAutoDetectLocalControllerEndpointUrl();

        if (localControllerEndpointUrl == null) {
            localControllerEndpointUrl = tryToGetLocalControllerEndpointUrlFromUser();
        }

        if (localControllerEndpointUrl == null) {
            return false;
        }

        WisebedPacketReaderConfigurationWizard.this.config.setControllerEndpointUrl(localControllerEndpointUrl);

        ConfidentialReservationData selectedReservation = selectReservationPage.getSelectedReservation();
        final List<SecretReservationKey> secretReservationKeys = newArrayList();
        for (Data data : selectedReservation.getData()) {
            final SecretReservationKey srk = new SecretReservationKey();
            srk.setUrnPrefix(data.getUrnPrefix());
            srk.setSecretReservationKey(data.getSecretReservationKey());
            secretReservationKeys.add(srk);
        }

        final WisebedPacketReader wisebedPacketReader = new WisebedPacketReader(config.getControllerEndpointUrl(),
                config.getSmEndpointUrl(), secretReservationKeys);

        SpyglassApp.spyglass.getConfigStore().getSpyglassConfig().setPacketReader(wisebedPacketReader);
        SpyglassApp.spyglass.getConfigStore().store();

        return true;
    }

    @Override
    public boolean canFinish() {
        return sessionManagementEndpointUrlPage.isComplete() && authenticationPage.isComplete()
                && selectReservationPage.isComplete();
    }

    private boolean authenticate(AuthenticationTriple triple) {
        SNAA snaa = SNAAServiceHelper.getSNAAService(config.getSnaaEndpointUrl());
        java.util.List<SecretAuthenticationKey> list = null;
        try {
            list = snaa.authenticate(ImmutableList.of(triple));
        } catch (Exception e) {
            return false;
        }
        authMap.put(triple, list.get(0));
        return true;

    }

    private void fillReservations() {

        final RS rs = RSServiceHelper.getRSService(config.getRsEndpointUrl());
        final GetReservations getReservationsRequest = new GetReservations();
        final DateTime from = new DateTime();
        final DateTime until = from.plusHours(24);

        getReservationsRequest.setFrom(datatypeFactory.newXMLGregorianCalendar(from.toGregorianCalendar()));
        getReservationsRequest.setTo(datatypeFactory.newXMLGregorianCalendar(until.toGregorianCalendar()));

        List<eu.wisebed.api.rs.SecretAuthenticationKey> secretAuthenticationKeys = BeanShellHelper
                .copySnaaToRs(Lists.<SecretAuthenticationKey>newArrayList(authMap.values()));

        final List<ConfidentialReservationData> rsData;
        try {
            rsData = rs.getConfidentialReservations(secretAuthenticationKeys, getReservationsRequest);
        } catch (RSExceptionException e) {
            throw new RuntimeException(e);
        }

        selectReservationPage.clearReservations();

        for (ConfidentialReservationData data : rsData) {
            selectReservationPage.addReservation(data);
        }

        if (selectReservationPage.reservationsTable.getItemCount() > 0) {
            selectReservationPage.reservationsTable.select(0);
        }
    }

    private String tryToGetLocalControllerEndpointUrlFromUser() {

        String localControllerEndpointUrl = askLocalControllerEndpointUrlFromUser();
        if (localControllerEndpointUrl != null) {
            try {
                URL url = new URL(localControllerEndpointUrl);
                if (checkIfServerSocketCanBeOpened(url.getHost(), url.getPort())) {
                    return localControllerEndpointUrl;
                }
                return null;
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    private String tryToAutoDetectLocalControllerEndpointUrl() {
        Vector<String> externalHostIps = BeanShellHelper.getExternalHostIps();
        final String localControllerEndpointUrl;
        String host = externalHostIps.get(0);
        int port = UrlUtils.getRandomUnprivilegedPort();
        int tries = 0;
        while (!checkIfServerSocketCanBeOpened(host, port)) {
            if (++tries == 3) {
                break;
            }
            int oldPort = port;
            port = UrlUtils.getRandomUnprivilegedPort();
            log.warn("Could not open ServerSocket on {}:{}. Retrying on port {}!",
                    new Object[] { host, oldPort, port });
        }

        localControllerEndpointUrl = "http://" + host + ":" + port + "/controller";
        return tries == 3 ? null : localControllerEndpointUrl;
    }

    private boolean checkIfServerSocketCanBeOpened(String host, int port) {
        try {
            ServerSocket socket = new ServerSocket();
            socket.bind(new InetSocketAddress(host, port));
            socket.close();
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    private String askLocalControllerEndpointUrlFromUser() {
        final InputDialog inputDialog = new InputDialog(null, "Please provide the local controller endpoint URL.",
                "Spyglass was unable to detect the external public IP of your computer. Please provide an "
                        + "endpoint URL for this computer which can be contacted from outside. The host and port "
                        + "in this URL must not be behind a firewall or NAT in order to work.",
                "http://REPLACE_WITH_FQDN.TLD:PORT/", new IInputValidator() {
                    @Override
                    public String isValid(final String s) {
                        try {
                            new URL(s);
                            return null;
                        } catch (MalformedURLException e) {
                            return "The string \"" + s + "\" is not a valid URL!";
                        }
                    }
                });
        inputDialog.setBlockOnOpen(true);
        int open = inputDialog.open();
        if (SWT.OK == open) {
            return inputDialog.getValue();
        }
        return null;
    }

}