org.apache.hadoop.eclipse.servers.HadoopLocationWizard.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.eclipse.servers.HadoopLocationWizard.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.eclipse.servers;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.eclipse.server.ConfProp;
import org.apache.hadoop.eclipse.server.HadoopServer;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
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.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;

/**
 * Wizard for editing the settings of a Hadoop location
 * 
 * The wizard contains 3 tabs: General, Tunneling and Advanced. It edits
 * parameters of the location member which either a new location or a copy of
 * an existing registered location.
 */

public class HadoopLocationWizard extends WizardPage {

    Image circle;

    /**
     * The location effectively edited by the wizard. This location is a copy
     * or a new one.
     */
    private HadoopServer location;

    /**
     * The original location being edited by the wizard (null if we create a
     * new instance).
     */
    private HadoopServer original;

    /**
     * New Hadoop location wizard
     */
    public HadoopLocationWizard() {
        super("Hadoop Server", "New Hadoop Location", null);

        this.original = null;
        this.location = new HadoopServer();
        this.location.setLocationName("");
    }

    /**
     * Constructor to edit the parameters of an existing Hadoop server
     * 
     * @param server
     */
    public HadoopLocationWizard(HadoopServer server) {
        super("Create a new Hadoop location", "Edit Hadoop Location", null);

        this.original = server;
        this.location = new HadoopServer(server);
    }

    /**
     * Performs any actions appropriate in response to the user having pressed
     * the Finish button, or refuse if finishing now is not permitted.
     * 
     * @return the created or updated Hadoop location
     */

    public HadoopServer performFinish() {
        try {
            if (this.original == null) {
                // New location
                Display.getDefault().syncExec(new Runnable() {
                    public void run() {
                        ServerRegistry.getInstance().addServer(HadoopLocationWizard.this.location);
                    }
                });
                return this.location;

            } else {
                // Update location
                final String originalName = this.original.getLocationName();
                this.original.load(this.location);

                Display.getDefault().syncExec(new Runnable() {
                    public void run() {
                        ServerRegistry.getInstance().updateServer(originalName, HadoopLocationWizard.this.location);
                    }
                });
                return this.original;

            }
        } catch (Exception e) {
            e.printStackTrace();
            setMessage("Invalid server location values", IMessageProvider.ERROR);
            return null;
        }
    }

    /**
     * Validates the current Hadoop location settings (look for Hadoop
     * installation directory).
     * 
     */
    private void testLocation() {
        setMessage("Not implemented yet", IMessageProvider.WARNING);
    }

    /**
     * Location is not complete (and finish button not available) until a host
     * name is specified.
     * 
     * @inheritDoc
     */
    @Override
    public boolean isPageComplete() {

        {
            String locName = location.getConfProp(ConfProp.PI_LOCATION_NAME);
            if ((locName == null) || (locName.length() == 0) || locName.contains("/")) {

                setMessage("Bad location name: " + "the location name should not contain "
                        + "any character prohibited in a file name.", WARNING);

                return false;
            }
        }

        {
            String master = location.getConfProp(ConfProp.PI_JOB_TRACKER_HOST);
            if ((master == null) || (master.length() == 0)) {

                setMessage("Bad master host name: " + "the master host name refers to the machine "
                        + "that runs the Job tracker.", WARNING);

                return false;
            }
        }

        {
            String jobTracker = location.getConfProp(ConfProp.JOB_TRACKER_URI);
            String[] strs = jobTracker.split(":");
            boolean ok = (strs.length == 2);
            if (ok) {
                try {
                    int port = Integer.parseInt(strs[1]);
                    ok = (port >= 0) && (port < 65536);
                } catch (NumberFormatException nfe) {
                    ok = false;
                }
            }
            if (!ok) {
                setMessage("The job tracker information (" + ConfProp.JOB_TRACKER_URI.name + ") is invalid. "
                        + "This usually looks like \"host:port\"", WARNING);
                return false;
            }
        }

        {
            String fsDefaultURI = location.getConfProp(ConfProp.FS_DEFAULT_URI);
            try {
                URI uri = new URI(fsDefaultURI);
            } catch (URISyntaxException e) {

                setMessage(
                        "The default file system URI is invalid. "
                                + "This usually looks like \"hdfs://host:port/\" " + "or \"file:///dir/\"",
                        WARNING);
            }
        }

        setMessage("Define the location of a Hadoop infrastructure " + "for running MapReduce applications.");
        return true;
    }

