org.ow2.proactive_grid_cloud_portal.common.client.LoginPage.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive_grid_cloud_portal.common.client.LoginPage.java

Source

/*
 * ################################################################
 *
 * ProActive Parallel Suite(TM): The Java(TM) library for
 *    Parallel, Distributed, Multi-Core Computing for
 *    Enterprise Grids & Clouds
 *
 * Copyright (C) 1997-2015 INRIA/University of
 *                 Nice-Sophia Antipolis/ActiveEon
 * Contact: proactive@ow2.org or contact@activeeon.com
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; version 3 of
 * the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 *
 *  Initial developer(s):               The ProActive Team
 *                        http://proactive.inria.fr/team_members.htm
 *  Contributor(s):
 *
 * ################################################################
 * $$PROACTIVE_INITIAL_DEV$$
 */
package org.ow2.proactive_grid_cloud_portal.common.client;

import org.ow2.proactive_grid_cloud_portal.common.client.json.JSONUtils;
import org.ow2.proactive_grid_cloud_portal.common.shared.Config;

import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.AnimationEffect;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.AnimationCallback;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.DrawEvent;
import com.smartgwt.client.widgets.events.DrawHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.events.ItemKeyPressEvent;
import com.smartgwt.client.widgets.form.events.ItemKeyPressHandler;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.PasswordItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.form.validator.CustomValidator;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.layout.VLayout;

/**
 * Page shown when the user is not logged in
 * <p>
 * Allows plain and credentials authentication through a specific servlet
 * 
 * 
 * @author mschnoor
 *
 */
public class LoginPage {

    /** root layout: parent to all widgets of this view */
    private Layout layout = null;

    private Controller controller;

    /** credential/plain auth */
    private DynamicForm authTypeSelectForm = null;

    // some ui fields kept global for convenience
    private HLayout authSelLayout = null;
    private Label optsLabel = null;
    private Runnable switchPlainCredForm = null;
    private Label motdLabel = null;
    private Canvas motdMargin = null;
    private HLayout motdCanvas = null;

    /** true before the page is rendered for the first time,
     * used to hack the apparition of the sshkey upload form */
    private boolean disableFormWrapper = true;

    /** displays error messages when login fails */
    private Label errorLabel = null;

    /**
     * Default constructor
     *
     * @param controller Controller that created this page
     * @param initialErrorMessage error message to display at the creation of the page, or null
     */
    public LoginPage(Controller controller, String initialErrorMessage) {
        this.controller = controller;
        buildAndShow();

        if (initialErrorMessage != null && initialErrorMessage.length() > 0) {
            errorLabel.setContents("<span style='color:red;'>" + initialErrorMessage + "</span>");
            errorLabel.animateShow(AnimationEffect.FLY);
        }
    }

