mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-04 20:28:00 +08:00
PL-6104 Allow to login as anonymous
This commit is contained in:
parent
dbfcadbc28
commit
c27f7a85a6
@ -19,6 +19,7 @@ package com.haulmont.cuba.client;
|
||||
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.security.app.UserSessionService;
|
||||
import com.haulmont.cuba.security.global.ClientBasedSession;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -28,13 +29,14 @@ import java.util.TimeZone;
|
||||
/**
|
||||
* Client-side extension of {@link UserSession}.
|
||||
*
|
||||
* <p>Sends updates of the user session properties to the middleware.</p>
|
||||
*
|
||||
* <p>Sends updates of the user session properties to the middleware if authenticated.</p>
|
||||
*/
|
||||
public class ClientUserSession extends UserSession {
|
||||
public class ClientUserSession extends UserSession implements ClientBasedSession {
|
||||
|
||||
private static final long serialVersionUID = -5358664165808633540L;
|
||||
|
||||
protected volatile boolean authenticated = false; // indicates whether user passed authentication
|
||||
|
||||
public ClientUserSession(UserSession src) {
|
||||
super(src);
|
||||
}
|
||||
@ -42,35 +44,63 @@ public class ClientUserSession extends UserSession {
|
||||
@Override
|
||||
public void setAttribute(String name, Serializable value) {
|
||||
super.setAttribute(name, value);
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionAttribute(id, name, value);
|
||||
|
||||
if (authenticated) {
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionAttribute(id, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(Locale locale) {
|
||||
super.setLocale(locale);
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionLocale(id, locale);
|
||||
|
||||
if (authenticated) {
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionLocale(id, locale);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeZone(TimeZone timeZone) {
|
||||
super.setTimeZone(timeZone);
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionTimeZone(id, timeZone);
|
||||
|
||||
if (authenticated) {
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionTimeZone(id, timeZone);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddress(String address) {
|
||||
super.setAddress(address);
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionAddress(id, address);
|
||||
|
||||
if (authenticated) {
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionAddress(id, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(String clientInfo) {
|
||||
super.setClientInfo(clientInfo);
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionClientInfo(id, clientInfo);
|
||||
|
||||
if (authenticated) {
|
||||
UserSessionService uss = AppBeans.get(UserSessionService.NAME);
|
||||
uss.setSessionClientInfo(id, clientInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocaleRequestScoped() {
|
||||
return !authenticated;
|
||||
}
|
||||
}
|
@ -806,6 +806,10 @@ values ('60885987-1b61-4247-94c7-dff348347f93', current_timestamp, 0, 'admin', '
|
||||
'cc2229d1b8a052423d9e1c9ef0113b850086586a',
|
||||
'Administrator', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
|
||||
|
||||
insert into SEC_ROLE (ID, CREATE_TS, VERSION, NAME, ROLE_TYPE)
|
||||
values ('0c018061-b26f-4de2-a5be-dff348347f93', current_timestamp, 0, 'Administrators', 10)^
|
||||
|
||||
|
@ -854,6 +854,10 @@ values ('60885987-1b61-4247-94c7-dff348347f93', current_timestamp, 0, 'admin', '
|
||||
'cc2229d1b8a052423d9e1c9ef0113b850086586a',
|
||||
'Administrator', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', 1)^
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', current_timestamp, 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', 1)^
|
||||
|
||||
insert into SEC_ROLE (ID, CREATE_TS, VERSION, NAME, ROLE_TYPE)
|
||||
values ('0c018061-b26f-4de2-a5be-dff348347f93', current_timestamp, 0, 'Administrators', 10)^
|
||||
|
||||
|
@ -861,6 +861,10 @@ values ('608859871b61424794c7dff348347f93', current_timestamp, 0, 'admin', 'admi
|
||||
'cc2229d1b8a052423d9e1c9ef0113b850086586a',
|
||||
'Administrator', '0fa2b1a51d684d699fbddff348347f93', 1)^
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59e6744f638afe269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a51d684d699fbddff348347f93', true)^
|
||||
|
||||
insert into SEC_ROLE (ID, CREATE_TS, VERSION, NAME, ROLE_TYPE)
|
||||
values ('0c018061b26f4de2a5bedff348347f93', current_timestamp, 0, 'Administrators', 10)^
|
||||
|
||||
|
@ -740,6 +740,10 @@ values ('608859871b61424794c7dff348347f93', current_timestamp, 0, 'admin', 'admi
|
||||
'cc2229d1b8a052423d9e1c9ef0113b850086586a',
|
||||
'Administrator', '0fa2b1a51d684d699fbddff348347f93', 1)^
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59e6744f638afe269dda788fe8', current_timestamp, 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a51d684d699fbddff348347f93', 1)^
|
||||
|
||||
insert into SEC_ROLE (ID, CREATE_TS, VERSION, NAME, ROLE_TYPE)
|
||||
values ('0c018061b26f4de2a5bedff348347f93', current_timestamp, 0, 'Administrators', 10)^
|
||||
|
||||
|
@ -833,6 +833,10 @@ values ('60885987-1b61-4247-94c7-dff348347f93', now(), 0, 'admin', 'admin',
|
||||
'cc2229d1b8a052423d9e1c9ef0113b850086586a',
|
||||
'Administrator', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
|
||||
|
||||
insert into SEC_ROLE (ID, CREATE_TS, VERSION, NAME, ROLE_TYPE)
|
||||
values ('0c018061-b26f-4de2-a5be-dff348347f93', now(), 0, 'Administrators', 10)^
|
||||
|
||||
|
5
modules/core/db/update/hsql/16/160725-anonymousLogin.sql
Normal file
5
modules/core/db/update/hsql/16/160725-anonymousLogin.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- add anonymous user
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
|
@ -0,0 +1,5 @@
|
||||
-- add anonymous user
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', current_timestamp, 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', 1)^
|
@ -0,0 +1,5 @@
|
||||
-- add anonymous user
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59e6744f638afe269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a51d684d699fbddff348347f93', true)^
|
@ -0,0 +1,5 @@
|
||||
-- add anonymous user
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59e6744f638afe269dda788fe8', current_timestamp, 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a51d684d699fbddff348347f93', 1)^
|
@ -0,0 +1,5 @@
|
||||
-- add anonymous user
|
||||
|
||||
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
|
||||
values ('a405db59-e674-4f63-8afe-269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
|
||||
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true);
|
@ -24,7 +24,6 @@ import com.haulmont.cuba.core.config.defaults.*;
|
||||
|
||||
/**
|
||||
* Configuration parameters interface used by the CORE layer.
|
||||
*
|
||||
*/
|
||||
@Source(type = SourceType.APP)
|
||||
public interface ServerConfig extends Config {
|
||||
@ -193,4 +192,9 @@ public interface ServerConfig extends Config {
|
||||
@Source(type = SourceType.DATABASE)
|
||||
@DefaultInt(60)
|
||||
int getBruteForceBlockIntervalSec();
|
||||
}
|
||||
|
||||
@Property("cuba.anonymousLogin")
|
||||
@Source(type = SourceType.DATABASE)
|
||||
@Default("anonymous")
|
||||
String getAnonymousLogin();
|
||||
}
|
@ -19,8 +19,10 @@ package com.haulmont.cuba.core.sys.remoting;
|
||||
import com.haulmont.cuba.core.app.ServerConfig;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.core.sys.UserInvocationContext;
|
||||
import com.haulmont.cuba.security.app.LoginService;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.security.sys.UserSessionManager;
|
||||
@ -31,39 +33,43 @@ import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationExecutor;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Executes {@link CubaRemoteInvocation} on middleware, setting and clearing a {@link SecurityContext} in the request
|
||||
* handling thread.
|
||||
*
|
||||
*/
|
||||
public class CubaRemoteInvocationExecutor implements RemoteInvocationExecutor {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(CubaRemoteInvocationExecutor.class);
|
||||
private final Logger log = LoggerFactory.getLogger(CubaRemoteInvocationExecutor.class);
|
||||
|
||||
private UserSessionManager userSessionManager;
|
||||
|
||||
private volatile ClusterInvocationSupport clusterInvocationSupport;
|
||||
|
||||
private Configuration configuration;
|
||||
private GlobalConfig globalConfig;
|
||||
|
||||
public CubaRemoteInvocationExecutor() {
|
||||
userSessionManager = AppBeans.get("cuba_UserSessionManager");
|
||||
configuration = AppBeans.get(Configuration.NAME);
|
||||
globalConfig = configuration.getConfig(GlobalConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(RemoteInvocation invocation, Object targetObject)
|
||||
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
if (invocation instanceof CubaRemoteInvocation) {
|
||||
UUID sessionId = ((CubaRemoteInvocation) invocation).getSessionId();
|
||||
CubaRemoteInvocation cubaInvocation = (CubaRemoteInvocation) invocation;
|
||||
|
||||
UUID sessionId = cubaInvocation.getSessionId();
|
||||
if (sessionId != null) {
|
||||
UserSession session = userSessionManager.findSession(sessionId);
|
||||
if (session == null) {
|
||||
String sessionProviderUrl = configuration.getConfig(ServerConfig.class).getUserSessionProviderUrl();
|
||||
if (StringUtils.isNotBlank(sessionProviderUrl)) {
|
||||
log.debug("User session " + sessionId + " not found, trying to get it from " + sessionProviderUrl);
|
||||
log.debug("User session {} not found, trying to get it from {}", sessionId, sessionProviderUrl);
|
||||
try {
|
||||
HttpServiceProxy proxyFactory = new HttpServiceProxy(
|
||||
getClusterInvocationSupport(sessionProviderUrl));
|
||||
@ -76,19 +82,27 @@ public class CubaRemoteInvocationExecutor implements RemoteInvocationExecutor {
|
||||
if (userSession != null) {
|
||||
userSessionManager.storeSession(userSession);
|
||||
} else {
|
||||
log.debug("User session " + sessionId + " not found on " + sessionProviderUrl);
|
||||
log.debug("User session {} not found on {}", sessionId, sessionProviderUrl);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error getting user session from " + sessionProviderUrl, e);
|
||||
log.error("Error getting user session from {}", sessionProviderUrl, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppContext.setSecurityContext(new SecurityContext(sessionId));
|
||||
}
|
||||
|
||||
if (cubaInvocation.getLocale() != null) {
|
||||
Locale locale = Locale.forLanguageTag(cubaInvocation.getLocale());
|
||||
if (globalConfig.getAvailableLocales().containsValue(locale)) {
|
||||
UserInvocationContext.setRequestScopeLocale(sessionId, locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
Object result = invocation.invoke(targetObject);
|
||||
AppContext.setSecurityContext(null);
|
||||
UserInvocationContext.clearRequestScopeLocale();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,14 @@ package com.haulmont.cuba.core.sys.remoting;
|
||||
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.core.sys.UserInvocationContext;
|
||||
import com.haulmont.cuba.core.sys.serialization.SerializationSupport;
|
||||
import org.apache.commons.lang.ClassUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LocalServiceInvokerImpl implements LocalServiceInvoker {
|
||||
|
||||
@ -80,6 +82,11 @@ public class LocalServiceInvokerImpl implements LocalServiceInvoker {
|
||||
else
|
||||
AppContext.setSecurityContext(null);
|
||||
|
||||
if (invocation.getLocale() != null) {
|
||||
Locale locale = Locale.forLanguageTag(invocation.getLocale());
|
||||
UserInvocationContext.setRequestScopeLocale(invocation.getSessionId(), locale);
|
||||
}
|
||||
|
||||
Method method = target.getClass().getMethod(invocation.getMethodName(), parameterTypes);
|
||||
Object data = method.invoke(target, arguments);
|
||||
|
||||
@ -97,6 +104,7 @@ public class LocalServiceInvokerImpl implements LocalServiceInvoker {
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(clientClassLoader);
|
||||
AppContext.setSecurityContext(null);
|
||||
UserInvocationContext.clearRequestScopeLocale();
|
||||
}
|
||||
}
|
||||
}
|
@ -94,6 +94,14 @@ public interface LoginWorker {
|
||||
*/
|
||||
UserSession loginSystem(String login) throws LoginException;
|
||||
|
||||
/**
|
||||
* Login anonymous session for trusted clients
|
||||
*
|
||||
* @return anonymous user session that is not replicated in cluster
|
||||
* @throws LoginException
|
||||
*/
|
||||
UserSession loginAnonymous() throws LoginException;
|
||||
|
||||
/**
|
||||
* @see com.haulmont.cuba.security.app.LoginService#checkRememberMe(String, String)
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
|
||||
@ -144,8 +145,6 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
UserSession session = userSessionManager.createSession(user, userLocale, false);
|
||||
checkPermissions(login, params, userLocale, session);
|
||||
|
||||
log.info("Logged in: " + session);
|
||||
|
||||
tx.commit();
|
||||
|
||||
userSessionManager.clearPermissionsOnUser(session);
|
||||
@ -162,6 +161,8 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
userSessionManager.storeSession(session);
|
||||
}
|
||||
|
||||
log.info("Logged in: {}", session);
|
||||
|
||||
return session;
|
||||
} finally {
|
||||
tx.end();
|
||||
@ -179,17 +180,51 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
Transaction tx = persistence.createTransaction();
|
||||
try {
|
||||
User user = loadUser(login);
|
||||
if (user == null)
|
||||
if (user == null) {
|
||||
throw new LoginException(getInvalidCredentialsMessage(login, locale));
|
||||
}
|
||||
|
||||
UserSession session = userSessionManager.createSession(user, locale, true);
|
||||
log.info("Logged in: " + session);
|
||||
|
||||
tx.commit();
|
||||
|
||||
userSessionManager.clearPermissionsOnUser(session);
|
||||
userSessionManager.storeSession(session);
|
||||
|
||||
log.info("Logged in: {}", session);
|
||||
|
||||
return session;
|
||||
} finally {
|
||||
tx.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSession loginAnonymous() throws LoginException {
|
||||
GlobalConfig globalConfig = configuration.getConfig(GlobalConfig.class);
|
||||
UUID anonymousSessionId = globalConfig.getAnonymousSessionId();
|
||||
|
||||
ServerConfig serverConfig = configuration.getConfig(ServerConfig.class);
|
||||
String anonymousLogin = serverConfig.getAnonymousLogin();
|
||||
|
||||
Locale locale = messages.getTools().trimLocale(messages.getTools().getDefaultLocale());
|
||||
|
||||
Transaction tx = persistence.createTransaction();
|
||||
try {
|
||||
User user = loadUser(anonymousLogin);
|
||||
if (user == null) {
|
||||
throw new LoginException(getInvalidCredentialsMessage(anonymousLogin, locale));
|
||||
}
|
||||
|
||||
UserSession session = userSessionManager.createSession(anonymousSessionId, user, locale, true);
|
||||
session.setClientInfo("System anonymous session");
|
||||
tx.commit();
|
||||
|
||||
userSessionManager.clearPermissionsOnUser(session);
|
||||
userSessionManager.storeSession(session);
|
||||
|
||||
log.info("Logged in: {}", session);
|
||||
|
||||
return session;
|
||||
} finally {
|
||||
tx.end();
|
||||
@ -239,8 +274,9 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
log.debug("Unable to check trusted client IP when obtaining system session");
|
||||
}
|
||||
|
||||
if (!trustedLoginHandler.checkPassword(password))
|
||||
if (!trustedLoginHandler.checkPassword(password)) {
|
||||
throw new LoginException(getInvalidCredentialsMessage(login, locale));
|
||||
}
|
||||
|
||||
Transaction tx = persistence.createTransaction();
|
||||
try {
|
||||
@ -258,7 +294,7 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
UserSession session = userSessionManager.createSession(user, userLocale, false);
|
||||
checkPermissions(login, params, userLocale, session);
|
||||
|
||||
log.info("Logged in: " + session);
|
||||
log.info("Logged in: {}", session);
|
||||
|
||||
tx.commit();
|
||||
|
||||
@ -300,13 +336,13 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
UserSession session = userSessionManager.createSession(user, userLocale, false);
|
||||
checkPermissions(login, params, userLocale, session);
|
||||
|
||||
log.info("Logged in: " + session);
|
||||
|
||||
tx.commit();
|
||||
|
||||
userSessionManager.clearPermissionsOnUser(session);
|
||||
userSessionManager.storeSession(session);
|
||||
|
||||
log.info("Logged in: {}", session);
|
||||
|
||||
return session;
|
||||
} finally {
|
||||
tx.end();
|
||||
@ -318,9 +354,9 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
try {
|
||||
UserSession session = userSessionSource.getUserSession();
|
||||
userSessionManager.removeSession(session);
|
||||
log.info("Logged out: " + session);
|
||||
log.info("Logged out: {}", session);
|
||||
} catch (SecurityException e) {
|
||||
log.warn("Couldn't logout: " + e);
|
||||
log.warn("Couldn't logout: {}", e);
|
||||
} catch (NoUserSessionException e) {
|
||||
log.warn("NoUserSessionException thrown on logout");
|
||||
}
|
||||
@ -408,15 +444,40 @@ public class LoginWorkerBean implements LoginWorker {
|
||||
|
||||
protected void checkPermissions(String login, Map<String, Object> params, Locale userLocale, UserSession session)
|
||||
throws LoginException {
|
||||
|
||||
String clientTypeParam = (String) params.get(ClientType.class.getName());
|
||||
if (ClientType.DESKTOP.name().equals(clientTypeParam) || ClientType.WEB.name().equals(clientTypeParam)) {
|
||||
if (!session.isSpecificPermitted("cuba.gui.loginToClient")) {
|
||||
log.warn(String.format("Attempt of login to %s for user '%s' without cuba.gui.loginToClient permission",
|
||||
clientTypeParam, login));
|
||||
log.warn("Attempt of login to {} for user '{}' without cuba.gui.loginToClient permission",
|
||||
clientTypeParam, login);
|
||||
|
||||
throw new LoginException(getInvalidCredentialsMessage(login, userLocale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
AppContext.addListener(new AppContext.Listener() {
|
||||
@Override
|
||||
public void applicationStarted() {
|
||||
initializeAnonymousSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applicationStopped() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void initializeAnonymousSession() {
|
||||
log.debug("Initialize anonymous session");
|
||||
|
||||
try {
|
||||
loginAnonymous();
|
||||
|
||||
log.debug("Anonymous session initialized");
|
||||
} catch (LoginException e) {
|
||||
log.error("Unable to login anonymous session", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -344,10 +344,12 @@ public class UserManagementServiceBean implements UserManagementService {
|
||||
|
||||
@Override
|
||||
public void saveOwnLocale(String locale) {
|
||||
log.debug("Saving user's language settings: " + locale);
|
||||
UUID userId = userSessionSource.getUserSession().getUser().getId();
|
||||
log.debug("Saving user's {} language settings: {}", userId, locale);
|
||||
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
EntityManager em = persistence.getEntityManager();
|
||||
User user = em.find(User.class, userSessionSource.getUserSession().getUser().getId(), "user.locale");
|
||||
User user = em.find(User.class, userId, "user.locale");
|
||||
if (user == null)
|
||||
throw new EntityAccessException();
|
||||
|
||||
|
@ -44,7 +44,6 @@ import java.util.UUID;
|
||||
|
||||
/**
|
||||
* System-level class managing {@link UserSession}s.
|
||||
*
|
||||
*/
|
||||
@Component(UserSessionManager.NAME)
|
||||
public class UserSessionManager implements UserSessionFinder {
|
||||
@ -79,13 +78,25 @@ public class UserSessionManager implements UserSessionFinder {
|
||||
* @return new session instance
|
||||
*/
|
||||
public UserSession createSession(User user, Locale locale, boolean system) {
|
||||
return createSession(uuidSource.createUuid(), user, locale, system);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new session and fill it with security data. Must be called inside a transaction.
|
||||
* @param sessionId target session id
|
||||
* @param user user instance
|
||||
* @param locale user locale
|
||||
* @param system create system session
|
||||
* @return new session instance
|
||||
*/
|
||||
public UserSession createSession(UUID sessionId, User user, Locale locale, boolean system) {
|
||||
List<Role> roles = new ArrayList<>();
|
||||
for (UserRole userRole : user.getUserRoles()) {
|
||||
if (userRole.getRole() != null) {
|
||||
roles.add(userRole.getRole());
|
||||
}
|
||||
}
|
||||
UserSession session = new UserSession(uuidSource.createUuid(), user, roles, locale, system);
|
||||
UserSession session = new UserSession(sessionId, user, roles, locale, system);
|
||||
compilePermissions(session, roles);
|
||||
if (user.getGroup() == null)
|
||||
throw new IllegalStateException("User is not in a Group");
|
||||
@ -179,8 +190,8 @@ public class UserSessionManager implements UserSessionFinder {
|
||||
List<SessionAttribute> list = new ArrayList<>(group.getSessionAttributes());
|
||||
|
||||
EntityManager em = persistence.getEntityManager();
|
||||
Query q = em.createQuery("select a from sec$GroupHierarchy h join h.parent.sessionAttributes a " +
|
||||
"where h.group.id = ?1 order by h.level desc");
|
||||
TypedQuery<SessionAttribute> q = em.createQuery("select a from sec$GroupHierarchy h join h.parent.sessionAttributes a " +
|
||||
"where h.group.id = ?1 order by h.level desc", SessionAttribute.class);
|
||||
q.setParameter(1, group);
|
||||
List<SessionAttribute> attributes = q.getResultList();
|
||||
list.addAll(attributes);
|
||||
|
@ -85,6 +85,8 @@ cuba.passwordPolicyEnabled=false
|
||||
cuba.passwordPolicyRegExp=((?=.*\\d)(?=.*\\p{javaLowerCase})(?=.*\\p{javaUpperCase}).{6,20})
|
||||
cuba.passwordEncryptionModule=cuba_Sha1EncryptionModule
|
||||
|
||||
cuba.anonymousSessionId=9c91dbdf-3e73-428e-9088-d586da2434c5
|
||||
|
||||
###############################################################################
|
||||
# Presentation #
|
||||
###############################################################################
|
||||
|
@ -60,7 +60,7 @@ public abstract class DesktopAbstractOptionsField<C extends JComponent>
|
||||
|
||||
protected CollectionDatasource<Entity<Object>, Object> optionsDatasource;
|
||||
protected List optionsList;
|
||||
protected Map<String, Object> optionsMap;
|
||||
protected Map<String, ?> optionsMap;
|
||||
protected Class<? extends EnumClass> optionsEnum;
|
||||
|
||||
protected Datasource datasource;
|
||||
@ -104,12 +104,12 @@ public abstract class DesktopAbstractOptionsField<C extends JComponent>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptionsMap() {
|
||||
public Map<String, ?> getOptionsMap() {
|
||||
return optionsMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
optionsMap = map;
|
||||
}
|
||||
|
||||
@ -262,7 +262,7 @@ public abstract class DesktopAbstractOptionsField<C extends JComponent>
|
||||
|
||||
Object selectedItem;
|
||||
if (optionsMap != null) {
|
||||
for (Map.Entry<String, Object> entry : optionsMap.entrySet()) {
|
||||
for (Map.Entry<String, ?> entry : optionsMap.entrySet()) {
|
||||
if (value.equals(entry.getValue())) {
|
||||
setSelectedItem(new MapKeyWrapper(entry.getKey()));
|
||||
return;
|
||||
|
@ -478,7 +478,7 @@ public class DesktopLookupField extends DesktopAbstractOptionsField<JComponent>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
super.setOptionsMap(map);
|
||||
if (optionsInitialized) {
|
||||
optionsInitialized = false;
|
||||
|
@ -158,7 +158,7 @@ public class DesktopOptionsGroup extends DesktopAbstractOptionsField<JPanel> imp
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
if (optionsInitialized)
|
||||
return;
|
||||
|
||||
|
@ -501,7 +501,7 @@ public class DesktopSearchField extends DesktopAbstractOptionsField<JComponent>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ public class DesktopSuggestionField extends DesktopAbstractOptionsField<JCompone
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -255,12 +255,12 @@ public class DesktopTokenList extends DesktopAbstractField<JPanel> implements To
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptionsMap() {
|
||||
public Map<String, ?> getOptionsMap() {
|
||||
return lookupPickerField.getOptionsMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
lookupPickerField.setOptionsMap(map);
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,13 @@ import com.haulmont.cuba.core.config.defaults.DefaultBoolean;
|
||||
import com.haulmont.cuba.core.config.defaults.DefaultInt;
|
||||
import com.haulmont.cuba.core.config.defaults.DefaultString;
|
||||
import com.haulmont.cuba.core.config.type.Factory;
|
||||
import com.haulmont.cuba.core.config.type.UuidTypeFactory;
|
||||
import com.haulmont.cuba.core.sys.AvailableLocalesFactory;
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Configuration parameters interface used by all layers: CORE, WEB, DESKTOP.
|
||||
@ -181,5 +183,8 @@ public interface GlobalConfig extends Config {
|
||||
@Property("cuba.numberIdCacheSize")
|
||||
@DefaultInt(100)
|
||||
int getNumberIdCacheSize();
|
||||
}
|
||||
|
||||
@Property("cuba.anonymousSessionId")
|
||||
@Factory(factory = UuidTypeFactory.class)
|
||||
UUID getAnonymousSessionId();
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.core.sys;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Parameters of user invocation, may be passed by client tier
|
||||
*/
|
||||
public final class UserInvocationContext {
|
||||
private static final ThreadLocal<RequestScopeLocale> userRequestScopeLocale = new ThreadLocal<>();
|
||||
|
||||
public static void setRequestScopeLocale(UUID sessionId, Locale locale) {
|
||||
userRequestScopeLocale.set(new RequestScopeLocale(sessionId, locale));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Locale getRequestScopeLocale(UUID sessionId) {
|
||||
RequestScopeLocale requestScopeLocale = userRequestScopeLocale.get();
|
||||
if (requestScopeLocale != null && Objects.equals(sessionId, requestScopeLocale.getSessionId())) {
|
||||
return requestScopeLocale.getLocale();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void clearRequestScopeLocale() {
|
||||
userRequestScopeLocale.set(null);
|
||||
}
|
||||
|
||||
protected static final class RequestScopeLocale {
|
||||
private final UUID sessionId;
|
||||
private final Locale locale;
|
||||
|
||||
public RequestScopeLocale(UUID sessionId, Locale locale) {
|
||||
this.sessionId = sessionId;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public UUID getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
}
|
@ -32,7 +32,6 @@ import java.util.List;
|
||||
/**
|
||||
* HttpInvokerRequestExecutor that executes a request on a server which is selected according to the current cluster
|
||||
* topology, provided by {@link ClusterInvocationSupport}.
|
||||
*
|
||||
*/
|
||||
public class ClusteredHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {
|
||||
|
||||
@ -45,7 +44,8 @@ public class ClusteredHttpInvokerRequestExecutor extends SimpleHttpInvokerReques
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws IOException, ClassNotFoundException {
|
||||
protected RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
|
||||
throws IOException, ClassNotFoundException {
|
||||
List<String> urlList = support.getUrlList(config.getServiceUrl());
|
||||
if (urlList.isEmpty())
|
||||
throw new IllegalStateException("URL list is empty");
|
||||
@ -65,7 +65,8 @@ public class ClusteredHttpInvokerRequestExecutor extends SimpleHttpInvokerReques
|
||||
result = readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
logger.info("Invocation of " + url + " failed: " + e);
|
||||
logger.info(String.format("Invocation of %s failed: %s", url, e));
|
||||
|
||||
if (i < urlList.size() - 1) {
|
||||
logger.info("Trying to invoke the next available URL: " + urlList.get(i + 1));
|
||||
continue;
|
||||
@ -80,7 +81,7 @@ public class ClusteredHttpInvokerRequestExecutor extends SimpleHttpInvokerReques
|
||||
protected HttpURLConnection openConnection(String serviceUrl) throws IOException {
|
||||
URLConnection con = new URL(serviceUrl).openConnection();
|
||||
if (!(con instanceof HttpURLConnection)) {
|
||||
throw new IOException("Service URL [" + serviceUrl + "] is not an HTTP URL");
|
||||
throw new IOException(String.format("Service URL [%s] is not an HTTP URL", serviceUrl));
|
||||
}
|
||||
return (HttpURLConnection) con;
|
||||
}
|
||||
|
@ -23,21 +23,31 @@ import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Encapsulates a remote invocation of a middleware service.
|
||||
* Additionally transfers the current user session identifier.
|
||||
*
|
||||
* Additionally transfers the current user session identifier and request scope locale (for anonymous sessions).
|
||||
*/
|
||||
public class CubaRemoteInvocation extends RemoteInvocation {
|
||||
|
||||
private static final long serialVersionUID = 5460262566597755733L;
|
||||
|
||||
private UUID sessionId;
|
||||
private String locale;
|
||||
|
||||
public CubaRemoteInvocation(MethodInvocation methodInvocation, UUID sessionId) {
|
||||
super(methodInvocation);
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public CubaRemoteInvocation(MethodInvocation methodInvocation, UUID sessionId, String locale) {
|
||||
super(methodInvocation);
|
||||
this.sessionId = sessionId;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public UUID getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ package com.haulmont.cuba.core.sys.remoting;
|
||||
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.security.global.ClientBasedSession;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationFactory;
|
||||
@ -27,6 +29,19 @@ public class CubaRemoteInvocationFactory implements RemoteInvocationFactory {
|
||||
@Override
|
||||
public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
|
||||
SecurityContext securityContext = AppContext.getSecurityContext();
|
||||
return new CubaRemoteInvocation(methodInvocation, securityContext == null ? null : securityContext.getSessionId());
|
||||
|
||||
String requestScopeLocale = null;
|
||||
if (securityContext != null) {
|
||||
UserSession session = securityContext.getSession();
|
||||
if (session instanceof ClientBasedSession) {
|
||||
if (((ClientBasedSession) session).isLocaleRequestScoped()) {
|
||||
requestScopeLocale = session.getLocale() != null ? session.getLocale().toLanguageTag() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new CubaRemoteInvocation(methodInvocation,
|
||||
securityContext == null ? null : securityContext.getSessionId(),
|
||||
requestScopeLocale);
|
||||
}
|
||||
}
|
@ -1,35 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.web;
|
||||
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Base class for application's UI content.
|
||||
*
|
||||
* @see LoginWindow
|
||||
* @see AppWindow
|
||||
*
|
||||
*/
|
||||
public abstract class UIView extends VerticalLayout {
|
||||
|
||||
public abstract String getTitle();
|
||||
|
||||
public void show() {
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.security.global;
|
||||
|
||||
/**
|
||||
* Interface for client sessions that allow anonymous requests
|
||||
*/
|
||||
public interface ClientBasedSession {
|
||||
boolean isLocaleRequestScoped();
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.security.global;
|
||||
|
||||
import com.haulmont.cuba.core.global.Logging;
|
||||
import com.haulmont.cuba.core.global.SupportedByClient;
|
||||
|
||||
@SupportedByClient
|
||||
@Logging(Logging.Type.BRIEF)
|
||||
public class LoginFailedException extends LoginException {
|
||||
public LoginFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoginFailedException(String template, Object... params) {
|
||||
super(template, params);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package com.haulmont.cuba.security.global;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.cuba.core.sys.UserInvocationContext;
|
||||
import com.haulmont.cuba.security.entity.*;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -42,8 +43,8 @@ public class UserSession implements Serializable {
|
||||
protected UUID id;
|
||||
protected User user;
|
||||
protected User substitutedUser;
|
||||
private List<String> roles = new ArrayList<>();
|
||||
private EnumSet<RoleType> roleTypes = EnumSet.noneOf(RoleType.class);
|
||||
protected List<String> roles = new ArrayList<>();
|
||||
protected EnumSet<RoleType> roleTypes = EnumSet.noneOf(RoleType.class);
|
||||
protected Locale locale;
|
||||
protected TimeZone timeZone;
|
||||
protected String address;
|
||||
@ -162,6 +163,11 @@ public class UserSession implements Serializable {
|
||||
* User locale
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
Locale requestScopeLocale = UserInvocationContext.getRequestScopeLocale(id);
|
||||
if (requestScopeLocale != null) {
|
||||
return requestScopeLocale;
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,8 @@ public class UserBrowser extends AbstractLookup {
|
||||
|
||||
@Override
|
||||
public void init(Map<String, Object> params) {
|
||||
super.init(params);
|
||||
|
||||
MetaClass userMetaClass = metadata.getClassNN(User.class);
|
||||
|
||||
final boolean hasPermissionsToCreateUsers =
|
||||
|
@ -112,6 +112,8 @@ public class UserEditor extends AbstractEditor<User> {
|
||||
|
||||
@Override
|
||||
public void init(Map<String, Object> params) {
|
||||
super.init(params);
|
||||
|
||||
userDs.addItemPropertyChangeListener(new NameBuilderListener<>(userDs));
|
||||
userDs.addItemPropertyChangeListener(e -> {
|
||||
if ("timeZoneAuto".equals(e.getProperty())) {
|
||||
|
@ -525,14 +525,24 @@ public class AbstractFrame implements Frame, Frame.Wrapper, Component.Wrapper, C
|
||||
this.styleName = styleName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <X> X unwrap(Class<X> internalComponentClass) {
|
||||
return (X) getComponent();
|
||||
if (getComponent() instanceof Component.Wrapper) {
|
||||
return (X) ((Component.Wrapper) frame).getComponent();
|
||||
}
|
||||
|
||||
return (X) frame;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <X> X unwrapComposition(Class<X> internalCompositionClass) {
|
||||
return (X) getComponent();
|
||||
if (getComposition() instanceof Component.Wrapper) {
|
||||
return (X) ((Component.Wrapper) frame).getComposition();
|
||||
}
|
||||
|
||||
return (X) frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,9 +25,8 @@ import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Base class for controller of application Main window
|
||||
*
|
||||
*/
|
||||
public class AbstractMainWindow extends AbstractWindow implements Window.MainWindow {
|
||||
public class AbstractMainWindow extends AbstractTopLevelWindow implements Window.MainWindow {
|
||||
|
||||
private AppWorkArea workArea;
|
||||
private UserIndicator userIndicator;
|
||||
@ -62,19 +61,4 @@ public class AbstractMainWindow extends AbstractWindow implements Window.MainWin
|
||||
public void setFoldersPane(FoldersPane foldersPane) {
|
||||
this.foldersPane = foldersPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(String actionId) {
|
||||
throw new UnsupportedOperationException("Close operation for Main window is unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(String actionId, boolean force) {
|
||||
throw new UnsupportedOperationException("Close operation for Main window is unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeAndRun(String actionId, Runnable runnable) {
|
||||
throw new UnsupportedOperationException("Close operation for Main window is unsupported");
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
public class AbstractTopLevelWindow extends AbstractWindow implements Window.TopLevelWindow {
|
||||
@Override
|
||||
public boolean close(String actionId) {
|
||||
throw new UnsupportedOperationException("Close operation for TopLevelWindow is unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(String actionId, boolean force) {
|
||||
throw new UnsupportedOperationException("Close operation for TopLevelWindow is unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeAndRun(String actionId, Runnable runnable) {
|
||||
throw new UnsupportedOperationException("Close operation for TopLevelWindow is unsupported");
|
||||
}
|
||||
}
|
@ -41,8 +41,8 @@ public interface OptionsField extends Field {
|
||||
List getOptionsList();
|
||||
void setOptionsList(List optionsList);
|
||||
|
||||
Map<String, Object> getOptionsMap();
|
||||
void setOptionsMap(Map<String, Object> map);
|
||||
Map<String, ?> getOptionsMap();
|
||||
void setOptionsMap(Map<String, ?> map);
|
||||
|
||||
Class<? extends EnumClass> getOptionsEnum();
|
||||
void setOptionsEnum(Class<? extends EnumClass> optionsEnum);
|
||||
|
@ -59,8 +59,8 @@ public interface TokenList extends Field, Component.BelongToFrame, Component.Has
|
||||
java.util.List getOptionsList();
|
||||
void setOptionsList(java.util.List optionsList);
|
||||
|
||||
Map<String, Object> getOptionsMap();
|
||||
void setOptionsMap(Map<String, Object> map);
|
||||
Map<String, ?> getOptionsMap();
|
||||
void setOptionsMap(Map<String, ?> map);
|
||||
|
||||
boolean isLookup();
|
||||
void setLookup(boolean lookup);
|
||||
|
@ -361,17 +361,27 @@ public interface Window extends Frame, Component.HasCaption {
|
||||
}
|
||||
}
|
||||
|
||||
interface MainWindow extends Window {
|
||||
interface TopLevelWindow extends Window {
|
||||
}
|
||||
|
||||
interface HasWorkArea {
|
||||
@Nullable
|
||||
AppWorkArea getWorkArea();
|
||||
}
|
||||
|
||||
interface HasUserIndicator {
|
||||
@Nullable
|
||||
UserIndicator getUserIndicator();
|
||||
}
|
||||
|
||||
interface HasFoldersPane {
|
||||
@Nullable
|
||||
FoldersPane getFoldersPane();
|
||||
}
|
||||
|
||||
interface MainWindow extends TopLevelWindow, HasWorkArea, HasUserIndicator, HasFoldersPane {
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to be notified when a screen is closed.
|
||||
*/
|
||||
|
@ -22,23 +22,11 @@ import com.haulmont.cuba.security.global.UserSession;
|
||||
|
||||
/**
|
||||
* User session that holds middleware session.
|
||||
*
|
||||
*/
|
||||
public class PortalSession extends ClientUserSession {
|
||||
private static final long serialVersionUID = 64089583666599524L;
|
||||
|
||||
private volatile boolean authenticated; // indicates whether user passed authentication
|
||||
|
||||
public PortalSession(UserSession src) {
|
||||
super(src);
|
||||
authenticated = false;
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,11 +19,14 @@ package com.haulmont.cuba.portal.sys.remoting;
|
||||
|
||||
import com.haulmont.cuba.core.global.RemoteException;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.core.sys.serialization.SerializationSupport;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceDirectory;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvocation;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvocationResult;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvoker;
|
||||
import com.haulmont.cuba.security.global.ClientBasedSession;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.remoting.support.RemoteAccessor;
|
||||
@ -123,9 +126,21 @@ public class LocalServiceProxy extends RemoteAccessor implements FactoryBean<Obj
|
||||
}
|
||||
}
|
||||
|
||||
UUID sessionId = AppContext.getSecurityContext() == null ? null : AppContext.getSecurityContext().getSessionId();
|
||||
SecurityContext securityContext = AppContext.getSecurityContext();
|
||||
UUID sessionId = securityContext == null ? null : securityContext.getSessionId();
|
||||
|
||||
String requestScopeLocale = null;
|
||||
if (securityContext != null) {
|
||||
UserSession session = securityContext.getSession();
|
||||
if (session instanceof ClientBasedSession) {
|
||||
if (((ClientBasedSession) session).isLocaleRequestScoped()) {
|
||||
requestScopeLocale = session.getLocale() != null ? session.getLocale().toLanguageTag() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalServiceInvocation invocation = new LocalServiceInvocation(
|
||||
method.getName(), parameterTypeNames, argumentsData, notSerializableArguments, sessionId);
|
||||
method.getName(), parameterTypeNames, argumentsData, notSerializableArguments, sessionId, requestScopeLocale);
|
||||
|
||||
LocalServiceInvocationResult result = invoker.invoke(invocation);
|
||||
AppContext.setSecurityContext(AppContext.getSecurityContext());//need reset application name in LogMDC for the current thread
|
||||
|
@ -77,4 +77,6 @@ cuba.rest.client.secret=secret
|
||||
cuba.rest.client.tokenExpirationTimeSec=43200
|
||||
|
||||
# A comma-separated list of allowed origins for cross-domain requests
|
||||
cuba.rest.allowedOrigins=*
|
||||
cuba.rest.allowedOrigins=*
|
||||
|
||||
cuba.anonymousSessionId=9c91dbdf-3e73-428e-9088-d586da2434c5
|
@ -17,23 +17,26 @@
|
||||
|
||||
package com.haulmont.cuba.core.sys.remoting;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LocalServiceInvocation {
|
||||
|
||||
private String methodName;
|
||||
private String[] parameterTypeNames;
|
||||
private byte[][] argumentsData;
|
||||
private Object[] notSerializableArguments;
|
||||
private UUID sessionId;
|
||||
private String locale;
|
||||
|
||||
public LocalServiceInvocation(String methodName, String[] parameterTypeNames,
|
||||
byte[][] argumentsData, Object[] notSerializableArguments, UUID sessionId) {
|
||||
byte[][] argumentsData, Object[] notSerializableArguments, UUID sessionId,
|
||||
@Nullable String locale) {
|
||||
this.methodName = methodName;
|
||||
this.parameterTypeNames = parameterTypeNames;
|
||||
this.argumentsData = argumentsData;
|
||||
this.notSerializableArguments = notSerializableArguments;
|
||||
this.sessionId = sessionId;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public byte[][] getArgumentsData() {
|
||||
@ -55,4 +58,8 @@ public class LocalServiceInvocation {
|
||||
public UUID getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
}
|
@ -17,8 +17,6 @@
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.cuba.client.ClientUserSession;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
@ -38,32 +36,48 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Abstract class that encapsulates common connection behaviour for web-client.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractConnection implements Connection {
|
||||
|
||||
protected Logger log = LoggerFactory.getLogger(getClass());
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractConnection.class);
|
||||
|
||||
protected Map<ConnectionListener, Object> connListeners = new HashMap<>();
|
||||
protected Map<UserSubstitutionListener, Object> usListeners = new HashMap<>();
|
||||
protected List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||
protected List<UserSubstitutionListener> userSubstitutionListeners = new ArrayList<>();
|
||||
|
||||
protected boolean connected;
|
||||
|
||||
protected LoginService loginService = AppBeans.get(LoginService.NAME);
|
||||
protected UserSessionService userSessionService = AppBeans.get(UserSessionService.NAME);
|
||||
protected Messages messages = AppBeans.get(Messages.NAME);
|
||||
@Inject
|
||||
protected LoginService loginService;
|
||||
@Inject
|
||||
protected UserSessionService userSessionService;
|
||||
@Inject
|
||||
protected Messages messages;
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
if (!connected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UserSession session = getSession();
|
||||
return session instanceof ClientUserSession
|
||||
&& ((ClientUserSession) session).isAuthenticated();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public UserSession getSession() {
|
||||
@ -95,8 +109,9 @@ public abstract class AbstractConnection implements Connection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(UserSession session) throws LoginException {
|
||||
public void update(UserSession session, SessionMode sessionMode) throws LoginException {
|
||||
ClientUserSession clientUserSession = new ClientUserSession(session);
|
||||
clientUserSession.setAuthenticated(sessionMode == SessionMode.AUTHENTICATED);
|
||||
|
||||
setSession(clientUserSession);
|
||||
|
||||
@ -118,11 +133,17 @@ public abstract class AbstractConnection implements Connection {
|
||||
|
||||
App app = App.getInstance();
|
||||
|
||||
if (!StringUtils.isBlank(session.getUser().getIpMask())) {
|
||||
boolean sessionIsAuthenticated = true;
|
||||
if (session instanceof ClientUserSession) {
|
||||
sessionIsAuthenticated = ((ClientUserSession) session).isAuthenticated();
|
||||
}
|
||||
|
||||
if (sessionIsAuthenticated && !StringUtils.isBlank(session.getUser().getIpMask())) {
|
||||
IpMatcher ipMatcher = new IpMatcher(session.getUser().getIpMask());
|
||||
if (!ipMatcher.match(app.getClientAddress())) {
|
||||
log.info(String.format("IP address %s is not permitted for user %s", app.getClientAddress(), session.getUser().toString()));
|
||||
throw new LoginException(messages.getMessage(getClass(), "login.invalidIP"));
|
||||
log.info("IP address {} is not permitted for user {}", app.getClientAddress(), session.getUser());
|
||||
|
||||
throw new LoginException(messages.getMainMessage("login.invalidIP"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,29 +151,28 @@ public abstract class AbstractConnection implements Connection {
|
||||
String clientInfo = makeClientInfo();
|
||||
session.setClientInfo(clientInfo);
|
||||
|
||||
if (Boolean.TRUE.equals(session.getUser().getTimeZoneAuto()))
|
||||
if (Boolean.TRUE.equals(session.getUser().getTimeZoneAuto())) {
|
||||
session.setTimeZone(detectTimeZone());
|
||||
}
|
||||
|
||||
fireConnectionListeners();
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Logged in: user=%s, ip=%s, clientInfo=%s",
|
||||
session.getUser().getLogin(), app.getClientAddress(), clientInfo));
|
||||
}
|
||||
log.debug("Logged in: user={}, ip={}, clientInfo={}",
|
||||
session.getUser().getLogin(), app.getClientAddress(), clientInfo);
|
||||
}
|
||||
|
||||
protected String makeClientInfo() {
|
||||
Page page = AppUI.getCurrent().getPage();
|
||||
WebBrowser webBrowser = page.getWebBrowser();
|
||||
|
||||
Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
GlobalConfig globalConfig = configuration.getConfig(GlobalConfig.class);
|
||||
String serverInfo = "Web (" +
|
||||
globalConfig.getWebHostName() + ":" +
|
||||
globalConfig.getWebPort() + "/" +
|
||||
globalConfig.getWebContextName() + ") ";
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
String serverInfo = String.format("Web (%s:%s/%s) %s",
|
||||
globalConfig.getWebHostName(),
|
||||
globalConfig.getWebPort(),
|
||||
globalConfig.getWebContextName(),
|
||||
webBrowser.getBrowserApplication());
|
||||
|
||||
return serverInfo + webBrowser.getBrowserApplication();
|
||||
return serverInfo;
|
||||
}
|
||||
|
||||
protected TimeZone detectTimeZone() {
|
||||
@ -161,9 +181,9 @@ public abstract class AbstractConnection implements Connection {
|
||||
|
||||
int offset = webBrowser.getTimezoneOffset() / 1000 / 60;
|
||||
String hours = StringUtils.leftPad(String.valueOf(offset / 60), 2, '0');
|
||||
String mins = StringUtils.leftPad(String.valueOf(offset % 60), 2, '0');
|
||||
String minutes = StringUtils.leftPad(String.valueOf(offset % 60), 2, '0');
|
||||
char sign = offset >= 0 ? '+' : '-';
|
||||
return TimeZone.getTimeZone("GMT" + sign + hours + mins);
|
||||
return TimeZone.getTimeZone("GMT" + sign + hours + minutes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -173,55 +193,59 @@ public abstract class AbstractConnection implements Connection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logout() {
|
||||
if (!connected)
|
||||
return null;
|
||||
public void logout() {
|
||||
internalLogout();
|
||||
try {
|
||||
fireConnectionListeners();
|
||||
} catch (LoginException e) {
|
||||
log.warn("Exception on logout:", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void internalLogout() {
|
||||
loginService.logout();
|
||||
if (getSession() instanceof ClientUserSession
|
||||
&& ((ClientUserSession) getSession()).isAuthenticated()) {
|
||||
loginService.logout();
|
||||
}
|
||||
|
||||
AppContext.setSecurityContext(null);
|
||||
usListeners.clear();
|
||||
userSubstitutionListeners.clear();
|
||||
connected = false;
|
||||
setSession(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConnectionListener(ConnectionListener listener) {
|
||||
connListeners.put(listener, null);
|
||||
if (!connectionListeners.contains(listener)) {
|
||||
connectionListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConnectionListener(ConnectionListener listener) {
|
||||
connListeners.remove(listener);
|
||||
connectionListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSubstitutionListener(UserSubstitutionListener listener) {
|
||||
usListeners.put(listener, null);
|
||||
if (!userSubstitutionListeners.contains(listener)) {
|
||||
userSubstitutionListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSubstitutionListener(UserSubstitutionListener listener) {
|
||||
usListeners.remove(listener);
|
||||
userSubstitutionListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void fireConnectionListeners() throws LoginException {
|
||||
for (ConnectionListener listener : connListeners.keySet()) {
|
||||
for (ConnectionListener listener : new ArrayList<>(connectionListeners)) {
|
||||
listener.connectionStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireSubstitutionListeners() {
|
||||
for (UserSubstitutionListener listener : usListeners.keySet()) {
|
||||
for (UserSubstitutionListener listener : new ArrayList<>(userSubstitutionListeners)) {
|
||||
listener.userSubstituted(this);
|
||||
}
|
||||
}
|
||||
|
@ -17,17 +17,20 @@
|
||||
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.cuba.client.sys.cache.ClientCacheManager;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.core.global.MessageTools;
|
||||
import com.haulmont.cuba.gui.components.Frame;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.executors.IllegalConcurrentAccessException;
|
||||
import com.haulmont.cuba.gui.settings.SettingsClient;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstants;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
|
||||
import com.haulmont.cuba.security.app.UserSessionService;
|
||||
import com.haulmont.cuba.security.global.NoUserSessionException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.auth.RequestContext;
|
||||
import com.haulmont.cuba.web.auth.WebAuthConfig;
|
||||
import com.haulmont.cuba.web.exception.ExceptionHandlers;
|
||||
@ -37,20 +40,21 @@ import com.haulmont.cuba.web.sys.AppCookies;
|
||||
import com.haulmont.cuba.web.sys.BackgroundTaskManager;
|
||||
import com.haulmont.cuba.web.sys.LinkHandler;
|
||||
import com.vaadin.server.AbstractClientConnector;
|
||||
import com.vaadin.server.ErrorHandler;
|
||||
import com.vaadin.server.VaadinServlet;
|
||||
import com.vaadin.server.VaadinSession;
|
||||
import com.vaadin.ui.UI;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@ -60,11 +64,16 @@ import java.util.concurrent.Future;
|
||||
* Use {@link #getInstance()} static method to obtain the reference to the current App instance.
|
||||
*/
|
||||
public abstract class App {
|
||||
|
||||
public static final String NAME = "cuba_App";
|
||||
|
||||
public static final String USER_SESSION_ATTR = "userSessionId";
|
||||
|
||||
public static final String APP_THEME_COOKIE_PREFIX = "APP_THEME_NAME_";
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(App.class);
|
||||
public static final String COOKIE_LOCALE = "LAST_LOCALE";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(App.class);
|
||||
|
||||
static {
|
||||
AbstractClientConnector.setIncorrectConcurrentAccessHandler(() -> {
|
||||
@ -78,22 +87,41 @@ public abstract class App {
|
||||
|
||||
protected ExceptionHandlers exceptionHandlers;
|
||||
|
||||
protected final GlobalConfig globalConfig;
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
protected final WebConfig webConfig;
|
||||
@Inject
|
||||
protected WebConfig webConfig;
|
||||
|
||||
protected final WebAuthConfig webAuthConfig;
|
||||
@Inject
|
||||
protected WebAuthConfig webAuthConfig;
|
||||
|
||||
@Inject
|
||||
protected WindowConfig windowConfig;
|
||||
|
||||
@Inject
|
||||
protected ThemeConstantsRepository themeConstantsRepository;
|
||||
|
||||
@Inject
|
||||
protected ClientCacheManager clientCacheManager;
|
||||
|
||||
@Inject
|
||||
protected UserSessionService userSessionService;
|
||||
|
||||
@Inject
|
||||
protected MessageTools messageTools;
|
||||
|
||||
@Inject
|
||||
protected SettingsClient settingsClient;
|
||||
|
||||
protected AppCookies cookies;
|
||||
|
||||
protected LinkHandler linkHandler;
|
||||
|
||||
protected final BackgroundTaskManager backgroundTaskManager;
|
||||
protected BackgroundTaskManager backgroundTaskManager = new BackgroundTaskManager();
|
||||
|
||||
protected Principal principal;
|
||||
|
||||
protected Locale locale = Locale.getDefault();
|
||||
|
||||
protected String webResourceTimestamp = "DEBUG";
|
||||
|
||||
protected String clientAddress;
|
||||
@ -101,51 +129,23 @@ public abstract class App {
|
||||
protected ThemeConstants themeConstants;
|
||||
|
||||
public App() {
|
||||
log.trace("Creating application " + this);
|
||||
try {
|
||||
Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
|
||||
webConfig = configuration.getConfig(WebConfig.class);
|
||||
webAuthConfig = configuration.getConfig(WebAuthConfig.class);
|
||||
globalConfig = configuration.getConfig(GlobalConfig.class);
|
||||
|
||||
appLog = new AppLog();
|
||||
|
||||
connection = createConnection();
|
||||
exceptionHandlers = new ExceptionHandlers(this);
|
||||
cookies = new AppCookies();
|
||||
backgroundTaskManager = new BackgroundTaskManager();
|
||||
|
||||
themeConstants = loadTheme();
|
||||
|
||||
VaadinServlet vaadinServlet = VaadinServlet.getCurrent();
|
||||
ServletContext sc = vaadinServlet.getServletContext();
|
||||
String resourcesTimestamp = sc.getInitParameter("webResourcesTs");
|
||||
if (StringUtils.isNotEmpty(resourcesTimestamp)) {
|
||||
this.webResourceTimestamp = resourcesTimestamp;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error initializing application", e);
|
||||
|
||||
throw new Error("Error initializing application. See log for details.");
|
||||
}
|
||||
log.trace("Creating application {}", this);
|
||||
}
|
||||
|
||||
protected ThemeConstants loadTheme() {
|
||||
ThemeConstantsRepository themeRepository = AppBeans.get(ThemeConstantsRepository.NAME);
|
||||
String appWindowTheme = webConfig.getAppWindowTheme();
|
||||
String userAppTheme = cookies.getCookieValue(APP_THEME_COOKIE_PREFIX + globalConfig.getWebContextName());
|
||||
if (userAppTheme != null) {
|
||||
if (!StringUtils.equals(userAppTheme, appWindowTheme)) {
|
||||
// check theme support
|
||||
Set<String> supportedThemes = themeRepository.getAvailableThemes();
|
||||
Set<String> supportedThemes = themeConstantsRepository.getAvailableThemes();
|
||||
if (supportedThemes.contains(userAppTheme)) {
|
||||
appWindowTheme = userAppTheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThemeConstants theme = themeRepository.getConstants(appWindowTheme);
|
||||
ThemeConstants theme = themeConstantsRepository.getConstants(appWindowTheme);
|
||||
if (theme == null) {
|
||||
throw new IllegalStateException("Unable to use theme constants '" + appWindowTheme + "'");
|
||||
}
|
||||
@ -154,11 +154,10 @@ public abstract class App {
|
||||
}
|
||||
|
||||
protected void applyTheme(String appWindowTheme) {
|
||||
ThemeConstantsRepository themeRepository = AppBeans.get(ThemeConstantsRepository.NAME);
|
||||
ThemeConstants theme = themeRepository.getConstants(appWindowTheme);
|
||||
ThemeConstants theme = themeConstantsRepository.getConstants(appWindowTheme);
|
||||
|
||||
if (theme == null) {
|
||||
log.warn("Unable to use theme constants '" + appWindowTheme + "'");
|
||||
log.warn("Unable to use theme constants '{}'", appWindowTheme);
|
||||
} else {
|
||||
this.themeConstants = theme;
|
||||
setUserAppTheme(appWindowTheme);
|
||||
@ -179,11 +178,8 @@ public abstract class App {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AppWindow displayed in the current UI. Can be null if not logged in.
|
||||
*/
|
||||
public AppWindow getAppWindow() {
|
||||
return AppUI.getCurrent().getAppWindow();
|
||||
public Window.TopLevelWindow getTopLevelWindow() {
|
||||
return getAppUI().getTopLevelWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,36 +199,127 @@ public abstract class App {
|
||||
if (ui instanceof AppUI)
|
||||
list.add((AppUI) ui);
|
||||
else
|
||||
log.warn("Invalid UI in the session: " + ui);
|
||||
log.warn("Invalid UI in the session: {}", ui);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected abstract boolean loginOnStart();
|
||||
|
||||
protected abstract Connection createConnection();
|
||||
protected Connection createConnection() {
|
||||
return AppBeans.getPrototype(Connection.NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when <em>the first</em> UI of the session is initialized.
|
||||
*/
|
||||
protected void init() {
|
||||
protected void init(Locale requestLocale) {
|
||||
VaadinSession vSession = VaadinSession.getCurrent();
|
||||
vSession.setAttribute(App.class, this);
|
||||
|
||||
vSession.setLocale(messageTools.getDefaultLocale());
|
||||
|
||||
// set root error handler for all session
|
||||
vSession.setErrorHandler((ErrorHandler) event -> {
|
||||
try {
|
||||
getExceptionHandlers().handle(event);
|
||||
getAppLog().log(event);
|
||||
} catch (Throwable e) {
|
||||
//noinspection ThrowableResultOfMethodCallIgnored
|
||||
log.error("Error handling exception\nOriginal exception:\n{}\nException in handlers:\n{}",
|
||||
ExceptionUtils.getStackTrace(event.getThrowable()), ExceptionUtils.getStackTrace(e)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
appLog = new AppLog();
|
||||
|
||||
connection = createConnection();
|
||||
exceptionHandlers = new ExceptionHandlers(this);
|
||||
cookies = new AppCookies();
|
||||
|
||||
themeConstants = loadTheme();
|
||||
|
||||
VaadinServlet vaadinServlet = VaadinServlet.getCurrent();
|
||||
ServletContext sc = vaadinServlet.getServletContext();
|
||||
String resourcesTimestamp = sc.getInitParameter("webResourcesTs");
|
||||
if (StringUtils.isNotEmpty(resourcesTimestamp)) {
|
||||
this.webResourceTimestamp = resourcesTimestamp;
|
||||
}
|
||||
|
||||
log.debug("Initializing application");
|
||||
|
||||
// get default locale from config
|
||||
MessageTools messageTools = AppBeans.get(MessageTools.NAME);
|
||||
locale = messageTools.getDefaultLocale();
|
||||
Locale targetLocale = resolveLocale(requestLocale);
|
||||
setLocale(targetLocale);
|
||||
|
||||
clientCacheManager.initialize();
|
||||
|
||||
if (webAuthConfig.getExternalAuthentication()) {
|
||||
principal = RequestContext.get().getRequest().getUserPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
protected Locale resolveLocale(@Nullable Locale requestLocale) {
|
||||
Map<String, Locale> locales = globalConfig.getAvailableLocales();
|
||||
|
||||
if (globalConfig.getLocaleSelectVisible()) {
|
||||
String lastLocale = getCookieValue(COOKIE_LOCALE);
|
||||
if (lastLocale != null) {
|
||||
for (Locale locale : locales.values()) {
|
||||
if (locale.toLanguageTag().equals(lastLocale)) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requestLocale != null) {
|
||||
Locale requestTrimmedLocale = messageTools.trimLocale(requestLocale);
|
||||
if (locales.containsValue(requestTrimmedLocale)) {
|
||||
return requestTrimmedLocale;
|
||||
}
|
||||
|
||||
// if not found and application locale contains country, try to match by language only
|
||||
if (!StringUtils.isEmpty(requestLocale.getCountry())) {
|
||||
Locale appLocale = Locale.forLanguageTag(requestLocale.getLanguage());
|
||||
for (Locale locale : locales.values()) {
|
||||
if (Locale.forLanguageTag(locale.getLanguage()).equals(appLocale)) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return default locale
|
||||
return messageTools.getDefaultLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on each UI initialization.
|
||||
*
|
||||
* @param ui initialized UI
|
||||
* Called on each browser tab initialization.
|
||||
*/
|
||||
protected void initView(AppUI ui) {
|
||||
public void createTopLevelWindow(AppUI ui) {
|
||||
WebWindowManager wm = new WebWindowManager(ui);
|
||||
|
||||
String topLevelWindowId = routeTopLevelWindowId();
|
||||
wm.createTopLevelWindow(windowConfig.getWindowInfo(topLevelWindowId));
|
||||
}
|
||||
|
||||
protected abstract String routeTopLevelWindowId();
|
||||
|
||||
public void createTopLevelWindow() {
|
||||
createTopLevelWindow(AppUI.getCurrent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize new TopLevelWindow and replace current
|
||||
*
|
||||
* @param topLevelWindowId target top level window id
|
||||
*/
|
||||
public void navigateTo(String topLevelWindowId) {
|
||||
WebWindowManager wm = new WebWindowManager(AppUI.getCurrent());
|
||||
|
||||
wm.createTopLevelWindow(windowConfig.getWindowInfo(topLevelWindowId));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,13 +327,14 @@ public abstract class App {
|
||||
* Used for ping middleware session and show session messages
|
||||
*/
|
||||
public void onHeartbeat() {
|
||||
if (getConnection().isConnected()) {
|
||||
Connection connection = getConnection();
|
||||
|
||||
if (getConnection().isConnected() && connection.isAuthenticated()) {
|
||||
// Ping middleware session if connected and show messages
|
||||
log.debug("Ping session");
|
||||
|
||||
try {
|
||||
UserSessionService service = AppBeans.get(UserSessionService.NAME);
|
||||
String message = service.getMessages();
|
||||
String message = userSessionService.getMessages();
|
||||
if (message != null) {
|
||||
message = message.replace("\n", "<br/>");
|
||||
getWindowManager().showNotification(message, Frame.NotificationType.ERROR_HTML);
|
||||
@ -291,15 +379,16 @@ public abstract class App {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WindowManager instance or null if the current UI has no AppWindow
|
||||
* @return WindowManager instance or null if the current UI has no MainWindow
|
||||
*/
|
||||
public WebWindowManager getWindowManager() {
|
||||
if (getAppUI() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AppWindow appWindow = getAppUI().getAppWindow();
|
||||
return appWindow != null ? appWindow.getWindowManager() : null;
|
||||
Window.TopLevelWindow topLevelWindow = getTopLevelWindow();
|
||||
|
||||
return topLevelWindow != null ? (WebWindowManager) topLevelWindow.getWindowManager() : null;
|
||||
}
|
||||
|
||||
public AppLog getAppLog() {
|
||||
@ -310,26 +399,6 @@ public abstract class App {
|
||||
return exceptionHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the login window instance.
|
||||
*
|
||||
* @param ui current UI
|
||||
* @return login window
|
||||
*/
|
||||
protected UIView createLoginWindow(AppUI ui) {
|
||||
return new LoginWindow(ui);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the main window instance.
|
||||
*
|
||||
* @param ui current UI
|
||||
* @return main window
|
||||
*/
|
||||
protected AppWindow createAppWindow(AppUI ui) {
|
||||
return new AppWindow(ui);
|
||||
}
|
||||
|
||||
public String getCookieValue(String name) {
|
||||
return cookies.getCookieValue(name);
|
||||
}
|
||||
@ -355,14 +424,27 @@ public abstract class App {
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
return VaadinSession.getCurrent().getLocale();
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
UserSession session = getConnection().getSession();
|
||||
if (session != null) {
|
||||
session.setLocale(locale);
|
||||
}
|
||||
|
||||
UI.getCurrent().setLocale(locale);
|
||||
VaadinSession.getCurrent().setLocale(locale);
|
||||
AppUI currentUi = AppUI.getCurrent();
|
||||
|
||||
currentUi.getSession().setLocale(locale);
|
||||
currentUi.updateClientSystemMessages(locale);
|
||||
|
||||
for (AppUI ui : getAppUIs()) {
|
||||
if (ui != currentUi) {
|
||||
ui.accessSynchronously(() ->
|
||||
ui.updateClientSystemMessages(locale)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getClientAddress() {
|
||||
@ -371,9 +453,10 @@ public abstract class App {
|
||||
String xForwardedFor = request.getHeader("X_FORWARDED_FOR");
|
||||
if (!StringUtils.isBlank(xForwardedFor)) {
|
||||
String[] strings = xForwardedFor.split(",");
|
||||
clientAddress = strings[strings.length - 1].trim();
|
||||
} else
|
||||
clientAddress = StringUtils.trimToEmpty(strings[strings.length - 1]);
|
||||
} else {
|
||||
clientAddress = request.getRemoteAddr();
|
||||
}
|
||||
}
|
||||
|
||||
return clientAddress;
|
||||
@ -387,10 +470,6 @@ public abstract class App {
|
||||
return webResourceTimestamp;
|
||||
}
|
||||
|
||||
public BackgroundTaskManager getTaskManager() {
|
||||
return backgroundTaskManager;
|
||||
}
|
||||
|
||||
public void addBackgroundTask(Future task) {
|
||||
backgroundTaskManager.addTask(task);
|
||||
}
|
||||
@ -406,15 +485,16 @@ public abstract class App {
|
||||
public void closeAllWindows() {
|
||||
log.debug("Closing all windows");
|
||||
try {
|
||||
for (final AppUI ui : getAppUIs()) {
|
||||
for (AppUI ui : getAppUIs()) {
|
||||
ui.accessSynchronously(() -> {
|
||||
AppWindow appWindow = ui.getAppWindow();
|
||||
if (appWindow != null) {
|
||||
WebWindowManager webWindowManager = appWindow.getWindowManager();
|
||||
Window.TopLevelWindow topLevelWindow = getTopLevelWindow();
|
||||
if (topLevelWindow != null) {
|
||||
WebWindowManager webWindowManager = (WebWindowManager) topLevelWindow.getWindowManager();
|
||||
webWindowManager.disableSavingScreenHistory = true;
|
||||
webWindowManager.closeAll();
|
||||
}
|
||||
|
||||
// also remove all native Vaadin windows, that is not under CUBA control
|
||||
for (com.vaadin.ui.Window win : new ArrayList<>(ui.getWindows())) {
|
||||
ui.removeWindow(win);
|
||||
}
|
||||
@ -426,7 +506,6 @@ public abstract class App {
|
||||
}
|
||||
|
||||
protected void clearSettingsCache() {
|
||||
WebSettingsClient webSettingsClient = AppBeans.get(SettingsClient.NAME);
|
||||
webSettingsClient.clearCache();
|
||||
((WebSettingsClient) settingsClient).clearCache();
|
||||
}
|
||||
}
|
@ -17,46 +17,74 @@
|
||||
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.client.ClientUserSession;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.global.ScreenProfilerConfig;
|
||||
import com.haulmont.cuba.gui.TestIdManager;
|
||||
import com.haulmont.cuba.gui.components.Window.TopLevelWindow;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
|
||||
import com.haulmont.cuba.security.app.UserSessionService;
|
||||
import com.haulmont.cuba.security.global.LoginException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.app.UserSettingsTools;
|
||||
import com.haulmont.cuba.web.controllers.ControllerUtils;
|
||||
import com.haulmont.cuba.web.sys.LinkHandler;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaClientManager;
|
||||
import com.haulmont.cuba.web.toolkit.ui.*;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.appui.AppUIClientRpc;
|
||||
import com.vaadin.annotations.PreserveOnRefresh;
|
||||
import com.vaadin.annotations.Push;
|
||||
import com.vaadin.server.*;
|
||||
import com.vaadin.server.ErrorHandler;
|
||||
import com.vaadin.server.Extension;
|
||||
import com.vaadin.server.VaadinRequest;
|
||||
import com.vaadin.server.WrappedSession;
|
||||
import com.vaadin.shared.ui.ui.Transport;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.*;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Single window / page of web application. Root component of Vaadin layout.
|
||||
*/
|
||||
@org.springframework.stereotype.Component(AppUI.NAME)
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@Push(transport = Transport.WEBSOCKET_XHR)
|
||||
@PreserveOnRefresh
|
||||
public class AppUI extends UI implements ErrorHandler {
|
||||
public class AppUI extends UI implements ErrorHandler, CubaHistoryControl.HistoryBackHandler {
|
||||
|
||||
public static final String APPLICATION_CLASS_CONFIG_KEY = "Application";
|
||||
public static final String NAME = "cuba_AppUI";
|
||||
|
||||
public static final String LAST_REQUEST_ACTION_ATTR = "lastRequestAction";
|
||||
|
||||
public static final String LAST_REQUEST_PARAMS_ATTR = "lastRequestParams";
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(AppUI.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(AppUI.class);
|
||||
|
||||
protected final App app;
|
||||
protected App app;
|
||||
|
||||
protected boolean applicationInitRequired = false;
|
||||
@Inject
|
||||
protected Messages messages;
|
||||
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Inject
|
||||
protected WebConfig webConfig;
|
||||
|
||||
@Inject
|
||||
protected ScreenProfilerConfig screenProfilerConfig;
|
||||
|
||||
@Inject
|
||||
protected UserSettingsTools userSettingsTools;
|
||||
|
||||
@Inject
|
||||
protected ThemeConstantsRepository themeConstantsRepository;
|
||||
|
||||
protected TestIdManager testIdManager = new TestIdManager();
|
||||
|
||||
@ -68,47 +96,21 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
|
||||
protected CubaClientManager clientManager;
|
||||
|
||||
protected ScreenClientProfilerAgent clientProfiler;
|
||||
|
||||
protected CubaFileDownloader fileDownloader;
|
||||
|
||||
protected CubaHistoryControl historyControl;
|
||||
|
||||
protected TopLevelWindow topLevelWindow;
|
||||
|
||||
public AppUI() {
|
||||
log.trace("Creating UI {}", this);
|
||||
if (!App.isBound()) {
|
||||
app = createApplication();
|
||||
|
||||
VaadinSession vSession = VaadinSession.getCurrent();
|
||||
vSession.setAttribute(App.class, app);
|
||||
|
||||
// set root error handler for all session
|
||||
vSession.setErrorHandler((ErrorHandler) event -> {
|
||||
try {
|
||||
app.getExceptionHandlers().handle(event);
|
||||
app.getAppLog().log(event);
|
||||
} catch (Throwable e) {
|
||||
//noinspection ThrowableResultOfMethodCallIgnored
|
||||
log.error("Error handling exception\nOriginal exception:\n{}\nException in handlers:\n{}",
|
||||
ExceptionUtils.getStackTrace(event.getThrowable()), ExceptionUtils.getStackTrace(e)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
applicationInitRequired = true;
|
||||
} else {
|
||||
app = App.getInstance();
|
||||
}
|
||||
|
||||
Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
testMode = configuration.getConfig(GlobalConfig.class).getTestMode();
|
||||
|
||||
// do not grab focus
|
||||
setTabIndex(-1);
|
||||
|
||||
initJsLibraries();
|
||||
|
||||
initInternalComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically init external JS libraries.
|
||||
* You should create JavaScriptExtension class and extend UI object here. <br/>
|
||||
*
|
||||
* <p>
|
||||
* Example: <br/>
|
||||
* <pre><code>
|
||||
* JavaScriptExtension:
|
||||
@ -132,7 +134,7 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
* protected void initJsLibraries() {
|
||||
* new JQueryIntegration().extend(this);
|
||||
* }</code></pre>
|
||||
*
|
||||
* <p>
|
||||
* If you want to include scripts to generated page statically see {@link com.haulmont.cuba.web.sys.CubaBootstrapListener}.
|
||||
*/
|
||||
protected void initJsLibraries() {
|
||||
@ -141,60 +143,128 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
protected void initInternalComponents() {
|
||||
clientManager = new CubaClientManager();
|
||||
clientManager.extend(this);
|
||||
|
||||
fileDownloader = new CubaFileDownloader();
|
||||
fileDownloader.extend(this);
|
||||
|
||||
clientProfiler = new ScreenClientProfilerAgent();
|
||||
clientProfiler.extend(this);
|
||||
|
||||
if (webConfig.getAllowHandleBrowserHistoryBack()) {
|
||||
historyControl = new CubaHistoryControl();
|
||||
historyControl.extend(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
protected App createApplication() {
|
||||
String applicationClass = getApplicationClass();
|
||||
App application;
|
||||
try {
|
||||
Class<?> aClass = getClass().getClassLoader().loadClass(applicationClass);
|
||||
application = (App) aClass.newInstance();
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
||||
throw new Error(String.format("Unable to create application '%s'", applicationClass), e);
|
||||
}
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
protected String getApplicationClass() {
|
||||
DeploymentConfiguration vConf = VaadinService.getCurrent().getDeploymentConfiguration();
|
||||
return vConf.getApplicationOrSystemProperty(APPLICATION_CLASS_CONFIG_KEY,
|
||||
DefaultApp.class.getCanonicalName());
|
||||
return AppBeans.getPrototype(App.NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(VaadinRequest request) {
|
||||
log.debug("Initializing AppUI");
|
||||
if (applicationInitRequired) {
|
||||
app.init();
|
||||
log.trace("Initializing UI {}", this);
|
||||
|
||||
MessageTools messageTools = AppBeans.get(MessageTools.NAME);
|
||||
Locale locale = messageTools.trimLocale(request.getLocale());
|
||||
app.setLocale(locale);
|
||||
try {
|
||||
this.testMode = globalConfig.getTestMode();
|
||||
|
||||
applicationInitRequired = false;
|
||||
// init error handlers
|
||||
setErrorHandler(this);
|
||||
|
||||
// do not grab focus
|
||||
setTabIndex(-1);
|
||||
|
||||
initJsLibraries();
|
||||
|
||||
initInternalComponents();
|
||||
|
||||
if (!App.isBound()) {
|
||||
App app = createApplication();
|
||||
app.init(request.getLocale());
|
||||
|
||||
this.app = app;
|
||||
} else {
|
||||
this.app = App.getInstance();
|
||||
}
|
||||
|
||||
setupUI();
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to init ui", e);
|
||||
|
||||
// unable to connect to middle ware
|
||||
showCriticalExceptionMessage(e);
|
||||
return;
|
||||
}
|
||||
// init error handlers
|
||||
setErrorHandler(this);
|
||||
// open login or main window
|
||||
app.initView(this);
|
||||
|
||||
processExternalLink(request);
|
||||
}
|
||||
|
||||
protected void showCriticalExceptionMessage(Exception e) {
|
||||
String initErrorCaption = messages.getMainMessage("app.initErrorCaption");
|
||||
String initErrorMessage = messages.getMainMessage("app.initErrorMessage");
|
||||
|
||||
VerticalLayout content = new VerticalLayout();
|
||||
content.setStyleName("cuba-init-error-view");
|
||||
content.setSizeFull();
|
||||
|
||||
VerticalLayout errorPanel = new VerticalLayout();
|
||||
errorPanel.setStyleName("cuba-init-error-panel");
|
||||
errorPanel.setWidthUndefined();
|
||||
errorPanel.setSpacing(true);
|
||||
|
||||
Label captionLabel = new Label(initErrorCaption);
|
||||
captionLabel.setWidthUndefined();
|
||||
captionLabel.setStyleName("cuba-init-error-caption");
|
||||
captionLabel.addStyleName("h2");
|
||||
captionLabel.setValue(initErrorCaption);
|
||||
|
||||
errorPanel.addComponent(captionLabel);
|
||||
|
||||
Label messageLabel = new Label(initErrorCaption);
|
||||
messageLabel.setWidthUndefined();
|
||||
messageLabel.setStyleName("cuba-init-error-message");
|
||||
messageLabel.setValue(initErrorMessage);
|
||||
|
||||
errorPanel.addComponent(messageLabel);
|
||||
|
||||
Button retryButton = new Button(messages.getMainMessage("app.initRetry"));
|
||||
retryButton.setStyleName("cuba-init-error-retry");
|
||||
retryButton.addClickListener((Button.ClickListener) event -> {
|
||||
// always restart UI
|
||||
String url = ControllerUtils.getLocationWithoutParams() + "?restartApp";
|
||||
getPage().open(url, "_self");
|
||||
});
|
||||
|
||||
errorPanel.addComponent(retryButton);
|
||||
errorPanel.setComponentAlignment(retryButton, Alignment.MIDDLE_CENTER);
|
||||
|
||||
content.addComponent(errorPanel);
|
||||
content.setComponentAlignment(errorPanel, Alignment.MIDDLE_CENTER);
|
||||
|
||||
setContent(content);
|
||||
}
|
||||
|
||||
protected void setupUI() throws LoginException {
|
||||
if (!app.getConnection().isConnected() && !app.loginOnStart()) {
|
||||
app.getConnection().loginAnonymous(app.getLocale());
|
||||
} else {
|
||||
app.createTopLevelWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refresh(VaadinRequest request) {
|
||||
super.refresh(request);
|
||||
|
||||
// handle page refresh
|
||||
if (app.getConnection().isConnected()) {
|
||||
if (app.getConnection().isAuthenticated()) {
|
||||
// Ping middleware session if connected
|
||||
log.debug("Check middleware session");
|
||||
log.debug("Ping middleware session");
|
||||
|
||||
try {
|
||||
UserSessionService service = AppBeans.get(UserSessionService.NAME);
|
||||
UserSession session = app.getConnection().getSession();
|
||||
if (session != null) {
|
||||
if (session instanceof ClientUserSession
|
||||
&& ((ClientUserSession) session).isAuthenticated()) {
|
||||
service.getUserSession(session.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -209,17 +279,6 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
processExternalLink(request);
|
||||
}
|
||||
|
||||
public void showView(UIView view) {
|
||||
try {
|
||||
setContent(view);
|
||||
getPage().setTitle(view.getTitle());
|
||||
|
||||
view.show();
|
||||
} catch (Exception e) {
|
||||
error(new com.vaadin.server.ErrorEvent(e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current AppUI
|
||||
*/
|
||||
@ -234,15 +293,18 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AppWindow instance or null if not logged in
|
||||
*/
|
||||
public AppWindow getAppWindow() {
|
||||
Component currentUIView = getContent();
|
||||
if (currentUIView instanceof AppWindow) {
|
||||
return (AppWindow) currentUIView;
|
||||
} else {
|
||||
return null;
|
||||
public TopLevelWindow getTopLevelWindow() {
|
||||
return topLevelWindow;
|
||||
}
|
||||
|
||||
public void setTopLevelWindow(TopLevelWindow window) {
|
||||
if (this.topLevelWindow != window) {
|
||||
this.topLevelWindow = window;
|
||||
|
||||
// unregister previous components
|
||||
setContent(null);
|
||||
|
||||
setContent(topLevelWindow.unwrapComposition(Component.class));
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,14 +330,14 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
}
|
||||
|
||||
public void processExternalLink(VaadinRequest request) {
|
||||
String action = (String) request.getWrappedSession().getAttribute(LAST_REQUEST_ACTION_ATTR);
|
||||
WrappedSession wrappedSession = request.getWrappedSession();
|
||||
|
||||
String action = (String) wrappedSession.getAttribute(LAST_REQUEST_ACTION_ATTR);
|
||||
|
||||
Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
WebConfig webConfig = configuration.getConfig(WebConfig.class);
|
||||
if (webConfig.getLinkHandlerActions().contains(action)) {
|
||||
//noinspection unchecked
|
||||
Map<String, String> params =
|
||||
(Map<String, String>) request.getWrappedSession().getAttribute(LAST_REQUEST_PARAMS_ATTR);
|
||||
(Map<String, String>) wrappedSession.getAttribute(LAST_REQUEST_PARAMS_ATTR);
|
||||
if (params == null) {
|
||||
log.warn("Unable to process the external link: lastRequestParams not found in session");
|
||||
return;
|
||||
@ -327,14 +389,15 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
}
|
||||
|
||||
public void clearProfiledScreens(List<String> profilerMarkers) {
|
||||
for (String profilerMarker : profilerMarkers) {
|
||||
profiledScreens.remove(profilerMarker);
|
||||
if (profiledScreens != null) {
|
||||
for (String profilerMarker : profilerMarkers) {
|
||||
profiledScreens.remove(profilerMarker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateClientSystemMessages(Locale locale) {
|
||||
CubaClientManager.SystemMessages msgs = new CubaClientManager.SystemMessages();
|
||||
Messages messages = AppBeans.get(Messages.NAME);
|
||||
|
||||
msgs.communicationErrorCaption = messages.getMainMessage("communicationErrorCaption", locale);
|
||||
msgs.communicationErrorMessage = messages.getMainMessage("communicationErrorMessage", locale);
|
||||
@ -350,4 +413,81 @@ public class AppUI extends UI implements ErrorHandler {
|
||||
getReconnectDialogConfiguration().setDialogText(messages.getMainMessage("reconnectDialogText", locale));
|
||||
getReconnectDialogConfiguration().setDialogTextGaveUp(messages.getMainMessage("reconnectDialogTextGaveUp", locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHistoryBackPerformed() {
|
||||
TopLevelWindow topLevelWindow = getTopLevelWindow();
|
||||
if (topLevelWindow instanceof CubaHistoryControl.HistoryBackHandler) {
|
||||
((CubaHistoryControl.HistoryBackHandler) topLevelWindow).onHistoryBackPerformed();
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractComponent getTopLevelWindowComposition() {
|
||||
if (topLevelWindow == null) {
|
||||
throw new IllegalStateException("UI does not have top level window");
|
||||
}
|
||||
|
||||
return topLevelWindow.unwrapComposition(AbstractComponent.class);
|
||||
}
|
||||
|
||||
public List<CubaTimer> getTimers() {
|
||||
AbstractComponent timersHolder = getTopLevelWindowComposition();
|
||||
|
||||
List<CubaTimer> timers = new ArrayList<>();
|
||||
for (Extension extension : timersHolder.getExtensions()) {
|
||||
if (extension instanceof CubaTimer) {
|
||||
timers.add((CubaTimer) extension);
|
||||
}
|
||||
}
|
||||
return timers;
|
||||
}
|
||||
|
||||
public void addTimer(CubaTimer timer) {
|
||||
AbstractComponent timersHolder = getTopLevelWindowComposition();
|
||||
|
||||
if (!timersHolder.getExtensions().contains(timer)) {
|
||||
timer.extend(timersHolder);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTimer(CubaTimer timer) {
|
||||
AbstractComponent timersHolder = getTopLevelWindowComposition();
|
||||
|
||||
timersHolder.removeExtension(timer);
|
||||
}
|
||||
|
||||
public void beforeTopLevelWindowInit() {
|
||||
updateUiTheme();
|
||||
|
||||
setProfilerParameters();
|
||||
|
||||
updateClientSystemMessages(app.getLocale());
|
||||
|
||||
getTestIdManager().reset();
|
||||
}
|
||||
|
||||
protected void setProfilerParameters() {
|
||||
clientProfiler.setFlushEventsCount(screenProfilerConfig.getFlushEventsCount());
|
||||
clientProfiler.setFlushTimeout(screenProfilerConfig.getFlushTimeout());
|
||||
}
|
||||
|
||||
protected void updateUiTheme() {
|
||||
// load theme from user settings
|
||||
String themeName = webConfig.getAppWindowTheme();
|
||||
|
||||
themeName = userSettingsTools.loadAppWindowTheme() == null ? themeName : userSettingsTools.loadAppWindowTheme();
|
||||
|
||||
if (!Objects.equals(themeName, getTheme())) {
|
||||
// check theme support
|
||||
Set<String> supportedThemes = themeConstantsRepository.getAvailableThemes();
|
||||
if (supportedThemes.contains(themeName)) {
|
||||
app.applyTheme(themeName);
|
||||
setTheme(themeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CubaFileDownloader getFileDownloader() {
|
||||
return fileDownloader;
|
||||
}
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.global.UserSessionSource;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.components.mainwindow.UserIndicator;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.config.WindowInfo;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
|
||||
import com.haulmont.cuba.web.app.UserSettingsTools;
|
||||
import com.haulmont.cuba.web.toolkit.ui.*;
|
||||
import com.vaadin.server.Extension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Standard main application window.
|
||||
* <p/>
|
||||
* To use a specific implementation override {@link App#createAppWindow(AppUI)} method.
|
||||
*/
|
||||
public class AppWindow extends UIView implements CubaHistoryControl.HistoryBackHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AppWindow.class);
|
||||
|
||||
protected final AppUI ui;
|
||||
|
||||
protected final App app;
|
||||
|
||||
protected final Connection connection;
|
||||
|
||||
protected final WebWindowManager windowManager;
|
||||
|
||||
protected CubaFileDownloader fileDownloader;
|
||||
|
||||
protected CubaHistoryControl historyControl;
|
||||
|
||||
protected ScreenClientProfilerAgent clientProfiler;
|
||||
|
||||
protected WebConfig webConfig;
|
||||
|
||||
protected Window.MainWindow mainWindow;
|
||||
|
||||
protected Messages messages = AppBeans.get(Messages.NAME);
|
||||
|
||||
public AppWindow(AppUI ui) {
|
||||
log.trace("Creating " + this);
|
||||
|
||||
this.ui = ui;
|
||||
this.app = ui.getApp();
|
||||
this.connection = app.getConnection();
|
||||
this.windowManager = createWindowManager();
|
||||
|
||||
Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
webConfig = configuration.getConfig(WebConfig.class);
|
||||
|
||||
setSizeFull();
|
||||
|
||||
initInternalComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
updateClientSystemMessages();
|
||||
|
||||
beforeInitLayout();
|
||||
|
||||
initAppMainWindow();
|
||||
}
|
||||
|
||||
protected void initAppMainWindow() {
|
||||
WindowConfig windowConfig = AppBeans.get(WindowConfig.NAME);
|
||||
WindowInfo mainWindowInfo = windowConfig.getWindowInfo("mainWindow");
|
||||
windowManager.initMainWindow(mainWindowInfo);
|
||||
}
|
||||
|
||||
public AppUI getAppUI() {
|
||||
return ui;
|
||||
}
|
||||
|
||||
public WebWindowManager getWindowManager() {
|
||||
return windowManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new instance of {@link WebWindowManager}
|
||||
*/
|
||||
protected WebWindowManager createWindowManager() {
|
||||
return new WebWindowManager(app, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* init system components
|
||||
*/
|
||||
protected void initInternalComponents() {
|
||||
fileDownloader = new CubaFileDownloader();
|
||||
fileDownloader.extend(this);
|
||||
|
||||
clientProfiler = new ScreenClientProfilerAgent();
|
||||
clientProfiler.extend(this);
|
||||
|
||||
if (webConfig.getAllowHandleBrowserHistoryBack()) {
|
||||
historyControl = new CubaHistoryControl();
|
||||
historyControl.extend(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateClientSystemMessages() {
|
||||
UserSessionSource sessionSource = AppBeans.get(UserSessionSource.NAME);
|
||||
Locale locale = sessionSource.getLocale();
|
||||
|
||||
ui.updateClientSystemMessages(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user presses browser "Back" button and {@code cuba.web.allowHandleBrowserHistoryBack}
|
||||
* application property is true.
|
||||
* <p>Override this method and implement your logic to handle the "Back" button.
|
||||
*/
|
||||
@Override
|
||||
public void onHistoryBackPerformed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getAppCaption();
|
||||
}
|
||||
|
||||
public Window.MainWindow getMainWindow() {
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
protected void setMainWindow(Window.MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Application caption to be shown in browser page title
|
||||
*/
|
||||
protected String getAppCaption() {
|
||||
return messages.getMainMessage("application.caption");
|
||||
}
|
||||
|
||||
public CubaFileDownloader getFileDownloader() {
|
||||
return fileDownloader;
|
||||
}
|
||||
|
||||
public List<CubaTimer> getTimers() {
|
||||
List<CubaTimer> timers = new LinkedList<>();
|
||||
for (Extension extension : this.getExtensions()) {
|
||||
if (extension instanceof CubaTimer) {
|
||||
timers.add((CubaTimer) extension);
|
||||
}
|
||||
}
|
||||
return timers;
|
||||
}
|
||||
|
||||
public void addTimer(CubaTimer timer) {
|
||||
if (!getExtensions().contains(timer)) {
|
||||
timer.extend(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTimer(CubaTimer timer) {
|
||||
removeExtension(timer);
|
||||
}
|
||||
|
||||
protected void beforeInitLayout() {
|
||||
// load theme from user settings
|
||||
String themeName = webConfig.getAppWindowTheme();
|
||||
UserSettingsTools userSettingsTools = AppBeans.get(UserSettingsTools.NAME);
|
||||
themeName = userSettingsTools.loadAppWindowTheme() == null ? themeName : userSettingsTools.loadAppWindowTheme();
|
||||
|
||||
if (!Objects.equals(themeName, ui.getTheme())) {
|
||||
// check theme support
|
||||
ThemeConstantsRepository themeRepository = AppBeans.get(ThemeConstantsRepository.NAME);
|
||||
Set<String> supportedThemes = themeRepository.getAvailableThemes();
|
||||
if (supportedThemes.contains(themeName)) {
|
||||
app.applyTheme(themeName);
|
||||
ui.setTheme(themeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshUserSubstitutions() {
|
||||
UserIndicator userIndicator = getMainWindow().getUserIndicator();
|
||||
if (userIndicator != null) {
|
||||
userIndicator.refreshUserSubstitutions();
|
||||
}
|
||||
}
|
||||
}
|
@ -25,10 +25,16 @@ import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects that connect web-client to the middleware.
|
||||
*
|
||||
*/
|
||||
public interface Connection {
|
||||
|
||||
String NAME = "cuba_Connection";
|
||||
|
||||
enum SessionMode {
|
||||
AUTHENTICATED,
|
||||
ANONYMOUS
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in to the system.
|
||||
* @param login user login name
|
||||
@ -38,6 +44,13 @@ public interface Connection {
|
||||
*/
|
||||
void login(String login, String password, Locale locale) throws LoginException;
|
||||
|
||||
/**
|
||||
* Log in to the system.
|
||||
* @param locale user locale
|
||||
* @throws LoginException in case of unsuccessful login due to wrong credentials or other issues
|
||||
*/
|
||||
void loginAnonymous(Locale locale) throws LoginException;
|
||||
|
||||
/**
|
||||
* Log in to the system.
|
||||
* @param login user login name
|
||||
@ -52,7 +65,7 @@ public interface Connection {
|
||||
* Returns URL to which the user will be redirected after logout.
|
||||
* @return redirection URL
|
||||
*/
|
||||
String logout();
|
||||
void logout();
|
||||
|
||||
/**
|
||||
* Substitute a user in the current session with another user. This method creates a new UserSession instance,
|
||||
@ -69,6 +82,12 @@ public interface Connection {
|
||||
*/
|
||||
boolean isConnected();
|
||||
|
||||
/**
|
||||
* Check if the client was authenticated.
|
||||
* @return true if authenticated
|
||||
*/
|
||||
boolean isAuthenticated();
|
||||
|
||||
/**
|
||||
* Check if session is alive on middleware
|
||||
*
|
||||
@ -97,7 +116,7 @@ public interface Connection {
|
||||
* @param session new UserSession object
|
||||
* @throws LoginException in case of unsuccessful update
|
||||
*/
|
||||
void update(UserSession session) throws LoginException;
|
||||
void update(UserSession session, SessionMode sessionMode) throws LoginException;
|
||||
|
||||
/**
|
||||
* Add a connection listener.
|
||||
|
@ -21,7 +21,6 @@ import com.haulmont.cuba.security.global.LoginException;
|
||||
/**
|
||||
* Listener of connection events. See {@link com.haulmont.cuba.web.Connection}.
|
||||
*/
|
||||
public interface ConnectionListener
|
||||
{
|
||||
public interface ConnectionListener {
|
||||
void connectionStateChanged(Connection connection) throws LoginException;
|
||||
}
|
||||
}
|
@ -16,54 +16,74 @@
|
||||
*/
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.cuba.client.sys.cache.ClientCacheManager;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.cuba.core.global.UserSessionSource;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.WindowManager.OpenType;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.config.WindowInfo;
|
||||
import com.haulmont.cuba.security.entity.User;
|
||||
import com.haulmont.cuba.security.global.LoginException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.app.loginwindow.AppLoginWindow;
|
||||
import com.haulmont.cuba.web.auth.ExternallyAuthenticatedConnection;
|
||||
import com.vaadin.server.*;
|
||||
import com.vaadin.server.VaadinService;
|
||||
import com.vaadin.server.VaadinSession;
|
||||
import com.vaadin.server.WrappedHttpSession;
|
||||
import com.vaadin.server.WrappedSession;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Default {@link App} implementation that shows {@link LoginWindow} on start.
|
||||
* Default {@link App} implementation that shows {@link AppLoginWindow} on start.
|
||||
* Supports SSO through external authentication.
|
||||
*
|
||||
*/
|
||||
@Component(App.NAME)
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class DefaultApp extends App implements ConnectionListener, UserSubstitutionListener {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(DefaultApp.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(DefaultApp.class);
|
||||
|
||||
// Login on start only on first request from user
|
||||
protected boolean tryLoginOnStart = true;
|
||||
|
||||
@Inject
|
||||
protected UserSessionSource userSessionSource;
|
||||
|
||||
public DefaultApp() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection createConnection() {
|
||||
Connection connection = new DefaultConnection();
|
||||
Connection connection = super.createConnection();
|
||||
connection.addConnectionListener(this);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionStateChanged(Connection connection) throws LoginException {
|
||||
log.debug("connectionStateChanged connected: {}, authenticated: {}",
|
||||
connection.isConnected(), connection.isAuthenticated());
|
||||
|
||||
cleanupBackgroundTasks();
|
||||
closeAllWindows();
|
||||
clearSettingsCache();
|
||||
|
||||
if (connection.isConnected()) {
|
||||
UserSession userSession = connection.getSession();
|
||||
if (userSession == null) {
|
||||
throw new IllegalStateException("Unable to obtain session from connected Connection");
|
||||
}
|
||||
setLocale(userSession.getLocale());
|
||||
|
||||
// substitution listeners are cleared by connection on logout
|
||||
connection.addSubstitutionListener(this);
|
||||
|
||||
ClientCacheManager clientCacheManager = AppBeans.get(ClientCacheManager.NAME);
|
||||
clientCacheManager.initialize();
|
||||
|
||||
if (webConfig.getUseSessionFixationProtection()) {
|
||||
VaadinService.reinitializeSession(VaadinService.getCurrentRequest());
|
||||
|
||||
@ -71,18 +91,23 @@ public class DefaultApp extends App implements ConnectionListener, UserSubstitut
|
||||
int timeout = webConfig.getHttpSessionExpirationTimeoutSec();
|
||||
session.setMaxInactiveInterval(timeout);
|
||||
|
||||
HttpSession httpSession = session instanceof WrappedHttpSession ? ((WrappedHttpSession) session).getHttpSession() : null;
|
||||
log.debug("connectionStateChanged: HttpSession={}, timeout={}sec, UserSession={}", httpSession, timeout, connection.getSession());
|
||||
} else {
|
||||
log.debug("connectionStateChanged");
|
||||
HttpSession httpSession = session instanceof WrappedHttpSession ?
|
||||
((WrappedHttpSession) session).getHttpSession() : null;
|
||||
log.debug("Session reinitialized: HttpSession={}, timeout={}sec, UserSession={}",
|
||||
httpSession, timeout, connection.getSession());
|
||||
}
|
||||
|
||||
initExceptionHandlers(true);
|
||||
for (final AppUI ui : getAppUIs()) {
|
||||
ui.accessSynchronously(() -> {
|
||||
AppWindow appWindow = createAppWindow(ui);
|
||||
ui.showView(appWindow);
|
||||
});
|
||||
|
||||
AppUI currentUi = AppUI.getCurrent();
|
||||
createTopLevelWindow(currentUi);
|
||||
|
||||
for (AppUI ui : getAppUIs()) {
|
||||
if (currentUi != ui) {
|
||||
ui.accessSynchronously(() ->
|
||||
createTopLevelWindow(ui)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (linkHandler != null) {
|
||||
@ -92,30 +117,20 @@ public class DefaultApp extends App implements ConnectionListener, UserSubstitut
|
||||
|
||||
afterLoggedIn();
|
||||
} else {
|
||||
cleanupBackgroundTasks();
|
||||
closeAllWindows();
|
||||
clearSettingsCache();
|
||||
|
||||
for (final AppUI ui : getAppUIs()) {
|
||||
ui.accessSynchronously(() -> {
|
||||
if (ui.isTestMode()) {
|
||||
ui.getTestIdManager().reset();
|
||||
}
|
||||
|
||||
UIView window = createLoginWindow(ui);
|
||||
ui.showView(window);
|
||||
});
|
||||
}
|
||||
initExceptionHandlers(false);
|
||||
|
||||
setLocale(resolveLocale(null));
|
||||
|
||||
getConnection().loginAnonymous(getLocale());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView(AppUI ui) {
|
||||
if (connection.isAlive() || loginOnStart()) {
|
||||
ui.showView(createAppWindow(ui));
|
||||
protected String routeTopLevelWindowId() {
|
||||
if (connection.isConnected() && connection.isAuthenticated()) {
|
||||
return "mainWindow";
|
||||
} else {
|
||||
ui.showView(createLoginWindow(ui));
|
||||
return "loginWindow";
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,24 +138,23 @@ public class DefaultApp extends App implements ConnectionListener, UserSubstitut
|
||||
* Perform actions after successful login
|
||||
*/
|
||||
protected void afterLoggedIn() {
|
||||
if (!webAuthConfig.getExternalAuthentication()) {
|
||||
UserSessionSource sessionSource = AppBeans.get(UserSessionSource.NAME);
|
||||
final User user = sessionSource.getUserSession().getUser();
|
||||
if (connection.isAuthenticated() && !webAuthConfig.getExternalAuthentication()) {
|
||||
User user = userSessionSource.getUserSession().getUser();
|
||||
// Change password on logon
|
||||
if (Boolean.TRUE.equals(user.getChangePasswordAtNextLogon())) {
|
||||
final WebWindowManager wm = getWindowManager();
|
||||
for (com.haulmont.cuba.gui.components.Window window : wm.getOpenWindows())
|
||||
WebWindowManager wm = getWindowManager();
|
||||
for (Window window : wm.getOpenWindows()) {
|
||||
window.setEnabled(false);
|
||||
}
|
||||
|
||||
WindowConfig windowConfig = AppBeans.get(WindowConfig.NAME);
|
||||
WindowInfo changePasswordDialog = windowConfig.getWindowInfo("sec$User.changePassword");
|
||||
wm.getDialogParams().setCloseable(false);
|
||||
Map<String, Object> params = Collections.singletonMap("cancelEnabled", (Object) Boolean.FALSE);
|
||||
com.haulmont.cuba.gui.components.Window changePasswordWindow = wm.openWindow(changePasswordDialog,
|
||||
WindowManager.OpenType.DIALOG, params);
|
||||
|
||||
Window changePasswordWindow = wm.openWindow(changePasswordDialog,
|
||||
OpenType.DIALOG.closeable(false),
|
||||
ParamsMap.of("cancelEnabled", Boolean.FALSE));
|
||||
|
||||
changePasswordWindow.addCloseListener(actionId -> {
|
||||
for (com.haulmont.cuba.gui.components.Window window : wm.getOpenWindows()) {
|
||||
for (Window window : wm.getOpenWindows()) {
|
||||
window.setEnabled(true);
|
||||
}
|
||||
});
|
||||
@ -150,14 +164,14 @@ public class DefaultApp extends App implements ConnectionListener, UserSubstitut
|
||||
|
||||
@Override
|
||||
protected boolean loginOnStart() {
|
||||
if (tryLoginOnStart &&
|
||||
principal != null
|
||||
if (tryLoginOnStart
|
||||
&& principal != null
|
||||
&& webAuthConfig.getExternalAuthentication()) {
|
||||
|
||||
String userName = principal.getName();
|
||||
log.debug("Trying to login after external authentication as " + userName);
|
||||
log.debug("Trying to login after external authentication as {}", userName);
|
||||
try {
|
||||
((ExternallyAuthenticatedConnection) connection).loginAfterExternalAuthentication(userName, locale);
|
||||
((ExternallyAuthenticatedConnection) connection).loginAfterExternalAuthentication(userName, getLocale());
|
||||
|
||||
return true;
|
||||
} catch (LoginException e) {
|
||||
@ -175,15 +189,17 @@ public class DefaultApp extends App implements ConnectionListener, UserSubstitut
|
||||
public void userSubstituted(Connection connection) {
|
||||
cleanupBackgroundTasks();
|
||||
clearSettingsCache();
|
||||
closeAllWindows();
|
||||
|
||||
for (final AppUI ui : getAppUIs()) {
|
||||
ui.accessSynchronously(() -> {
|
||||
if (ui.isTestMode()) {
|
||||
ui.getTestIdManager().reset();
|
||||
}
|
||||
AppUI currentUi = AppUI.getCurrent();
|
||||
createTopLevelWindow(currentUi);
|
||||
|
||||
ui.showView(createAppWindow(ui));
|
||||
});
|
||||
for (AppUI ui : getAppUIs()) {
|
||||
if (currentUi != ui) {
|
||||
ui.accessSynchronously(() ->
|
||||
createTopLevelWindow(ui)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,24 +18,34 @@
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.ClientType;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.security.global.LoginException;
|
||||
import com.haulmont.cuba.security.global.LoginFailedException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.auth.ExternallyAuthenticatedConnection;
|
||||
import com.haulmont.cuba.web.auth.WebAuthConfig;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Default {@link Connection} implementation for web-client.
|
||||
*
|
||||
*/
|
||||
@Component(Connection.NAME)
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class DefaultConnection extends AbstractConnection implements ExternallyAuthenticatedConnection {
|
||||
|
||||
protected Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Inject
|
||||
protected WebAuthConfig webAuthConfig;
|
||||
|
||||
@Override
|
||||
public void login(String login, String password, Locale locale) throws LoginException {
|
||||
@ -43,45 +53,72 @@ public class DefaultConnection extends AbstractConnection implements ExternallyA
|
||||
throw new IllegalArgumentException("Locale is null");
|
||||
}
|
||||
|
||||
update(doLogin(login, password, locale, getLoginParams()));
|
||||
update(doLogin(login, password, locale, getLoginParams()), SessionMode.AUTHENTICATED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loginAnonymous(Locale locale) throws LoginException {
|
||||
UUID anonymousSessionId = globalConfig.getAnonymousSessionId();
|
||||
|
||||
UserSession session = doLoginAnonymous(anonymousSessionId, locale);
|
||||
if (session == null) {
|
||||
throw new LoginFailedException("Unable to obtain anonymous session");
|
||||
}
|
||||
session.setLocale(locale);
|
||||
|
||||
update(session, SessionMode.ANONYMOUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward login logic to {@link com.haulmont.cuba.security.app.LoginService}.
|
||||
* Can be overridden to change login logic.
|
||||
*
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @return created user session
|
||||
* @throws LoginException in case of unsuccessful login
|
||||
*/
|
||||
protected UserSession doLogin(String login, String password, Locale locale, Map<String, Object> loginParams) throws LoginException {
|
||||
protected UserSession doLogin(String login, String password, Locale locale, Map<String, Object> loginParams)
|
||||
throws LoginException {
|
||||
return loginService.login(login, password, locale, loginParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward login logic to {@link com.haulmont.cuba.security.app.LoginService}.
|
||||
* Can be overridden to change login logic.
|
||||
*
|
||||
* @param locale client locale
|
||||
* @return obtained user session
|
||||
* @throws LoginException in case of unsuccessful login
|
||||
*/
|
||||
protected UserSession doLoginAnonymous(UUID anonymousSessionId, Locale locale) throws LoginException {
|
||||
return loginService.getSession(anonymousSessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loginByRememberMe(String login, String rememberMeToken, Locale locale) throws LoginException {
|
||||
if (locale == null) {
|
||||
throw new IllegalArgumentException("Locale is null");
|
||||
}
|
||||
|
||||
update(doLoginByRememberMe(login, rememberMeToken, locale, getLoginParams()));
|
||||
update(doLoginByRememberMe(login, rememberMeToken, locale, getLoginParams()), SessionMode.AUTHENTICATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward login logic to {@link com.haulmont.cuba.security.app.LoginService}.
|
||||
* Can be overridden to change login logic.
|
||||
*
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @return created user session
|
||||
* @throws LoginException in case of unsuccessful login
|
||||
*/
|
||||
protected UserSession doLoginByRememberMe(String login, String password, Locale locale, Map<String, Object> loginParams) throws LoginException {
|
||||
protected UserSession doLoginByRememberMe(String login, String password, Locale locale, Map<String, Object> loginParams)
|
||||
throws LoginException {
|
||||
return loginService.loginByRememberMe(login, password, locale, loginParams);
|
||||
}
|
||||
|
||||
@ -91,8 +128,8 @@ public class DefaultConnection extends AbstractConnection implements ExternallyA
|
||||
throw new IllegalArgumentException("Locale is null");
|
||||
}
|
||||
|
||||
String password = configuration.getConfig(WebAuthConfig.class).getTrustedClientPassword();
|
||||
update(doLoginTrusted(login, password, locale, getLoginParams()));
|
||||
String password = webAuthConfig.getTrustedClientPassword();
|
||||
update(doLoginTrusted(login, password, locale, getLoginParams()), SessionMode.AUTHENTICATED);
|
||||
|
||||
UserSession session = getSession();
|
||||
if (session == null) {
|
||||
@ -105,14 +142,15 @@ public class DefaultConnection extends AbstractConnection implements ExternallyA
|
||||
* Forward login logic to {@link com.haulmont.cuba.security.app.LoginService}.
|
||||
* Can be overridden to change login logic.
|
||||
*
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @param login login name
|
||||
* @param password encrypted password
|
||||
* @param locale client locale
|
||||
* @param loginParams login params
|
||||
* @return created user session
|
||||
* @throws LoginException in case of unsuccessful login
|
||||
*/
|
||||
protected UserSession doLoginTrusted(String login, String password, Locale locale, Map<String, Object> loginParams) throws LoginException {
|
||||
protected UserSession doLoginTrusted(String login, String password, Locale locale, Map<String, Object> loginParams)
|
||||
throws LoginException {
|
||||
return loginService.loginTrusted(login, password, locale, loginParams);
|
||||
}
|
||||
|
||||
@ -120,12 +158,6 @@ public class DefaultConnection extends AbstractConnection implements ExternallyA
|
||||
return ParamsMap.of(ClientType.class.getName(), ClientType.WEB.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logout() {
|
||||
super.logout();
|
||||
return configuration.getConfig(WebAuthConfig.class).getExternalAuthentication() ? "login" : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkRememberMe(String login, String rememberMeToken) {
|
||||
return loginService.checkRememberMe(login, rememberMeToken);
|
||||
|
@ -1,658 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.web;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.gui.AppConfig;
|
||||
import com.haulmont.cuba.gui.TestIdManager;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstants;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
|
||||
import com.haulmont.cuba.security.app.LoginService;
|
||||
import com.haulmont.cuba.security.app.UserManagementService;
|
||||
import com.haulmont.cuba.security.entity.User;
|
||||
import com.haulmont.cuba.security.global.LoginException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.auth.CubaAuthProvider;
|
||||
import com.haulmont.cuba.web.auth.DomainAliasesResolver;
|
||||
import com.haulmont.cuba.web.auth.ExternallyAuthenticatedConnection;
|
||||
import com.haulmont.cuba.web.auth.WebAuthConfig;
|
||||
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
import com.haulmont.cuba.web.toolkit.VersionedThemeResource;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaButton;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaCheckBox;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaPasswordField;
|
||||
import com.vaadin.data.Property;
|
||||
import com.vaadin.event.ShortcutAction;
|
||||
import com.vaadin.event.ShortcutListener;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.ui.*;
|
||||
import com.vaadin.ui.Notification.Type;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Standard login window.
|
||||
* <p/>
|
||||
* To use a specific implementation override {@link App#createLoginWindow(AppUI)} method.
|
||||
*/
|
||||
public class LoginWindow extends UIView {
|
||||
|
||||
public static final String COOKIE_LOGIN = "rememberMe.Login";
|
||||
public static final String COOKIE_PASSWORD = "rememberMe.Password";
|
||||
public static final String COOKIE_REMEMBER_ME = "rememberMe";
|
||||
public static final String COOKIE_LOCALE = "LAST_LOCALE";
|
||||
|
||||
protected static final Logger log = LoggerFactory.getLogger(LoginWindow.class);
|
||||
|
||||
protected final App app;
|
||||
protected final AppUI ui;
|
||||
protected final Connection connection;
|
||||
|
||||
protected TextField loginField;
|
||||
protected CubaPasswordField passwordField;
|
||||
protected ComboBox localesSelect;
|
||||
|
||||
protected Locale resolvedLocale;
|
||||
protected Map<String, Locale> locales;
|
||||
|
||||
protected GlobalConfig globalConfig;
|
||||
protected WebConfig webConfig;
|
||||
|
||||
protected CheckBox rememberMeCheckBox;
|
||||
protected boolean rememberMeAllowed = false;
|
||||
protected boolean loginByRememberMe = false;
|
||||
|
||||
protected Property.ValueChangeListener loginChangeListener;
|
||||
|
||||
protected Button okButton;
|
||||
protected SubmitListener submitListener;
|
||||
|
||||
protected Messages messages = AppBeans.get(Messages.NAME);
|
||||
|
||||
protected Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
|
||||
protected LoginService loginService = AppBeans.get(LoginService.class);
|
||||
|
||||
protected Boolean bruteForceProtectionEnabled;
|
||||
|
||||
public LoginWindow(AppUI ui) {
|
||||
log.trace("Creating {}", this);
|
||||
this.ui = ui;
|
||||
|
||||
globalConfig = configuration.getConfig(GlobalConfig.class);
|
||||
webConfig = configuration.getConfig(WebConfig.class);
|
||||
locales = globalConfig.getAvailableLocales();
|
||||
|
||||
app = ui.getApp();
|
||||
|
||||
resolvedLocale = resolveLocale(app);
|
||||
|
||||
connection = app.getConnection();
|
||||
|
||||
loginField = new TextField();
|
||||
passwordField = new CubaPasswordField();
|
||||
localesSelect = new ComboBox();
|
||||
localesSelect.setTextInputAllowed(false);
|
||||
|
||||
// make fields immediate to resync fast in case of login is already performed from another UI (i.e. browser tab)
|
||||
loginField.setImmediate(true);
|
||||
passwordField.setImmediate(true);
|
||||
|
||||
localesSelect.setImmediate(true);
|
||||
|
||||
okButton = new CubaButton();
|
||||
submitListener = new SubmitListener();
|
||||
|
||||
rememberMeAllowed = webConfig.getRememberMeEnabled();
|
||||
|
||||
if (rememberMeAllowed) {
|
||||
rememberMeCheckBox = new CubaCheckBox();
|
||||
}
|
||||
|
||||
setSizeFull();
|
||||
|
||||
// load theme from cookies if it is changed by user in settings dialog
|
||||
applyUserTheme();
|
||||
|
||||
initUI();
|
||||
|
||||
localesSelect.addValueChangeListener(event -> {
|
||||
if (!resolvedLocale.equals(getUserLocale())) {
|
||||
resolvedLocale = getUserLocale();
|
||||
clearUI();
|
||||
initUI();
|
||||
}
|
||||
});
|
||||
|
||||
if (ui.isTestMode()) {
|
||||
loginField.setCubaId("loginField");
|
||||
passwordField.setCubaId("passwordField");
|
||||
localesSelect.setCubaId("localesField");
|
||||
okButton.setCubaId("loginSubmitButton");
|
||||
|
||||
if (rememberMeCheckBox != null) {
|
||||
rememberMeCheckBox.setCubaId("rememberMeCheckBox");
|
||||
}
|
||||
|
||||
TestIdManager testIdManager = ui.getTestIdManager();
|
||||
|
||||
loginField.setId(testIdManager.reserveId("loginField"));
|
||||
passwordField.setId(testIdManager.reserveId("passwordField"));
|
||||
localesSelect.setId(testIdManager.reserveId("localesField"));
|
||||
|
||||
okButton.setId(testIdManager.reserveId("loginSubmitButton"));
|
||||
if (rememberMeCheckBox != null) {
|
||||
rememberMeCheckBox.setId(testIdManager.reserveId("rememberMeCheckBox"));
|
||||
}
|
||||
}
|
||||
|
||||
addShortcutListener(new ShortcutListener("Default key", ShortcutAction.KeyCode.ENTER, null) {
|
||||
@Override
|
||||
public void handleAction(Object sender, Object target) {
|
||||
doLogin();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void applyUserTheme() {
|
||||
String uiTheme = ui.getTheme();
|
||||
String userAppTheme = app.getCookieValue(App.APP_THEME_COOKIE_PREFIX + globalConfig.getWebContextName());
|
||||
|
||||
if (userAppTheme != null) {
|
||||
if (!StringUtils.equals(userAppTheme, uiTheme)) {
|
||||
// check theme support
|
||||
ThemeConstantsRepository themeRepository = AppBeans.get(ThemeConstantsRepository.NAME);
|
||||
Set<String> supportedThemes = themeRepository.getAvailableThemes();
|
||||
if (supportedThemes.contains(userAppTheme)) {
|
||||
app.applyTheme(userAppTheme);
|
||||
ui.setTheme(userAppTheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Locale resolveLocale(App app) {
|
||||
if (globalConfig.getLocaleSelectVisible()) {
|
||||
String lastLocale = app.getCookieValue(COOKIE_LOCALE);
|
||||
if (lastLocale != null) {
|
||||
for (Locale locale : locales.values()) {
|
||||
if (locale.toLanguageTag().equals(lastLocale)) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Locale locale : locales.values()) {
|
||||
if (locale.equals(app.getLocale())) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
// if not found and application locale contains country, try to match by language only
|
||||
if (!StringUtils.isEmpty(app.getLocale().getCountry())) {
|
||||
Locale appLocale = Locale.forLanguageTag(app.getLocale().getLanguage());
|
||||
for (Locale locale : locales.values()) {
|
||||
if (Locale.forLanguageTag(locale.getLanguage()).equals(appLocale)) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return first locale set in the cuba.availableLocales app property
|
||||
return locales.values().iterator().next();
|
||||
}
|
||||
|
||||
protected void initStandartUI(int formWidth, int formHeight, int fieldWidth, boolean localesSelectVisible) {
|
||||
setStyleName("cuba-login-main-layout");
|
||||
|
||||
VerticalLayout centerLayout = createCenterLayout(formWidth, formHeight, fieldWidth, localesSelectVisible);
|
||||
|
||||
addComponent(centerLayout);
|
||||
setSizeFull();
|
||||
setComponentAlignment(centerLayout, Alignment.MIDDLE_CENTER);
|
||||
|
||||
initFields();
|
||||
loginField.focus();
|
||||
}
|
||||
|
||||
protected VerticalLayout createCenterLayout(int formWidth, int formHeight, int fieldWidth, boolean localesSelectVisible) {
|
||||
VerticalLayout centerLayout = new VerticalLayout();
|
||||
centerLayout.setStyleName("cuba-login-bottom");
|
||||
centerLayout.setWidth(formWidth + "px");
|
||||
centerLayout.setHeight(formHeight + "px");
|
||||
|
||||
HorizontalLayout titleLayout = createTitleLayout();
|
||||
centerLayout.addComponent(titleLayout);
|
||||
centerLayout.setComponentAlignment(titleLayout, Alignment.MIDDLE_CENTER);
|
||||
|
||||
FormLayout loginFormLayout = createLoginFormLayout(fieldWidth, localesSelectVisible);
|
||||
centerLayout.addComponent(loginFormLayout);
|
||||
centerLayout.setComponentAlignment(loginFormLayout, Alignment.MIDDLE_CENTER);
|
||||
return centerLayout;
|
||||
}
|
||||
|
||||
protected HorizontalLayout createTitleLayout() {
|
||||
HorizontalLayout titleLayout = new HorizontalLayout();
|
||||
titleLayout.setStyleName("cuba-login-title");
|
||||
titleLayout.setSpacing(true);
|
||||
|
||||
Image logoImage = getLogoImage();
|
||||
if (logoImage != null) {
|
||||
logoImage.setStyleName("cuba-login-icon");
|
||||
titleLayout.addComponent(logoImage);
|
||||
titleLayout.setComponentAlignment(logoImage, Alignment.MIDDLE_LEFT);
|
||||
}
|
||||
|
||||
String welcomeMsg = messages.getMainMessage("loginWindow.welcomeLabel", resolvedLocale);
|
||||
Label label = new Label(welcomeMsg.replace("\n", "<br/>"));
|
||||
label.setContentMode(ContentMode.HTML);
|
||||
label.setWidthUndefined();
|
||||
label.setStyleName("cuba-login-caption");
|
||||
|
||||
if (!StringUtils.isBlank(label.getValue())) {
|
||||
titleLayout.addComponent(label);
|
||||
titleLayout.setComponentAlignment(label, Alignment.MIDDLE_LEFT);
|
||||
}
|
||||
return titleLayout;
|
||||
}
|
||||
|
||||
protected FormLayout createLoginFormLayout(int fieldWidth, boolean localesSelectVisible) {
|
||||
FormLayout loginFormLayout = new FormLayout();
|
||||
loginFormLayout.setStyleName("cuba-login-form");
|
||||
loginFormLayout.setSpacing(true);
|
||||
loginFormLayout.setSizeUndefined();
|
||||
|
||||
|
||||
loginField.setCaption(messages.getMainMessage("loginWindow.loginField", resolvedLocale));
|
||||
loginFormLayout.addComponent(loginField);
|
||||
loginField.setWidth(fieldWidth + "px");
|
||||
loginField.setStyleName("username-field");
|
||||
loginFormLayout.setComponentAlignment(loginField, Alignment.MIDDLE_CENTER);
|
||||
|
||||
passwordField.setCaption(messages.getMainMessage("loginWindow.passwordField", resolvedLocale));
|
||||
passwordField.setWidth(fieldWidth + "px");
|
||||
passwordField.setAutocomplete(true);
|
||||
passwordField.setStyleName("password-field");
|
||||
loginFormLayout.addComponent(passwordField);
|
||||
loginFormLayout.setComponentAlignment(passwordField, Alignment.MIDDLE_CENTER);
|
||||
|
||||
if (localesSelectVisible) {
|
||||
localesSelect.setCaption(messages.getMainMessage("loginWindow.localesSelect", resolvedLocale));
|
||||
localesSelect.setWidth(fieldWidth + "px");
|
||||
localesSelect.setNullSelectionAllowed(false);
|
||||
loginFormLayout.addComponent(localesSelect);
|
||||
loginFormLayout.setComponentAlignment(localesSelect, Alignment.MIDDLE_CENTER);
|
||||
}
|
||||
|
||||
if (rememberMeAllowed) {
|
||||
rememberMeCheckBox.setCaption(messages.getMainMessage("loginWindow.rememberMe", resolvedLocale));
|
||||
rememberMeCheckBox.setStyleName("remember-me");
|
||||
loginFormLayout.addComponent(rememberMeCheckBox);
|
||||
loginFormLayout.setComponentAlignment(rememberMeCheckBox, Alignment.MIDDLE_CENTER);
|
||||
}
|
||||
|
||||
okButton.setCaption(messages.getMainMessage("loginWindow.okButton", resolvedLocale));
|
||||
okButton.addClickListener(submitListener);
|
||||
okButton.setStyleName("cuba-login-submit");
|
||||
okButton.setIcon(WebComponentsHelper.getIcon("app/images/login-button.png"));
|
||||
|
||||
loginFormLayout.addComponent(okButton);
|
||||
loginFormLayout.setComponentAlignment(okButton, Alignment.MIDDLE_CENTER);
|
||||
return loginFormLayout;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Image getLogoImage() {
|
||||
final String loginLogoImagePath = messages.getMainMessage("loginWindow.logoImage", resolvedLocale);
|
||||
if (StringUtils.isBlank(loginLogoImagePath) || "loginWindow.logoImage".equals(loginLogoImagePath))
|
||||
return null;
|
||||
|
||||
return new Image(null, new VersionedThemeResource(loginLogoImagePath));
|
||||
}
|
||||
|
||||
protected void initUI() {
|
||||
ui.updateClientSystemMessages(resolvedLocale);
|
||||
|
||||
boolean localeSelectVisible = globalConfig.getLocaleSelectVisible();
|
||||
|
||||
ThemeConstants theme = app.getThemeConstants();
|
||||
int formWidth = theme.getInt("cuba.web.LoginWindow.form.width");
|
||||
int formHeight = theme.getInt("cuba.web.LoginWindow.form.height");
|
||||
int fieldWidth = theme.getInt("cuba.web.LoginWindow.field.width");
|
||||
|
||||
initStandartUI(formWidth, formHeight, fieldWidth, localeSelectVisible);
|
||||
}
|
||||
|
||||
protected void clearUI() {
|
||||
okButton.removeClickListener(submitListener);
|
||||
removeAllComponents();
|
||||
}
|
||||
|
||||
protected void initRememberMe() {
|
||||
String rememberMeCookie = app.getCookieValue(COOKIE_REMEMBER_ME);
|
||||
if (Boolean.parseBoolean(rememberMeCookie)) {
|
||||
String login;
|
||||
String encodedLogin = app.getCookieValue(COOKIE_LOGIN) != null ? app.getCookieValue(COOKIE_LOGIN) : "";
|
||||
try {
|
||||
login = URLDecoder.decode(encodedLogin, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
login = encodedLogin;
|
||||
}
|
||||
|
||||
String rememberMeToken = app.getCookieValue(COOKIE_PASSWORD) != null ? app.getCookieValue(COOKIE_PASSWORD) : "";
|
||||
if (connection.checkRememberMe(login, rememberMeToken)) {
|
||||
rememberMeCheckBox.setValue(true);
|
||||
loginField.setValue(login);
|
||||
|
||||
passwordField.setValue(rememberMeToken);
|
||||
loginByRememberMe = true;
|
||||
}
|
||||
|
||||
loginChangeListener = new Property.ValueChangeListener() {
|
||||
@Override
|
||||
public void valueChange(Property.ValueChangeEvent event) {
|
||||
loginByRememberMe = false;
|
||||
}
|
||||
};
|
||||
|
||||
loginField.addValueChangeListener(loginChangeListener);
|
||||
passwordField.addValueChangeListener(loginChangeListener);
|
||||
} else {
|
||||
rememberMeCheckBox.setValue(false);
|
||||
loginChangeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void initFields() {
|
||||
String currLocale = messages.getTools().localeToString(resolvedLocale);
|
||||
String selected = null;
|
||||
for (Map.Entry<String, Locale> entry : locales.entrySet()) {
|
||||
localesSelect.addItem(entry.getKey());
|
||||
if (messages.getTools().localeToString(entry.getValue()).equals(currLocale)) {
|
||||
selected = entry.getKey();
|
||||
}
|
||||
}
|
||||
if (selected == null) {
|
||||
selected = locales.keySet().iterator().next();
|
||||
}
|
||||
localesSelect.setValue(selected);
|
||||
|
||||
if (configuration.getConfig(WebAuthConfig.class).getExternalAuthentication()) {
|
||||
loginField.setValue(app.getPrincipal() == null ? "" : app.getPrincipal().getName());
|
||||
passwordField.setValue("");
|
||||
} else {
|
||||
String defaultUser = webConfig.getLoginDialogDefaultUser();
|
||||
if (!StringUtils.isBlank(defaultUser) && !"<disabled>".equals(defaultUser)) {
|
||||
loginField.setValue(defaultUser);
|
||||
} else {
|
||||
loginField.setValue("");
|
||||
}
|
||||
|
||||
String defaultPassw = webConfig.getLoginDialogDefaultPassword();
|
||||
if (!StringUtils.isBlank(defaultPassw) && !"<disabled>".equals(defaultPassw)) {
|
||||
passwordField.setValue(defaultPassw);
|
||||
} else {
|
||||
passwordField.setValue("");
|
||||
}
|
||||
}
|
||||
|
||||
if (rememberMeAllowed) {
|
||||
initRememberMe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return messages.getMainMessage("loginWindow.caption", resolvedLocale);
|
||||
}
|
||||
|
||||
public class SubmitListener implements Button.ClickListener {
|
||||
@Override
|
||||
public void buttonClick(Button.ClickEvent event) {
|
||||
doLogin();
|
||||
}
|
||||
}
|
||||
|
||||
protected void login() {
|
||||
String login = loginField.getValue();
|
||||
String password = passwordField.getValue() != null ? passwordField.getValue() : "";
|
||||
|
||||
if (StringUtils.isEmpty(login) || StringUtils.isEmpty(password)) {
|
||||
String message = messages.getMainMessage("loginWindow.emptyLoginOrPassword", resolvedLocale);
|
||||
Notification notification = new Notification(message, Type.WARNING_MESSAGE);
|
||||
notification.setDelayMsec(WebWindowManager.WARNING_NOTIFICATION_DELAY_MSEC);
|
||||
notification.show(ui.getPage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bruteForceProtectionCheck(login, app.getClientAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Locale locale = getUserLocale();
|
||||
app.setLocale(locale);
|
||||
|
||||
PasswordEncryption passwordEncryption = AppBeans.get(PasswordEncryption.NAME);
|
||||
|
||||
if (loginByRememberMe && rememberMeAllowed) {
|
||||
loginByRememberMe(login, password, locale);
|
||||
} else if (configuration.getConfig(WebAuthConfig.class).getExternalAuthentication()) {
|
||||
// try to login as externally authenticated user, fallback to regular authentication
|
||||
// we use resolved locale for error messages
|
||||
if (authenticateExternally(login, password, resolvedLocale)) {
|
||||
login = convertLoginString(login);
|
||||
|
||||
((ExternallyAuthenticatedConnection) connection).loginAfterExternalAuthentication(login, locale);
|
||||
} else {
|
||||
login(login, passwordEncryption.getPlainHash(password), locale);
|
||||
}
|
||||
} else {
|
||||
login(login, passwordEncryption.getPlainHash(password), locale);
|
||||
}
|
||||
// locale could be set on the server
|
||||
if (connection.getSession() != null) {
|
||||
app.setLocale(connection.getSession().getLocale());
|
||||
if (globalConfig.getLocaleSelectVisible()) {
|
||||
app.addCookie(COOKIE_LOCALE, locale.toLanguageTag());
|
||||
}
|
||||
}
|
||||
} catch (LoginException e) {
|
||||
log.info("Login failed: {}", e.toString());
|
||||
|
||||
String message = StringUtils.abbreviate(e.getMessage(), 1000);
|
||||
String bruteForceMsg = registerUnsuccessfulLoginAttempt(login, app.getClientAddress());
|
||||
if (!Strings.isNullOrEmpty(bruteForceMsg)) {
|
||||
message = bruteForceMsg;
|
||||
}
|
||||
showLoginException(message);
|
||||
} catch (Exception e) {
|
||||
log.warn("Unable to login", e);
|
||||
showException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isBruteForceProtectionEnabled() {
|
||||
if (bruteForceProtectionEnabled == null) {
|
||||
bruteForceProtectionEnabled = loginService.isBruteForceProtectionEnabled();
|
||||
}
|
||||
return bruteForceProtectionEnabled;
|
||||
}
|
||||
|
||||
protected boolean bruteForceProtectionCheck(String login, String ipAddress) {
|
||||
if (isBruteForceProtectionEnabled()) {
|
||||
if (loginService.loginAttemptsLeft(login, ipAddress) <= 0) {
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed", resolvedLocale);
|
||||
String message = messages.formatMessage(messages.getMainMessagePack(),
|
||||
"loginWindow.loginAttemptsNumberExceeded",
|
||||
resolvedLocale,
|
||||
loginService.getBruteForceBlockIntervalSec());
|
||||
|
||||
new Notification(title, message, Type.ERROR_MESSAGE, true).show(ui.getPage());
|
||||
log.info("Blocked user login attempt: login={}, ip={}", login, ipAddress);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String registerUnsuccessfulLoginAttempt(String login, String ipAddress) {
|
||||
String message = null;
|
||||
if (isBruteForceProtectionEnabled()) {
|
||||
int loginAttemptsLeft = loginService.registerUnsuccessfulLogin(login, ipAddress);
|
||||
if (loginAttemptsLeft > 0) {
|
||||
message = messages.formatMessage(messages.getMainMessagePack(),
|
||||
"loginWindow.loginFailedAttemptsLeft",
|
||||
resolvedLocale,
|
||||
loginAttemptsLeft);
|
||||
} else {
|
||||
message = messages.formatMessage(messages.getMainMessagePack(),
|
||||
"loginWindow.loginAttemptsNumberExceeded",
|
||||
resolvedLocale,
|
||||
loginService.getBruteForceBlockIntervalSec());
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
protected void showLoginException(String message){
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed", resolvedLocale);
|
||||
new Notification(title, message, Type.ERROR_MESSAGE, true).show(ui.getPage());
|
||||
|
||||
if (loginByRememberMe) {
|
||||
loginByRememberMe = false;
|
||||
loginField.removeValueChangeListener(loginChangeListener);
|
||||
passwordField.removeValueChangeListener(loginChangeListener);
|
||||
loginChangeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void showException(Exception e){
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed", resolvedLocale);
|
||||
String message = messages.getMainMessage("loginWindow.pleaseContactAdministrator", resolvedLocale);
|
||||
new Notification(title, message, Type.ERROR_MESSAGE, true).show(ui.getPage());
|
||||
}
|
||||
|
||||
protected boolean authenticateExternally(String login, String passwordValue, Locale locale) {
|
||||
CubaAuthProvider authProvider = AppBeans.get(CubaAuthProvider.NAME);
|
||||
try {
|
||||
authProvider.authenticate(login, passwordValue, locale);
|
||||
} catch (Exception e) {
|
||||
log.debug("External authentication failed", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert userName to db form
|
||||
* In database users stores in form DOMAIN\userName
|
||||
*
|
||||
* @param login Login string
|
||||
* @return login in form DOMAIN\userName
|
||||
*/
|
||||
private String convertLoginString(String login) {
|
||||
DomainAliasesResolver aliasesResolver = AppBeans.get(DomainAliasesResolver.NAME);
|
||||
int slashPos = login.indexOf("\\");
|
||||
if (slashPos >= 0) {
|
||||
String domainAlias = login.substring(0, slashPos);
|
||||
String domain = aliasesResolver.getDomainName(domainAlias).toUpperCase();
|
||||
String userName = login.substring(slashPos + 1);
|
||||
login = domain + "\\" + userName;
|
||||
} else {
|
||||
int atSignPos = login.indexOf("@");
|
||||
if (atSignPos >= 0) {
|
||||
String domainAlias = login.substring(atSignPos + 1);
|
||||
String domain = aliasesResolver.getDomainName(domainAlias).toUpperCase();
|
||||
String userName = login.substring(0, atSignPos);
|
||||
login = domain + "\\" + userName;
|
||||
}
|
||||
}
|
||||
return login;
|
||||
}
|
||||
|
||||
protected void login(String login, String password, Locale locale) throws LoginException {
|
||||
connection.login(login, password, locale);
|
||||
}
|
||||
|
||||
protected void loginByRememberMe(String login, String rememberMeToken, Locale locale) throws LoginException {
|
||||
connection.loginByRememberMe(login, rememberMeToken, locale);
|
||||
}
|
||||
|
||||
protected void doLogin() {
|
||||
login();
|
||||
|
||||
if (connection.isConnected()) {
|
||||
if (rememberMeAllowed) {
|
||||
if (Boolean.TRUE.equals(rememberMeCheckBox.getValue())) {
|
||||
if (!loginByRememberMe) {
|
||||
app.addCookie(COOKIE_REMEMBER_ME, Boolean.TRUE.toString());
|
||||
|
||||
String login = loginField.getValue();
|
||||
|
||||
String encodedLogin;
|
||||
try {
|
||||
encodedLogin = URLEncoder.encode(login, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
encodedLogin = login;
|
||||
}
|
||||
|
||||
app.addCookie(COOKIE_LOGIN, StringEscapeUtils.escapeJava(encodedLogin));
|
||||
|
||||
UserSession session = connection.getSession();
|
||||
if (session == null) {
|
||||
throw new IllegalStateException("Unable to get session after login");
|
||||
}
|
||||
|
||||
User user = session.getUser();
|
||||
|
||||
UserManagementService userManagementService = AppBeans.get(UserManagementService.NAME);
|
||||
String rememberMeToken = userManagementService.generateRememberMeToken(user.getId());
|
||||
|
||||
app.addCookie(COOKIE_PASSWORD, rememberMeToken);
|
||||
}
|
||||
} else {
|
||||
app.removeCookie(COOKIE_REMEMBER_ME);
|
||||
app.removeCookie(COOKIE_LOGIN);
|
||||
app.removeCookie(COOKIE_PASSWORD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Locale getUserLocale() {
|
||||
String lang = (String) localesSelect.getValue();
|
||||
return locales.get(lang);
|
||||
}
|
||||
|
||||
protected String getMessagesPack() {
|
||||
return AppConfig.getMessagesPack();
|
||||
}
|
||||
}
|
@ -272,4 +272,18 @@ public interface WebConfig extends Config {
|
||||
@Property("cuba.web.pushEnabled")
|
||||
@DefaultBoolean(value = true)
|
||||
boolean getPushEnabled();
|
||||
|
||||
/**
|
||||
* @return true if production mode is enabled
|
||||
*/
|
||||
@Property("cuba.web.productionMode")
|
||||
@DefaultBoolean(value = true)
|
||||
boolean getProductionMode();
|
||||
|
||||
/**
|
||||
* @return GWT widgetset class
|
||||
*/
|
||||
@Property("cuba.web.widgetSet")
|
||||
@Default("com.haulmont.cuba.web.toolkit.ui.WidgetSet")
|
||||
String getWidgetSet();
|
||||
}
|
@ -17,15 +17,22 @@
|
||||
package com.haulmont.cuba.web;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.haulmont.bali.datastruct.Pair;
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.cuba.client.ClientConfig;
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.gui.*;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.DevelopmentException;
|
||||
import com.haulmont.cuba.core.global.SilentException;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.DialogParams;
|
||||
import com.haulmont.cuba.gui.ScreenHistorySupport;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.app.core.dev.LayoutAnalyzer;
|
||||
import com.haulmont.cuba.gui.app.core.dev.LayoutTip;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.components.Action.Status;
|
||||
import com.haulmont.cuba.gui.components.Component.BelongToFrame;
|
||||
import com.haulmont.cuba.gui.components.DialogAction.Type;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.components.mainwindow.AppMenu;
|
||||
@ -44,6 +51,7 @@ import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
import com.haulmont.cuba.web.gui.components.mainwindow.WebAppWorkArea;
|
||||
import com.haulmont.cuba.web.sys.WindowBreadCrumbs;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaLabel;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaOrderedActionsLayout;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaTabSheet;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaWindow;
|
||||
import com.vaadin.event.ShortcutAction;
|
||||
@ -80,7 +88,6 @@ public class WebWindowManager extends WindowManager {
|
||||
|
||||
protected App app;
|
||||
protected AppUI ui;
|
||||
protected AppWindow appWindow;
|
||||
|
||||
protected final WebConfig webConfig;
|
||||
protected final ClientConfig clientConfig;
|
||||
@ -88,17 +95,16 @@ public class WebWindowManager extends WindowManager {
|
||||
protected ScreenProfiler screenProfiler;
|
||||
|
||||
protected final Map<ComponentContainer, WindowBreadCrumbs> tabs = new HashMap<>();
|
||||
protected final Map<WindowBreadCrumbs, Stack<Map.Entry<Window, Integer>>> stacks = new HashMap<>();
|
||||
protected final Map<WindowBreadCrumbs, Stack<Pair<Window, Integer>>> stacks = new HashMap<>();
|
||||
protected final Map<Window, WindowOpenInfo> windowOpenMode = new LinkedHashMap<>();
|
||||
protected final Map<Window, Integer> windows = new HashMap<>();
|
||||
|
||||
protected boolean disableSavingScreenHistory;
|
||||
protected ScreenHistorySupport screenHistorySupport;
|
||||
|
||||
public WebWindowManager(final App app, AppWindow appWindow) {
|
||||
this.ui = app.getAppUI();
|
||||
this.app = app;
|
||||
this.appWindow = appWindow;
|
||||
public WebWindowManager(AppUI ui) {
|
||||
this.ui = ui;
|
||||
this.app = ui.getApp();
|
||||
|
||||
webConfig = configuration.getConfig(WebConfig.class);
|
||||
clientConfig = configuration.getConfig(ClientConfig.class);
|
||||
@ -252,7 +258,7 @@ public class WebWindowManager extends WindowManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Stack<Map.Entry<Window, Integer>> getStack(WindowBreadCrumbs breadCrumbs) {
|
||||
protected Stack<Pair<Window, Integer>> getStack(WindowBreadCrumbs breadCrumbs) {
|
||||
return stacks.get(breadCrumbs);
|
||||
}
|
||||
|
||||
@ -310,12 +316,9 @@ public class WebWindowManager extends WindowManager {
|
||||
WindowBreadCrumbs oldBreadCrumbs = tabs.get(oldLayout);
|
||||
if (oldBreadCrumbs != null) {
|
||||
Window oldWindow = oldBreadCrumbs.getCurrentWindow();
|
||||
oldWindow.closeAndRun(MAIN_MENU_ACTION_ID, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showWindow(window, caption, description, OpenType.NEW_TAB, false);
|
||||
}
|
||||
});
|
||||
oldWindow.closeAndRun(MAIN_MENU_ACTION_ID, () ->
|
||||
showWindow(window, caption, description, OpenType.NEW_TAB, false)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -329,7 +332,7 @@ public class WebWindowManager extends WindowManager {
|
||||
final WindowBreadCrumbs oldBreadCrumbs = tabs.get(oldLayout);
|
||||
|
||||
if (oldBreadCrumbs != null
|
||||
&& windowOpenMode.containsKey(oldBreadCrumbs.getCurrentWindow().<Window>getFrame())
|
||||
&& windowOpenMode.containsKey(oldBreadCrumbs.getCurrentWindow().getFrame())
|
||||
&& !multipleOpen) {
|
||||
Window oldWindow = oldBreadCrumbs.getCurrentWindow();
|
||||
selectWindowTab(((Window.Wrapper) oldBreadCrumbs.getCurrentWindow()).getWrappedWindow());
|
||||
@ -342,19 +345,16 @@ public class WebWindowManager extends WindowManager {
|
||||
}
|
||||
|
||||
final int finalTabPosition = tabPosition;
|
||||
oldWindow.closeAndRun(MAIN_MENU_ACTION_ID, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showWindow(window, caption, description, OpenType.NEW_TAB, false);
|
||||
oldWindow.closeAndRun(MAIN_MENU_ACTION_ID, () -> {
|
||||
showWindow(window, caption, description, OpenType.NEW_TAB, false);
|
||||
|
||||
Window wrappedWindow = window;
|
||||
if (window instanceof Window.Wrapper) {
|
||||
wrappedWindow = ((Window.Wrapper) window).getWrappedWindow();
|
||||
}
|
||||
Window wrappedWindow = window;
|
||||
if (window instanceof Window.Wrapper) {
|
||||
wrappedWindow = ((Window.Wrapper) window).getWrappedWindow();
|
||||
}
|
||||
|
||||
if (finalTabPosition >= 0 && finalTabPosition < tabSheet.getComponentCount() - 1) {
|
||||
moveWindowTab(workArea, wrappedWindow, finalTabPosition);
|
||||
}
|
||||
if (finalTabPosition >= 0 && finalTabPosition < tabSheet.getComponentCount() - 1) {
|
||||
moveWindowTab(workArea, wrappedWindow, finalTabPosition);
|
||||
}
|
||||
});
|
||||
return;
|
||||
@ -509,8 +509,10 @@ public class WebWindowManager extends WindowManager {
|
||||
newTab = tabSheet.addTab(layout);
|
||||
|
||||
if (ui.isTestMode()) {
|
||||
tabSheet.setTestId(newTab, ui.getTestIdManager().getTestId("tab_" + window.getId()));
|
||||
tabSheet.setCubaId(newTab, "tab_" + window.getId());
|
||||
String id = "tab_" + window.getId();
|
||||
|
||||
tabSheet.setTestId(newTab, ui.getTestIdManager().getTestId(id));
|
||||
tabSheet.setCubaId(newTab, id);
|
||||
}
|
||||
}
|
||||
String formattedCaption = formatTabCaption(window.getCaption(), window.getDescription());
|
||||
@ -523,19 +525,15 @@ public class WebWindowManager extends WindowManager {
|
||||
}
|
||||
|
||||
newTab.setClosable(true);
|
||||
tabSheet.setTabCloseHandler(layout,
|
||||
new CubaTabSheet.TabCloseHandler() {
|
||||
@Override
|
||||
public void onClose(TabSheet tabSheet, Component tabContent) {
|
||||
//noinspection SuspiciousMethodCalls
|
||||
WindowBreadCrumbs breadCrumbs = tabs.get(tabContent);
|
||||
Runnable closeTask = new TabCloseTask(breadCrumbs);
|
||||
closeTask.run();
|
||||
tabSheet.setTabCloseHandler(layout, (targetTabSheet, tabContent) -> {
|
||||
//noinspection SuspiciousMethodCalls
|
||||
WindowBreadCrumbs breadCrumbs1 = tabs.get(tabContent);
|
||||
Runnable closeTask = new TabCloseTask(breadCrumbs1);
|
||||
closeTask.run();
|
||||
|
||||
// it is needed to force redraw tabsheet if it has a lot of tabs and part of them are hidden
|
||||
tabSheet.markAsDirty();
|
||||
}
|
||||
});
|
||||
// it is needed to force redraw tabsheet if it has a lot of tabs and part of them are hidden
|
||||
targetTabSheet.markAsDirty();
|
||||
});
|
||||
tabSheet.setSelectedTab(layout);
|
||||
} else {
|
||||
tabs.put(layout, breadCrumbs);
|
||||
@ -609,13 +607,13 @@ public class WebWindowManager extends WindowManager {
|
||||
for (Map.Entry<Window, Integer> entry : set) {
|
||||
if (entry.getKey().equals(currentWindow)) {
|
||||
windows.remove(currentWindow);
|
||||
getStack(breadCrumbs).push(entry);
|
||||
getStack(breadCrumbs).push(new Pair<>(entry.getKey(), entry.getValue()));
|
||||
pushed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pushed) {
|
||||
getStack(breadCrumbs).push(new AbstractMap.SimpleEntry<Window, Integer>(currentWindow, null));
|
||||
getStack(breadCrumbs).push(new Pair<>(currentWindow, null));
|
||||
}
|
||||
|
||||
removeFromWindowMap(currentWindow);
|
||||
@ -648,11 +646,16 @@ public class WebWindowManager extends WindowManager {
|
||||
}
|
||||
|
||||
protected WebAppWorkArea getConfiguredWorkArea() {
|
||||
AppWorkArea workArea = appWindow.getMainWindow().getWorkArea();
|
||||
if (workArea == null) {
|
||||
throw new IllegalStateException("Application does not have any configured work area");
|
||||
Window.TopLevelWindow topLevelWindow = ui.getTopLevelWindow();
|
||||
|
||||
if (topLevelWindow instanceof Window.MainWindow) {
|
||||
AppWorkArea workArea = ((Window.MainWindow) topLevelWindow).getWorkArea();
|
||||
if (workArea != null) {
|
||||
return (WebAppWorkArea) workArea;
|
||||
}
|
||||
}
|
||||
return (WebAppWorkArea) workArea;
|
||||
|
||||
throw new IllegalStateException("Application does not have any configured work area");
|
||||
}
|
||||
|
||||
protected Component showWindowDialog(final Window window, OpenType openType, boolean forciblyDialog) {
|
||||
@ -744,7 +747,7 @@ public class WebWindowManager extends WindowManager {
|
||||
protected WindowBreadCrumbs createWindowBreadCrumbs() {
|
||||
WindowBreadCrumbs windowBreadCrumbs = new WindowBreadCrumbs(getConfiguredWorkArea());
|
||||
windowBreadCrumbs.setVisible(webConfig.getShowBreadCrumbs());
|
||||
stacks.put(windowBreadCrumbs, new Stack<Map.Entry<Window, Integer>>());
|
||||
stacks.put(windowBreadCrumbs, new Stack<>());
|
||||
return windowBreadCrumbs;
|
||||
}
|
||||
|
||||
@ -872,7 +875,6 @@ public class WebWindowManager extends WindowManager {
|
||||
MessageType.WARNING,
|
||||
new Action[]{
|
||||
new AbstractAction(messages.getMessage(WebWindow.class, "closeTabs")) {
|
||||
|
||||
{
|
||||
ThemeConstantsManager thCM = AppBeans.get(ThemeConstantsManager.NAME);
|
||||
icon = thCM.getThemeValue("actions.dialog.Ok.icon");
|
||||
@ -936,7 +938,7 @@ public class WebWindowManager extends WindowManager {
|
||||
switch (openInfo.getOpenMode()) {
|
||||
case DIALOG: {
|
||||
final CubaWindow cubaDialogWindow = (CubaWindow) openInfo.getData();
|
||||
cubaDialogWindow.dispose();
|
||||
cubaDialogWindow.forceClose();
|
||||
fireListeners(window, tabs.size() != 0);
|
||||
break;
|
||||
}
|
||||
@ -980,8 +982,8 @@ public class WebWindowManager extends WindowManager {
|
||||
breadCrumbs.removeWindow();
|
||||
Window currentWindow = breadCrumbs.getCurrentWindow();
|
||||
if (!getStack(breadCrumbs).empty()) {
|
||||
Map.Entry<Window, Integer> entry = getStack(breadCrumbs).pop();
|
||||
putToWindowMap(entry.getKey(), entry.getValue());
|
||||
Pair<Window, Integer> entry = getStack(breadCrumbs).pop();
|
||||
putToWindowMap(entry.getFirst(), entry.getSecond());
|
||||
}
|
||||
final Component component = WebComponentsHelper.getComposition(currentWindow);
|
||||
component.setSizeFull();
|
||||
@ -1129,12 +1131,9 @@ public class WebWindowManager extends WindowManager {
|
||||
button.setCaption(action.getCaption());
|
||||
button.setIcon(WebComponentsHelper.getIcon(action.getIcon()));
|
||||
button.addStyleName(WebButton.ICON_STYLE);
|
||||
button.addClickListener(new Button.ClickListener() {
|
||||
@Override
|
||||
public void buttonClick(Button.ClickEvent event) {
|
||||
vWindow.close();
|
||||
}
|
||||
});
|
||||
button.addClickListener((Button.ClickListener) event ->
|
||||
vWindow.close()
|
||||
);
|
||||
|
||||
buttonsContainer.addComponent(button);
|
||||
button.focus();
|
||||
@ -1350,21 +1349,18 @@ public class WebWindowManager extends WindowManager {
|
||||
@Override
|
||||
public void initDebugIds(final Frame frame) {
|
||||
if (ui.isTestMode()) {
|
||||
com.haulmont.cuba.gui.ComponentsHelper.walkComponents(frame, new ComponentVisitor() {
|
||||
@Override
|
||||
public void visit(com.haulmont.cuba.gui.components.Component component, String name) {
|
||||
if (component.getDebugId() == null) {
|
||||
Frame componentFrame = null;
|
||||
if (component instanceof com.haulmont.cuba.gui.components.Component.BelongToFrame) {
|
||||
componentFrame = ((com.haulmont.cuba.gui.components.Component.BelongToFrame) component).getFrame();
|
||||
}
|
||||
if (componentFrame == null) {
|
||||
log.warn("Frame for component " + component.getClass() + " is not assigned");
|
||||
} else {
|
||||
if (component instanceof WebAbstractComponent) {
|
||||
WebAbstractComponent webComponent = (WebAbstractComponent) component;
|
||||
webComponent.assignAutoDebugId();
|
||||
}
|
||||
com.haulmont.cuba.gui.ComponentsHelper.walkComponents(frame, (component, name) -> {
|
||||
if (component.getDebugId() == null) {
|
||||
Frame componentFrame = null;
|
||||
if (component instanceof BelongToFrame) {
|
||||
componentFrame = ((BelongToFrame) component).getFrame();
|
||||
}
|
||||
if (componentFrame == null) {
|
||||
log.warn("Frame for component " + component.getClass() + " is not assigned");
|
||||
} else {
|
||||
if (component instanceof WebAbstractComponent) {
|
||||
WebAbstractComponent webComponent = (WebAbstractComponent) component;
|
||||
webComponent.assignAutoDebugId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1389,7 +1385,7 @@ public class WebWindowManager extends WindowManager {
|
||||
|
||||
@Override
|
||||
protected Window getWindow(Integer hashCode) {
|
||||
AppWorkArea workArea = appWindow.getMainWindow().getWorkArea();
|
||||
AppWorkArea workArea = getConfiguredWorkArea();
|
||||
if (workArea == null || workArea.getMode() == AppWorkArea.Mode.SINGLE) {
|
||||
return null;
|
||||
}
|
||||
@ -1426,46 +1422,49 @@ public class WebWindowManager extends WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected void initMainWindow(WindowInfo windowInfo) {
|
||||
public void createTopLevelWindow(WindowInfo windowInfo) {
|
||||
ui.beforeTopLevelWindowInit();
|
||||
|
||||
String template = windowInfo.getTemplate();
|
||||
|
||||
Window mainWindow;
|
||||
Window.TopLevelWindow topLevelWindow;
|
||||
|
||||
Map<String, Object> params = Collections.emptyMap();
|
||||
if (template != null) {
|
||||
//noinspection unchecked
|
||||
mainWindow = createWindow(windowInfo, OpenType.NEW_TAB, params, LayoutLoaderConfig.getWindowLoaders());
|
||||
topLevelWindow = (Window.TopLevelWindow) createWindow(windowInfo, OpenType.NEW_TAB, params,
|
||||
LayoutLoaderConfig.getWindowLoaders());
|
||||
} else {
|
||||
Class screenClass = windowInfo.getScreenClass();
|
||||
if (screenClass != null) {
|
||||
//noinspection unchecked
|
||||
mainWindow = createWindowByScreenClass(windowInfo, params);
|
||||
topLevelWindow = (Window.TopLevelWindow) createWindowByScreenClass(windowInfo, params);
|
||||
} else {
|
||||
throw new DevelopmentException("Unable to load app window");
|
||||
throw new DevelopmentException("Unable to load top level window");
|
||||
}
|
||||
}
|
||||
|
||||
// detect work area
|
||||
WebWindow windowImpl = (WebWindow) ((Window.Wrapper) mainWindow).getWrappedWindow();
|
||||
Window windowImpl = ((Window.Wrapper) topLevelWindow).getWrappedWindow();
|
||||
|
||||
// bind system UI components to AbstractMainWindow
|
||||
ComponentsHelper.walkComponents(windowImpl, component -> {
|
||||
if (component instanceof AppWorkArea) {
|
||||
((AbstractMainWindow) mainWindow).setWorkArea((AppWorkArea) component);
|
||||
} else if (component instanceof UserIndicator) {
|
||||
((AbstractMainWindow) mainWindow).setUserIndicator((UserIndicator) component);
|
||||
} else if (component instanceof FoldersPane) {
|
||||
((AbstractMainWindow) mainWindow).setFoldersPane((FoldersPane) component);
|
||||
}
|
||||
if (topLevelWindow instanceof AbstractMainWindow) {
|
||||
AbstractMainWindow mainWindow = (AbstractMainWindow) topLevelWindow;
|
||||
|
||||
return false;
|
||||
});
|
||||
// bind system UI components to AbstractMainWindow
|
||||
ComponentsHelper.walkComponents(windowImpl, component -> {
|
||||
if (component instanceof AppWorkArea) {
|
||||
mainWindow.setWorkArea((AppWorkArea) component);
|
||||
} else if (component instanceof UserIndicator) {
|
||||
mainWindow.setUserIndicator((UserIndicator) component);
|
||||
} else if (component instanceof FoldersPane) {
|
||||
mainWindow.setFoldersPane((FoldersPane) component);
|
||||
}
|
||||
|
||||
// attach main window to UI
|
||||
Component windowLayout = windowImpl.getComposition();
|
||||
appWindow.addComponent(windowLayout, 0);
|
||||
appWindow.setExpandRatio(windowLayout, 1);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
appWindow.setMainWindow((Window.MainWindow) mainWindow);
|
||||
ui.setTopLevelWindow(topLevelWindow);
|
||||
|
||||
// load menu
|
||||
ComponentsHelper.walkComponents(windowImpl, component -> {
|
||||
@ -1477,30 +1476,35 @@ public class WebWindowManager extends WindowManager {
|
||||
return false;
|
||||
});
|
||||
|
||||
AppWorkArea workArea = appWindow.getMainWindow().getWorkArea();
|
||||
if (workArea != null) {
|
||||
workArea.addStateChangeListener(new AppWorkArea.StateChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(AppWorkArea.State newState) {
|
||||
if (newState == AppWorkArea.State.WINDOW_CONTAINER) {
|
||||
initTabShortcuts();
|
||||
if (topLevelWindow instanceof Window.HasWorkArea) {
|
||||
AppWorkArea workArea = ((Window.HasWorkArea) topLevelWindow).getWorkArea();
|
||||
if (workArea != null) {
|
||||
workArea.addStateChangeListener(new AppWorkArea.StateChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(AppWorkArea.State newState) {
|
||||
if (newState == AppWorkArea.State.WINDOW_CONTAINER) {
|
||||
initTabShortcuts();
|
||||
|
||||
// listener used only once
|
||||
getConfiguredWorkArea().removeStateChangeListener(this);
|
||||
// listener used only once
|
||||
getConfiguredWorkArea().removeStateChangeListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
afterShowWindow(mainWindow);
|
||||
afterShowWindow(topLevelWindow);
|
||||
}
|
||||
|
||||
protected void initTabShortcuts() {
|
||||
Window.TopLevelWindow topLevelWindow = ui.getTopLevelWindow();
|
||||
CubaOrderedActionsLayout actionsLayout = topLevelWindow.unwrap(CubaOrderedActionsLayout.class);
|
||||
|
||||
if (getConfiguredWorkArea().getMode() == AppWorkArea.Mode.TABBED) {
|
||||
appWindow.addShortcutListener(createNextWindowTabShortcut());
|
||||
appWindow.addShortcutListener(createPreviousWindowTabShortcut());
|
||||
actionsLayout.addShortcutListener(createNextWindowTabShortcut());
|
||||
actionsLayout.addShortcutListener(createPreviousWindowTabShortcut());
|
||||
}
|
||||
appWindow.addShortcutListener(createCloseShortcut());
|
||||
actionsLayout.addShortcutListener(createCloseShortcut());
|
||||
}
|
||||
|
||||
protected boolean hasDialogWindows() {
|
||||
@ -1531,12 +1535,9 @@ public class WebWindowManager extends WindowManager {
|
||||
if (stacks.get(breadCrumbs).empty()) {
|
||||
final Component previousTab = tabSheet.getPreviousTab(layout);
|
||||
if (previousTab != null) {
|
||||
breadCrumbs.getCurrentWindow().closeAndRun(Window.CLOSE_ACTION_ID, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
tabSheet.setSelectedTab(previousTab);
|
||||
}
|
||||
});
|
||||
breadCrumbs.getCurrentWindow().closeAndRun(Window.CLOSE_ACTION_ID, () ->
|
||||
tabSheet.setSelectedTab(previousTab)
|
||||
);
|
||||
} else {
|
||||
breadCrumbs.getCurrentWindow().close(Window.CLOSE_ACTION_ID);
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import com.haulmont.cuba.security.app.UserSettingService;
|
||||
import com.haulmont.cuba.security.entity.SearchFolder;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.haulmont.cuba.web.app.UserSettingsTools;
|
||||
import com.haulmont.cuba.web.filestorage.WebExportDisplay;
|
||||
@ -64,7 +63,6 @@ import static com.haulmont.cuba.gui.components.Window.COMMIT_ACTION_ID;
|
||||
|
||||
/**
|
||||
* Left panel containing application and search folders.
|
||||
*
|
||||
*/
|
||||
public class CubaFoldersPane extends VerticalLayout {
|
||||
|
||||
@ -227,7 +225,7 @@ public class CubaFoldersPane extends VerticalLayout {
|
||||
protected void setupUpdateTimer() {
|
||||
int period = webConfig.getAppFoldersRefreshPeriodSec() * 1000;
|
||||
|
||||
AppWindow appWindow = App.getInstance().getAppWindow();
|
||||
AppUI appWindow = AppUI.getCurrent();
|
||||
for (CubaTimer t : appWindow.getTimers()) {
|
||||
if (t instanceof FoldersPaneTimer) {
|
||||
t.stop();
|
||||
|
@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.web.app.loginwindow;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.core.global.PasswordEncryption;
|
||||
import com.haulmont.cuba.core.global.UserSessionSource;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.security.app.LoginService;
|
||||
import com.haulmont.cuba.security.app.UserManagementService;
|
||||
import com.haulmont.cuba.security.entity.User;
|
||||
import com.haulmont.cuba.security.global.LoginException;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.Connection;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.haulmont.cuba.web.auth.CubaAuthProvider;
|
||||
import com.haulmont.cuba.web.auth.DomainAliasesResolver;
|
||||
import com.haulmont.cuba.web.auth.ExternallyAuthenticatedConnection;
|
||||
import com.haulmont.cuba.web.auth.WebAuthConfig;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class AppLoginWindow extends AbstractWindow implements Window.TopLevelWindow {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AppLoginWindow.class);
|
||||
|
||||
protected static final ThreadLocal<AuthInfo> authInfoThreadLocal = new ThreadLocal<>();
|
||||
|
||||
public static final String COOKIE_REMEMBER_ME = "rememberMe";
|
||||
public static final String COOKIE_LOGIN = "rememberMe.Login";
|
||||
public static final String COOKIE_PASSWORD = "rememberMe.Password";
|
||||
|
||||
public static class AuthInfo {
|
||||
private String login;
|
||||
private String password;
|
||||
private Boolean rememberMe;
|
||||
|
||||
public AuthInfo(String login, String password, Boolean rememberMe) {
|
||||
this.login = login;
|
||||
this.password = password;
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public Boolean getRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Inject
|
||||
protected WebConfig webConfig;
|
||||
|
||||
@Inject
|
||||
protected WebAuthConfig webAuthConfig;
|
||||
|
||||
@Inject
|
||||
protected LoginService loginService;
|
||||
|
||||
@Inject
|
||||
protected UserSessionSource userSessionSource;
|
||||
|
||||
@Inject
|
||||
protected PasswordEncryption passwordEncryption;
|
||||
|
||||
@Inject
|
||||
protected DomainAliasesResolver domainAliasesResolver;
|
||||
|
||||
@Inject
|
||||
protected CubaAuthProvider cubaAuthProvider;
|
||||
|
||||
@Inject
|
||||
protected UserManagementService userManagementService;
|
||||
|
||||
@Inject
|
||||
protected Embedded logoImage;
|
||||
|
||||
@Inject
|
||||
protected TextField loginField;
|
||||
|
||||
@Inject
|
||||
protected CheckBox rememberMeCheckBox;
|
||||
|
||||
@Inject
|
||||
protected PasswordField passwordField;
|
||||
|
||||
@Inject
|
||||
protected LookupField localesSelect;
|
||||
|
||||
protected boolean loginByRememberMe = false;
|
||||
|
||||
protected ValueChangeListener loginChangeListener;
|
||||
|
||||
protected Boolean bruteForceProtectionEnabled;
|
||||
|
||||
@Override
|
||||
public void init(Map<String, Object> params) {
|
||||
super.init(params);
|
||||
|
||||
loginField.requestFocus();
|
||||
|
||||
initLogoImage();
|
||||
|
||||
initDefaultCredentials();
|
||||
|
||||
initLocales();
|
||||
|
||||
initRememberMe();
|
||||
}
|
||||
|
||||
protected void initLocales() {
|
||||
Map<String, Locale> locales = globalConfig.getAvailableLocales();
|
||||
|
||||
localesSelect.setOptionsMap(locales);
|
||||
localesSelect.setValue(App.getInstance().getLocale());
|
||||
localesSelect.setVisible(globalConfig.getLocaleSelectVisible());
|
||||
|
||||
localesSelect.addValueChangeListener(e -> {
|
||||
Locale selectedLocale = (Locale) e.getValue();
|
||||
|
||||
App app = App.getInstance();
|
||||
app.setLocale(selectedLocale);
|
||||
|
||||
authInfoThreadLocal.set(new AuthInfo(loginField.getValue(), passwordField.getValue(),
|
||||
rememberMeCheckBox.getValue()));
|
||||
try {
|
||||
app.createTopLevelWindow();
|
||||
} finally {
|
||||
authInfoThreadLocal.set(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void initLogoImage() {
|
||||
String loginLogoImagePath = messages.getMainMessage("loginWindow.logoImage", userSessionSource.getLocale());
|
||||
if (StringUtils.isBlank(loginLogoImagePath) || "loginWindow.logoImage".equals(loginLogoImagePath)) {
|
||||
logoImage.setVisible(false);
|
||||
} else {
|
||||
logoImage.setSource("theme://" + loginLogoImagePath);
|
||||
}
|
||||
}
|
||||
|
||||
protected void initRememberMe() {
|
||||
loginChangeListener = e -> loginByRememberMe = false;
|
||||
|
||||
if (!webConfig.getRememberMeEnabled()) {
|
||||
rememberMeCheckBox.setValue(false);
|
||||
rememberMeCheckBox.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
App app = App.getInstance();
|
||||
|
||||
String rememberMeCookie = app.getCookieValue(COOKIE_REMEMBER_ME);
|
||||
if (Boolean.parseBoolean(rememberMeCookie)) {
|
||||
String login;
|
||||
String encodedLogin = app.getCookieValue(COOKIE_LOGIN) != null ? app.getCookieValue(COOKIE_LOGIN) : "";
|
||||
try {
|
||||
login = URLDecoder.decode(encodedLogin, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
login = encodedLogin;
|
||||
}
|
||||
|
||||
String rememberMeToken = app.getCookieValue(COOKIE_PASSWORD) != null ? app.getCookieValue(COOKIE_PASSWORD) : "";
|
||||
if (app.getConnection().checkRememberMe(login, rememberMeToken)) {
|
||||
rememberMeCheckBox.setValue(true);
|
||||
loginField.setValue(login);
|
||||
|
||||
passwordField.setValue(rememberMeToken);
|
||||
loginByRememberMe = true;
|
||||
}
|
||||
|
||||
loginField.addValueChangeListener(loginChangeListener);
|
||||
passwordField.addValueChangeListener(loginChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
protected void initDefaultCredentials() {
|
||||
AuthInfo authInfo = authInfoThreadLocal.get();
|
||||
if (authInfo != null) {
|
||||
loginField.setValue(authInfo.getLogin());
|
||||
passwordField.setValue(authInfo.getPassword());
|
||||
rememberMeCheckBox.setValue(authInfo.getRememberMe());
|
||||
|
||||
localesSelect.requestFocus();
|
||||
|
||||
authInfoThreadLocal.set(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
App app = App.getInstance();
|
||||
|
||||
if (webAuthConfig.getExternalAuthentication()) {
|
||||
loginField.setValue(app.getPrincipal() == null ? "" : app.getPrincipal().getName());
|
||||
passwordField.setValue("");
|
||||
} else {
|
||||
String defaultUser = webConfig.getLoginDialogDefaultUser();
|
||||
if (!StringUtils.isBlank(defaultUser) && !"<disabled>".equals(defaultUser)) {
|
||||
loginField.setValue(defaultUser);
|
||||
} else {
|
||||
loginField.setValue("");
|
||||
}
|
||||
|
||||
String defaultPassw = webConfig.getLoginDialogDefaultPassword();
|
||||
if (!StringUtils.isBlank(defaultPassw) && !"<disabled>".equals(defaultPassw)) {
|
||||
passwordField.setValue(defaultPassw);
|
||||
} else {
|
||||
passwordField.setValue("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert userName to db form
|
||||
* In database users stores in form DOMAIN\userName
|
||||
*
|
||||
* @param login Login string
|
||||
* @return login in form DOMAIN\userName
|
||||
*/
|
||||
protected String convertLoginString(String login) {
|
||||
int slashPos = login.indexOf("\\");
|
||||
if (slashPos >= 0) {
|
||||
String domainAlias = login.substring(0, slashPos);
|
||||
String domain = domainAliasesResolver.getDomainName(domainAlias).toUpperCase();
|
||||
String userName = login.substring(slashPos + 1);
|
||||
login = domain + "\\" + userName;
|
||||
} else {
|
||||
int atSignPos = login.indexOf("@");
|
||||
if (atSignPos >= 0) {
|
||||
String domainAlias = login.substring(atSignPos + 1);
|
||||
String domain = domainAliasesResolver.getDomainName(domainAlias).toUpperCase();
|
||||
String userName = login.substring(0, atSignPos);
|
||||
login = domain + "\\" + userName;
|
||||
}
|
||||
}
|
||||
return login;
|
||||
}
|
||||
|
||||
protected void showUnhandledExceptionOnLogin(Exception e) {
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed", userSessionSource.getLocale());
|
||||
String message = messages.getMainMessage("loginWindow.pleaseContactAdministrator", userSessionSource.getLocale());
|
||||
|
||||
showNotification(title, message, NotificationType.ERROR);
|
||||
}
|
||||
|
||||
protected void showLoginException(String message){
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed", userSessionSource.getLocale());
|
||||
|
||||
showNotification(title, message, NotificationType.ERROR);
|
||||
|
||||
if (loginByRememberMe) {
|
||||
loginByRememberMe = false;
|
||||
|
||||
loginField.removeValueChangeListener(loginChangeListener);
|
||||
passwordField.removeValueChangeListener(loginChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void login() {
|
||||
doLogin();
|
||||
|
||||
App app = App.getInstance();
|
||||
Connection connection = app.getConnection();
|
||||
|
||||
if (connection.isConnected()) {
|
||||
if (webConfig.getRememberMeEnabled()) {
|
||||
if (Boolean.TRUE.equals(rememberMeCheckBox.getValue())) {
|
||||
if (!loginByRememberMe) {
|
||||
app.addCookie(COOKIE_REMEMBER_ME, Boolean.TRUE.toString());
|
||||
|
||||
String login = loginField.getValue();
|
||||
|
||||
String encodedLogin;
|
||||
try {
|
||||
encodedLogin = URLEncoder.encode(login, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
encodedLogin = login;
|
||||
}
|
||||
|
||||
app.addCookie(COOKIE_LOGIN, StringEscapeUtils.escapeJava(encodedLogin));
|
||||
|
||||
UserSession session = connection.getSession();
|
||||
if (session == null) {
|
||||
throw new IllegalStateException("Unable to get session after login");
|
||||
}
|
||||
|
||||
User user = session.getUser();
|
||||
|
||||
String rememberMeToken = userManagementService.generateRememberMeToken(user.getId());
|
||||
|
||||
app.addCookie(COOKIE_PASSWORD, rememberMeToken);
|
||||
}
|
||||
} else {
|
||||
app.removeCookie(COOKIE_REMEMBER_ME);
|
||||
app.removeCookie(COOKIE_LOGIN);
|
||||
app.removeCookie(COOKIE_PASSWORD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void doLogin() {
|
||||
String login = loginField.getValue();
|
||||
String password = passwordField.getValue() != null ? passwordField.getValue() : "";
|
||||
|
||||
if (StringUtils.isEmpty(login) || StringUtils.isEmpty(password)) {
|
||||
showNotification(messages.getMainMessage("loginWindow.emptyLoginOrPassword"), NotificationType.WARNING);
|
||||
}
|
||||
|
||||
App app = App.getInstance();
|
||||
if (!bruteForceProtectionCheck(login, app.getClientAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Connection connection = app.getConnection();
|
||||
|
||||
Locale selectedLocale = localesSelect.getValue();
|
||||
app.setLocale(selectedLocale);
|
||||
|
||||
if (loginByRememberMe && webConfig.getRememberMeEnabled()) {
|
||||
doLoginByRememberMe(login, password, selectedLocale);
|
||||
} else if (webAuthConfig.getExternalAuthentication()) {
|
||||
// try to login as externally authenticated user, fallback to regular authentication
|
||||
// we use resolved locale for error messages
|
||||
if (authenticateExternally(login, password, selectedLocale)) {
|
||||
login = convertLoginString(login);
|
||||
|
||||
((ExternallyAuthenticatedConnection) connection).loginAfterExternalAuthentication(login, selectedLocale);
|
||||
} else {
|
||||
doLogin(login, passwordEncryption.getPlainHash(password), selectedLocale);
|
||||
}
|
||||
} else {
|
||||
doLogin(login, passwordEncryption.getPlainHash(password), selectedLocale);
|
||||
}
|
||||
// locale could be set on the server
|
||||
if (connection.getSession() != null) {
|
||||
Locale loggedInLocale = userSessionSource.getLocale();
|
||||
|
||||
if (globalConfig.getLocaleSelectVisible()) {
|
||||
app.addCookie(App.COOKIE_LOCALE, loggedInLocale.toLanguageTag());
|
||||
}
|
||||
}
|
||||
} catch (LoginException e) {
|
||||
log.info("Login failed: {}", e.toString());
|
||||
|
||||
String message = StringUtils.abbreviate(e.getMessage(), 1000);
|
||||
String bruteForceMsg = registerUnsuccessfulLoginAttempt(login, app.getClientAddress());
|
||||
if (!Strings.isNullOrEmpty(bruteForceMsg)) {
|
||||
message = bruteForceMsg;
|
||||
}
|
||||
showLoginException(message);
|
||||
} catch (Exception e) {
|
||||
log.warn("Unable to login", e);
|
||||
|
||||
showUnhandledExceptionOnLogin(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doLogin(String login, String password, Locale locale) throws LoginException {
|
||||
App app = App.getInstance();
|
||||
|
||||
app.getConnection().login(login, password, locale);
|
||||
}
|
||||
|
||||
protected void doLoginByRememberMe(String login, String rememberMeToken, Locale locale) throws LoginException {
|
||||
App app = App.getInstance();
|
||||
|
||||
app.getConnection().loginByRememberMe(login, rememberMeToken, locale);
|
||||
}
|
||||
|
||||
protected boolean authenticateExternally(String login, String passwordValue, Locale locale) {
|
||||
try {
|
||||
cubaAuthProvider.authenticate(login, passwordValue, locale);
|
||||
} catch (Exception e) {
|
||||
log.debug("External authentication failed", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isBruteForceProtectionEnabled() {
|
||||
if (bruteForceProtectionEnabled == null) {
|
||||
bruteForceProtectionEnabled = loginService.isBruteForceProtectionEnabled();
|
||||
}
|
||||
return bruteForceProtectionEnabled;
|
||||
}
|
||||
|
||||
protected boolean bruteForceProtectionCheck(String login, String ipAddress) {
|
||||
if (isBruteForceProtectionEnabled()) {
|
||||
if (loginService.loginAttemptsLeft(login, ipAddress) <= 0) {
|
||||
String title = messages.getMainMessage("loginWindow.loginFailed");
|
||||
String message = messages.formatMainMessage(
|
||||
"loginWindow.loginAttemptsNumberExceeded",
|
||||
loginService.getBruteForceBlockIntervalSec());
|
||||
|
||||
showNotification(title, message, NotificationType.ERROR_HTML);
|
||||
|
||||
log.info("Blocked user login attempt: login={}, ip={}", login, ipAddress);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String registerUnsuccessfulLoginAttempt(String login, String ipAddress) {
|
||||
String message = null;
|
||||
if (isBruteForceProtectionEnabled()) {
|
||||
int loginAttemptsLeft = loginService.registerUnsuccessfulLogin(login, ipAddress);
|
||||
if (loginAttemptsLeft > 0) {
|
||||
message = messages.formatMainMessage(
|
||||
"loginWindow.loginFailedAttemptsLeft",
|
||||
loginAttemptsLeft);
|
||||
} else {
|
||||
message = messages.formatMainMessage(
|
||||
"loginWindow.loginAttemptsNumberExceeded",
|
||||
loginService.getBruteForceBlockIntervalSec());
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
<!--
|
||||
~ Copyright (c) 2008-2016 Haulmont.
|
||||
~
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
|
||||
class="com.haulmont.cuba.web.app.loginwindow.AppLoginWindow"
|
||||
caption="mainMsg://loginWindow.caption">
|
||||
|
||||
<actions>
|
||||
<action id="submit" shortcut="ENTER" invoke="login"
|
||||
caption="mainMsg://loginWindow.okButton"
|
||||
icon="app/images/login-button.png"/>
|
||||
</actions>
|
||||
|
||||
<layout stylename="cuba-login-main-layout">
|
||||
<vbox stylename="cuba-login-panel" width="AUTO"
|
||||
margin="true" spacing="true" align="MIDDLE_CENTER">
|
||||
<hbox stylename="cuba-login-title" spacing="true" align="MIDDLE_CENTER">
|
||||
<embedded id="logoImage"
|
||||
width="AUTO"
|
||||
height="AUTO"
|
||||
type="IMAGE"
|
||||
align="MIDDLE_LEFT"
|
||||
stylename="cuba-login-icon"/>
|
||||
|
||||
<label id="welcomeLabel"
|
||||
align="MIDDLE_LEFT"
|
||||
stylename="cuba-login-caption"
|
||||
value="mainMsg://loginWindow.welcomeLabel"/>
|
||||
</hbox>
|
||||
|
||||
<grid stylename="cuba-login-form" spacing="true">
|
||||
<columns count="2"/>
|
||||
<rows>
|
||||
<row>
|
||||
<label id="loginFieldLabel" value="mainMsg://loginWindow.loginField" align="MIDDLE_LEFT"
|
||||
stylename="login-form-label"/>
|
||||
|
||||
<textField id="loginField" stylename="cuba-login-username"
|
||||
width="theme://cuba.web.LoginWindow.field.width"/>
|
||||
</row>
|
||||
<row>
|
||||
<label id="passwordFieldLabel" value="mainMsg://loginWindow.passwordField" align="MIDDLE_LEFT"
|
||||
stylename="login-form-label"/>
|
||||
|
||||
<passwordField id="passwordField" stylename="cuba-login-password" autocomplete="true"
|
||||
width="theme://cuba.web.LoginWindow.field.width"/>
|
||||
</row>
|
||||
<row>
|
||||
<label id="localesSelectLabel" value="mainMsg://loginWindow.localesSelect" align="MIDDLE_LEFT"
|
||||
stylename="login-form-label"/>
|
||||
|
||||
<lookupField id="localesSelect" width="theme://cuba.web.LoginWindow.field.width"
|
||||
nullOptionVisible="false" textInputAllowed="false"/>
|
||||
</row>
|
||||
<row>
|
||||
<label id="rememberMeSpacer"/>
|
||||
|
||||
<checkBox id="rememberMeCheckBox" caption="mainMsg://loginWindow.rememberMe"/>
|
||||
</row>
|
||||
<row>
|
||||
<label id="submitSpacer"/>
|
||||
|
||||
<button id="loginButton" action="submit"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</vbox>
|
||||
</layout>
|
||||
</window>
|
@ -21,7 +21,7 @@ import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.cuba.client.ClientConfig;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.FtsConfigHelper;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.WindowManager.OpenType;
|
||||
import com.haulmont.cuba.gui.app.core.dev.LayoutAnalyzer;
|
||||
import com.haulmont.cuba.gui.app.core.dev.LayoutTip;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
@ -32,7 +32,7 @@ import com.haulmont.cuba.gui.components.mainwindow.FtsField;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaHorizontalSplitPanel;
|
||||
import com.vaadin.server.Sizeable;
|
||||
import com.vaadin.server.Sizeable.Unit;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.vaadin.peter.contextmenu.ContextMenu;
|
||||
|
||||
@ -84,20 +84,16 @@ public class AppMainWindow extends AbstractMainWindow {
|
||||
if (clientConfig.getLayoutAnalyzerEnabled()) {
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
contextMenu.setOpenAutomatically(true);
|
||||
contextMenu.setAsContextMenuOf(logoImage.unwrap(com.vaadin.ui.Embedded.class));
|
||||
contextMenu.setAsContextMenuOf(logoImage.unwrap(com.vaadin.ui.AbstractComponent.class));
|
||||
ContextMenu.ContextMenuItem analyzeLayout = contextMenu.addItem(messages.getMainMessage("actions.analyzeLayout"));
|
||||
analyzeLayout.addItemClickListener(new ContextMenu.ContextMenuItemClickListener() {
|
||||
@Override
|
||||
public void contextMenuItemClicked(ContextMenu.ContextMenuItemClickEvent event) {
|
||||
Window window = AppMainWindow.this;
|
||||
LayoutAnalyzer analyzer = new LayoutAnalyzer();
|
||||
List<LayoutTip> tipsList = analyzer.analyze(window);
|
||||
analyzeLayout.addItemClickListener(event -> {
|
||||
LayoutAnalyzer analyzer = new LayoutAnalyzer();
|
||||
List<LayoutTip> tipsList = analyzer.analyze(this);
|
||||
|
||||
if (tipsList.isEmpty()) {
|
||||
window.showNotification("No layout problems found", Frame.NotificationType.HUMANIZED);
|
||||
} else {
|
||||
window.openWindow("layoutAnalyzer", WindowManager.OpenType.DIALOG, ParamsMap.of("tipsList", tipsList));
|
||||
}
|
||||
if (tipsList.isEmpty()) {
|
||||
showNotification("No layout problems found", NotificationType.HUMANIZED);
|
||||
} else {
|
||||
openWindow("layoutAnalyzer", OpenType.DIALOG, ParamsMap.of("tipsList", tipsList));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -119,7 +115,7 @@ public class AppMainWindow extends AbstractMainWindow {
|
||||
|
||||
CubaHorizontalSplitPanel vSplitPanel = (CubaHorizontalSplitPanel) WebComponentsHelper.unwrap(foldersSplit);
|
||||
vSplitPanel.setDefaultPosition(webConfig.getFoldersPaneDefaultWidth() + "px");
|
||||
vSplitPanel.setMaxSplitPosition(50, Sizeable.Unit.PERCENTAGE);
|
||||
vSplitPanel.setMaxSplitPosition(50, Unit.PERCENTAGE);
|
||||
vSplitPanel.setDockable(true);
|
||||
} else {
|
||||
foldersPane.setEnabled(false);
|
||||
|
@ -17,7 +17,8 @@
|
||||
|
||||
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
|
||||
xmlns:main="http://schemas.haulmont.com/cuba/mainwindow.xsd"
|
||||
class="com.haulmont.cuba.web.app.mainwindow.AppMainWindow">
|
||||
class="com.haulmont.cuba.web.app.mainwindow.AppMainWindow"
|
||||
caption="mainMsg://application.caption">
|
||||
|
||||
<layout expand="foldersSplit">
|
||||
<hbox id="titleBar" stylename="cuba-app-menubar"
|
||||
|
@ -17,12 +17,20 @@
|
||||
package com.haulmont.cuba.web.app.ui.security.user;
|
||||
|
||||
import com.haulmont.cuba.gui.app.security.user.browse.UserBrowser;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.components.mainwindow.UserIndicator;
|
||||
import com.haulmont.cuba.web.App;
|
||||
|
||||
public class UserBrowserCompanion implements UserBrowser.Companion {
|
||||
|
||||
@Override
|
||||
public void refreshUserSubstitutions() {
|
||||
App.getInstance().getAppWindow().refreshUserSubstitutions();
|
||||
Window.TopLevelWindow topLevelWindow = App.getInstance().getTopLevelWindow();
|
||||
|
||||
if (topLevelWindow instanceof Window.HasUserIndicator) {
|
||||
UserIndicator userIndicator = ((Window.HasUserIndicator) topLevelWindow).getUserIndicator();
|
||||
if (userIndicator != null) {
|
||||
userIndicator.refreshUserSubstitutions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,13 +19,14 @@ package com.haulmont.cuba.web.app.ui.security.user;
|
||||
|
||||
import com.haulmont.cuba.gui.app.security.user.edit.UserEditor;
|
||||
import com.haulmont.cuba.gui.components.PasswordField;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.components.mainwindow.UserIndicator;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.auth.WebAuthConfig;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class UserEditorCompanion implements UserEditor.Companion {
|
||||
|
||||
@Inject
|
||||
protected WebAuthConfig config;
|
||||
|
||||
@ -36,6 +37,13 @@ public class UserEditorCompanion implements UserEditor.Companion {
|
||||
|
||||
@Override
|
||||
public void refreshUserSubstitutions() {
|
||||
App.getInstance().getAppWindow().refreshUserSubstitutions();
|
||||
Window.TopLevelWindow topLevelWindow = App.getInstance().getTopLevelWindow();
|
||||
|
||||
if (topLevelWindow instanceof Window.HasUserIndicator) {
|
||||
UserIndicator userIndicator = ((Window.HasUserIndicator) topLevelWindow).getUserIndicator();
|
||||
if (userIndicator != null) {
|
||||
userIndicator.refreshUserSubstitutions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import com.haulmont.cuba.gui.components.Frame;
|
||||
import com.haulmont.cuba.gui.executors.BackgroundWorker;
|
||||
import com.haulmont.cuba.gui.export.*;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaFileDownloader;
|
||||
import com.vaadin.server.StreamResource;
|
||||
@ -100,7 +101,7 @@ public class WebExportDisplay implements ExportDisplay {
|
||||
}
|
||||
}
|
||||
|
||||
CubaFileDownloader fileDownloader = App.getInstance().getAppWindow().getFileDownloader();
|
||||
CubaFileDownloader fileDownloader = AppUI.getCurrent().getFileDownloader();
|
||||
|
||||
StreamResource resource = new StreamResource(new StreamResource.StreamSource() {
|
||||
@Override
|
||||
|
@ -35,7 +35,6 @@ import com.haulmont.cuba.gui.data.DsContext;
|
||||
import com.haulmont.cuba.gui.settings.Settings;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsManager;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebWindowManager;
|
||||
import com.haulmont.cuba.web.gui.components.WebAbstractComponent;
|
||||
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
@ -44,6 +43,7 @@ import com.haulmont.cuba.web.toolkit.ui.CubaGroupBox;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaTree;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaVerticalActionsLayout;
|
||||
import com.vaadin.event.ItemClickEvent;
|
||||
import com.vaadin.server.Page;
|
||||
import com.vaadin.server.Sizeable.Unit;
|
||||
import com.vaadin.shared.ui.MarginInfo;
|
||||
import com.vaadin.ui.*;
|
||||
@ -668,8 +668,7 @@ public class WebWindow implements Window, Component.Wrapper,
|
||||
|
||||
@Override
|
||||
public void addTimer(Timer timer) {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
appWindow.addTimer(((WebTimer) timer).getTimerImpl());
|
||||
AppUI.getCurrent().addTimer(((WebTimer) timer).getTimerImpl());
|
||||
|
||||
if (timers == null) {
|
||||
timers = new LinkedList<>();
|
||||
@ -687,12 +686,12 @@ public class WebWindow implements Window, Component.Wrapper,
|
||||
}
|
||||
|
||||
public void stopTimers() {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
AppUI appUI = AppUI.getCurrent();
|
||||
if (timers != null) {
|
||||
for (Timer timer : timers) {
|
||||
timer.stop();
|
||||
WebTimer webTimer = (WebTimer) timer;
|
||||
appWindow.removeTimer(webTimer.getTimerImpl());
|
||||
appUI.removeTimer(webTimer.getTimerImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1150,6 +1149,10 @@ public class WebWindow implements Window, Component.Wrapper,
|
||||
dialogWindow.setCaption(caption);
|
||||
}
|
||||
}
|
||||
|
||||
if (getWrapper() instanceof TopLevelWindow) {
|
||||
Page.getCurrent().setTitle(caption);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +46,7 @@ public abstract class WebAbstractOptionsField<T extends com.vaadin.ui.AbstractSe
|
||||
implements OptionsField {
|
||||
|
||||
protected List optionsList;
|
||||
protected Map<String, Object> optionsMap;
|
||||
protected Map<String, ?> optionsMap;
|
||||
protected Class<? extends EnumClass> optionsEnum;
|
||||
protected CollectionDatasource optionsDatasource;
|
||||
|
||||
@ -117,12 +117,12 @@ public abstract class WebAbstractOptionsField<T extends com.vaadin.ui.AbstractSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> options) {
|
||||
public void setOptionsMap(Map<String, ?> options) {
|
||||
if (metaProperty != null && metaProperty.getRange().isEnum()) {
|
||||
List constants = Arrays.asList(metaProperty.getRange().asEnumeration().getJavaClass().getEnumConstants());
|
||||
List opts = new ArrayList();
|
||||
|
||||
for (Map.Entry<String, Object> entry : options.entrySet()) {
|
||||
for (Map.Entry<String, ?> entry : options.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object itemId = entry.getValue();
|
||||
|
||||
@ -138,7 +138,7 @@ public abstract class WebAbstractOptionsField<T extends com.vaadin.ui.AbstractSe
|
||||
setCaptionMode(CaptionMode.ITEM);
|
||||
} else {
|
||||
List opts = new ArrayList();
|
||||
for (Map.Entry<String, Object> entry : options.entrySet()) {
|
||||
for (Map.Entry<String, ?> entry : options.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object itemId = entry.getValue();
|
||||
|
||||
@ -271,7 +271,7 @@ public abstract class WebAbstractOptionsField<T extends com.vaadin.ui.AbstractSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptionsMap() {
|
||||
public Map<String, ?> getOptionsMap() {
|
||||
return optionsMap;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ import com.haulmont.cuba.gui.data.impl.DsContextImplementation;
|
||||
import com.haulmont.cuba.gui.settings.Settings;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentLoader;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebWindowManager;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaAccordion;
|
||||
import com.vaadin.ui.Layout;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@ -482,8 +482,8 @@ public class WebAccordion extends WebAbstractComponent<CubaAccordion> implements
|
||||
// init debug ids after all
|
||||
if (AppUI.getCurrent().isTestMode()) {
|
||||
context.addPostInitTask((context1, window1) -> {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
appWindow.getWindowManager().initDebugIds(window1);
|
||||
Window.TopLevelWindow appWindow = AppUI.getCurrent().getTopLevelWindow();
|
||||
((WebWindowManager) appWindow.getWindowManager()).initDebugIds(window1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -31,15 +31,12 @@ public class WebButton extends WebAbstractComponent<CubaButton> implements Butto
|
||||
|
||||
public WebButton() {
|
||||
component = new CubaButton();
|
||||
component.addClickListener(new com.vaadin.ui.Button.ClickListener() {
|
||||
@Override
|
||||
public void buttonClick(com.vaadin.ui.Button.ClickEvent event) {
|
||||
beforeActionPerformed();
|
||||
if (action != null) {
|
||||
performAction(action);
|
||||
}
|
||||
afterActionPerformed();
|
||||
component.addClickListener((com.vaadin.ui.Button.ClickListener) event -> {
|
||||
beforeActionPerformed();
|
||||
if (action != null) {
|
||||
performAction(action);
|
||||
}
|
||||
afterActionPerformed();
|
||||
});
|
||||
component.setDescription(null);
|
||||
}
|
||||
@ -114,20 +111,17 @@ public class WebButton extends WebAbstractComponent<CubaButton> implements Butto
|
||||
|
||||
action.addOwner(this);
|
||||
|
||||
actionPropertyChangeListener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (Action.PROP_ICON.equals(evt.getPropertyName())) {
|
||||
setIcon(WebButton.this.action.getIcon());
|
||||
} else if (Action.PROP_CAPTION.equals(evt.getPropertyName())) {
|
||||
setCaption(WebButton.this.action.getCaption());
|
||||
} else if (Action.PROP_DESCRIPTION.equals(evt.getPropertyName())) {
|
||||
setDescription(WebButton.this.action.getDescription());
|
||||
} else if (Action.PROP_ENABLED.equals(evt.getPropertyName())) {
|
||||
setEnabled(WebButton.this.action.isEnabled());
|
||||
} else if (Action.PROP_VISIBLE.equals(evt.getPropertyName())) {
|
||||
setVisible(WebButton.this.action.isVisible());
|
||||
}
|
||||
actionPropertyChangeListener = evt -> {
|
||||
if (Action.PROP_ICON.equals(evt.getPropertyName())) {
|
||||
setIcon(WebButton.this.action.getIcon());
|
||||
} else if (Action.PROP_CAPTION.equals(evt.getPropertyName())) {
|
||||
setCaption(WebButton.this.action.getCaption());
|
||||
} else if (Action.PROP_DESCRIPTION.equals(evt.getPropertyName())) {
|
||||
setDescription(WebButton.this.action.getDescription());
|
||||
} else if (Action.PROP_ENABLED.equals(evt.getPropertyName())) {
|
||||
setEnabled(WebButton.this.action.isEnabled());
|
||||
} else if (Action.PROP_VISIBLE.equals(evt.getPropertyName())) {
|
||||
setVisible(WebButton.this.action.isVisible());
|
||||
}
|
||||
};
|
||||
action.addPropertyChangeListener(actionPropertyChangeListener);
|
||||
|
@ -21,7 +21,6 @@ import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.gui.components.Component;
|
||||
import com.haulmont.cuba.gui.components.Embedded;
|
||||
import com.haulmont.cuba.gui.export.ExportDataProvider;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
@ -44,12 +43,11 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WebEmbedded extends WebAbstractComponent<com.vaadin.ui.Embedded> implements Embedded, Component.Disposable {
|
||||
public class WebEmbedded extends WebAbstractComponent<com.vaadin.ui.Embedded> implements Embedded {
|
||||
|
||||
protected Map<String, String> parameters = null;
|
||||
protected Type type = Type.IMAGE;
|
||||
protected Resource resource;
|
||||
protected boolean disposed;
|
||||
|
||||
public WebEmbedded() {
|
||||
component = new com.vaadin.ui.Embedded();
|
||||
@ -222,18 +220,7 @@ public class WebEmbedded extends WebAbstractComponent<com.vaadin.ui.Embedded> im
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisposed() {
|
||||
return disposed;
|
||||
}
|
||||
|
||||
protected static class EmptyStreamSource implements StreamResource.StreamSource {
|
||||
|
||||
public static final String EMPTY_IMAGE_PATH = "/com/haulmont/cuba/web/gui/components/resources/empty.png";
|
||||
|
||||
protected byte[] emptyImage;
|
||||
|
@ -24,9 +24,6 @@ import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.global.Metadata;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.components.Table;
|
||||
import com.haulmont.cuba.gui.components.TextField;
|
||||
import com.haulmont.cuba.gui.components.Tree;
|
||||
import com.haulmont.cuba.gui.components.filter.ConditionsTree;
|
||||
import com.haulmont.cuba.gui.components.filter.FilterHelper;
|
||||
import com.haulmont.cuba.gui.components.filter.condition.AbstractCondition;
|
||||
@ -35,7 +32,6 @@ import com.haulmont.cuba.gui.components.mainwindow.FoldersPane;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.presentations.Presentations;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.haulmont.cuba.web.app.folders.AppFolderEditWindow;
|
||||
import com.haulmont.cuba.web.app.folders.CubaFoldersPane;
|
||||
@ -85,8 +81,12 @@ public class WebFilterHelper implements FilterHelper {
|
||||
@Override
|
||||
@Nullable
|
||||
public AbstractSearchFolder saveFolder(AbstractSearchFolder folder) {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
FoldersPane foldersPane = appWindow.getMainWindow().getFoldersPane();
|
||||
Window.TopLevelWindow topLevelWindow = AppUI.getCurrent().getTopLevelWindow();
|
||||
FoldersPane foldersPane = null;
|
||||
if (topLevelWindow instanceof Window.HasFoldersPane) {
|
||||
foldersPane = ((Window.HasFoldersPane) topLevelWindow).getFoldersPane();
|
||||
}
|
||||
|
||||
if (foldersPane == null)
|
||||
return null;
|
||||
|
||||
@ -214,8 +214,12 @@ public class WebFilterHelper implements FilterHelper {
|
||||
|
||||
@Override
|
||||
public Object getFoldersPane() {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
FoldersPane foldersPane = appWindow.getMainWindow().getFoldersPane();
|
||||
Window.TopLevelWindow topLevelWindow = AppUI.getCurrent().getTopLevelWindow();
|
||||
FoldersPane foldersPane = null;
|
||||
if (topLevelWindow instanceof Window.HasFoldersPane) {
|
||||
foldersPane = ((Window.HasFoldersPane) topLevelWindow).getFoldersPane();
|
||||
}
|
||||
|
||||
if (foldersPane == null) {
|
||||
return null;
|
||||
}
|
||||
@ -225,8 +229,12 @@ public class WebFilterHelper implements FilterHelper {
|
||||
|
||||
@Override
|
||||
public void removeFolderFromFoldersPane(Folder folder) {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
FoldersPane foldersPane = appWindow.getMainWindow().getFoldersPane();
|
||||
Window.TopLevelWindow topLevelWindow = AppUI.getCurrent().getTopLevelWindow();
|
||||
FoldersPane foldersPane = null;
|
||||
if (topLevelWindow instanceof Window.HasFoldersPane) {
|
||||
foldersPane = ((Window.HasFoldersPane) topLevelWindow).getFoldersPane();
|
||||
}
|
||||
|
||||
if (foldersPane == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ public class WebLookupField extends WebAbstractOptionsField<CubaComboBox> implem
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> options) {
|
||||
public void setOptionsMap(Map<String, ?> options) {
|
||||
super.setOptionsMap(options);
|
||||
|
||||
checkMissingValue();
|
||||
|
@ -198,7 +198,7 @@ public class WebSearchField extends WebLookupField implements SearchField {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> options) {
|
||||
public void setOptionsMap(Map<String, ?> options) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ import com.haulmont.cuba.gui.settings.Settings;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentLoader;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebWindowManager;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaTabSheet;
|
||||
import com.vaadin.ui.Layout;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@ -515,8 +515,8 @@ public class WebTabSheet extends WebAbstractComponent<CubaTabSheet> implements T
|
||||
// init debug ids after all
|
||||
if (AppUI.getCurrent().isTestMode()) {
|
||||
context.addPostInitTask((context1, window1) -> {
|
||||
AppWindow appWindow = AppUI.getCurrent().getAppWindow();
|
||||
appWindow.getWindowManager().initDebugIds(window1);
|
||||
Window.TopLevelWindow appWindow = AppUI.getCurrent().getTopLevelWindow();
|
||||
((WebWindowManager) appWindow.getWindowManager()).initDebugIds(window1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -289,12 +289,12 @@ public class WebTokenList extends WebAbstractField<WebTokenList.CubaTokenList> i
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getOptionsMap() {
|
||||
public Map<String, ?> getOptionsMap() {
|
||||
return lookupPickerField.getOptionsMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionsMap(Map<String, Object> map) {
|
||||
public void setOptionsMap(Map<String, ?> map) {
|
||||
lookupPickerField.setOptionsMap(map);
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,8 @@ import com.haulmont.cuba.gui.components.mainwindow.LogoutButton;
|
||||
import com.haulmont.cuba.web.Connection;
|
||||
import com.haulmont.cuba.web.WebWindowManager;
|
||||
import com.haulmont.cuba.web.gui.components.WebAbstractComponent;
|
||||
import com.haulmont.cuba.web.gui.components.WebButton;
|
||||
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaButton;
|
||||
import com.vaadin.ui.Button;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class WebLogoutButton extends WebAbstractComponent<CubaButton> implements LogoutButton {
|
||||
|
||||
@ -36,12 +33,9 @@ public class WebLogoutButton extends WebAbstractComponent<CubaButton> implements
|
||||
public WebLogoutButton() {
|
||||
component = new CubaButton();
|
||||
component.addStyleName(LOGOUT_BUTTON_STYLENAME);
|
||||
component.addClickListener(new Button.ClickListener() {
|
||||
@Override
|
||||
public void buttonClick(Button.ClickEvent event) {
|
||||
logout();
|
||||
}
|
||||
});
|
||||
component.addClickListener((Button.ClickListener) event ->
|
||||
logout()
|
||||
);
|
||||
component.setDescription(null);
|
||||
}
|
||||
|
||||
@ -54,12 +48,9 @@ public class WebLogoutButton extends WebAbstractComponent<CubaButton> implements
|
||||
window.saveSettings();
|
||||
|
||||
final WebWindowManager wm = (WebWindowManager) window.getWindowManager();
|
||||
wm.checkModificationsAndCloseAll(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Connection connection = wm.getApp().getConnection();
|
||||
connection.logout();
|
||||
}
|
||||
wm.checkModificationsAndCloseAll(() -> {
|
||||
Connection connection = wm.getApp().getConnection();
|
||||
connection.logout();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ import com.haulmont.cuba.gui.executors.impl.TaskHandlerImpl;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.vaadin.server.VaadinSession;
|
||||
import com.vaadin.ui.UI;
|
||||
@ -115,8 +114,7 @@ public class WebBackgroundWorker implements BackgroundWorker {
|
||||
}
|
||||
|
||||
// create task executor
|
||||
AppWindow appWindow = appInstance.getAppWindow();
|
||||
final WebTaskExecutor<T, V> taskExecutor = new WebTaskExecutor<>(appWindow, task);
|
||||
final WebTaskExecutor<T, V> taskExecutor = new WebTaskExecutor<>(appInstance.getAppUI(), task);
|
||||
|
||||
// add thread to taskSet
|
||||
appInstance.addBackgroundTask(taskExecutor.getFuture());
|
||||
@ -145,41 +143,34 @@ public class WebBackgroundWorker implements BackgroundWorker {
|
||||
}
|
||||
|
||||
protected static void withUserSessionAsync(UI ui, Runnable handler) {
|
||||
ui.access(() -> {
|
||||
SecurityContext oldSecurityContext = AppContext.getSecurityContext();
|
||||
try {
|
||||
UserSession userSession = ui.getSession().getAttribute(UserSession.class);
|
||||
if (userSession != null) {
|
||||
AppContext.setSecurityContext(new SecurityContext(userSession));
|
||||
}
|
||||
|
||||
handler.run();
|
||||
} finally {
|
||||
AppContext.setSecurityContext(oldSecurityContext);
|
||||
}
|
||||
});
|
||||
ui.access(() ->
|
||||
executeOnUiThread(ui, handler)
|
||||
);
|
||||
}
|
||||
|
||||
protected static void withUserSessionInvoke(UI ui, Runnable handler) {
|
||||
ui.accessSynchronously(() -> {
|
||||
SecurityContext oldSecurityContext = AppContext.getSecurityContext();
|
||||
try {
|
||||
UserSession userSession = ui.getSession().getAttribute(UserSession.class);
|
||||
if (userSession != null) {
|
||||
AppContext.setSecurityContext(new SecurityContext(userSession));
|
||||
}
|
||||
ui.accessSynchronously(() ->
|
||||
executeOnUiThread(ui, handler)
|
||||
);
|
||||
}
|
||||
|
||||
handler.run();
|
||||
} finally {
|
||||
AppContext.setSecurityContext(oldSecurityContext);
|
||||
protected static void executeOnUiThread(UI ui, Runnable handler) {
|
||||
SecurityContext oldSecurityContext = AppContext.getSecurityContext();
|
||||
try {
|
||||
UserSession userSession = ui.getSession().getAttribute(UserSession.class);
|
||||
if (userSession != null) {
|
||||
AppContext.setSecurityContext(new SecurityContext(userSession));
|
||||
}
|
||||
});
|
||||
|
||||
handler.run();
|
||||
} finally {
|
||||
AppContext.setSecurityContext(oldSecurityContext);
|
||||
}
|
||||
}
|
||||
|
||||
private class WebTaskExecutor<T, V> implements TaskExecutor<T, V>, Callable<V> {
|
||||
|
||||
private App app;
|
||||
private AppWindow appWindow;
|
||||
private AppUI ui;
|
||||
|
||||
private FutureTask<V> future;
|
||||
|
||||
@ -195,10 +186,9 @@ public class WebBackgroundWorker implements BackgroundWorker {
|
||||
private Map<String, Object> params;
|
||||
private TaskHandlerImpl<T, V> taskHandler;
|
||||
|
||||
private WebTaskExecutor(AppWindow appWindow, BackgroundTask<T, V> runnableTask) {
|
||||
private WebTaskExecutor(AppUI ui, BackgroundTask<T, V> runnableTask) {
|
||||
this.runnableTask = runnableTask;
|
||||
this.appWindow = appWindow;
|
||||
this.app = appWindow.getAppUI().getApp();
|
||||
this.ui = ui;
|
||||
|
||||
this.params = runnableTask.getParams() != null ?
|
||||
Collections.unmodifiableMap(runnableTask.getParams()) :
|
||||
@ -294,7 +284,7 @@ public class WebBackgroundWorker implements BackgroundWorker {
|
||||
// do not allow to cancel task from done listeners and exception handler
|
||||
isClosed = true;
|
||||
|
||||
app.removeBackgroundTask(future);
|
||||
ui.getApp().removeBackgroundTask(future);
|
||||
watchDog.removeTask(taskHandler);
|
||||
|
||||
try {
|
||||
@ -422,8 +412,6 @@ public class WebBackgroundWorker implements BackgroundWorker {
|
||||
}
|
||||
|
||||
protected final void withUserSessionAsync(Runnable handler) {
|
||||
AppUI ui = appWindow.getAppUI();
|
||||
|
||||
WebBackgroundWorker.withUserSessionAsync(ui, handler);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import java.util.List;
|
||||
|
||||
public class AppLog {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(AppLog.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(AppLog.class);
|
||||
|
||||
private transient LinkedList<LogItem> items = new LinkedList<>();
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
@include=com.haulmont.cuba.gui
|
||||
|
||||
app.initErrorCaption = Unexpected error
|
||||
app.initErrorMessage = Please contact system administrator
|
||||
app.initRetry = Retry
|
||||
|
||||
menu-config.sys$Category.browse=Dynamic Attributes
|
||||
menu-config.serverLog=Server Log
|
||||
menu-config.printDomain=Data Model
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
@include=com.haulmont.cuba.gui
|
||||
|
||||
app.initErrorCaption = Непредвиденная ошибка
|
||||
app.initErrorMessage = Пожалуйста свяжитесь с администратором системы
|
||||
app.initRetry = Попробовать ещё раз
|
||||
|
||||
menu-config.sys$Category.browse=Динамические атрибуты
|
||||
menu-config.serverLog=Журнал сервера
|
||||
menu-config.printDomain=Модель данных
|
||||
|
@ -31,7 +31,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* User settings provider for web application. Caches settings in HTTP session.
|
||||
*
|
||||
*/
|
||||
@Component(SettingsClient.NAME)
|
||||
public class WebSettingsClient implements SettingsClient {
|
||||
@ -42,6 +41,7 @@ public class WebSettingsClient implements SettingsClient {
|
||||
@Override
|
||||
public String getSetting(String name) {
|
||||
Map<String, Optional<String>> settings = getCache();
|
||||
//noinspection Guava
|
||||
Optional<String> cached = settings.get(name);
|
||||
if (cached != null) {
|
||||
return cached.orNull();
|
||||
@ -61,7 +61,7 @@ public class WebSettingsClient implements SettingsClient {
|
||||
|
||||
@Override
|
||||
public void deleteSettings(String name) {
|
||||
getCache().put(name, Optional.<String>absent());
|
||||
getCache().put(name, Optional.absent());
|
||||
userSettingService.deleteSettings(ClientType.WEB, name);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class BackgroundTaskManager {
|
||||
// Clean task set
|
||||
taskSet.clear();
|
||||
if (count > 0) {
|
||||
log.debug(String.format("Interrupted %s background tasks", count));
|
||||
log.debug("Interrupted {} background tasks", count);
|
||||
}
|
||||
}
|
||||
}
|
@ -124,6 +124,19 @@ public class CubaApplicationServlet extends VaadinServlet {
|
||||
initParameters.setProperty(Constants.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, String.valueOf(sessionPingPeriod));
|
||||
}
|
||||
|
||||
String widgetSet = webConfig.getWidgetSet();
|
||||
initParameters.setProperty(Constants.PARAMETER_WIDGETSET, widgetSet);
|
||||
|
||||
boolean productionMode = webConfig.getProductionMode();
|
||||
if (!productionMode) {
|
||||
initParameters.setProperty(Constants.SERVLET_PARAMETER_PRODUCTION_MODE, String.valueOf(false));
|
||||
}
|
||||
|
||||
initParameters.setProperty(Constants.SERVLET_PARAMETER_UI_PROVIDER, CubaUIProvider.class.getCanonicalName());
|
||||
|
||||
// not actually used by CubaUIProvider
|
||||
initParameters.setProperty(VaadinSession.UI_PARAMETER, AppUI.class.getCanonicalName());
|
||||
|
||||
return super.createDeploymentConfiguration(initParameters);
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,13 @@ import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.GlobalConfig;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstantsRepository;
|
||||
import com.haulmont.cuba.web.App;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.WebConfig;
|
||||
import com.vaadin.server.DefaultUIProvider;
|
||||
import com.vaadin.server.UICreateEvent;
|
||||
import com.vaadin.shared.communication.PushMode;
|
||||
import com.vaadin.shared.ui.ui.Transport;
|
||||
import com.vaadin.ui.UI;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
@ -39,6 +41,9 @@ import java.util.Set;
|
||||
public class CubaUIProvider extends DefaultUIProvider {
|
||||
protected Configuration configuration = AppBeans.get(Configuration.NAME);
|
||||
|
||||
public CubaUIProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTheme(UICreateEvent event) {
|
||||
// get theme from cookies before app ui initialized for smooth theme enabling
|
||||
@ -96,4 +101,9 @@ public class CubaUIProvider extends DefaultUIProvider {
|
||||
|
||||
return super.getPushTransport(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UI createInstance(UICreateEvent event) {
|
||||
return AppBeans.getPrototype(AppUI.NAME);
|
||||
}
|
||||
}
|
@ -358,8 +358,27 @@ public class CubaVaadinServletService extends VaadinServletService {
|
||||
Component component = (Component) connector;
|
||||
String id = component.getId() == null ? super.createConnectorId(connector) : component.getId();
|
||||
UserSession session = getAttribute(UserSession.class);
|
||||
String login = session != null ? session.getCurrentOrSubstitutedUser().getLogin() : null;
|
||||
return login != null ? login + "-" + id : id;
|
||||
|
||||
String login = null;
|
||||
String locale = null;
|
||||
|
||||
if (session != null) {
|
||||
login = session.getCurrentOrSubstitutedUser().getLogin();
|
||||
if (session.getLocale() != null) {
|
||||
locale = session.getLocale().toLanguageTag();
|
||||
}
|
||||
}
|
||||
|
||||
List<String> idParts = new ArrayList<>(3);
|
||||
if (login != null) {
|
||||
idParts.add(login);
|
||||
}
|
||||
if (locale != null) {
|
||||
idParts.add(locale);
|
||||
}
|
||||
idParts.add(id);
|
||||
|
||||
return StringUtils.join(idParts, "-");
|
||||
}
|
||||
return super.createConnectorId(connector);
|
||||
}
|
||||
|
@ -22,14 +22,15 @@ import com.haulmont.cuba.core.global.DevelopmentException;
|
||||
import com.haulmont.cuba.core.global.UserSessionSource;
|
||||
import com.haulmont.cuba.gui.NoSuchScreenException;
|
||||
import com.haulmont.cuba.gui.TestIdManager;
|
||||
import com.haulmont.cuba.gui.components.Window;
|
||||
import com.haulmont.cuba.gui.components.mainwindow.AppMenu;
|
||||
import com.haulmont.cuba.gui.config.*;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import com.haulmont.cuba.web.AppUI;
|
||||
import com.haulmont.cuba.web.AppWindow;
|
||||
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
|
||||
import com.haulmont.cuba.web.toolkit.MenuShortcutAction;
|
||||
import com.haulmont.cuba.web.toolkit.ui.CubaMenuBar;
|
||||
import com.vaadin.ui.AbstractComponent;
|
||||
import com.vaadin.ui.MenuBar;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -49,7 +50,7 @@ public class MenuBuilder {
|
||||
|
||||
protected CubaMenuBar menuBar;
|
||||
|
||||
protected AppWindow appWindow;
|
||||
protected Window.TopLevelWindow topLevelWindow;
|
||||
|
||||
protected MenuConfig menuConfig = AppBeans.get(MenuConfig.NAME);
|
||||
|
||||
@ -59,7 +60,7 @@ public class MenuBuilder {
|
||||
public MenuBuilder(AppMenu menu) {
|
||||
this.session = uss.getUserSession();
|
||||
this.menuBar = (CubaMenuBar) WebComponentsHelper.unwrap(menu);
|
||||
this.appWindow = ((AppUI) menuBar.getUI()).getAppWindow();
|
||||
this.topLevelWindow = ((AppUI) menuBar.getUI()).getTopLevelWindow();
|
||||
}
|
||||
|
||||
public void build() {
|
||||
@ -186,14 +187,14 @@ public class MenuBuilder {
|
||||
protected void assignShortcut(MenuBar.MenuItem menuItem, MenuItem item) {
|
||||
if (item.getShortcut() != null && menuItem.getCommand() != null) {
|
||||
MenuShortcutAction shortcut = new MenuShortcutAction(menuItem, "shortcut_" + item.getId(), item.getShortcut());
|
||||
appWindow.addShortcutListener(shortcut);
|
||||
topLevelWindow.unwrap(AbstractComponent.class).addShortcutListener(shortcut);
|
||||
menuBar.setShortcut(menuItem, item.getShortcut());
|
||||
}
|
||||
}
|
||||
|
||||
protected void assignTestId(MenuBar.MenuItem menuItem, MenuItem conf) {
|
||||
if (menuBar.getId() != null && menuBar.getCubaId() != null && !conf.isSeparator()) {
|
||||
TestIdManager testIdManager = appWindow.getAppUI().getTestIdManager();
|
||||
TestIdManager testIdManager = AppUI.getCurrent().getTestIdManager();
|
||||
|
||||
String id = testIdManager.normalize(conf.getId());
|
||||
String testId = menuBar.getId() + "_" + id;
|
||||
|
@ -19,11 +19,14 @@ package com.haulmont.cuba.web.sys.remoting;
|
||||
|
||||
import com.haulmont.cuba.core.global.RemoteException;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.core.sys.SecurityContext;
|
||||
import com.haulmont.cuba.core.sys.serialization.SerializationSupport;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceDirectory;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvocation;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvocationResult;
|
||||
import com.haulmont.cuba.core.sys.remoting.LocalServiceInvoker;
|
||||
import com.haulmont.cuba.security.global.ClientBasedSession;
|
||||
import com.haulmont.cuba.security.global.UserSession;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.remoting.support.RemoteAccessor;
|
||||
@ -96,7 +99,7 @@ public class LocalServiceProxy extends RemoteAccessor implements FactoryBean<Obj
|
||||
String entryName = connectionUrlList.substring(connectionUrlList.lastIndexOf('/') + 1) + serviceName;
|
||||
LocalServiceInvoker invoker = LocalServiceDirectory.getInvoker(entryName);
|
||||
if (invoker == null)
|
||||
throw new IllegalArgumentException("Service " + entryName + " is not registered in LocalServiceDirectory");
|
||||
throw new IllegalArgumentException(String.format("Service %s is not registered in LocalServiceDirectory", entryName));
|
||||
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
String[] parameterTypeNames = new String[parameterTypes.length];
|
||||
@ -123,9 +126,21 @@ public class LocalServiceProxy extends RemoteAccessor implements FactoryBean<Obj
|
||||
}
|
||||
}
|
||||
|
||||
UUID sessionId = AppContext.getSecurityContext() == null ? null : AppContext.getSecurityContext().getSessionId();
|
||||
SecurityContext securityContext = AppContext.getSecurityContext();
|
||||
UUID sessionId = securityContext == null ? null : securityContext.getSessionId();
|
||||
|
||||
String requestScopeLocale = null;
|
||||
if (securityContext != null) {
|
||||
UserSession session = securityContext.getSession();
|
||||
if (session instanceof ClientBasedSession) {
|
||||
if (((ClientBasedSession) session).isLocaleRequestScoped()) {
|
||||
requestScopeLocale = session.getLocale() != null ? session.getLocale().toLanguageTag() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalServiceInvocation invocation = new LocalServiceInvocation(
|
||||
method.getName(), parameterTypeNames, argumentsData, notSerializableArguments, sessionId);
|
||||
method.getName(), parameterTypeNames, argumentsData, notSerializableArguments, sessionId, requestScopeLocale);
|
||||
|
||||
LocalServiceInvocationResult result = invoker.invoke(invocation);
|
||||
AppContext.setSecurityContext(AppContext.getSecurityContext());//need reset application name in LogMDC for the current thread
|
||||
|
@ -24,7 +24,6 @@ import com.haulmont.cuba.web.sys.CubaApplicationServlet;
|
||||
import com.haulmont.cuba.web.sys.CubaDispatcherServlet;
|
||||
import com.haulmont.cuba.web.sys.CubaHttpFilter;
|
||||
import com.haulmont.cuba.web.sys.WebAppContextLoader;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
@ -38,7 +37,6 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* {@link AppContext} loader of the web application block packed in a WAR together with the middleware block.
|
||||
|
@ -18,13 +18,10 @@
|
||||
package com.haulmont.cuba.web.toolkit.ui;
|
||||
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.historycontrol.CubaHistoryControlServerRpc;
|
||||
import com.vaadin.server.AbstractClientConnector;
|
||||
import com.vaadin.server.AbstractExtension;
|
||||
import com.vaadin.server.ClientConnector;
|
||||
import com.vaadin.ui.Layout;
|
||||
import com.vaadin.ui.AbstractComponent;
|
||||
|
||||
public class CubaHistoryControl extends AbstractExtension {
|
||||
|
||||
protected HistoryBackHandler handler;
|
||||
|
||||
public CubaHistoryControl() {
|
||||
@ -35,17 +32,12 @@ public class CubaHistoryControl extends AbstractExtension {
|
||||
});
|
||||
}
|
||||
|
||||
public void extend(AbstractClientConnector target, HistoryBackHandler handler) {
|
||||
public void extend(AbstractComponent target, HistoryBackHandler handler) {
|
||||
super.extend(target);
|
||||
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ClientConnector> getSupportedParentType() {
|
||||
return Layout.class;
|
||||
}
|
||||
|
||||
public interface HistoryBackHandler {
|
||||
|
||||
void onHistoryBackPerformed();
|
||||
|
@ -19,11 +19,11 @@ package com.haulmont.cuba.web.toolkit.ui;
|
||||
|
||||
import com.haulmont.cuba.core.global.RemoteException;
|
||||
import com.haulmont.cuba.security.global.NoUserSessionException;
|
||||
import com.haulmont.cuba.web.UIView;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.timer.CubaTimerClientRpc;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.timer.CubaTimerServerRpc;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.timer.CubaTimerState;
|
||||
import com.vaadin.server.AbstractExtension;
|
||||
import com.vaadin.ui.AbstractComponent;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -42,8 +42,8 @@ public class CubaTimer extends AbstractExtension implements CubaTimerServerRpc {
|
||||
registerRpc(this);
|
||||
}
|
||||
|
||||
public void extend(UIView view) {
|
||||
super.extend(view);
|
||||
public void extend(AbstractComponent component) {
|
||||
super.extend(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,7 +108,8 @@ public class CubaTimer extends AbstractExtension implements CubaTimerServerRpc {
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
if (System.currentTimeMillis() - startTime > 2000) {
|
||||
log.warn("Too long timer '" + getLoggingTimerId() + "' processing: " + (endTime - startTime) + " ms ");
|
||||
long duration = endTime - startTime;
|
||||
log.warn("Too long timer {} processing: {} ms ", getLoggingTimerId(), duration);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
handleOnTimerException(e);
|
||||
@ -124,13 +125,13 @@ public class CubaTimer extends AbstractExtension implements CubaTimerServerRpc {
|
||||
for (RemoteException.Cause cause : re.getCauses()) {
|
||||
//noinspection ThrowableResultOfMethodCallIgnored
|
||||
if (cause.getThrowable() instanceof NoUserSessionException) {
|
||||
log.warn("NoUserSessionException in timer '" + getLoggingTimerId() + "', timer will be stopped");
|
||||
log.warn("NoUserSessionException in timer {}, timer will be stopped", getLoggingTimerId());
|
||||
stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (ExceptionUtils.indexOfThrowable(e, NoUserSessionException.class) > -1) {
|
||||
log.warn("NoUserSessionException in timer '" + getLoggingTimerId() + "', timer will be stopped");
|
||||
log.warn("NoUserSessionException in timer {}, timer will be stopped", getLoggingTimerId());
|
||||
stop();
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class CubaWindow extends Window {
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
public void forceClose() {
|
||||
super.close();
|
||||
}
|
||||
}
|
@ -20,26 +20,19 @@ import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Configuration;
|
||||
import com.haulmont.cuba.core.global.ScreenProfilerConfig;
|
||||
import com.haulmont.cuba.web.ScreenProfiler;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.profiler.ScreenClientProfilerState;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.profiler.ScreenClientProfilerServerRpc;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.profiler.ScreenProfilerClientEvent;
|
||||
import com.haulmont.cuba.web.toolkit.ui.client.profiler.ScreenClientProfilerState;
|
||||
import com.vaadin.server.AbstractClientConnector;
|
||||
import com.vaadin.server.AbstractExtension;
|
||||
|
||||
public class ScreenClientProfilerAgent extends AbstractExtension {
|
||||
|
||||
protected ScreenProfiler screenProfiler = AppBeans.get(ScreenProfiler.NAME);
|
||||
|
||||
public ScreenClientProfilerAgent() {
|
||||
registerRpc(new ScreenClientProfilerServerRpc() {
|
||||
@Override
|
||||
public void flushEvents(ScreenProfilerClientEvent[] clientEvents) {
|
||||
ScreenProfiler screenProfiler = AppBeans.get(ScreenProfiler.NAME);
|
||||
screenProfiler.flush(clientEvents);
|
||||
}
|
||||
});
|
||||
Configuration configuration = AppBeans.get(Configuration.class);
|
||||
ScreenProfilerConfig screenProfilerConfig = configuration.getConfig(ScreenProfilerConfig.class);
|
||||
getState().flushEventsCount = screenProfilerConfig.getFlushEventsCount();
|
||||
getState().flushTimeout = screenProfilerConfig.getFlushTimeout();
|
||||
registerRpc((ScreenClientProfilerServerRpc) clientEvents ->
|
||||
screenProfiler.flush(clientEvents)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,4 +49,20 @@ public class ScreenClientProfilerAgent extends AbstractExtension {
|
||||
protected ScreenClientProfilerState getState(boolean markAsDirty) {
|
||||
return (ScreenClientProfilerState) super.getState(markAsDirty);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFlushTimeout(int flushTimeout) {
|
||||
getState().flushTimeout = flushTimeout;
|
||||
}
|
||||
|
||||
public int getFlushTimeout() {
|
||||
return getState(false).flushTimeout;
|
||||
}
|
||||
|
||||
public void setFlushEventsCount(int flushEventsCount) {
|
||||
getState().flushEventsCount = flushEventsCount;
|
||||
}
|
||||
|
||||
public int getFlushEventsCount() {
|
||||
return getState(false).flushEventsCount;
|
||||
}
|
||||
}
|
@ -77,6 +77,8 @@ cuba.httpSessionExpirationTimeoutSec=1800
|
||||
cuba.trustedClientPassword=MLdWm1Ik4NmM
|
||||
cuba.passwordEncryptionModule=cuba_Sha1EncryptionModule
|
||||
|
||||
cuba.anonymousSessionId=9c91dbdf-3e73-428e-9088-d586da2434c5
|
||||
|
||||
# Default user accout to show in login dialog. Comment out for production mode.
|
||||
cuba.web.loginDialogDefaultUser=admin
|
||||
cuba.web.loginDialogDefaultPassword=admin
|
||||
@ -85,9 +87,6 @@ cuba.web.loginDialogDefaultPassword=admin
|
||||
# Presentation #
|
||||
###############################################################################
|
||||
|
||||
# Client-side debug mode. Set to true for production mode.
|
||||
com.vaadin.terminal.gwt.server.productionMode=false
|
||||
|
||||
# Enable Testing mode: true or false (by default)
|
||||
cuba.testMode=false
|
||||
|
||||
|
@ -74,4 +74,7 @@
|
||||
<screen id="mainWindow"
|
||||
template="/com/haulmont/cuba/web/app/mainwindow/mainwindow.xml"/>
|
||||
|
||||
<screen id="loginWindow"
|
||||
template="/com/haulmont/cuba/web/app/loginwindow/loginwindow.xml"/>
|
||||
|
||||
</screen-config>
|
@ -21,7 +21,7 @@ cuba.web.mainWindow.header.height=40px
|
||||
|
||||
# Overrides
|
||||
|
||||
cuba.gui.AboutWindow.width=520
|
||||
cuba.gui.AboutWindow.width=560
|
||||
cuba.gui.scheduled-task-edit.smallField.width=205
|
||||
|
||||
cuba.gui.entity-log-browse.button.width=100px
|
||||
@ -105,8 +105,6 @@ cuba.web.FolderEditWindow.field.width=250px
|
||||
|
||||
cuba.web.JmxInstanceEditor.width=480
|
||||
|
||||
cuba.web.LoginWindow.form.width=310
|
||||
cuba.web.LoginWindow.form.height=-1
|
||||
cuba.web.LoginWindow.field.width=150
|
||||
|
||||
cuba.web.ScreenHistoryBrowse.width=500
|
||||
|
@ -91,9 +91,7 @@ cuba.web.FolderEditWindow.field.width=250px
|
||||
|
||||
cuba.web.JmxInstanceEditor.width=480
|
||||
|
||||
cuba.web.LoginWindow.form.width=310
|
||||
cuba.web.LoginWindow.form.height=-1
|
||||
cuba.web.LoginWindow.field.width=125
|
||||
cuba.web.LoginWindow.field.width=150
|
||||
|
||||
cuba.web.ScreenHistoryBrowse.width=500
|
||||
cuba.web.ScreenHistoryBrowse.height=480
|
||||
|
@ -16,32 +16,18 @@
|
||||
*/
|
||||
|
||||
@mixin cuba-login-window {
|
||||
.cuba-login-bottom {
|
||||
.cuba-login-panel {
|
||||
background: $v-panel-background-color;
|
||||
border: valo-border();
|
||||
border-radius: $v-border-radius;
|
||||
padding: $v-layout-margin-top $v-layout-margin-right $v-layout-margin-bottom $v-layout-margin-left;
|
||||
padding: $v-layout-margin-top $v-layout-margin-right*4 $v-layout-margin-bottom $v-layout-margin-left*4;
|
||||
}
|
||||
|
||||
.cuba-login-main-layout {
|
||||
background-color: $v-app-background-color;
|
||||
}
|
||||
|
||||
.cuba-login-title {
|
||||
padding-bottom: $v-layout-spacing-horizontal;
|
||||
}
|
||||
|
||||
.cuba-login-form {
|
||||
font-weight: normal;
|
||||
|
||||
.v-formlayout > table,
|
||||
.v-formlayout > table > tbody {
|
||||
border: 0;
|
||||
border-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cuba-login-icon {
|
||||
.cuba-login-icon > img {
|
||||
height: 32px;
|
||||
}
|
||||
}
|
@ -16,51 +16,26 @@
|
||||
*/
|
||||
|
||||
@mixin cuba-login-window {
|
||||
|
||||
.cuba-login-bottom {
|
||||
.cuba-login-panel {
|
||||
background: $cuba-loginform-background-color;
|
||||
border: thin solid $cuba-loginform-border-color;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.25);
|
||||
-moz-box-shadow: 0 0 5px rgba(0,0,0,0.25);
|
||||
-webkit-box-shadow: 0 0 5px rgba(0,0,0,0.25);
|
||||
|
||||
.cuba-login-username-field.v-caption {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
color: #2B4666;
|
||||
}
|
||||
|
||||
.v-captiontext {
|
||||
padding-right: 5px;
|
||||
float: none;
|
||||
}
|
||||
padding: 10px 40px 10px 40px;
|
||||
}
|
||||
|
||||
.cuba-login-main-layout {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.cuba-login-title {
|
||||
padding-top: 3px;
|
||||
.cuba-login-icon > img {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.cuba-login-form {
|
||||
font-weight: normal;
|
||||
|
||||
.v-formlayout {
|
||||
float: left;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cuba-login-form-caption {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.cuba-login-bottom > div:first-child {
|
||||
padding-top: 5px;
|
||||
.login-form-label {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
color: #2B4666;
|
||||
}
|
||||
}
|
@ -31,12 +31,6 @@
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<description>Vaadin production mode</description>
|
||||
<param-name>productionMode</param-name>
|
||||
<param-value>false</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<description>Web resources version for correct caching in browser</description>
|
||||
<param-name>webResourcesTs</param-name>
|
||||
@ -53,26 +47,6 @@
|
||||
<servlet>
|
||||
<servlet-name>cuba_servlet</servlet-name>
|
||||
<servlet-class>com.haulmont.cuba.web.sys.CubaApplicationServlet</servlet-class>
|
||||
<init-param>
|
||||
<description>UI class</description>
|
||||
<param-name>UI</param-name>
|
||||
<param-value>com.haulmont.cuba.web.AppUI</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>UIProvider class</description>
|
||||
<param-name>UIProvider</param-name>
|
||||
<param-value>com.haulmont.cuba.web.sys.CubaUIProvider</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>Application class</description>
|
||||
<param-name>Application</param-name>
|
||||
<param-value>com.haulmont.cuba.web.DefaultApp</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>Widgetset name</description>
|
||||
<param-name>widgetset</param-name>
|
||||
<param-value>com.haulmont.cuba.web.toolkit.ui.WidgetSet</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>0</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
|
Loading…
Reference in New Issue
Block a user