    /**
     * Create the wizard
     */
    /* @inheritDoc */
    public void createControl(Composite parent) {
        setTitle("Define Hadoop location");
        setDescription("Define the location of a Hadoop infrastructure " + "for running MapReduce applications.");

        Composite panel = new Composite(parent, SWT.FILL);
        GridLayout glayout = new GridLayout(2, false);
        panel.setLayout(glayout);

        TabMediator mediator = new TabMediator(panel);
        {
            GridData gdata = new GridData(GridData.FILL_BOTH);
            gdata.horizontalSpan = 2;
            mediator.folder.setLayoutData(gdata);
        }
        this.setControl(panel /* mediator.folder */);
        {
            final Button btn = new Button(panel, SWT.NONE);
            btn.setText("&Load from file");
            btn.setEnabled(false);
            btn.setToolTipText("Not yet implemented");
            btn.addListener(SWT.Selection, new Listener() {
                public void handleEvent(Event e) {
                    // TODO
                }
            });
        }
        {
            final Button validate = new Button(panel, SWT.NONE);
            validate.setText("&Validate location");
            validate.setEnabled(false);
            validate.setToolTipText("Not yet implemented");
            validate.addListener(SWT.Selection, new Listener() {
                public void handleEvent(Event e) {
                    testLocation();
                }
            });
        }
    }

    private interface TabListener {
        void notifyChange(ConfProp prop, String propValue);
    }

    /*
     * Mediator pattern to keep tabs synchronized with each other and with the
     * location state.
     */

    private class TabMediator {
        TabFolder folder;

        private Set<TabListener> tabs = new HashSet<TabListener>();

        TabMediator(Composite parent) {
            folder = new TabFolder(parent, SWT.NONE);
            tabs.add(new TabMain(this));
            tabs.add(new TabAdvanced(this));
        }

        /**
         * Access to current configuration settings
         * 
         * @param propName the property name
         * @return the current property value
         */
        String get(String propName) {
            return location.getConfProp(propName);
        }

        String get(ConfProp prop) {
            return location.getConfProp(prop);
        }

