/* * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package ch.ethz.seb.sebserver.gui; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.AbstractEntryPoint; import org.eclipse.rap.rwt.application.Application; import org.eclipse.rap.rwt.application.ApplicationConfiguration; import org.eclipse.rap.rwt.application.EntryPoint; import org.eclipse.rap.rwt.application.EntryPointFactory; import org.eclipse.rap.rwt.client.WebClient; import org.eclipse.rap.rwt.internal.theme.ThemeUtil; import org.eclipse.rap.rwt.service.ResourceLoader; import org.eclipse.rap.rwt.service.ServiceManager; import org.eclipse.swt.widgets.Composite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext; public class RAPConfiguration implements ApplicationConfiguration { private static final String DEFAULT_THEME_NAME = "sebserver"; private static final Logger log = LoggerFactory.getLogger(RAPConfiguration.class); @Override public void configure(final Application application) { try { final String guiEntrypoint = StaticApplicationPropertyResolver .getProperty("sebserver.gui.entrypoint", "/gui"); final String proctoringEntrypoint = StaticApplicationPropertyResolver .getProperty("sebserver.gui.remote.proctoring.entrypoint", "/remote-proctoring"); // TODO get file path from properties //application.addStyleSheet(RWT.DEFAULT_THEME_ID, "static/css/sebserver.css"); application.addStyleSheet(DEFAULT_THEME_NAME, "resource/theme/default.css"); application.addStyleSheet(DEFAULT_THEME_NAME, "static/css/sebserver.css"); application.addStyleSheet("sms", "resource/theme/default.css"); application.addStyleSheet("sms", "static/css/sms.css"); application.addResource("fav_icon", new ResourceLoader() { @Override public InputStream getResourceAsStream(final String resourceName) throws IOException { return RAPConfiguration.class.getClassLoader().getResourceAsStream("static/images/fav_icon.png"); } }); final Map properties = new HashMap<>(); properties.put(WebClient.PAGE_TITLE, "SEB Server"); properties.put(WebClient.BODY_HTML, "Loading Application"); properties.put(WebClient.THEME_ID, DEFAULT_THEME_NAME); properties.put(WebClient.FAVICON, "fav_icon"); application.addEntryPoint(guiEntrypoint, new RAPSpringEntryPointFactory(), properties); application.addEntryPoint(proctoringEntrypoint, new RAPRemoteProcotringEntryPointFactory(), properties); } catch (final RuntimeException re) { throw re; } catch (final Exception e) { log.error("Error during CSS parsing. Please check the custom CSS files for errors.", e); } } public interface EntryPointService { void loadLoginPage(final Composite parent); void loadMainPage(final Composite parent); void loadProctoringView(Composite parent); } public static final class RAPRemoteProcotringEntryPointFactory implements EntryPointFactory { @Override public EntryPoint create() { return new AbstractEntryPoint() { private static final long serialVersionUID = -1299125117752916270L; @Override protected void createContents(final Composite parent) { final HttpSession httpSession = RWT .getUISession(parent.getDisplay()) .getHttpSession(); final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession); final boolean authenticated = isAuthenticated(httpSession, webApplicationContext); if (authenticated) { final EntryPointService entryPointService = webApplicationContext .getBean(EntryPointService.class); entryPointService.loadProctoringView(parent); } else { final HttpServletResponse response = RWT.getResponse(); response.setStatus(HttpStatus.FORBIDDEN.value()); } } }; } } public static final class RAPSpringEntryPointFactory implements EntryPointFactory { private boolean initialized = false; @Override public EntryPoint create() { return new AbstractEntryPoint() { private static final long serialVersionUID = -1299125117752916270L; @Override protected void createContents(final Composite parent) { final HttpSession httpSession = RWT .getUISession(parent.getDisplay()) .getHttpSession(); log.debug("Create new GUI entrypoint. HttpSession: " + httpSession); if (httpSession == null) { log.error("HttpSession not available from RWT.getUISession().getHttpSession()"); throw new IllegalStateException( "HttpSession not available from RWT.getUISession().getHttpSession()"); } final Object themeId = httpSession.getAttribute("themeId"); if (themeId != null) { ThemeUtil.setCurrentThemeId(RWT.getUISession(parent.getDisplay()), String.valueOf(themeId)); parent.redraw(); parent.layout(true); parent.redraw(); } final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession); initSpringBasedRAPServices(webApplicationContext); final EntryPointService entryPointService = webApplicationContext .getBean(EntryPointService.class); if (isAuthenticated(httpSession, webApplicationContext)) { entryPointService.loadMainPage(parent); } else { entryPointService.loadLoginPage(parent); } } }; } private void initSpringBasedRAPServices(final WebApplicationContext webApplicationContext) { if (!this.initialized) { try { final ServiceManager manager = RWT.getServiceManager(); final DownloadService downloadService = webApplicationContext.getBean(DownloadService.class); manager.registerServiceHandler(DownloadService.DOWNLOAD_SERVICE_NAME, downloadService); this.initialized = true; } catch (final IllegalArgumentException iae) { log.warn("Failed to register DownloadService on ServiceManager. Already registered: ", iae); } } } } private static boolean isAuthenticated( final HttpSession httpSession, final WebApplicationContext webApplicationContext) { final AuthorizationContextHolder authorizationContextHolder = webApplicationContext .getBean(AuthorizationContextHolder.class); final SEBServerAuthorizationContext authorizationContext = authorizationContextHolder .getAuthorizationContext(httpSession); return authorizationContext.isValid() && authorizationContext.isLoggedIn(); } private static WebApplicationContext getWebApplicationContext(final HttpSession httpSession) { try { final ServletContext servletContext = httpSession.getServletContext(); log.debug("Initialize Spring-Context on Servlet-Context: " + servletContext); return WebApplicationContextUtils .getRequiredWebApplicationContext(servletContext); } catch (final RuntimeException e) { log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession); throw e; } catch (final Exception e) { log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession); throw new RuntimeException("Failed to initialize Spring-Context on HttpSession: " + httpSession); } } }