    /**
     * Creates the layout and add it to the page
     */
    private void buildAndShow() {

        Img logo = new Img(controller.getLogo350Url(), 349, 75);

        // contains the forms for authentication
        final VLayout auth = new VLayout();
        auth.setBackgroundColor("#f0f0f0");
        auth.setBorder("1px solid #ccc");
        auth.setWidth(350);
        auth.setHeight(140);
        auth.setAlign(VerticalAlignment.CENTER);
        auth.setPadding(10);

        authSelLayout = new HLayout();
        authSelLayout.setAlign(Alignment.CENTER);
        //authSel.setMargin(5);
        authSelLayout.setWidth100();
        authSelLayout.setHeight(20);

        final SelectItem sl = new SelectItem("Mode");
        sl.setValueMap("Basic", "Credentials");
        sl.setValue("Basic");
        authTypeSelectForm = new DynamicForm();
        authTypeSelectForm.setNumCols(1);
        authTypeSelectForm.setFields(sl);
        authSelLayout.addMember(authTypeSelectForm);
        authSelLayout.setVisible(false);

        optsLabel = new Label(
                "<nobr style='color:#003168;font-size: 1.2em;cursor:pointer'>" + "more options</nobr>");
        optsLabel.setHeight(30);
        optsLabel.setIcon(Images.instance.expand_16().getSafeUri().asString());
        optsLabel.setAlign(Alignment.RIGHT);
        optsLabel.setValign(VerticalAlignment.TOP);
        optsLabel.setWidth100();

        final Layout plainLayout = getPlainAuth();
        final Layout credLayout = getCredAuth();
        credLayout.hide();

        Label label = new Label("<nobr style='color:#003168;font-size:1.2em;'><strong>"
                + Config.get().getApplicationName() + "</strong> login</nobr>");
        label.setHeight(30);
        label.setValign(VerticalAlignment.TOP);

        Canvas filler = new Canvas();
        filler.setWidth100();

        HLayout labelLayout = new HLayout();
        labelLayout.setWidth100();
        labelLayout.setHeight(30);
        labelLayout.setMembers(label, optsLabel);

        motdCanvas = new HLayout();
        motdCanvas.setPadding(5);
        motdCanvas.setMembersMargin(5);
        //motdCanvas.setBackgroundColor("#ddd");

        Img img = new Img(Images.instance.info_32().getSafeUri().asString(), 32, 32);
        img.setLayoutAlign(Alignment.CENTER);

        motdLabel = new Label("wait");
        motdLabel.setBackgroundColor("#e8e8e8");
        motdLabel.setWidth100();

        motdCanvas.addMember(img);
        //motdCanvas.addMember(separator);
        motdCanvas.addMember(motdLabel);

        motdMargin = new Canvas();
        motdMargin.setHeight(10);

        motdCanvas.setVisible(false);
        motdMargin.setVisible(false);

        auth.addMember(motdCanvas);
        auth.addMember(motdMargin);

        String motdUrl = URL.encode(GWT.getModuleBaseURL() + "motd");
        RequestBuilder rqb = new RequestBuilder(RequestBuilder.GET, motdUrl);
        try {
            rqb.sendRequest(null, new RequestCallback() {
                @Override
                public void onResponseReceived(Request request, Response response) {
                    String content;
                    if (response.getStatusCode() == 200) {
                        content = response.getText();
                        if (content.trim().length() == 0) {
                            return;
                        }
                    } else if (response.getStatusCode() == 0) {
                        return;
                    } else {
                        content = "Failed to get MOTD (" + response.getStatusCode() + " " + response.getStatusText()
                                + ")";
                    }
                    motdLabel.setContents(
                            "<div style='color:#003168;font-size: 1.2em;border-left:5px solid #ccc;padding-left:5px'>"
                                    + content + "</div>");
                    motdCanvas.setVisible(true);
                    motdMargin.setVisible(true);

                }

                @Override
                public void onError(Request request, Throwable exception) {
                    System.out.println(exception);
                }
            });
        } catch (RequestException e) {
            // not much we can do here...
            // not really important enough to display a trace on screen
        }

        auth.addMember(labelLayout);
        auth.addMember(authSelLayout);
        auth.addMember(plainLayout);
        auth.addMember(credLayout);

        switchPlainCredForm = new Runnable() {
            @Override
            public void run() {
                if (sl.getValueAsString().equals("Basic")) {
                    plainLayout.animateShow(AnimationEffect.FLY);
                    credLayout.animateHide(AnimationEffect.FLY);
                } else {
                    credLayout.animateShow(AnimationEffect.FLY);
                    plainLayout.animateHide(AnimationEffect.FLY);
                }
            }
        };

        sl.addChangedHandler(new ChangedHandler() {
            public void onChanged(ChangedEvent event) {
                switchPlainCredForm.run();
            }
        });

        this.errorLabel = new Label();
        errorLabel.setBorder("1px solid red");
        errorLabel.setBackgroundColor("#fff0f0");
        //errorLabel.setMargin(5);
        errorLabel.setPadding(5);
        errorLabel.setHeight(30);
        errorLabel.setAlign(Alignment.CENTER);

        // contains the logo and the forms
        VLayout vlayout = new VLayout();
        vlayout.setMembersMargin(15);
        // 350(auth) + 2*10(padding) = 370
        vlayout.setWidth(370);
        // 140(auth) + 15(membersMargin) + 88(logo) + 2*10(padding) = 263
        vlayout.setHeight(263);
        vlayout.setPadding(10);
        vlayout.setBackgroundColor("#fafafa");
        vlayout.setBorder("1px solid #ccc");
        vlayout.setShowShadow(true);
        vlayout.setShadowSoftness(8);
        vlayout.setShadowOffset(3);

        vlayout.addMember(logo);
        vlayout.addMember(errorLabel);
        vlayout.addMember(auth);

        vlayout.hideMember(errorLabel);

        // dummy box for horizontal centering
        HLayout hlayout = new HLayout();
        hlayout.setWidth100();
        hlayout.setHeight(263);
        hlayout.setAlign(Alignment.CENTER);
        hlayout.addMember(vlayout);

        // dummy box for vertical centering
        this.layout = new VLayout();
        this.layout.setHeight100();
        this.layout.setWidth100();
        this.layout.setAlign(VerticalAlignment.CENTER);
        this.layout.addMember(hlayout);
        this.layout.draw();
    }