        /**
         * Implements change notifications from any tab: update the location
         * state and other tabs
         * 
         * @param source origin of the notification (one of the tree tabs)
         * @param propName modified property
         * @param propValue new value
         */
        void notifyChange(TabListener source, final ConfProp prop, final String propValue) {
            // Ignore notification when no change
            String oldValue = location.getConfProp(prop);
            if ((oldValue != null) && oldValue.equals(propValue))
                return;

            location.setConfProp(prop, propValue);
            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    getContainer().updateButtons();
                }
            });

            this.fireChange(source, prop, propValue);

            /*
             * Now we deal with dependencies between settings
             */
            final String jobTrackerHost = location.getConfProp(ConfProp.PI_JOB_TRACKER_HOST);
            final String jobTrackerPort = location.getConfProp(ConfProp.PI_JOB_TRACKER_PORT);
            final String nameNodeHost = location.getConfProp(ConfProp.PI_NAME_NODE_HOST);
            final String nameNodePort = location.getConfProp(ConfProp.PI_NAME_NODE_PORT);
            final boolean colocate = location.getConfProp(ConfProp.PI_COLOCATE_MASTERS).equalsIgnoreCase("yes");
            final String jobTrackerURI = location.getConfProp(ConfProp.JOB_TRACKER_URI);
            final String fsDefaultURI = location.getConfProp(ConfProp.FS_DEFAULT_URI);
            final String socksServerURI = location.getConfProp(ConfProp.SOCKS_SERVER);
            final boolean socksProxyEnable = location.getConfProp(ConfProp.PI_SOCKS_PROXY_ENABLE)
                    .equalsIgnoreCase("yes");
            final String socksProxyHost = location.getConfProp(ConfProp.PI_SOCKS_PROXY_HOST);
            final String socksProxyPort = location.getConfProp(ConfProp.PI_SOCKS_PROXY_PORT);

            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    switch (prop) {
                    case PI_JOB_TRACKER_HOST: {
                        if (colocate)
                            notifyChange(null, ConfProp.PI_NAME_NODE_HOST, jobTrackerHost);
                        String newJobTrackerURI = String.format("%s:%s", jobTrackerHost, jobTrackerPort);
                        notifyChange(null, ConfProp.JOB_TRACKER_URI, newJobTrackerURI);
                        break;
                    }
                    case PI_JOB_TRACKER_PORT: {
                        String newJobTrackerURI = String.format("%s:%s", jobTrackerHost, jobTrackerPort);
                        notifyChange(null, ConfProp.JOB_TRACKER_URI, newJobTrackerURI);
                        break;
                    }
                    case PI_NAME_NODE_HOST: {
                        String newHDFSURI = String.format("hdfs://%s:%s/", nameNodeHost, nameNodePort);
                        notifyChange(null, ConfProp.FS_DEFAULT_URI, newHDFSURI);

                        // Break colocation if someone force the DFS Master
                        if (!colocate && !nameNodeHost.equals(jobTrackerHost))
                            notifyChange(null, ConfProp.PI_COLOCATE_MASTERS, "no");
                        break;
                    }
                    case PI_NAME_NODE_PORT: {
                        String newHDFSURI = String.format("hdfs://%s:%s/", nameNodeHost, nameNodePort);
                        notifyChange(null, ConfProp.FS_DEFAULT_URI, newHDFSURI);
                        break;
                    }
                    case PI_SOCKS_PROXY_HOST: {
                        String newSocksProxyURI = String.format("%s:%s", socksProxyHost, socksProxyPort);
                        notifyChange(null, ConfProp.SOCKS_SERVER, newSocksProxyURI);
                        break;
                    }
                    case PI_SOCKS_PROXY_PORT: {
                        String newSocksProxyURI = String.format("%s:%s", socksProxyHost, socksProxyPort);
                        notifyChange(null, ConfProp.SOCKS_SERVER, newSocksProxyURI);
                        break;
                    }
                    case JOB_TRACKER_URI: {
                        String[] strs = jobTrackerURI.split(":", 2);
                        String host = strs[0];
                        String port = (strs.length == 2) ? strs[1] : "";
                        notifyChange(null, ConfProp.PI_JOB_TRACKER_HOST, host);
                        notifyChange(null, ConfProp.PI_JOB_TRACKER_PORT, port);
                        break;
                    }
                    case FS_DEFAULT_URI: {
                        try {
                            URI uri = new URI(fsDefaultURI);
                            if (uri.getScheme().equals("hdfs")) {
                                String host = uri.getHost();
                                String port = Integer.toString(uri.getPort());
                                notifyChange(null, ConfProp.PI_NAME_NODE_HOST, host);
                                notifyChange(null, ConfProp.PI_NAME_NODE_PORT, port);
                            }
                        } catch (URISyntaxException use) {
                            // Ignore the update!
                        }
                        break;
                    }
                    case SOCKS_SERVER: {
                        String[] strs = socksServerURI.split(":", 2);
                        String host = strs[0];
                        String port = (strs.length == 2) ? strs[1] : "";
                        notifyChange(null, ConfProp.PI_SOCKS_PROXY_HOST, host);
                        notifyChange(null, ConfProp.PI_SOCKS_PROXY_PORT, port);
                        break;
                    }
                    case PI_COLOCATE_MASTERS: {
                        if (colocate)
                            notifyChange(null, ConfProp.PI_NAME_NODE_HOST, jobTrackerHost);
                        break;
                    }
                    case PI_SOCKS_PROXY_ENABLE: {
                        if (socksProxyEnable) {
                            notifyChange(null, ConfProp.SOCKET_FACTORY_DEFAULT,
                                    "org.apache.hadoop.net.SocksSocketFactory");
                        } else {
                            notifyChange(null, ConfProp.SOCKET_FACTORY_DEFAULT,
                                    "org.apache.hadoop.net.StandardSocketFactory");
                        }
                        break;
                    }
                    }
                }
            });

        }

        /**
         * Change notifications on properties (by name). A property might not be
         * reflected as a ConfProp enum. If it is, the notification is forwarded
         * to the ConfProp notifyChange method. If not, it is processed here.
         * 
         * @param source
         * @param propName
         * @param propValue
         */
        void notifyChange(TabListener source, String propName, String propValue) {

            ConfProp prop = ConfProp.getByName(propName);
            if (prop != null)
                notifyChange(source, prop, propValue);

            location.setConfProp(propName, propValue);
        }

        /**
         * Broadcast a property change to all registered tabs. If a tab is
         * identified as the source of the change, this tab will not be notified.
         * 
         * @param source TODO
         * @param prop
         * @param value
         */
        private void fireChange(TabListener source, ConfProp prop, String value) {
            for (TabListener tab : tabs) {
                if (tab != source)
                    tab.notifyChange(prop, value);
            }
        }

    }

    /**
     * Create a SWT Text component for the given {@link ConfProp} text
     * configuration property.
     * 
     * @param listener
     * @param parent
     * @param prop
     * @return
     */
    private Text createConfText(ModifyListener listener, Composite parent, ConfProp prop) {

        Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        text.setLayoutData(data);
        text.setData("hProp", prop);
        text.setText(location.getConfProp(prop));
        text.addModifyListener(listener);

        return text;
    }

    /**
     * Create a SWT Checked Button component for the given {@link ConfProp}
     * boolean configuration property.
     * 
     * @param listener
     * @param parent
     * @param prop
     * @return
     */
    private Button createConfCheckButton(SelectionListener listener, Composite parent, ConfProp prop, String text) {

        Button button = new Button(parent, SWT.CHECK);
        button.setText(text);
        button.setData("hProp", prop);
        button.setSelection(location.getConfProp(prop).equalsIgnoreCase("yes"));
        button.addSelectionListener(listener);

        return button;
    }

    /**
     * Create editor entry for the given configuration property. The editor is
     * a couple (Label, Text).
     * 
     * @param listener the listener to trigger on property change
     * @param parent the SWT parent container
     * @param prop the property to create an editor for
     * @param labelText a label (null will defaults to the property name)
     * 
     * @return a SWT Text field
     */
    private Text createConfLabelText(ModifyListener listener, Composite parent, ConfProp prop, String labelText) {

        Label label = new Label(parent, SWT.NONE);
        if (labelText == null)
            labelText = prop.name;
        label.setText(labelText);

        return createConfText(listener, parent, prop);
    }

    /**
     * Create an editor entry for the given configuration name
     * 
     * @param listener the listener to trigger on property change
     * @param parent the SWT parent container
     * @param propName the name of the property to create an editor for
     * @param labelText a label (null will defaults to the property name)
     * 
     * @return a SWT Text field
     */
    private Text createConfNameEditor(ModifyListener listener, Composite parent, String propName,
            String labelText) {

        {
            ConfProp prop = ConfProp.getByName(propName);
            if (prop != null)
                return createConfLabelText(listener, parent, prop, labelText);
        }

        Label label = new Label(parent, SWT.NONE);
        if (labelText == null)
            labelText = propName;
        label.setText(labelText);

        Text text = new Text(parent, SWT.SINGLE | SWT.BORDER);
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        text.setLayoutData(data);
        text.setData("hPropName", propName);
        text.setText(location.getConfProp(propName));
        text.addModifyListener(listener);

        return text;
    }

    /**
     * Main parameters of the Hadoop location:
     * <li> host and port of the Map/Reduce master (Job tracker)
     * <li> host and port of the DFS master (Name node)
     * <li> SOCKS proxy
     */
    private class TabMain implements TabListener, ModifyListener, SelectionListener {

        TabMediator mediator;

        Text locationName;

        Text textJTHost;

        Text textNNHost;

        Button colocateMasters;

        Text textJTPort;

        Text textNNPort;

        Text userName;

        Button useSocksProxy;

        Text socksProxyHost;

        Text socksProxyPort;

        TabMain(TabMediator mediator) {
            this.mediator = mediator;
            TabItem tab = new TabItem(mediator.folder, SWT.NONE);
            tab.setText("General");
            tab.setToolTipText("General location parameters");
            tab.setImage(circle);
            tab.setControl(createControl(mediator.folder));
        }

        private Control createControl(Composite parent) {

            Composite panel = new Composite(parent, SWT.FILL);
            panel.setLayout(new GridLayout(2, false));

            GridData data;

            /*
             * Location name
             */
            {
                Composite subpanel = new Composite(panel, SWT.FILL);
                subpanel.setLayout(new GridLayout(2, false));
                data = new GridData();
                data.horizontalSpan = 2;
                data.horizontalAlignment = SWT.FILL;
                subpanel.setLayoutData(data);

                locationName = createConfLabelText(this, subpanel, ConfProp.PI_LOCATION_NAME, "&Location name:");
            }

            /*
             * Map/Reduce group
             */
            {
                Group groupMR = new Group(panel, SWT.SHADOW_NONE);
                groupMR.setText("Map/Reduce Master");
                groupMR.setToolTipText("Address of the Map/Reduce master node " + "(the Job Tracker).");
                GridLayout layout = new GridLayout(2, false);
                groupMR.setLayout(layout);
                data = new GridData();
                data.verticalAlignment = SWT.FILL;
                data.horizontalAlignment = SWT.CENTER;
                data.widthHint = 250;
                groupMR.setLayoutData(data);

                // Job Tracker host
                Label label = new Label(groupMR, SWT.NONE);
                label.setText("Host:");
                data = new GridData(GridData.BEGINNING, GridData.CENTER, false, true);
                label.setLayoutData(data);

                textJTHost = createConfText(this, groupMR, ConfProp.PI_JOB_TRACKER_HOST);
                data = new GridData(GridData.FILL, GridData.CENTER, true, true);
                textJTHost.setLayoutData(data);

                // Job Tracker port
                label = new Label(groupMR, SWT.NONE);
                label.setText("Port:");
                data = new GridData(GridData.BEGINNING, GridData.CENTER, false, true);
                label.setLayoutData(data);

                textJTPort = createConfText(this, groupMR, ConfProp.PI_JOB_TRACKER_PORT);
                data = new GridData(GridData.FILL, GridData.CENTER, true, true);
                textJTPort.setLayoutData(data);
            }

            /*
             * DFS group
             */
            {
                Group groupDFS = new Group(panel, SWT.SHADOW_NONE);
                groupDFS.setText("DFS Master");
                groupDFS.setToolTipText("Address of the Distributed FileSystem " + "master node (the Name Node).");
                GridLayout layout = new GridLayout(2, false);
                groupDFS.setLayout(layout);
                data = new GridData();
                data.horizontalAlignment = SWT.CENTER;
                data.widthHint = 250;
                groupDFS.setLayoutData(data);

                colocateMasters = createConfCheckButton(this, groupDFS, ConfProp.PI_COLOCATE_MASTERS,
                        "Use M/R Master host");
                data = new GridData();
                data.horizontalSpan = 2;
                colocateMasters.setLayoutData(data);

                // Job Tracker host
                Label label = new Label(groupDFS, SWT.NONE);
                data = new GridData();
                label.setText("Host:");
                label.setLayoutData(data);

                textNNHost = createConfText(this, groupDFS, ConfProp.PI_NAME_NODE_HOST);

                // Job Tracker port
                label = new Label(groupDFS, SWT.NONE);
                data = new GridData();
                label.setText("Port:");
                label.setLayoutData(data);

                textNNPort = createConfText(this, groupDFS, ConfProp.PI_NAME_NODE_PORT);
            }

            {
                Composite subpanel = new Composite(panel, SWT.FILL);
                subpanel.setLayout(new GridLayout(2, false));
                data = new GridData();
                data.horizontalSpan = 2;
                data.horizontalAlignment = SWT.FILL;
                subpanel.setLayoutData(data);

                userName = createConfLabelText(this, subpanel, ConfProp.PI_USER_NAME, "&User name:");
            }

            // SOCKS proxy group
            {
                Group groupSOCKS = new Group(panel, SWT.SHADOW_NONE);
                groupSOCKS.setText("SOCKS proxy");
                groupSOCKS
                        .setToolTipText("Address of the SOCKS proxy to use " + "to connect to the infrastructure.");
                GridLayout layout = new GridLayout(2, false);
                groupSOCKS.setLayout(layout);
                data = new GridData();
                data.horizontalAlignment = SWT.CENTER;
                data.horizontalSpan = 2;
                data.widthHint = 250;
                groupSOCKS.setLayoutData(data);

                useSocksProxy = createConfCheckButton(this, groupSOCKS, ConfProp.PI_SOCKS_PROXY_ENABLE,
                        "Enable SOCKS proxy");
                data = new GridData();
                data.horizontalSpan = 2;
                useSocksProxy.setLayoutData(data);

                // SOCKS proxy host
                Label label = new Label(groupSOCKS, SWT.NONE);
                data = new GridData();
                label.setText("Host:");
                label.setLayoutData(data);

                socksProxyHost = createConfText(this, groupSOCKS, ConfProp.PI_SOCKS_PROXY_HOST);

                // SOCKS proxy port
                label = new Label(groupSOCKS, SWT.NONE);
                data = new GridData();
                label.setText("Port:");
                label.setLayoutData(data);

                socksProxyPort = createConfText(this, groupSOCKS, ConfProp.PI_SOCKS_PROXY_PORT);
            }

            // Update the state of all widgets according to the current values!
            reloadConfProp(ConfProp.PI_COLOCATE_MASTERS);
            reloadConfProp(ConfProp.PI_SOCKS_PROXY_ENABLE);
            reloadConfProp(ConfProp.PI_JOB_TRACKER_HOST);

            return panel;
        }

        /**
         * Reload the given configuration property value
         * 
         * @param prop
         */
        private void reloadConfProp(ConfProp prop) {
            this.notifyChange(prop, location.getConfProp(prop));
        }

        public void notifyChange(ConfProp prop, String propValue) {
            switch (prop) {
            case PI_JOB_TRACKER_HOST: {
                textJTHost.setText(propValue);
                break;
            }
            case PI_JOB_TRACKER_PORT: {
                textJTPort.setText(propValue);
                break;
            }
            case PI_LOCATION_NAME: {
                locationName.setText(propValue);
                break;
            }
            case PI_USER_NAME: {
                userName.setText(propValue);
                break;
            }
            case PI_COLOCATE_MASTERS: {
                if (colocateMasters != null) {
                    boolean colocate = propValue.equalsIgnoreCase("yes");
                    colocateMasters.setSelection(colocate);
                    if (textNNHost != null) {
                        textNNHost.setEnabled(!colocate);
                    }
                }
                break;
            }
            case PI_NAME_NODE_HOST: {
                textNNHost.setText(propValue);
                break;
            }
            case PI_NAME_NODE_PORT: {
                textNNPort.setText(propValue);
                break;
            }
            case PI_SOCKS_PROXY_ENABLE: {
                if (useSocksProxy != null) {
                    boolean useProxy = propValue.equalsIgnoreCase("yes");
                    useSocksProxy.setSelection(useProxy);
                    if (socksProxyHost != null)
                        socksProxyHost.setEnabled(useProxy);
                    if (socksProxyPort != null)
                        socksProxyPort.setEnabled(useProxy);
                }
                break;
            }
            case PI_SOCKS_PROXY_HOST: {
                socksProxyHost.setText(propValue);
                break;
            }
            case PI_SOCKS_PROXY_PORT: {
                socksProxyPort.setText(propValue);
                break;
            }
            }
        }

        /* @inheritDoc */
        public void modifyText(ModifyEvent e) {
            final Text text = (Text) e.widget;
            final ConfProp prop = (ConfProp) text.getData("hProp");
            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    mediator.notifyChange(TabMain.this, prop, text.getText());
                }
            });
        }

        /* @inheritDoc */
        public void widgetDefaultSelected(SelectionEvent e) {
            this.widgetSelected(e);
        }

        /* @inheritDoc */
        public void widgetSelected(SelectionEvent e) {
            final Button button = (Button) e.widget;
            final ConfProp prop = (ConfProp) button.getData("hProp");

            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    // We want to receive the update also!
                    mediator.notifyChange(null, prop, button.getSelection() ? "yes" : "no");
                }
            });
        }

    }

    private class TabAdvanced implements TabListener, ModifyListener {
        TabMediator mediator;

        private Composite panel;

        private Map<String, Text> textMap = new TreeMap<String, Text>();

        TabAdvanced(TabMediator mediator) {
            this.mediator = mediator;
            TabItem tab = new TabItem(mediator.folder, SWT.NONE);
            tab.setText("Advanced parameters");
            tab.setToolTipText("Access to advanced Hadoop parameters");
            tab.setImage(circle);
            tab.setControl(createControl(mediator.folder));

        }

        private Control createControl(Composite parent) {
            ScrolledComposite sc = new ScrolledComposite(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);

            panel = new Composite(sc, SWT.NONE);
            sc.setContent(panel);

            sc.setExpandHorizontal(true);
            sc.setExpandVertical(true);

            sc.setMinSize(640, 480);

            GridLayout layout = new GridLayout();
            layout.numColumns = 2;
            layout.makeColumnsEqualWidth = false;
            panel.setLayout(layout);
            panel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1));

            // Sort by property name
            Configuration config = location.getConfiguration();
            SortedMap<String, String> map = new TreeMap<String, String>();
            Iterator<Entry<String, String>> it = config.iterator();
            while (it.hasNext()) {
                Entry<String, String> entry = it.next();
                map.put(entry.getKey(), entry.getValue());
            }

            for (Entry<String, String> entry : map.entrySet()) {
                Text text = createConfNameEditor(this, panel, entry.getKey(), null);
                textMap.put(entry.getKey(), text);
            }

            sc.setMinSize(panel.computeSize(SWT.DEFAULT, SWT.DEFAULT));

            return sc;
        }

        public void notifyChange(ConfProp prop, final String propValue) {
            Text text = textMap.get(prop.name);
            text.setText(propValue);
        }

        public void modifyText(ModifyEvent e) {
            final Text text = (Text) e.widget;
            Object hProp = text.getData("hProp");
            final ConfProp prop = (hProp != null) ? (ConfProp) hProp : null;
            Object hPropName = text.getData("hPropName");
            final String propName = (hPropName != null) ? (String) hPropName : null;

            Display.getDefault().syncExec(new Runnable() {
                public void run() {
                    if (prop != null)
                        mediator.notifyChange(TabAdvanced.this, prop, text.getText());
                    else
                        mediator.notifyChange(TabAdvanced.this, propName, text.getText());
                }
            });
        }
    }

}