/*
* Copyright 2000-2013 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.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.vaadin.server.ConnectorResource;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServletService;
import com.vaadin.shared.ApplicationConstants;
/**
* LoginForm is a Vaadin component to handle common problem among Ajax
* applications: browsers password managers don't fill dynamically created forms
* like all those UI elements created by Vaadin.
*
* For developer it is easy to use: add component to a desired place in you UI
* and add LoginListener to validate form input. Behind the curtain LoginForm
* creates an iframe with static html that browsers detect.
*
* Login form is by default 100% width and height, so consider using it inside a
* sized {@link Panel} or {@link Window}.
*
* Login page html can be overridden by replacing protected getLoginHTML method.
* As the login page is actually an iframe, styles must be handled manually. By
* default component tries to guess the right place for theme css.
*
* @since 5.3
* @deprecated As of 7.0. This component no longer fulfills its duty reliably in
* the supported browsers and a {@link VerticalLayout} with two
* {@link TextField}s can be used instead.
*/
@Deprecated
public class LoginForm extends CustomComponent {
private String usernameCaption = "Username";
private String passwordCaption = "Password";
private String loginButtonCaption = "Login";
private Embedded iframe = new Embedded();
@Override
public boolean handleConnectorRequest(final VaadinRequest request,
final VaadinResponse response, String path) throws IOException {
if (!path.equals("login")) {
return super.handleConnectorRequest(request, response, path);
}
final StringBuilder responseBuilder = new StringBuilder();
getUI().accessSynchronously(new Runnable() {
@Override
public void run() {
String method = VaadinServletService.getCurrentServletRequest()
.getMethod();
if (method.equalsIgnoreCase("post")) {
responseBuilder.append(handleLogin(request));
} else {
responseBuilder.append(getLoginHTML());
}
}
});
if (responseBuilder.length() > 0) {
response.setContentType("text/html; charset=utf-8");
response.setCacheTime(-1);
response.getWriter().write(responseBuilder.toString());
return true;
} else {
return false;
}
}
private String handleLogin(VaadinRequest request) {
// Ensure UI.getCurrent() works in listeners
Map parameters = VaadinService.getCurrentRequest()
.getParameterMap();
HashMap params = new HashMap();
// expecting single params
for (Iterator it = parameters.keySet().iterator(); it.hasNext();) {
String key = it.next();
String value = (parameters.get(key))[0];
params.put(key, value);
}
LoginEvent event = new LoginEvent(LoginForm.this, params);
fireEvent(event);
return "Login form handled."
+ "";
}
public LoginForm() {
iframe.setType(Embedded.TYPE_BROWSER);
iframe.setSizeFull();
setSizeFull();
setCompositionRoot(iframe);
addStyleName("v-loginform");
}
@Override
public void beforeClientResponse(boolean initial) {
// Generate magic URL now when UI id and connectorId are known
iframe.setSource(new ExternalResource(
ApplicationConstants.APP_PROTOCOL_PREFIX
+ ApplicationConstants.APP_PATH + '/'
+ ConnectorResource.CONNECTOR_PATH + '/'
+ getUI().getUIId() + '/' + getConnectorId() + "/login"));
super.beforeClientResponse(initial);
}
/**
* Returns byte array containing login page html. If you need to override
* the login html, use the default html as basis. Login page sets its target
* with javascript.
*
* @return byte array containing login page html
*/
protected String getLoginHTML() {
return "\n"
+ ""
+ ""
+ ""
+ "" + "";
}
private String getUIThemeClassName() {
if (getUI() != null) {
return getUI().getTheme();
}
return "";
}
/**
* This event is sent when login form is submitted.
*/
public static class LoginEvent extends Event {
private Map params;
private LoginEvent(Component source, Map params) {
super(source);
this.params = params;
}
/**
* Access method to form values by field names.
*
* @param name
* @return value in given field
*/
public String getLoginParameter(String name) {
if (params.containsKey(name)) {
return params.get(name);
} else {
return null;
}
}
}
/**
* Login listener is a class capable to listen LoginEvents sent from
* LoginBox
*/
public interface LoginListener extends Serializable {
/**
* This method is fired on each login form post.
*
* @param event
*/
public void onLogin(LoginForm.LoginEvent event);
}
private static final Method ON_LOGIN_METHOD;
private static final String UNDEFINED_HEIGHT = "140px";
private static final String UNDEFINED_WIDTH = "200px";
static {
try {
ON_LOGIN_METHOD = LoginListener.class.getDeclaredMethod("onLogin",
new Class[] { LoginEvent.class });
} catch (final java.lang.NoSuchMethodException e) {
// This should never happen
throw new java.lang.RuntimeException(
"Internal error finding methods in LoginForm");
}
}
/**
* Adds LoginListener to handle login logic
*
* @param listener
*/
public void addLoginListener(LoginListener listener) {
addListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
}
/**
* @deprecated As of 7.0, replaced by
* {@link #addLoginListener(LoginListener)}
**/
@Deprecated
public void addListener(LoginListener listener) {
addLoginListener(listener);
}
/**
* Removes LoginListener
*
* @param listener
*/
public void removeLoginListener(LoginListener listener) {
removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
}
/**
* @deprecated As of 7.0, replaced by
* {@link #removeLoginListener(LoginListener)}
**/
@Deprecated
public void removeListener(LoginListener listener) {
removeLoginListener(listener);
}
@Override
public void setWidth(float width, Unit unit) {
super.setWidth(width, unit);
if (iframe != null) {
if (width < 0) {
iframe.setWidth(UNDEFINED_WIDTH);
} else {
iframe.setWidth("100%");
}
}
}
@Override
public void setHeight(float height, Unit unit) {
super.setHeight(height, unit);
if (iframe != null) {
if (height < 0) {
iframe.setHeight(UNDEFINED_HEIGHT);
} else {
iframe.setHeight("100%");
}
}
}
/**
* Returns the caption for the user name field.
*
* @return String
*/
public String getUsernameCaption() {
return usernameCaption;
}
/**
* Sets the caption to show for the user name field. The caption cannot be
* changed after the form has been shown to the user.
*
* @param usernameCaption
*/
public void setUsernameCaption(String usernameCaption) {
this.usernameCaption = usernameCaption;
}
/**
* Returns the caption for the password field.
*
* @return String
*/
public String getPasswordCaption() {
return passwordCaption;
}
/**
* Sets the caption to show for the password field. The caption cannot be
* changed after the form has been shown to the user.
*
* @param passwordCaption
*/
public void setPasswordCaption(String passwordCaption) {
this.passwordCaption = passwordCaption;
}
/**
* Returns the caption for the login button.
*
* @return String
*/
public String getLoginButtonCaption() {
return loginButtonCaption;
}
/**
* Sets the caption (button text) to show for the login button. The caption
* cannot be changed after the form has been shown to the user.
*
* @param loginButtonCaption
*/
public void setLoginButtonCaption(String loginButtonCaption) {
this.loginButtonCaption = loginButtonCaption;
}
}