com.vaadin.ui.LoginForm.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.ui.LoginForm.java

Source

/*
 * Copyright 2000-2018 Vaadin Ltd.
 *
 * Licensed 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 com.vaadin.ui;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import com.vaadin.server.StreamResource;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.loginform.LoginFormConstants;
import com.vaadin.shared.ui.loginform.LoginFormRpc;
import com.vaadin.shared.ui.loginform.LoginFormState;
import com.vaadin.util.ReflectTools;

/**
 * Login form with auto-completion and auto-fill for all major browsers. You can
 * derive from this class and implement the
 * {@link #createContent(com.vaadin.ui.TextField, com.vaadin.ui.PasswordField, com.vaadin.ui.Button)}
 * method to build the layout using the text fields and login button that are
 * passed to that method. The supplied components are specially treated so that
 * they work with password managers.
 * <p>
 * To customize the fields or to replace them with your own implementations, you
 * can override {@link #createUsernameField()}, {@link #createPasswordField()}
 * and {@link #createLoginButton()}. These methods are called automatically and
 * cannot be called by your code. Captions can be reset by overriding
 * {@link #getUsernameCaption()}, {@link #getPasswordCaption()} and
 * {@link #getLoginButtonCaption()}.
 * <p>
 * Note that the API of LoginForm changed significantly in Vaadin 7.7.
 *
 * @since 5.3
 */
public class LoginForm extends AbstractSingleComponentContainer {

    /**
     * Event sent when the login form is submitted.
     */
    public static class LoginEvent extends Component.Event {

        private final Map<String, String> params;

        /**
         * Creates a login event using the given source and the given
         * parameters.
         *
         * @param source
         *            the source of the event
         * @param params
         */
        private LoginEvent(LoginForm source, Map<String, String> params) {
            super(source);
            this.params = params;
        }

        @Override
        public LoginForm getSource() {
            return (LoginForm) super.getSource();
        }

        /**
         * Gets the login parameter with the given name.
         *
         * @param name
         *            the name of the parameter
         * @return the value of the parameter or null if no such parameter is
         *         present
         */
        public String getLoginParameter(String name) {
            return params.get(name);
        }
    }

    /**
     * Listener triggered when a login occurs in a {@link LoginForm}.
     */
    @FunctionalInterface
    public interface LoginListener extends Serializable {
        /**
         * Event method invoked when the login button is pressed in a login
         * form.
         *
         * @param event
         *            the login event
         */
        public void onLogin(LoginEvent event);
    }

    /**
     * Internal stream source for the login URL - always returns "Success" and
     * ignores the values received.
     */
    private static class LoginStreamSource implements StreamResource.StreamSource {
        @Override
        public InputStream getStream() {
            return new ByteArrayInputStream("<html>Success</html>".getBytes(StandardCharsets.UTF_8));
        }
    }

    private static final Method ON_LOGIN_METHOD = ReflectTools.findMethod(LoginListener.class, "onLogin",
            LoginEvent.class);

    private boolean initialized;

    private String usernameCaption = "Username";
    private String passwordCaption = "Password";
    private String loginButtonCaption = "Login";

    /**
     * Customize the user name field. Only for overriding, do not call.
     *
     * @return the user name field
     * @since 7.7
     */
    protected TextField createUsernameField() {
        throwIfInitialized();
        TextField field = new TextField(getUsernameCaption());
        field.focus();
        return field;
    }

    /**
     * Gets the caption set with {@link #setUsernameCaption(String)}. Note that
     * this method might not match what is shown to the user if
     * {@link #createUsernameField()} has been overridden.
     *
     * @return the user name field caption
     */
    public String getUsernameCaption() {
        return usernameCaption;
    }

    /**
     * Sets the caption of the user name field. Note that the caption can only
     * be set with this method before the login form has been initialized
     * (attached).
     * <p>
     * As an alternative to calling this method, the method
     * {@link #createUsernameField()} can be overridden.
     *
     * @param usernameCaption
     *            the caption to set for the user name field
     */
    public void setUsernameCaption(String usernameCaption) {
        this.usernameCaption = usernameCaption;
    }

    /**
     * Customize the password field. Only for overriding, do not call.
     *
     * @return the password field
     * @since 7.7
     */
    protected PasswordField createPasswordField() {
        throwIfInitialized();
        return new PasswordField(getPasswordCaption());
    }

    /**
     * Gets the caption set with {@link #setPasswordCaption(String)}. Note that
     * this method might not match what is shown to the user if
     * {@link #createPasswordField()} has been overridden.
     *
     *
     * @return the password field caption
     */
    public String getPasswordCaption() {
        return passwordCaption;
    }

    /**
     * Set the caption of the password field. Note that the caption can only be
     * set with this method before the login form has been initialized
     * (attached).
     * <p>
     * As an alternative to calling this method, the method
     * {@link #createPasswordField()} can be overridden.
     *
     * @param passwordCaption
     *            the caption for the password field
     */
    public void setPasswordCaption(String passwordCaption) {
        this.passwordCaption = passwordCaption;
    }

