diff --git a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java index 42e4b7f7d0a..3f69e2b6ce9 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java @@ -23,6 +23,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import com.vaadin.flow.server.AbstractConfiguration; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.WrappedSession; @@ -30,7 +31,6 @@ import static com.vaadin.flow.server.Constants.POLYFILLS_DEFAULT_VALUE; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_POLYFILLS; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; /** * A collection of properties configured at deploy time as well as a way of @@ -39,23 +39,8 @@ * @author Vaadin Ltd * @since 1.0 */ -public interface DeploymentConfiguration extends Serializable { - - /** - * Returns whether Vaadin is in production mode. - * - * @return true if in production mode, false otherwise. - */ - boolean isProductionMode(); - - /** - * Returns whether Vaadin is running in useDeprecatedV14Bootstrapping. - * - * @return true if in useDeprecatedV14Bootstrapping, false otherwise. - */ - default boolean useV14Bootstrap() { - return getBooleanProperty(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, false); - } +public interface DeploymentConfiguration + extends AbstractConfiguration, Serializable { /** * Returns whether the server provides timing info to the client. @@ -195,6 +180,7 @@ T getApplicationOrSystemProperty(String propertyName, T defaultValue, * @return the property value, or the passed default value if no property * value is found */ + @Override default String getStringProperty(String propertyName, String defaultValue) { return getApplicationOrSystemProperty(propertyName, defaultValue, Function.identity()); @@ -224,6 +210,7 @@ default String getStringProperty(String propertyName, String defaultValue) { * @throws IllegalArgumentException * if property value string is not a boolean value */ + @Override default boolean getBooleanProperty(String propertyName, boolean defaultValue) throws IllegalArgumentException { String booleanString = getStringProperty(propertyName, null); @@ -283,7 +270,8 @@ default boolean disableAutomaticServletRegistration() { * false to not serve Brotli files. */ default boolean isBrotli() { - return getBooleanProperty(InitParameters.SERVLET_PARAMETER_BROTLI, false); + return getBooleanProperty(InitParameters.SERVLET_PARAMETER_BROTLI, + false); } default String getCompiledWebComponentsPath() { @@ -295,8 +283,8 @@ default String getCompiledWebComponentsPath() { * Returns an array with polyfills to be loaded when the app is loaded. * * The default value is empty, but it can be changed by setting the - * {@link InitParameters#SERVLET_PARAMETER_POLYFILLS} as a comma separated list - * of JS files to load. + * {@link InitParameters#SERVLET_PARAMETER_POLYFILLS} as a comma separated + * list of JS files to load. * * @return polyfills to load */ @@ -308,16 +296,6 @@ default List getPolyfills() { .collect(Collectors.toList()); } - /** - * Get if the dev server should be enabled. True by default - * - * @return true if dev server should be used - */ - default boolean enableDevServer() { - return getBooleanProperty(InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, - true); - } - /** * Get if the dev server should be reused on each reload. True by default, * set it to false in tests so as dev server is not kept as a daemon after @@ -326,8 +304,8 @@ default boolean enableDevServer() { * @return true if dev server should be reused */ default boolean reuseDevServer() { - return getBooleanProperty(InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, - true); + return getBooleanProperty( + InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, true); } /** @@ -377,18 +355,9 @@ default boolean isEagerServerLoad() { /** * Checks if dev mode live reload is enabled or not. * - * @return {@code true} if dev mode live reload is enabled, {@code false} otherwise + * @return {@code true} if dev mode live reload is enabled, {@code false} + * otherwise */ boolean isDevModeLiveReloadEnabled(); - /** - * Returns whether pnpm is enabled or not. - * - * @return {@code true} if enabled, {@code false} if not - * @since 2.2 - */ - default boolean isPnpmEnabled() { - return getBooleanProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, - Boolean.valueOf(Constants.ENABLE_PNPM_DEFAULT_STRING)); - } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java new file mode 100644 index 00000000000..1e18943f691 --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java @@ -0,0 +1,97 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server; + +import java.io.Serializable; + +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; + +/** + * Defines a base contract for configuration (e.g. on an application level, + * servlet level,...). + * + * @author Vaadin Ltd + * @since + * + */ +public interface AbstractConfiguration extends Serializable { + /** + * Returns whether Vaadin is in production mode. + * + * @return true if in production mode, false otherwise. + */ + boolean isProductionMode(); + + /** + * Get if the dev server should be enabled. True by default + * + * @return true if dev server should be used + */ + default boolean enableDevServer() { + return getBooleanProperty( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, true); + } + + /** + * Returns whether Vaadin is running in useDeprecatedV14Bootstrapping. + * + * @return true if in useDeprecatedV14Bootstrapping, false otherwise. + */ + default boolean useV14Bootstrap() { + return getBooleanProperty(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, false); + } + + /** + * Gets a configured property as a string. + * + * @param name + * The simple of the property, in some contexts, lookup might be + * performed using variations of the provided name. + * @param defaultValue + * the default value that should be used if no value has been + * defined + * @return the property value, or the passed default value if no property + * value is found + */ + String getStringProperty(String name, String defaultValue); + + /** + * Gets a configured property as a boolean. + * + * + * @param name + * The simple of the property, in some contexts, lookup might be + * performed using variations of the provided name. + * @param defaultValue + * the default value that should be used if no value has been + * defined + * @return the property value, or the passed default value if no property + * value is found + * + */ + boolean getBooleanProperty(String name, boolean defaultValue); + + /** + * Returns whether pnpm is enabled or not. + * + * @return {@code true} if enabled, {@code false} if not + */ + default boolean isPnpmEnabled() { + return getBooleanProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + Boolean.valueOf(Constants.ENABLE_PNPM_DEFAULT_STRING)); + } + +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractDeploymentConfiguration.java index be31517b155..59bf64c06ae 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/AbstractDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractDeploymentConfiguration.java @@ -15,6 +15,8 @@ */ package com.vaadin.flow.server; +import java.util.Map; + import com.vaadin.flow.component.UI; import com.vaadin.flow.function.DeploymentConfiguration; @@ -26,8 +28,18 @@ * @author Vaadin Ltd * @since 1.0 */ -public abstract class AbstractDeploymentConfiguration - implements DeploymentConfiguration { +public abstract class AbstractDeploymentConfiguration extends + AbstractPropertyConfiguration implements DeploymentConfiguration { + + /** + * Creates a new configuration based on {@code properties}. + * + * @param properties + * configuration properties + */ + protected AbstractDeploymentConfiguration(Map properties) { + super(properties); + } @Override public String getUIClassName() { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java new file mode 100644 index 00000000000..0914f4e30c9 --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; + +import static com.vaadin.flow.server.Constants.VAADIN_PREFIX; + +/** + * Provides a configuration based on string properties. + * + * @author Vaadin Ltd + * @since + * + */ +public abstract class AbstractPropertyConfiguration + implements AbstractConfiguration { + + private final Map properties; + + /** + * Creates a new instance with given {@code properties}. + * + * @param properties + * configuration properties + */ + public AbstractPropertyConfiguration(Map properties) { + this.properties = properties; + } + + @Override + public String getStringProperty(String name, String defaultValue) { + return getApplicationOrSystemProperty(name, defaultValue, + Function.identity()); + } + + @Override + public boolean getBooleanProperty(String name, boolean defaultValue) { + /* + * Considers {@code ""} to be equal {@code true} in order to treat + * params like {@code -Dtest.param} as enabled ({@code test.param == + * true}). + */ + String booleanString = getStringProperty(name, null); + if (booleanString == null) { + return defaultValue; + } else if (booleanString.isEmpty()) { + return true; + } else { + boolean parsedBoolean = Boolean.parseBoolean(booleanString); + if (Boolean.toString(parsedBoolean) + .equalsIgnoreCase(booleanString)) { + return parsedBoolean; + } else { + throw new IllegalArgumentException(String.format( + "Property named '%s' is boolean, but contains incorrect value '%s' that is not boolean '%s'", + name, booleanString, parsedBoolean)); + } + } + } + + /** + * Gets an application property value. + * + * @param parameterName + * the Name or the parameter. + * @return String value or null if not found + */ + public String getApplicationProperty(String parameterName) { + + String val = properties.get(parameterName); + if (val != null) { + return val; + } + + // Try lower case application properties for backward compatibility + // with 3.0.2 and earlier + val = properties.get(parameterName.toLowerCase()); + + return val; + } + + /** + * Gets unmodifiable underlying properties. + * + * @return the properties map + */ + protected Map getProperties() { + return Collections.unmodifiableMap(properties); + } + + /** + * Gets a configured property. The properties are typically read from e.g. + * web.xml or from system properties of the JVM. + * + * @param propertyName + * The simple of the property, in some contexts, lookup might be + * performed using variations of the provided name. + * @param defaultValue + * the default value that should be used if no value has been + * defined + * @param converter + * the way string should be converted into the required property + * @param + * type of a property + * @return the property value, or the passed default value if no property + * value is found + */ + public T getApplicationOrSystemProperty(String propertyName, + T defaultValue, Function converter) { + // Try system properties + String val = getSystemProperty(propertyName); + if (val != null) { + return converter.apply(val); + } + + // Try application properties + val = getApplicationProperty(propertyName); + if (val != null) { + return converter.apply(val); + } + + return defaultValue; + } + + /** + * Gets an system property value. + * + * @param parameterName + * the Name or the parameter. + * @return String value or null if not found + */ + protected String getSystemProperty(String parameterName) { + // version prefixed with just "vaadin." + return System.getProperty(VAADIN_PREFIX + parameterName); + } + +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index ee8008829ce..57f9beff739 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; @@ -41,29 +42,14 @@ import com.vaadin.flow.internal.AnnotationReader; import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.AbstractConfigurationFactory; import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; -import static com.vaadin.flow.server.Constants.CONNECT_APPLICATION_PROPERTIES_TOKEN; -import static com.vaadin.flow.server.Constants.CONNECT_GENERATED_TS_DIR_TOKEN; -import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; -import static com.vaadin.flow.server.Constants.CONNECT_OPEN_API_FILE_TOKEN; -import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_FILE; -import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_FILE_TOKEN; -import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_URL; -import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_URL_TOKEN; -import static com.vaadin.flow.server.Constants.FRONTEND_TOKEN; -import static com.vaadin.flow.server.Constants.NPM_TOKEN; -import static com.vaadin.flow.server.Constants.VAADIN_PREFIX; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_INITIAL_UIDL; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_TOKEN_FILE; -import static com.vaadin.flow.server.frontend.FrontendUtils.PROJECT_BASEDIR; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; /** @@ -147,6 +133,7 @@ protected static Properties createInitParameters( readUiFromEnclosingClass(systemPropertyBaseClass, initParameters); readConfigurationAnnotation(systemPropertyBaseClass, initParameters); + // TODO : will be removed in futher commits // Read default parameters from server.xml final VaadinContext context = vaadinConfig.getVaadinContext(); for (final Enumeration e = context.getContextParameterNames(); e @@ -177,7 +164,10 @@ private static void readBuildInfo(Class systemPropertyBaseClass, // already set. if (json != null) { JsonObject buildInfo = JsonUtil.parse(json); - setInitParametersUsingTokenData(initParameters, buildInfo); + // TODO : will be rewritten properly without extra instantiation + Map params = new AbstractConfigurationFactory() + .getConfigParametersUsingTokenData(buildInfo); + initParameters.putAll(params); FallbackChunk fallbackChunk = FrontendUtils .readFallbackChunk(buildInfo); @@ -187,125 +177,6 @@ private static void readBuildInfo(Class systemPropertyBaseClass, } } - private static void setInitParametersUsingTokenData( - Properties initParameters, JsonObject buildInfo) { - if (buildInfo.hasKey(SERVLET_PARAMETER_PRODUCTION_MODE)) { - initParameters.setProperty(SERVLET_PARAMETER_PRODUCTION_MODE, - String.valueOf(buildInfo - .getBoolean(SERVLET_PARAMETER_PRODUCTION_MODE))); - } - if (buildInfo.hasKey(EXTERNAL_STATS_FILE_TOKEN) - || buildInfo.hasKey(EXTERNAL_STATS_URL_TOKEN)) { - // If external stats file is flagged then - // dev server should be false - only variable that can - // be configured, in addition to stats variables, is - // production mode - initParameters.setProperty(SERVLET_PARAMETER_ENABLE_DEV_SERVER, - Boolean.toString(false)); - initParameters.setProperty(EXTERNAL_STATS_FILE, - Boolean.toString(true)); - if (buildInfo.hasKey(EXTERNAL_STATS_URL_TOKEN)) { - initParameters.setProperty(EXTERNAL_STATS_URL, - buildInfo.getString(EXTERNAL_STATS_URL_TOKEN)); - } - // NO OTHER CONFIGURATION: - return; - } - if (buildInfo.hasKey(SERVLET_PARAMETER_USE_V14_BOOTSTRAP)) { - initParameters.setProperty(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, - String.valueOf(buildInfo - .getBoolean(SERVLET_PARAMETER_USE_V14_BOOTSTRAP))); - // Need to be sure that we remove the system property, - // because it has priority in the configuration getter - System.clearProperty( - VAADIN_PREFIX + SERVLET_PARAMETER_USE_V14_BOOTSTRAP); - } - if (buildInfo.hasKey(SERVLET_PARAMETER_INITIAL_UIDL)) { - initParameters.setProperty(SERVLET_PARAMETER_INITIAL_UIDL, - String.valueOf(buildInfo - .getBoolean(SERVLET_PARAMETER_INITIAL_UIDL))); - // Need to be sure that we remove the system property, - // because it has priority in the configuration getter - System.clearProperty( - VAADIN_PREFIX + SERVLET_PARAMETER_INITIAL_UIDL); - } - - if (buildInfo.hasKey(NPM_TOKEN)) { - initParameters.setProperty(PROJECT_BASEDIR, - buildInfo.getString(NPM_TOKEN)); - verifyFolderExists(initParameters, buildInfo.getString(NPM_TOKEN)); - } - - if (buildInfo.hasKey(FRONTEND_TOKEN)) { - initParameters.setProperty(FrontendUtils.PARAM_FRONTEND_DIR, - buildInfo.getString(FRONTEND_TOKEN)); - // Only verify frontend folder if it's not a subfolder of the - // npm folder. - if (!buildInfo.hasKey(NPM_TOKEN) - || !buildInfo.getString(FRONTEND_TOKEN) - .startsWith(buildInfo.getString(NPM_TOKEN))) { - verifyFolderExists(initParameters, - buildInfo.getString(FRONTEND_TOKEN)); - } - } - - // These should be internal only so if there is a System - // property override then the user probably knows what - // they are doing. - if (buildInfo.hasKey(SERVLET_PARAMETER_ENABLE_DEV_SERVER)) { - initParameters.setProperty(SERVLET_PARAMETER_ENABLE_DEV_SERVER, - String.valueOf(buildInfo - .getBoolean(SERVLET_PARAMETER_ENABLE_DEV_SERVER))); - } - if (buildInfo.hasKey(SERVLET_PARAMETER_REUSE_DEV_SERVER)) { - initParameters.setProperty(SERVLET_PARAMETER_REUSE_DEV_SERVER, - String.valueOf(buildInfo - .getBoolean(SERVLET_PARAMETER_REUSE_DEV_SERVER))); - } - if (buildInfo.hasKey(CONNECT_JAVA_SOURCE_FOLDER_TOKEN)) { - initParameters.setProperty(CONNECT_JAVA_SOURCE_FOLDER_TOKEN, - buildInfo.getString(CONNECT_JAVA_SOURCE_FOLDER_TOKEN)); - } - if (buildInfo.hasKey(CONNECT_OPEN_API_FILE_TOKEN)) { - initParameters.setProperty(CONNECT_OPEN_API_FILE_TOKEN, - buildInfo.getString(CONNECT_OPEN_API_FILE_TOKEN)); - } - if (buildInfo.hasKey(CONNECT_APPLICATION_PROPERTIES_TOKEN)) { - initParameters.setProperty(CONNECT_APPLICATION_PROPERTIES_TOKEN, - buildInfo.getString(CONNECT_APPLICATION_PROPERTIES_TOKEN)); - } - if (buildInfo.hasKey(CONNECT_GENERATED_TS_DIR_TOKEN)) { - initParameters.setProperty(CONNECT_GENERATED_TS_DIR_TOKEN, - buildInfo.getString(CONNECT_GENERATED_TS_DIR_TOKEN)); - } - - setDevModePropertiesUsingTokenData(initParameters, buildInfo); - } - - private static void setDevModePropertiesUsingTokenData( - Properties initParameters, JsonObject buildInfo) { - // read dev mode properties from the token and set init parameter only - // if it's not yet set - if (initParameters.getProperty( - InitParameters.SERVLET_PARAMETER_ENABLE_PNPM) == null - && buildInfo - .hasKey(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)) { - initParameters.setProperty( - InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, - String.valueOf(buildInfo.getBoolean( - InitParameters.SERVLET_PARAMETER_ENABLE_PNPM))); - } - if (initParameters.getProperty( - InitParameters.REQUIRE_HOME_NODE_EXECUTABLE) == null - && buildInfo - .hasKey(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE)) { - initParameters.setProperty( - InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, - String.valueOf(buildInfo.getBoolean( - InitParameters.REQUIRE_HOME_NODE_EXECUTABLE))); - } - } - private static String getTokenFileContents(Class systemPropertyBaseClass, Properties initParameters, VaadinContext context) { String json = null; diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index c6d12bea685..e2d95978044 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -15,9 +15,11 @@ */ package com.vaadin.flow.server; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; -import java.util.function.Function; import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.shared.communication.PushMode; @@ -29,7 +31,6 @@ import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REQUEST_TIMING; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SYNC_ID_CHECK; -import static com.vaadin.flow.server.Constants.VAADIN_PREFIX; /** * The property handling implementation of {@link DeploymentConfiguration} based @@ -40,9 +41,10 @@ public class PropertyDeploymentConfiguration extends AbstractDeploymentConfiguration { - private final Properties initParameters; private final Class systemPropertyBaseClass; + private final Properties initialParameters; + /** * Create a new property deployment configuration instance. * @@ -55,28 +57,11 @@ public class PropertyDeploymentConfiguration */ public PropertyDeploymentConfiguration(Class systemPropertyBaseClass, Properties initParameters) { - this.initParameters = initParameters; + super(filterStringProperties(initParameters)); + initialParameters = initParameters; this.systemPropertyBaseClass = systemPropertyBaseClass; } - @Override - public T getApplicationOrSystemProperty(String propertyName, - T defaultValue, Function converter) { - // Try system properties - String val = getSystemProperty(propertyName); - if (val != null) { - return converter.apply(val); - } - - // Try application properties - val = getApplicationProperty(propertyName); - if (val != null) { - return converter.apply(val); - } - - return defaultValue; - } - /** * Gets an system property value. * @@ -84,6 +69,7 @@ public T getApplicationOrSystemProperty(String propertyName, * the Name or the parameter. * @return String value or null if not found */ + @Override protected String getSystemProperty(String parameterName) { String pkgName; final Package pkg = systemPropertyBaseClass.getPackage(); @@ -116,10 +102,7 @@ protected String getSystemProperty(String parameterName) { return val; } - // version prefixed with just "vaadin." - val = System.getProperty(VAADIN_PREFIX + parameterName); - - return val; + return super.getSystemProperty(parameterName); } /** @@ -129,16 +112,17 @@ protected String getSystemProperty(String parameterName) { * the Name or the parameter. * @return String value or null if not found */ + @Override public String getApplicationProperty(String parameterName) { - String val = initParameters.getProperty(parameterName); + String val = getProperties().get(parameterName); if (val != null) { return val; } // Try lower case application properties for backward compatibility with // 3.0.2 and earlier - val = initParameters.getProperty(parameterName.toLowerCase()); + val = getProperties().get(parameterName.toLowerCase()); return val; } @@ -203,7 +187,7 @@ public String getPushURL() { @Override public Properties getInitParameters() { - return initParameters; + return initialParameters; } /** @@ -215,8 +199,23 @@ public Properties getInitParameters() { */ @Override public boolean isDevModeLiveReloadEnabled() { - return !isProductionMode() && getBooleanProperty( - SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD, true) + return !isProductionMode() + && getBooleanProperty( + SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD, true) && enableDevServer(); // gizmo excluded from prod bundle } + + private static Map filterStringProperties( + Properties properties) { + Map result = new HashMap<>(); + for (Entry entry : properties.entrySet()) { + Object key = entry.getKey(); + Object value = entry.getValue(); + // Hashtable doesn't allow null for key and value + if (key instanceof String && value instanceof String) { + result.put(key.toString(), value.toString()); + } + } + return result; + } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java new file mode 100644 index 00000000000..91c01ca7c41 --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -0,0 +1,205 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.startup; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.flow.server.InitParameters; +import com.vaadin.flow.server.frontend.FrontendUtils; + +import elemental.json.JsonObject; + +import static com.vaadin.flow.server.Constants.CONNECT_APPLICATION_PROPERTIES_TOKEN; +import static com.vaadin.flow.server.Constants.CONNECT_GENERATED_TS_DIR_TOKEN; +import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; +import static com.vaadin.flow.server.Constants.CONNECT_OPEN_API_FILE_TOKEN; +import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_FILE; +import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_FILE_TOKEN; +import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_URL; +import static com.vaadin.flow.server.Constants.EXTERNAL_STATS_URL_TOKEN; +import static com.vaadin.flow.server.Constants.FRONTEND_TOKEN; +import static com.vaadin.flow.server.Constants.NPM_TOKEN; +import static com.vaadin.flow.server.Constants.VAADIN_PREFIX; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_INITIAL_UIDL; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; +import static com.vaadin.flow.server.frontend.FrontendUtils.PROJECT_BASEDIR; + +/** + * A configuration factory base logic which reads the token file. + * + * @author Vaadin Ltd + * @since + * + */ +public class AbstractConfigurationFactory implements Serializable { + + public static final String DEV_FOLDER_MISSING_MESSAGE = "Running project in development mode with no access to folder '%s'.%n" + + "Build project in production mode instead, see https://vaadin.com/docs/v15/flow/production/tutorial-production-mode-basic.html"; + + /** + * Returns the config parameters from the token file data {@code buildInfo}. + * + * @param buildInfo + * the token file data + * @return the config parameters + */ + public Map getConfigParametersUsingTokenData( + JsonObject buildInfo) { + Map params = new HashMap<>(); + if (buildInfo.hasKey(SERVLET_PARAMETER_PRODUCTION_MODE)) { + params.put(SERVLET_PARAMETER_PRODUCTION_MODE, String.valueOf( + buildInfo.getBoolean(SERVLET_PARAMETER_PRODUCTION_MODE))); + } + if (buildInfo.hasKey(EXTERNAL_STATS_FILE_TOKEN) + || buildInfo.hasKey(EXTERNAL_STATS_URL_TOKEN)) { + // If external stats file is flagged then + // dev server should be false - only variable that can + // be configured, in addition to stats variables, is + // production mode + params.put(SERVLET_PARAMETER_ENABLE_DEV_SERVER, + Boolean.toString(false)); + params.put(EXTERNAL_STATS_FILE, Boolean.toString(true)); + if (buildInfo.hasKey(EXTERNAL_STATS_URL_TOKEN)) { + params.put(EXTERNAL_STATS_URL, + buildInfo.getString(EXTERNAL_STATS_URL_TOKEN)); + } + // NO OTHER CONFIGURATION: + return params; + } + if (buildInfo.hasKey(SERVLET_PARAMETER_USE_V14_BOOTSTRAP)) { + params.put(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, String.valueOf( + buildInfo.getBoolean(SERVLET_PARAMETER_USE_V14_BOOTSTRAP))); + // Need to be sure that we remove the system property, + // because it has priority in the configuration getter + System.clearProperty( + VAADIN_PREFIX + SERVLET_PARAMETER_USE_V14_BOOTSTRAP); + } + if (buildInfo.hasKey(SERVLET_PARAMETER_INITIAL_UIDL)) { + params.put(SERVLET_PARAMETER_INITIAL_UIDL, String.valueOf( + buildInfo.getBoolean(SERVLET_PARAMETER_INITIAL_UIDL))); + // Need to be sure that we remove the system property, + // because it has priority in the configuration getter + System.clearProperty( + VAADIN_PREFIX + SERVLET_PARAMETER_INITIAL_UIDL); + } + + if (buildInfo.hasKey(NPM_TOKEN)) { + params.put(PROJECT_BASEDIR, buildInfo.getString(NPM_TOKEN)); + verifyFolderExists(params, buildInfo.getString(NPM_TOKEN)); + } + + if (buildInfo.hasKey(FRONTEND_TOKEN)) { + params.put(FrontendUtils.PARAM_FRONTEND_DIR, + buildInfo.getString(FRONTEND_TOKEN)); + // Only verify frontend folder if it's not a subfolder of the + // npm folder. + if (!buildInfo.hasKey(NPM_TOKEN) + || !buildInfo.getString(FRONTEND_TOKEN) + .startsWith(buildInfo.getString(NPM_TOKEN))) { + verifyFolderExists(params, buildInfo.getString(FRONTEND_TOKEN)); + } + } + + // These should be internal only so if there is a System + // property override then the user probably knows what + // they are doing. + if (buildInfo.hasKey(SERVLET_PARAMETER_ENABLE_DEV_SERVER)) { + params.put(SERVLET_PARAMETER_ENABLE_DEV_SERVER, String.valueOf( + buildInfo.getBoolean(SERVLET_PARAMETER_ENABLE_DEV_SERVER))); + } + if (buildInfo.hasKey(SERVLET_PARAMETER_REUSE_DEV_SERVER)) { + params.put(SERVLET_PARAMETER_REUSE_DEV_SERVER, String.valueOf( + buildInfo.getBoolean(SERVLET_PARAMETER_REUSE_DEV_SERVER))); + } + if (buildInfo.hasKey(CONNECT_JAVA_SOURCE_FOLDER_TOKEN)) { + params.put(CONNECT_JAVA_SOURCE_FOLDER_TOKEN, + buildInfo.getString(CONNECT_JAVA_SOURCE_FOLDER_TOKEN)); + } + if (buildInfo.hasKey(CONNECT_OPEN_API_FILE_TOKEN)) { + params.put(CONNECT_OPEN_API_FILE_TOKEN, + buildInfo.getString(CONNECT_OPEN_API_FILE_TOKEN)); + } + if (buildInfo.hasKey(CONNECT_APPLICATION_PROPERTIES_TOKEN)) { + params.put(CONNECT_APPLICATION_PROPERTIES_TOKEN, + buildInfo.getString(CONNECT_APPLICATION_PROPERTIES_TOKEN)); + } + if (buildInfo.hasKey(CONNECT_GENERATED_TS_DIR_TOKEN)) { + params.put(CONNECT_GENERATED_TS_DIR_TOKEN, + buildInfo.getString(CONNECT_GENERATED_TS_DIR_TOKEN)); + } + + setDevModePropertiesUsingTokenData(params, buildInfo); + return params; + } + + /** + * Sets to the dev mode properties to the configuration parameters. + * + * @see #getConfigParametersUsingTokenData(JsonObject) + * + * @param params + * the configuration parameters to set dev mode properties to + * @param buildInfo + * the token file data + */ + protected void setDevModePropertiesUsingTokenData( + Map params, JsonObject buildInfo) { + // read dev mode properties from the token and set init parameter only + // if it's not yet set + if (params.get(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM) == null + && buildInfo + .hasKey(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)) { + params.put(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + String.valueOf(buildInfo.getBoolean( + InitParameters.SERVLET_PARAMETER_ENABLE_PNPM))); + } + if (params.get(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE) == null + && buildInfo + .hasKey(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE)) { + params.put(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, + String.valueOf(buildInfo.getBoolean( + InitParameters.REQUIRE_HOME_NODE_EXECUTABLE))); + } + } + + /** + * Verify that given folder actually exists on the system if we are not in + * production mode. + *

+ * If folder doesn't exist throw IllegalStateException saying that this + * should probably be a production mode build. + * + * @param params + * parameters map + * @param folder + * folder to check exists + */ + protected void verifyFolderExists(Map params, + String folder) { + Boolean productionMode = Boolean.parseBoolean(params + .getOrDefault(SERVLET_PARAMETER_PRODUCTION_MODE, "false")); + if (!productionMode && !new File(folder).exists()) { + String message = String.format(DEV_FOLDER_MISSING_MESSAGE, folder); + throw new IllegalStateException(message); + } + } +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java new file mode 100644 index 00000000000..5d972874d30 --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.startup; + +import javax.servlet.Servlet; + +import java.util.Enumeration; + +import com.vaadin.flow.di.Lookup; +import com.vaadin.flow.function.DeploymentConfiguration; +import com.vaadin.flow.server.AbstractConfiguration; +import com.vaadin.flow.server.VaadinContext; + +/** + * Configuration on the application level. + *

+ * Configuration is based on {@link VaadinContext} which provides application + * level data in contrast to {@link DeploymentConfiguration} which provides a + * {@link Servlet} level configuration. + * + * @author Vaadin Ltd + * @since + * + */ +public interface ApplicationConfiguration extends AbstractConfiguration { + + /** + * Gets a configuration instance for the given {code context}. + * + * @param context + * the context to get the configuration for + * @return the application level configuration for the given {@code context} + */ + static ApplicationConfiguration get(VaadinContext context) { + return context.getAttribute(ApplicationConfiguration.class, () -> { + Lookup lookup = context.getAttribute(Lookup.class); + ApplicationConfigurationFactory factory = lookup + .lookup(ApplicationConfigurationFactory.class); + return factory.create(context); + }); + } + + /** + * Returns the names of the configuration properties as an + * Enumeration, or an empty Enumeration if there + * are o initialization parameters. + * + * @return configuration properties as a Enumeration + */ + Enumeration getPropertyNames(); + + /** + * The context which the configuration is based on. + * + * @return the vaadin context + */ + VaadinContext getContext(); + +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfigurationFactory.java new file mode 100644 index 00000000000..7dabd70f0e6 --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfigurationFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.startup; + +import com.vaadin.flow.server.VaadinContext; + +/** + * A factory for {@link ApplicationConfiguration}. + * + * @author Vaadin Ltd + * @since + * + */ +public interface ApplicationConfigurationFactory { + + /** + * Creates a new instance of {@link ApplicationConfiguration} for the given + * {@code context}. + * + * @param context + * the context to create a configuration for + * @return the configuration created based on the {@code context} + */ + ApplicationConfiguration create(VaadinContext context); +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java new file mode 100644 index 00000000000..9bf5a9f707f --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -0,0 +1,207 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.startup; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.flow.di.Lookup; +import com.vaadin.flow.di.ResourceProvider; +import com.vaadin.flow.server.AbstractPropertyConfiguration; +import com.vaadin.flow.server.VaadinContext; +import com.vaadin.flow.server.frontend.FrontendUtils; + +import elemental.json.JsonObject; +import elemental.json.impl.JsonUtil; + +import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; +import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; + +/** + * Default implementation of {@link ApplicationConfigurationFactory}. + * + * @author Vaadin Ltd + * @since + * + */ +public class DefaultApplicationConfigurationFactory + extends AbstractConfigurationFactory + implements ApplicationConfigurationFactory { + + protected static class ApplicationConfigurationImpl extends + AbstractPropertyConfiguration implements ApplicationConfiguration { + + private final VaadinContext context; + + protected ApplicationConfigurationImpl(VaadinContext context, + Map properties) { + super(properties); + this.context = context; + } + + @Override + public boolean isProductionMode() { + return getBooleanProperty(SERVLET_PARAMETER_PRODUCTION_MODE, false); + } + + @Override + public Enumeration getPropertyNames() { + return Collections.enumeration(getProperties().keySet()); + } + + @Override + public VaadinContext getContext() { + return context; + } + + } + + @Override + public ApplicationConfiguration create(VaadinContext context) { + Map props = new HashMap<>(); + for (final Enumeration e = context.getContextParameterNames(); e + .hasMoreElements();) { + final String name = e.nextElement(); + props.put(name, context.getContextParameter(name)); + } + try { + JsonObject buildInfo = JsonUtil + .parse(getTokenFileFromClassloader(context)); + + props.putAll(getConfigParametersUsingTokenData(buildInfo)); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + return new ApplicationConfigurationImpl(context, props); + } + + /** + * Gets token file from the classpath using the provided {@code context}. + *

+ * The {@code contextClass} may be a class which is defined in the Web + * Application module/bundle and in this case it may be used to get Web + * Application resources. Also a {@link VaadinContext} {@code context} + * instance may be used to get a context of the Web Application (since the + * {@code contextClass} may be a class not from Web Application module). In + * WAR case it doesn't matter which class is used to get the resources (Web + * Application classes or e.g. "flow-server" classes) since they are loaded + * by the same {@link ClassLoader}. But in OSGi "flow-server" module classes + * can't be used to get Web Application resources since they are in + * different bundles. + * + * @param context + * a VaadinContext which may provide information how to get token + * file for the web application + * @return the token file content + * @throws IOException + * if I/O fails during access to the token file + */ + protected String getTokenFileFromClassloader(VaadinContext context) + throws IOException { + String tokenResource = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; + + Lookup lookup = context.getAttribute(Lookup.class); + ResourceProvider resourceProvider = lookup + .lookup(ResourceProvider.class); + + List resources = resourceProvider + .getApplicationResources(tokenResource); + + // Accept resource that doesn't contain + // 'jar!/META-INF/Vaadin/config/flow-build-info.json' + URL resource = resources.stream() + .filter(url -> !url.getPath().endsWith("jar!/" + tokenResource)) + .findFirst().orElse(null); + if (resource == null && !resources.isEmpty()) { + return getPossibleJarResource(context, resources); + } + return resource == null ? null + : FrontendUtils.streamToString(resource.openStream()); + + } + + /** + * Check if the webpack.generated.js resources is inside 2 jars + * (flow-server.jar and application.jar) if this is the case then we can + * accept a build info file from inside jar with a single jar in the path. + *

+ * Else we will accept any flow-build-info and log a warning that it may not + * be the correct file, but it's the best we could find. + */ + private String getPossibleJarResource(VaadinContext context, + List resources) throws IOException { + Objects.requireNonNull(resources); + + Lookup lookup = context.getAttribute(Lookup.class); + ResourceProvider resourceProvider = lookup + .lookup(ResourceProvider.class); + + assert !resources + .isEmpty() : "Possible jar resource requires resources to be available."; + + URL webpackGenerated = resourceProvider + .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); + + // If jar!/ exists 2 times for webpack.generated.json then we are + // running from a jar + if (webpackGenerated != null + && countInstances(webpackGenerated.getPath(), "jar!/") >= 2) { + for (URL resource : resources) { + // As we now know that we are running from a jar we can accept a + // build info with a single jar in the path + if (countInstances(resource.getPath(), "jar!/") == 1) { + return FrontendUtils.streamToString(resource.openStream()); + } + } + } + URL firstResource = resources.get(0); + if (resources.size() > 1) { + String warningMessage = String.format( + "Unable to fully determine correct flow-build-info.%n" + + "Accepting file '%s' first match of '%s' possible.%n" + + "Please verify flow-build-info file content.", + firstResource.getPath(), resources.size()); + getLogger().warn(warningMessage); + } else { + String debugMessage = String.format( + "Unable to fully determine correct flow-build-info.%n" + + "Accepting file '%s'", + firstResource.getPath()); + getLogger().debug(debugMessage); + } + return FrontendUtils.streamToString(firstResource.openStream()); + } + + private int countInstances(String input, String value) { + return input.split(value, -1).length - 1; + } + + private Logger getLogger() { + return LoggerFactory + .getLogger(DefaultApplicationConfigurationFactory.class); + } +} diff --git a/flow-server/src/test/java/com/vaadin/flow/server/AbstractDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/AbstractDeploymentConfigurationTest.java index 16c9e9379d1..a526d3d7273 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/AbstractDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/AbstractDeploymentConfigurationTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.server; +import java.util.Collections; import java.util.Optional; import java.util.Properties; import java.util.UUID; @@ -65,6 +66,7 @@ private static class DeploymentConfigImpl private Properties properties; DeploymentConfigImpl(Properties props) { + super(Collections.emptyMap()); properties = props; } diff --git a/flow-server/src/test/java/com/vaadin/tests/util/MockDeploymentConfiguration.java b/flow-server/src/test/java/com/vaadin/tests/util/MockDeploymentConfiguration.java index d932f2b3986..7c7cf8bb1bb 100644 --- a/flow-server/src/test/java/com/vaadin/tests/util/MockDeploymentConfiguration.java +++ b/flow-server/src/test/java/com/vaadin/tests/util/MockDeploymentConfiguration.java @@ -1,5 +1,6 @@ package com.vaadin.tests.util; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -30,6 +31,10 @@ public class MockDeploymentConfiguration private boolean eagerServerLoad = false; private boolean devModeLiveReloadEnabled = false; + public MockDeploymentConfiguration() { + super(Collections.emptyMap()); + } + @Override public boolean isProductionMode() { return productionMode; @@ -169,7 +174,8 @@ public boolean useV14Bootstrap() { return useDeprecatedV14Bootstrapping; } - public void useDeprecatedV14Bootstrapping(boolean useDeprecatedV14Bootstrapping) { + public void useDeprecatedV14Bootstrapping( + boolean useDeprecatedV14Bootstrapping) { this.useDeprecatedV14Bootstrapping = useDeprecatedV14Bootstrapping; } diff --git a/flow-test-generic/src/main/java/com/vaadin/flow/testutil/ClassesSerializableTest.java b/flow-test-generic/src/main/java/com/vaadin/flow/testutil/ClassesSerializableTest.java index 3189afd84fc..6f7d586e7b2 100644 --- a/flow-test-generic/src/main/java/com/vaadin/flow/testutil/ClassesSerializableTest.java +++ b/flow-test-generic/src/main/java/com/vaadin/flow/testutil/ClassesSerializableTest.java @@ -105,6 +105,7 @@ protected Stream getExcludedPatterns() { "com\\.vaadin\\.flow\\.server\\.VaadinServletRequest", "com\\.vaadin\\.flow\\.server\\.VaadinServletResponse", "com\\.vaadin\\.flow\\.server\\.startup\\.AnnotationValidator", + "com\\.vaadin\\.flow\\.server\\.startup\\.ApplicationConfigurationFactory", "com\\.vaadin\\.flow\\.server\\.startup\\.ApplicationRouteRegistry\\$RouteRegistryServletContextListener", "com\\.vaadin\\.flow\\.server\\.startup\\.ApplicationRouteRegistry\\$OSGiRouteRegistry", "com\\.vaadin\\.flow\\.server\\.startup\\.ApplicationRouteRegistry\\$OSGiDataCollector", diff --git a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java index 1b2a09d815c..577aaf16c96 100644 --- a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java +++ b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java @@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; + import java.io.File; import java.io.IOException; import java.io.Serializable; @@ -41,6 +42,9 @@ import java.util.Properties; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.vaadin.flow.component.UI; import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.internal.CurrentInstance; @@ -58,10 +62,8 @@ import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.VaadinSession; import com.vaadin.flow.uitest.servlet.CustomDeploymentConfiguration.Conf; -import elemental.json.JsonValue; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import elemental.json.JsonValue; @WebServlet(asyncSupported = true, urlPatterns = { "/*" }) public class ApplicationRunnerServlet extends VaadinServlet { @@ -153,11 +155,11 @@ private ProxyDeploymentConfiguration( @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getDeclaringClass() == DeploymentConfiguration.class) { + if (method.getDeclaringClass() + .isAssignableFrom(DeploymentConfiguration.class)) { // Find the configuration instance to delegate to DeploymentConfiguration configuration = findDeploymentConfiguration( originalConfiguration); - return method.invoke(configuration, args); } else { return method.invoke(proxy, args);