    /**
     * @return the forms and widgets for plain login/password authentication
     */
    private Layout getPlainAuth() {

        /* smartGWT forms don't allow simple multipart file upload,
         * so we use a smartGWT form for login/password/checkbox,
         * a pure GWT form for file upload, and upon submission,
         * put the fields from the first form as hidden fields of the
         * pure GWT form. It's a bit convoluted but like this we get
         * the pretty widgets and the nice features       */

        TextItem loginField = new TextItem("login", "User");
        loginField.setRequired(true);

        PasswordItem passwordField = new PasswordItem("password", "Password");
        passwordField.setRequired(true);

        final CheckboxItem moreField = new CheckboxItem("useSSH", "Use SSH private key");
        moreField.setValue(false);

        // smartGWT form: only used to input the data before filling the hidden fields
        // in the other form with it
        final DynamicForm form = new DynamicForm();
        form.setFields(loginField, passwordField, moreField);
        form.hideItem("useSSH");

        // pure GWT form for uploading, will be used to contact the servlet
        // even if no ssh key is used
        final FileUpload fileUpload = new FileUpload();
        fileUpload.setName("sshkey");
        final Hidden hiddenUser = new Hidden("username");
        final Hidden hiddenPass = new Hidden("password");
        final FormPanel formPanel = new FormPanel();
        formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
        formPanel.setMethod(FormPanel.METHOD_POST);
        formPanel.setAction(GWT.getModuleBaseURL() + "login");
        final VerticalPanel vpan = new VerticalPanel();
        vpan.add(hiddenUser);
        vpan.add(hiddenPass);
        vpan.add(fileUpload);
        formPanel.setWidget(vpan);
        formPanel.setWidth("100%");
        formPanel.setHeight("30px");
        final HLayout formWrapper = new HLayout();
        formWrapper.setAlign(Alignment.CENTER);
        formWrapper.addChild(formPanel);
        formWrapper.setWidth100();
        formWrapper.addDrawHandler(new DrawHandler() {
            public void onDraw(DrawEvent event) {
                // took me half a day to find this hack:
                // if the form is added to the page in a hidden element,
                // it is never created and submission fails without callback.
                // it needs to be visible so that it is created once, then
                // we can safely hide it and still use it
                if (disableFormWrapper) {
                    disableFormWrapper = false;
                    formWrapper.setVisible(false);
                }
            }
        });

        // hide/show the ssh key upload input
        moreField.addChangedHandler(new ChangedHandler() {
            public void onChanged(ChangedEvent event) {
                if (moreField.getValueAsBoolean()) {
                    //formWrapper.setVisible(true);
                    formWrapper.animateShow(AnimationEffect.FLY);
                } else {
                    //formWrapper.setVisible(false);
                    formWrapper.animateHide(AnimationEffect.FLY);
                    formPanel.reset();
                }
            }
        });
        // prevent form validation if no ssh key is selected
        Validator moreVal = new CustomValidator() {
            @Override
            protected boolean condition(Object value) {
                if (moreField.getValueAsBoolean()) {
                    String file = fileUpload.getFilename();
                    return (file != null && file.length() > 0);
                } else {
                    return true;
                }
            }
        };
        moreVal.setErrorMessage("No file selected");
        moreField.setValidators(moreVal);

        final Runnable advancedVisibilityChanged = new Runnable() {
            @Override
            public void run() {
                if (!moreField.getVisible()) {
                    authSelLayout.setVisible(true);
                    form.showItem("useSSH");
                    optsLabel.setIcon(Images.instance.close_16().getSafeUri().asString());
                    optsLabel.setContents(
                            "<nobr style='color:#003168;font-size: 1.2em;" + "cursor:pointer'>less options</nobr>");
                } else {
                    authTypeSelectForm.setValue("Mode", "Basic");
                    switchPlainCredForm.run();
                    authSelLayout.setVisible(false);
                    form.hideItem("useSSH");
                    formWrapper.animateHide(AnimationEffect.FLY);
                    moreField.setValue(false);
                    formPanel.reset();
                    optsLabel.setIcon(Images.instance.expand_16().getSafeUri().asString());
                    optsLabel.setContents(
                            "<nobr style='color:#003168;font-size: 1.2em;" + "cursor:pointer'>more options</nobr>");
                }
            }
        };
        optsLabel.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                advancedVisibilityChanged.run();
            }
        });

        String cacheLogin = Settings.get().getSetting(controller.getLoginSettingKey());
        if (cacheLogin != null) {
            form.setValue("login", cacheLogin);
        }

        final IButton okButton = new IButton();
        okButton.setShowDisabled(false);
        okButton.setIcon(Images.instance.connect_16().getSafeUri().asString());
        okButton.setTitle("Connect");
        okButton.setWidth(120);
        okButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (!form.validate())
                    return;

                String login = form.getValueAsString("login");
                String pw = form.getValueAsString("password");
                hiddenUser.setValue(login);
                hiddenPass.setValue(pw);

                okButton.setIcon("loading.gif");
                okButton.setTitle("Connecting...");
                form.disable();
                formWrapper.disable();

                authTypeSelectForm.disable();
                okButton.disable();

                // only submit once the the error message is hidden so we don't try to show it (on form response)
                // while the effect is played resulting in the message hidden staying hidden
                if (errorLabel.isDrawn() && errorLabel.isVisible()) {
                    errorLabel.animateHide(AnimationEffect.FLY, new AnimationCallback() {
                        @Override
                        public void execute(boolean earlyFinish) {
                            formPanel.submit();
                        }
                    });
                } else {
                    formPanel.submit();
                }
            }
        });

        formPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
            public void onSubmitComplete(SubmitCompleteEvent event) {
                String res = new HTML(event.getResults()).getText();
                boolean fail = false;
                try {
                    JSONValue val = controller.parseJSON(res);
                    JSONObject obj = val.isObject();
                    if (obj != null && obj.containsKey("sessionId")) {
                        String sess = obj.isObject().get("sessionId").isString().stringValue();
                        controller.login(sess, form.getValueAsString("login"));
                    } else {
                        fail = true;
                    }
                } catch (Throwable t) {
                    fail = true;
                }

                if (fail) {
                    String err = JSONUtils.getJsonErrorMessage(res);
                    int sta = JSONUtils.getJsonErrorCode(res);
                    if (sta != -1)
                        err += " (" + sta + ")";
                    errorLabel.setContents("<span style='color:red;'>Could not login: " + err + "</span>");
                    errorLabel.animateShow(AnimationEffect.FLY);

                    okButton.setIcon(Images.instance.connect_16().getSafeUri().asString());
                    okButton.setTitle("Connect");
                    formWrapper.enable();
                    form.enable();
                    authTypeSelectForm.enable();
                    okButton.enable();
                }
            }
        });

        form.addItemKeyPressHandler(new ItemKeyPressHandler() {
            public void onItemKeyPress(ItemKeyPressEvent event) {
                if ("Enter".equals(event.getKeyName())) {
                    okButton.fireEvent(new ClickEvent(null));
                }
            }
        });

        Layout formLayout = new VLayout();
        formLayout.setWidth100();
        formLayout.setMembersMargin(10);
        formLayout.addMember(form);
        formLayout.addMember(formWrapper);

        HLayout buttonBar = new HLayout();
        buttonBar.setWidth100();
        buttonBar.setAlign(Alignment.CENTER);
        buttonBar.addMember(okButton);
        formLayout.addMember(buttonBar);

        return formLayout;
    }

    /**
     * @return the forms and widgets for credentials authentication
     */
    private Layout getCredAuth() {
        final FileUpload fileUpload = new FileUpload();
        fileUpload.setName("credential");

        // actual form      
        final FormPanel formPanel = new FormPanel();
        formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
        formPanel.setMethod(FormPanel.METHOD_POST);
        formPanel.setAction(GWT.getModuleBaseURL() + "login");
        formPanel.add(fileUpload);
        formPanel.setWidth("100%");
        formPanel.setHeight("30px");

        // wraps the GWT component so that we may show/hide it
        final VLayout formWrapper = new VLayout();
        formWrapper.setAlign(Alignment.CENTER);
        formWrapper.addMember(formPanel);
        formWrapper.setWidth100();
        formWrapper.setMargin(10);

        final IButton okButton = new IButton();
        okButton.setShowDisabled(false);
        okButton.setIcon(Images.instance.connect_16().getSafeUri().asString());
        okButton.setTitle("Connect");
        okButton.setWidth(120);
        okButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                errorLabel.animateHide(AnimationEffect.FLY);

                okButton.setIcon("loading.gif");
                okButton.setTitle("Connecting...");
                formWrapper.disable();
                authTypeSelectForm.disable();
                okButton.disable();

                // submits the form to LoginServlet
                formPanel.submit();
            }
        });

        formPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
            public void onSubmitComplete(SubmitCompleteEvent event) {
                String res = event.getResults();
                boolean fail = false;
                try {
                    JSONValue val = controller.parseJSON(res);
                    JSONObject obj = val.isObject();
                    if (obj != null && obj.containsKey("sessionId")) {
                        String sess = obj.isObject().get("sessionId").isString().stringValue();
                        controller.login(sess, null);
                    } else {
                        fail = true;
                    }
                } catch (Throwable t) {
                    fail = true;
                }

                if (fail) {
                    String err = JSONUtils.getJsonErrorMessage(res);
                    errorLabel.setContents("<span style='color:red;'>Could not login: " + err + "</span>");
                    errorLabel.animateShow(AnimationEffect.FLY);

                    okButton.setIcon(Images.instance.connect_16().getSafeUri().asString());
                    okButton.setTitle("Connect");
                    formWrapper.enable();
                    authTypeSelectForm.enable();
                    okButton.enable();
                }
            }
        });
        Label createCred = new Label(
                "<nobr style='color:#003168;font-size: 1.2em;cursor:pointer'>" + "Create credentials</nobr>");
        createCred.setHeight(20);
        createCred.setAlign(Alignment.CENTER);
        createCred.setIcon(Images.instance.key_16().getSafeUri().asString());
        createCred.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                CredentialsWindow win = new CredentialsWindow();
                win.show();
            }
        });

        formWrapper.addMember(createCred);

        Layout formLayout = new VLayout();
        formLayout.setWidth100();
        formLayout.setMembersMargin(10);
        formLayout.addMember(formWrapper);

        HLayout buttonBar = new HLayout();
        buttonBar.setWidth100();
        buttonBar.setAlign(Alignment.CENTER);
        buttonBar.addMember(okButton);
        formLayout.addMember(buttonBar);

        return formLayout;
    }

    /**
     * Removes the layout and widgets from the page
     * Call this when the view should be definitely removed and GC's, else just hide() it
     */
    public void destroy() {
        this.layout.destroy();
        this.layout = null;
        this.controller = null;
    }
}