    /**
     * Customize the login button. Only for overriding, do not call.
     *
     * @return the login button
     * @since 7.7
     */
    protected Button createLoginButton() {
        throwIfInitialized();
        return new Button(getLoginButtonCaption());
    }

    /**
     * Gets the caption set with {@link #setLoginButtonCaption(String)}. Note
     * that this method might not match what is shown to the user if
     * {@link #createLoginButton()} has been overridden.
     *
     * @return the login button caption
     */
    public String getLoginButtonCaption() {
        return loginButtonCaption;
    }

    /**
     * Sets the caption of the login button. Note that the caption can only be
     * set with this method before the login form has been initialized
     * (attached).
     * <p>
     * As an alternative to calling this method, the method
     * {@link #createLoginButton()} can be overridden.
     *
     * @param loginButtonCaption
     *            new caption
     */
    public void setLoginButtonCaption(String loginButtonCaption) {
        this.loginButtonCaption = loginButtonCaption;
    }

    @Override
    protected LoginFormState getState() {
        return (LoginFormState) super.getState();
    }

    @Override
    protected LoginFormState getState(boolean markAsDirty) {
        return (LoginFormState) super.getState(markAsDirty);
    }

    @Override
    public void attach() {
        super.attach();
        init();
    }

    private void throwIfInitialized() {
        if (initialized) {
            throw new IllegalStateException(
                    "Already initialized. The create methods may not be called explicitly.");
        }
    }

    /**
     * Create the content for the login form with the supplied user name field,
     * password field and the login button. You cannot use any other text fields
     * or buttons for this purpose. To replace these components with your own
     * implementations, override {@link #createUsernameField()},
     * {@link #createPasswordField()} and {@link #createLoginButton()}. If you
     * only want to change the default captions, override
     * {@link #getUsernameCaption()}, {@link #getPasswordCaption()} and
     * {@link #getLoginButtonCaption()}. You do not have to use the login button
     * in your layout.
     *
     * @param userNameField
     *            the user name text field
     * @param passwordField
     *            the password field
     * @param loginButton
     *            the login button
     * @return content component
     * @since 7.7
     */
    protected Component createContent(TextField userNameField, PasswordField passwordField, Button loginButton) {
        VerticalLayout layout = new VerticalLayout();
        layout.setSpacing(true);
        layout.setMargin(true);
        layout.addComponent(userNameField);
        layout.addComponent(passwordField);
        layout.addComponent(loginButton);
        return layout;
    }

    private void init() {
        if (initialized) {
            return;
        }

        LoginFormState state = getState();
        state.userNameFieldConnector = createUsernameField();
        state.passwordFieldConnector = createPasswordField();
        state.loginButtonConnector = createLoginButton();

        StreamResource resource = new StreamResource(new LoginStreamSource(),
                LoginFormConstants.LOGIN_RESOURCE_NAME);
        resource.setMIMEType(ApplicationConstants.CONTENT_TYPE_TEXT_HTML_UTF_8);
        resource.setCacheTime(-1);
        setResource(LoginFormConstants.LOGIN_RESOURCE_NAME, resource);

        registerRpc((LoginFormRpc) this::login);

        initialized = true;

        setContent(createContent(getUsernameField(), getPasswordField(), getLoginButton()));
    }

    private TextField getUsernameField() {
        assert initialized;
        return (TextField) getState(false).userNameFieldConnector;
    }

    private PasswordField getPasswordField() {
        assert initialized;
        return (PasswordField) getState(false).passwordFieldConnector;
    }

    private Button getLoginButton() {
        assert initialized;
        return (Button) getState(false).loginButtonConnector;
    }

    /**
     * Handles the login.
     * <p>
     * In deferred mode, this method is called after the dummy POST request that
     * triggers the password manager has been completed. In direct mode (the
     * default setting), it is called directly when the user hits the enter key
     * or clicks on the login button. In the latter case, you cannot change the
     * URL in the method or the password manager will not be triggered.
     */
    private void login() {
        Map<String, String> params = new HashMap<>();
        params.put("username", getUsernameField().getValue());
        params.put("password", getPasswordField().getValue());
        LoginEvent event = new LoginEvent(LoginForm.this, params);
        fireEvent(event);
    }

    /**
     * Adds a {@link LoginListener}.
     * <p>
     * The listener is called when the user presses the login button.
     *
     * @param listener
     *            the listener to add
     * @return a registration object for removing the listener
     * @since 8.0
     */
    public Registration addLoginListener(LoginListener listener) {
        return addListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
    }

    /**
     * Removes a {@link LoginListener}.
     *
     * @param listener
     *            the listener to remove
     * @deprecated As of 8.0, replaced by {@link Registration#remove()} in the
     *             registration object returned from
     *             {@link #addLoginListener(LoginListener)}.
     */
    @Deprecated
    public void removeLoginListener(LoginListener listener) {
        removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
    }

}