Java tutorial
/* * 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.sys; import com.google.common.hash.HashCode; 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; import com.haulmont.cuba.security.global.UserSession; import com.haulmont.cuba.web.App; import com.haulmont.cuba.web.WebConfig; import com.haulmont.cuba.web.auth.WebAuthConfig; import com.haulmont.cuba.web.toolkit.ui.CubaFileUpload; import com.vaadin.server.*; import com.vaadin.server.communication.*; import com.vaadin.ui.Component; import com.vaadin.ui.UI; import elemental.json.Json; import elemental.json.JsonArray; import elemental.json.JsonObject; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; import static com.google.common.hash.Hashing.md5; public class CubaVaadinServletService extends VaadinServletService { private final Logger log = LoggerFactory.getLogger(CubaVaadinServletService.class); protected WebConfig webConfig; protected WebAuthConfig webAuthConfig; protected final String webResourceTimestamp; protected boolean testMode; public CubaVaadinServletService(VaadinServlet servlet, DeploymentConfiguration deploymentConfiguration) throws ServiceException { super(servlet, deploymentConfiguration); Configuration configuration = AppBeans.get(Configuration.NAME); webConfig = configuration.getConfig(WebConfig.class); webAuthConfig = configuration.getConfig(WebAuthConfig.class); testMode = configuration.getConfig(GlobalConfig.class).getTestMode(); ServletContext sc = servlet.getServletContext(); String resourcesTimestamp = sc.getInitParameter("webResourcesTs"); if (StringUtils.isNotEmpty(resourcesTimestamp)) { this.webResourceTimestamp = resourcesTimestamp; } else { this.webResourceTimestamp = "DEBUG"; } addSessionInitListener(event -> { WrappedSession wrappedSession = event.getSession().getSession(); wrappedSession.setMaxInactiveInterval(webConfig.getHttpSessionExpirationTimeoutSec()); HttpSession httpSession = wrappedSession instanceof WrappedHttpSession ? ((WrappedHttpSession) wrappedSession).getHttpSession() : null; log.debug("HttpSession {} initialized, timeout={}sec", httpSession, wrappedSession.getMaxInactiveInterval()); }); addSessionDestroyListener(event -> { WrappedSession wrappedSession = event.getSession().getSession(); HttpSession httpSession = wrappedSession instanceof WrappedHttpSession ? ((WrappedHttpSession) wrappedSession).getHttpSession() : null; log.debug("HttpSession destroyed: {}", httpSession); App app = event.getSession().getAttribute(App.class); if (app != null) { app.cleanupBackgroundTasks(); } }); setSystemMessagesProvider(systemMessagesInfo -> { Locale locale = systemMessagesInfo.getLocale(); CustomizedSystemMessages msgs = new CustomizedSystemMessages(); if (AppContext.isStarted()) { try { Messages messages = AppBeans.get(Messages.NAME); msgs.setInternalErrorCaption(messages.getMainMessage("internalErrorCaption", locale)); msgs.setInternalErrorMessage(messages.getMainMessage("internalErrorMessage", locale)); msgs.setCommunicationErrorCaption(messages.getMainMessage("communicationErrorCaption", locale)); msgs.setCommunicationErrorMessage(messages.getMainMessage("communicationErrorMessage", locale)); msgs.setSessionExpiredCaption(messages.getMainMessage("sessionExpiredErrorCaption", locale)); msgs.setSessionExpiredMessage(messages.getMainMessage("sessionExpiredErrorMessage", locale)); } catch (Exception e) { log.error("Unable to set system messages", e); throw new RuntimeException("Unable to set system messages. " + "It usually happens when the middleware web application is not responding due to " + "errors on start. See logs for details.", e); } } String redirectUri; if (RequestContext.get() != null) { HttpServletRequest request = RequestContext.get().getRequest(); redirectUri = StringUtils.replace(request.getRequestURI(), "/UIDL", ""); } else { String webContext = AppContext.getProperty("cuba.webContextName"); redirectUri = "/" + webContext; } msgs.setInternalErrorURL(redirectUri + "?restartApp"); return msgs; }); } @Override public String getConfiguredTheme(VaadinRequest request) { return webConfig.getAppWindowTheme(); } @Override public String getApplicationVersion() { return webResourceTimestamp; } @Override protected List<RequestHandler> createRequestHandlers() throws ServiceException { List<RequestHandler> requestHandlers = super.createRequestHandlers(); List<RequestHandler> cubaRequestHandlers = new ArrayList<>(); for (RequestHandler handler : requestHandlers) { if (handler instanceof UidlRequestHandler) { // replace UidlRequestHandler with CubaUidlRequestHandler cubaRequestHandlers.add(new UidlRequestHandler() { @Override protected UidlWriter createUidlWriter() { return new CubaUidlWriter(); } }); } else if (handler instanceof PublishedFileHandler) { // replace PublishedFileHandler with CubaPublishedFileHandler // for support resources from VAADIN directory cubaRequestHandlers.add(new CubaPublishedFileHandler()); } else if (handler instanceof ServletBootstrapHandler) { // replace ServletBootstrapHandler with CubaApplicationBootstrapHandler cubaRequestHandlers.add(new CubaServletBootstrapHandler()); } else if (handler instanceof HeartbeatHandler) { // replace HeartbeatHandler with CubaHeartbeatHandler cubaRequestHandlers.add(new CubaHeartbeatHandler()); } else if (handler instanceof FileUploadHandler) { // add support for jquery file upload cubaRequestHandlers.add(handler); cubaRequestHandlers.add(new CubaFileUploadHandler()); } else if (handler instanceof ServletUIInitHandler) { cubaRequestHandlers.add(new CubaServletUIInitHandler()); } else if (handler instanceof PushRequestHandler) { PushHandler pushHandler = ((PushRequestHandler) handler).getPushHandler(); pushHandler.setLongPollingSuspendTimeout(webConfig.getPushLongPollingSuspendTimeoutMs()); cubaRequestHandlers.add(handler); } else { cubaRequestHandlers.add(handler); } } cubaRequestHandlers.add(new CubaWebJarsHandler(getServlet().getServletContext())); return cubaRequestHandlers; } // Add ability to load JS and CSS resources from VAADIN directory protected static class CubaPublishedFileHandler extends PublishedFileHandler { @Override protected InputStream getApplicationResourceAsStream(Class<?> contextClass, String fileName) { ServletContext servletContext = VaadinServlet.getCurrent().getServletContext(); return servletContext.getResourceAsStream("/VAADIN/" + fileName); } } // Add support for CubaFileUpload component with XHR upload mechanism protected static class CubaFileUploadHandler extends FileUploadHandler { private final Logger log = LoggerFactory.getLogger(CubaFileUploadHandler.class); @Override protected boolean isSuitableUploadComponent(ClientConnector source) { if (!(source instanceof CubaFileUpload)) { // this is not jquery upload request return false; } log.trace("Uploading file using jquery file upload mechanism"); return true; } @Override protected void sendUploadResponse(VaadinRequest request, VaadinResponse response, String fileName, long contentLength) throws IOException { JsonArray json = Json.createArray(); JsonObject fileInfo = Json.createObject(); fileInfo.put("name", fileName); fileInfo.put("size", contentLength); // just fake addresses and parameters fileInfo.put("url", fileName); fileInfo.put("thumbnail_url", fileName); fileInfo.put("delete_url", fileName); fileInfo.put("delete_type", "POST"); json.set(0, fileInfo); PrintWriter writer = response.getWriter(); writer.write(json.toJson()); writer.close(); } } /** * Add ability to redirect to base application URL if we have unparsable path tail */ protected static class CubaServletBootstrapHandler extends ServletBootstrapHandler { @Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { String requestPath = request.getPathInfo(); // redirect to base URL if we have unparsable path tail if (!Objects.equals("/", requestPath)) { response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); response.setHeader("Location", request.getContextPath()); return true; } return super.handleRequest(session, request, response); } } // Add ability to handle heartbeats in App protected static class CubaHeartbeatHandler extends HeartbeatHandler { private final Logger log = LoggerFactory.getLogger(CubaHeartbeatHandler.class); @Override public boolean synchronizedHandleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { boolean result = super.synchronizedHandleRequest(session, request, response); if (log.isTraceEnabled()) { log.trace("Handle heartbeat {} {}", request.getRemoteHost(), request.getRemoteAddr()); } if (result && App.isBound()) { App.getInstance().onHeartbeat(); } return result; } } @Override protected VaadinSession createVaadinSession(VaadinRequest request) throws ServiceException { if (testMode) { return new TestVaadinSession(this); } else { return super.createVaadinSession(request); } } /** * Generates non-random IDs for components, used for performance testing. */ protected static class TestVaadinSession extends VaadinSession { public TestVaadinSession(VaadinService service) { super(service); } @Override public String createConnectorId(ClientConnector connector) { if (connector instanceof Component) { Component component = (Component) connector; String id = component.getId() == null ? super.createConnectorId(connector) : component.getId(); UserSession session = getAttribute(UserSession.class); String login = null; String locale = null; if (session != null) { login = session.getCurrentOrSubstitutedUser().getLogin(); if (session.getLocale() != null) { locale = session.getLocale().toLanguageTag(); } } StringBuilder idParts = new StringBuilder(); if (login != null) { idParts.append(login); } if (locale != null) { idParts.append(locale); } idParts.append(id); return toLongNumberString(idParts.toString()); } return super.createConnectorId(connector); } protected String toLongNumberString(String data) { HashCode hashCode = md5().hashString(data, StandardCharsets.UTF_8); byte[] hashBytes = hashCode.asBytes(); byte[] shortBytes = new byte[Long.BYTES]; System.arraycopy(hashBytes, 0, shortBytes, 0, Long.BYTES); ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); buffer.put(shortBytes); buffer.flip(); return Long.toString(Math.abs(buffer.getLong())); } } /* * Uses CubaUidlWriter instead of default UidlWriter to support reloading screens that contain components * that use web resources from WebJars */ protected static class CubaServletUIInitHandler extends ServletUIInitHandler { private final Logger log = LoggerFactory.getLogger(CubaServletUIInitHandler.class); @Override protected String getInitialUidl(VaadinRequest request, UI uI) throws IOException { // CAUTION: copied from parent class try (StringWriter writer = new StringWriter()) { writer.write("{"); VaadinSession session = uI.getSession(); if (session.getConfiguration().isXsrfProtectionEnabled()) { writer.write(getSecurityKeyUIDL(session)); } writer.write(getPushIdUIDL(session)); new CubaUidlWriter().write(uI, writer, false); writer.write("}"); String initialUIDL = writer.toString(); log.trace("Initial UIDL: {}", initialUIDL); return initialUIDL; } } } }