package com.constellio.app.ui.application;
import static com.constellio.app.ui.i18n.i18n.$;
import java.lang.reflect.InvocationTargetException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.LocalDateTime;
import com.constellio.app.modules.rm.ui.builders.UserToVOBuilder;
import com.constellio.app.modules.rm.ui.contextmenu.RMRecordContextMenuHandler;
import com.constellio.app.modules.rm.ui.menuBar.RMRecordMenuBarHandler;
import com.constellio.app.services.factories.AppLayerFactory;
import com.constellio.app.services.factories.ConstellioFactories;
import com.constellio.app.services.sso.SSOServices;
import com.constellio.app.ui.entities.RecordVO.VIEW_MODE;
import com.constellio.app.ui.entities.UserVO;
import com.constellio.app.ui.framework.components.contextmenu.RecordContextMenuHandler;
import com.constellio.app.ui.framework.components.menuBar.RecordMenuBarHandler;
import com.constellio.app.ui.framework.components.resource.ConstellioResourceHandler;
import com.constellio.app.ui.handlers.ConstellioErrorHandler;
import com.constellio.app.ui.i18n.i18n;
import com.constellio.app.ui.pages.base.ConstellioHeader;
import com.constellio.app.ui.pages.base.EnterViewListener;
import com.constellio.app.ui.pages.base.InitUIListener;
import com.constellio.app.ui.pages.base.MainLayoutImpl;
import com.constellio.app.ui.pages.base.SessionContext;
import com.constellio.app.ui.pages.base.SessionContextProvider;
import com.constellio.app.ui.pages.base.UIContext;
import com.constellio.app.ui.pages.base.VaadinSessionContext;
import com.constellio.app.ui.pages.login.LoginViewImpl;
import com.constellio.app.ui.pages.setup.ConstellioSetupViewImpl;
import com.constellio.data.utils.ImpossibleRuntimeException;
import com.constellio.data.utils.TimeProvider;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.security.global.UserCredential;
import com.constellio.model.entities.security.global.UserCredentialStatus;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.records.RecordServices;
import com.constellio.model.services.records.RecordServicesException;
import com.constellio.model.services.users.UserServices;
import com.vaadin.annotations.Theme;
import com.vaadin.event.UIEvents.PollListener;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.Page;
import com.vaadin.server.Page.BrowserWindowResizeEvent;
import com.vaadin.server.Page.BrowserWindowResizeListener;
import com.vaadin.server.RequestHandler;
import com.vaadin.server.Responsive;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.UI;
import com.vaadin.ui.themes.ValoTheme;
@SuppressWarnings("serial")
@Theme("constellio")
public class ConstellioUI extends UI implements SessionContextProvider, UIContext {
private SessionContext sessionContext;
private MainLayoutImpl mainLayout;
private List<RecordContextMenuHandler> recordContextMenuHandlers = new ArrayList<>();
private List<RecordMenuBarHandler> recordMenuBarHandlers = new ArrayList<>();
private Map<String, Object> uiContext = new HashMap<>();
public final RequestHandler requestHandler = new ConstellioResourceHandler();
private SSOServices ssoServices;
private View currentView;
@Override
protected void init(VaadinRequest request) {
getSession().addRequestHandler(requestHandler);
ssoServices = SSOServices.getInstance();
Page.getCurrent().setTitle($("ConstellioUI.pageTitle"));
// Important to allow update of components in current UI from another Thread
UI.getCurrent().setPollInterval(1000);
ConstellioFactories constellioFactories = ConstellioFactories.getInstance();
AppLayerFactory appLayerFactory = constellioFactories.getAppLayerFactory();
addRecordContextMenuHandler(new RMRecordContextMenuHandler(constellioFactories));
addRecordMenuBarHandler(new RMRecordMenuBarHandler(constellioFactories));
List<InitUIListener> initUIListeners = appLayerFactory.getInitUIListeners();
for (InitUIListener initUIListener : initUIListeners) {
initUIListener.beforeInitialize(this);
}
Responsive.makeResponsive(this);
addStyleName(ValoTheme.UI_WITH_MENU);
// Some views need to be aware of browser resize events so a
// BrowserResizeEvent gets fired to the event but on every occasion.
Page.getCurrent().addBrowserWindowResizeListener(
new BrowserWindowResizeListener() {
@Override
public void browserWindowResized(final BrowserWindowResizeEvent event) {
}
});
if (getErrorHandler() == null) {
setErrorHandler(new ConstellioErrorHandler());
}
if (sessionContext == null) {
sessionContext = new VaadinSessionContext();
}
VaadinSession.getCurrent().setLocale(i18n.getLocale());
sessionContext.setCurrentLocale(i18n.getLocale());
updateContent();
for (InitUIListener initUIListener : initUIListeners) {
initUIListener.afterInitialize(this);
}
}
@Override
public void detach() {
super.detach();
getSession().removeRequestHandler(requestHandler);
}
private UserVO ssoAuthenticate() {
UserVO currentUserVO;
ConstellioFactories constellioFactories = getConstellioFactories();
ModelLayerFactory modelLayerFactory = constellioFactories.getModelLayerFactory();
UserServices userServices = modelLayerFactory.newUserServices();
RecordServices recordServices = modelLayerFactory.newRecordServices();
Principal userPrincipal = sessionContext.getUserPrincipal();
if (userPrincipal != null) {
String username = userPrincipal.getName();
UserCredential userCredential = userServices.getUserCredential(username);
if (userCredential != null && userCredential.getStatus() == UserCredentialStatus.ACTIVE) {
List<String> collections = userCredential != null ? userCredential.getCollections() : new ArrayList<String>();
String lastCollection = null;
User userInLastCollection = null;
LocalDateTime lastLogin = null;
for (String collection : collections) {
User userInCollection = userServices.getUserInCollection(username, collection);
if (userInLastCollection == null) {
if (userInCollection != null) {
lastCollection = collection;
userInLastCollection = userInCollection;
lastLogin = userInCollection.getLastLogin();
}
} else {
if (lastLogin == null && userInCollection.getLastLogin() != null) {
lastCollection = collection;
userInLastCollection = userInCollection;
lastLogin = userInCollection.getLastLogin();
} else if (lastLogin != null && userInCollection.getLastLogin() != null && userInCollection.getLastLogin()
.isAfter(lastLogin)) {
lastCollection = collection;
userInLastCollection = userInCollection;
lastLogin = userInCollection.getLastLogin();
}
}
}
if (userInLastCollection != null) {
try {
recordServices.update(userInLastCollection
.setLastLogin(TimeProvider.getLocalDateTime())
.setLastIPAddress(sessionContext.getCurrentUserIPAddress()));
} catch (RecordServicesException e) {
throw new RuntimeException(e);
}
modelLayerFactory.newLoggingServices().login(userInLastCollection);
currentUserVO = new UserToVOBuilder()
.build(userInLastCollection.getWrappedRecord(), VIEW_MODE.DISPLAY, sessionContext);
sessionContext.setCurrentUser(currentUserVO);
sessionContext.setCurrentCollection(lastCollection);
sessionContext.setForcedSignOut(false);
} else {
currentUserVO = null;
}
} else {
currentUserVO = null;
}
} else {
currentUserVO = null;
}
return currentUserVO;
}
public void updateContent() {
if (isSetupRequired()) {
ConstellioSetupViewImpl setupView = new ConstellioSetupViewImpl();
setContent(setupView);
addStyleName("setupview");
} else {
ConstellioFactories constellioFactories = getConstellioFactories();
AppLayerFactory appLayerFactory = constellioFactories.getAppLayerFactory();
UserVO currentUserVO = sessionContext.getCurrentUser();
if (currentUserVO == null && ssoServices.isEnabled() && !sessionContext.isForcedSignOut()) {
currentUserVO = ssoAuthenticate();
}
if (currentUserVO != null) {
// Authenticated user
mainLayout = new MainLayoutImpl(appLayerFactory);
setContent(mainLayout);
Navigator navigator = getNavigator();
navigator.addViewChangeListener(new ViewChangeListener() {
@Override
public boolean beforeViewChange(ViewChangeEvent event) {
return true;
}
@Override
public void afterViewChange(ViewChangeEvent event) {
View oldView = event.getOldView();
if (oldView instanceof PollListener) {
removePollListener((PollListener) oldView);
}
View newView = event.getNewView();
ConstellioUI.this.currentView = newView;
ConstellioFactories constellioFactories = getConstellioFactories();
AppLayerFactory appLayerFactory = constellioFactories.getAppLayerFactory();
List<EnterViewListener> enterViewListeners = appLayerFactory.getEnterViewListeners();
for (EnterViewListener enterViewListener : enterViewListeners) {
enterViewListener.enterView(newView);
}
// if (enterViewListeners.isEmpty() && !isProductionMode()) {
// try {
// ConstellioSerializationUtils.validateSerializable(event.getOldView());
// } catch (Exception e) {
// LOGGER.warn(e.getMessage(), e);
// }
// try {
// ConstellioSerializationUtils.validateSerializable(event.getNewView());
// } catch (Exception e) {
// LOGGER.warn(e.getMessage(), e);
// }
// }
}
});
removeStyleName("setupview");
removeStyleName("loginview");
navigator.navigateTo(navigator.getState());
} else {
removeStyleName("setupview");
LoginViewImpl loginView = new LoginViewImpl();
setContent(loginView);
addStyleName("loginview");
}
}
}
private boolean isSetupRequired() {
ConstellioFactories constellioFactories = getConstellioFactories();
return constellioFactories.getAppLayerFactory().getCollectionsManager().getCollectionCodesExcludingSystem().isEmpty();
}
public ConstellioHeader getHeader() {
return mainLayout.getHeader();
}
public SessionContext getSessionContext() {
return sessionContext;
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
@Override
public ConstellioFactories getConstellioFactories() {
return ConstellioFactories.getInstance();
}
public static SessionContext getCurrentSessionContext() {
return getCurrent().getSessionContext();
}
public boolean isProductionMode() {
VaadinService service = VaadinService.getCurrent();
return service.getDeploymentConfiguration().isProductionMode();
}
public Navigation navigate() {
return new Navigation();
}
public CoreViews navigateTo() {
return navigateTo(CoreViews.class);
}
public <T extends CoreViews> T navigateTo(Class<T> navigatorClass) {
try {
return navigatorClass.getConstructor(Navigator.class).newInstance(getNavigator());
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new ImpossibleRuntimeException("The navigator does not provide a valid constructor");
}
}
public void addRecordContextMenuHandler(RecordContextMenuHandler recordContextMenuHandler) {
this.recordContextMenuHandlers.add(recordContextMenuHandler);
}
public void removeRecordContextMenuHandler(RecordContextMenuHandler recordContextMenuHandler) {
this.recordContextMenuHandlers.remove(recordContextMenuHandler);
}
public List<RecordContextMenuHandler> getRecordContextMenuHandlers() {
return recordContextMenuHandlers;
}
public void addRecordMenuBarHandler(RecordMenuBarHandler recordMenuBarHandler) {
this.recordMenuBarHandlers.add(recordMenuBarHandler);
}
public void removeRecordMenuBarHandler(RecordMenuBarHandler recordMenuBarHandler) {
this.recordContextMenuHandlers.remove(recordMenuBarHandler);
}
public List<RecordMenuBarHandler> getRecordMenuBarHandlers() {
return recordMenuBarHandlers;
}
public static ConstellioUI getCurrent() {
return (ConstellioUI) UI.getCurrent();
}
@Override
public void clearAttribute(String key) {
uiContext.remove(key);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getAttribute(String key) {
return (T) uiContext.get(key);
}
@Override
public <T> void setAttribute(String key, T value) {
uiContext.put(key, value);
}
public View getCurrentView() {
return currentView;
}
}