From f51011067c0488b31987b89c4fe763ae6a6c5ced Mon Sep 17 00:00:00 2001 From: Kamesh Sampath Date: Sun, 11 Jun 2017 12:22:23 +0530 Subject: [PATCH] Refactor: * added spring boot dependency to parse the spring boot properties * using spring boot run to make it compute env and retrieved props from it --- core/pom.xml | 7 + .../maven/core/util/SpringBootUtil.java | 363 ++++++++++-------- .../maven/core/util/SpringBootUtilTest.java | 216 ++++++++--- .../util/test-application-include.yml | 14 + .../util/test-application-merge-multi.yml | 9 + .../resources/util/test-application-multi.yml | 4 - .../resources/util/test-application-named.yml | 4 + .../springboot/SpringBootGenerator.java | 29 +- parent/pom.xml | 1 + .../watcher/standard/SpringBootWatcher.java | 7 +- 10 files changed, 434 insertions(+), 220 deletions(-) create mode 100644 core/src/test/resources/util/test-application-include.yml create mode 100644 core/src/test/resources/util/test-application-merge-multi.yml create mode 100644 core/src/test/resources/util/test-application-named.yml diff --git a/core/pom.xml b/core/pom.xml index 0a98e2a692..f0136969e2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -84,6 +84,13 @@ mockwebserver + + + org.springframework.boot + spring-boot + ${version.spring-boot} + + diff --git a/core/src/main/java/io/fabric8/maven/core/util/SpringBootUtil.java b/core/src/main/java/io/fabric8/maven/core/util/SpringBootUtil.java index 6777a33e79..2fee46ba64 100644 --- a/core/src/main/java/io/fabric8/maven/core/util/SpringBootUtil.java +++ b/core/src/main/java/io/fabric8/maven/core/util/SpringBootUtil.java @@ -17,20 +17,30 @@ package io.fabric8.maven.core.util; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.env.PropertiesPropertySourceLoader; +import org.springframework.boot.env.PropertySourcesLoader; +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.util.*; /** * Utility methods to access spring-boot resources. + * TODO: remove unwanted methods after Roland reviews and okays logic */ public class SpringBootUtil { @@ -43,182 +53,124 @@ public class SpringBootUtil { * @param activeProfiles - the comma separated String of profiles * @return properties - the merged properties of all profiles */ - public static Properties getApplicationProperties(MavenProject project, String activeProfiles) { + public static Properties getApplicationProperties(MavenProject project, String activeProfiles) throws IOException { return getApplicationProperties(project, getActiveProfiles(activeProfiles)); } + /** - * Returns the spring boot configuration (supports `application.properties` and `application.yml`) - * or an empty properties object if not found + * TODO: need to check with Roland to see if we can use this approach + * A simple short method where we simply run a small spring boot application during build and load the environment + * to get the property sources, then load the properties from + * + * @param activeProfiles - the active profiles to be used if {@code null}, its not passed to spring boot application run + * @return Properties - the application environment properties that will be used during image building process */ - public static Properties getApplicationProperties(MavenProject project, List activeProfiles) { - URLClassLoader compileClassLoader = MavenUtil.getCompileClassLoader(project); + public static Properties runAndLoadPropertiesUsingEnv(List activeProfiles) { + + SpringApplication sbBuilder; - Properties props = new Properties(); - addApplicationProperties(activeProfiles, compileClassLoader, props, null); + if (activeProfiles != null && activeProfiles.size() > 0) { + sbBuilder = new SpringApplicationBuilder(AnnotationConfigApplicationContext.class) + .web(false) + .headless(true) + .bannerMode(Banner.Mode.OFF) + .profiles(activeProfiles.toArray(new String[activeProfiles.size()])) + .build(); + } else { + sbBuilder = new SpringApplicationBuilder(AnnotationConfigApplicationContext.class) + .web(false) + .headless(true) + .bannerMode(Banner.Mode.OFF) + .build(); + } + + ConfigurableApplicationContext ctx = sbBuilder.run(); - //If the profiles are available load the profile resources as well - if (activeProfiles != null) { - for (String profile : activeProfiles) { - addApplicationProperties(activeProfiles, compileClassLoader, props, profile); + Properties applicationProperties = new Properties(); + + for (PropertySource propertySource : ctx.getEnvironment().getPropertySources()) { + + if (propertySource != null && propertySource instanceof MapPropertySource) { + applicationProperties.putAll(((MapPropertySource) propertySource).getSource()); } } - return props; + + return applicationProperties; + } + + /** + * Returns the spring boot configuration (supports `application.properties` and `application.yml`) + * or an empty properties object if not found + */ + public static Properties getApplicationProperties(MavenProject project, List activeProfiles) + throws IOException { + + return runAndLoadPropertiesUsingEnv(activeProfiles); + //Properties props = new Properties(); +// addApplicationProperties(project, props, null); +// +// //If the profiles are available load the profile resources as well +// if (activeProfiles != null && !activeProfiles.isEmpty()) { +// for (String profile : activeProfiles) { +// addApplicationProperties(project, props, profile); +// } +// } + //return props; } /** * Returns the given properties file on the project classpath if found or an empty properties object if not */ - public static Properties getPropertiesFile(MavenProject project, String propertiesFileName) { + public static Properties getPropertiesFile(MavenProject project, String propertiesFileName) throws IOException { URLClassLoader compileClassLoader = MavenUtil.getCompileClassLoader(project); URL resource = compileClassLoader.findResource(propertiesFileName); - return getPropertiesResource(resource); + return getPropertiesResource(resource, null); } /** * Returns the given properties resource on the project classpath if found or an empty properties object if not */ - protected static Properties getPropertiesResource(URL resource) { - Properties answer = new Properties(); + @SuppressWarnings("unchecked") + protected static Properties getPropertiesResource(URL resource, String profile) throws IOException { + Properties properties = new Properties(); if (resource != null) { - try (InputStream stream = resource.openStream()) { - answer.load(stream); - } catch (IOException e) { - throw new IllegalStateException("Error while reading resource from URL " + resource, e); + PropertiesPropertySourceLoader propertySourceLoader = new PropertiesPropertySourceLoader(); + PropertySource propertySource = (PropertySource) propertySourceLoader.load(resource.getFile(), + new UrlResource(resource), profile); + if (propertySource != null) { + properties.putAll(propertySource.getSource()); } } - return answer; - } - - /** - * Returns a {@code Properties} representation of the given Yaml file on the project classpath if found or an empty properties object if not - */ - public static Properties getPropertiesFromYamlFile(MavenProject project, String yamlFileName, - List activeProfiles) { - URLClassLoader compileClassLoader = MavenUtil.getCompileClassLoader(project); - URL resource = compileClassLoader.findResource(yamlFileName); - return getPropertiesFromYamlResource(resource, activeProfiles); + return properties; } /** * Returns a {@code Properties} representation of the given Yaml resource or an empty properties object if the resource is null */ - protected static Properties getPropertiesFromYamlResource(URL resource, List activeProfiles) { + @SuppressWarnings("unchecked") + protected static Properties getPropertiesFromYamlResource(URL resource, String profile) throws IOException { + Properties properties = new Properties(); if (resource != null) { - try (InputStream yamlStream = resource.openStream()) { - Yaml yaml = new Yaml(new SafeConstructor()); - - Map profileDocs = new HashMap<>(); - - Properties properties = new Properties(); - - Iterable yamlDoc = yaml.loadAll(yamlStream); - - Iterator yamlDocIterator = yamlDoc.iterator(); - - int docCount = 0; - while (yamlDocIterator.hasNext()) { - Map docRoot = (Map) yamlDocIterator.next(); - - String profiles = null; - - if (docRoot.containsKey("spring")) { - - LinkedHashMap value = (LinkedHashMap) docRoot.get("spring"); - - Object profilesValue = value.get("profiles"); - - if (profilesValue instanceof Map) { - Map profileMap = (Map) profilesValue; - if (activeProfiles.isEmpty() && docCount > 0) { - if (profileMap.containsKey("active")) { - activeProfiles.addAll(getActiveProfiles((String) profileMap.get("active"))); - } - } - } else if (profilesValue instanceof String) { - profiles = (String) profilesValue; - } - } - - if (profiles != null) { - String[] profileSplit = profiles.split("\\s*,\\s*"); - if (!CollectionUtils. - intersection(Arrays.asList(profileSplit), activeProfiles) - .isEmpty()) { - //if the profiles is in the list of active profiles we add it to our list of docs - profileDocs.put(profiles, docRoot); - } - } else if (docCount == 0) { - //the root doc - profileDocs.put("default", docRoot); - } + YamlPropertySourceLoader yamlPropertySourceLoader = new YamlPropertySourceLoader(); - docCount++; - } + PropertySource propertySource = (PropertySource) + yamlPropertySourceLoader.load(resource.getFile(), + new UrlResource(resource), profile); - LOG.debug("Spring Boot Profile docs:{}" + profileDocs); - - properties.putAll(getFlattenedMap(profileDocs.get("default"))); - - for (String activeProfile : activeProfiles) { - if (profileDocs.containsKey(activeProfile)) { - properties.putAll(getFlattenedMap(profileDocs.get(activeProfile))); - } - } - - return properties; - } catch (IOException e) { - throw new IllegalStateException("Error while reading Yaml resource from URL " + resource, e); + if (propertySource != null) { + properties.putAll(propertySource.getSource()); } } - return new Properties(); + return properties; } /** * Determine the spring-boot devtools version for the current project */ public static String getSpringBootDevToolsVersion(MavenProject mavenProject) { - return MavenUtil.getDependencyVersion(mavenProject, SpringBootProperties.SPRING_BOOT_GROUP_ID, SpringBootProperties.SPRING_BOOT_ARTIFACT_ID); - } - - /** - * Build a flattened representation of the Yaml tree. The conversion is compliant with the spring-boot rules. - */ - private static Map getFlattenedMap(Map source) { - Map result = new LinkedHashMap<>(); - buildFlattenedMap(result, source, null); - return result; - } - - @SuppressWarnings("unchecked") - private static void buildFlattenedMap(Map result, Map source, String path) { - for (Map.Entry entry : source.entrySet()) { - String key = entry.getKey(); - if (path != null && path.trim().length() > 0) { - if (key.startsWith("[")) { - key = path + key; - } else { - key = path + "." + key; - } - } - Object value = entry.getValue(); - if (value instanceof String) { - result.put(key, value); - } else if (value instanceof Map) { - - Map map = (Map) value; - buildFlattenedMap(result, map, key); - } else if (value instanceof Collection) { - Collection collection = (Collection) value; - int count = 0; - for (Object object : collection) { - buildFlattenedMap(result, - Collections.singletonMap("[" + (count++) + "]", object), key); - } - } else { - result.put(key, (value != null ? value : "")); - } - } + return MavenUtil.getDependencyVersion(mavenProject, SpringBootProperties.SPRING_BOOT_GROUP_ID, + SpringBootProperties.SPRING_BOOT_ARTIFACT_ID); } public static List getActiveProfiles(String strActiveProfiles) { @@ -242,32 +194,125 @@ private static URL getResourceFromClasspath(URLClassLoader compileClassLoader, S return urlResource; } + private static void runAndLoadEnv(String... profiles) { + SpringApplication mvnSpringApplication = + new SpringApplicationBuilder() + .profiles(profiles) + .build(); + mvnSpringApplication.setWebEnvironment(false); + + } + /** * Method to add the application properties from spring boot profile resources and merge them as one * - * @param activeProfiles - the active profiles list typically a comma separated string of profile names - * @param compileClassLoader - the classloader in which the resource will be searched - * @param mergedProperties - the merged properties container - * @param profile - the profile to use when searching the spring boot resources + * @param project - the maven project of the build + * @param mergedProperties - the merged properties container + * @param profile - the profile to use when searching the spring boot resources + */ + private static void addApplicationProperties(MavenProject project, Properties mergedProperties, + String profile) throws IOException { + + PropertySourcesLoader propertySourcesLoader = new PropertySourcesLoader(); + + //Applications can override the config file name using this system property + //Ref: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html + + String configFileName = System.getProperty("spring.config.name", "application"); + + Set includesResources = new LinkedHashSet<>(); + + if (profile == null) { + scanForApplicationPropertySources(project, configFileName, includesResources, null); + + } else { + scanForApplicationPropertySources(project, configFileName, includesResources, null); + } + + + Properties profileProperties = new Properties(); + + for (Resource resource : includesResources) { + MapPropertySource propertySource = (MapPropertySource) propertySourcesLoader.load(resource); + if (propertySource != null) { + profileProperties.putAll(propertySource.getSource()); + } + } + + mergedProperties.putAll(profileProperties); + } + + /** + * A utility method to scan for spring boot application sources {@code *.properties,*.yaml,*.json,*.yml} + * + * @param mavenProject - the maven project which houses the spring boot application + * @param configFileName - the configuration file name {@code spring.config.name} system property or defaults to application + * @param includesResources - the collection to which the scanned resources will be added + * @param profile - the Spring profile + * @throws IOException - any exception that might occur while scanning the resource */ - private static void addApplicationProperties(List activeProfiles, URLClassLoader compileClassLoader, - Properties mergedProperties, String profile) { - URL ymlResource; - URL propertiesResource; - Properties profileProperties; + private static void scanForApplicationPropertySources(MavenProject mavenProject, String configFileName, + Set includesResources, + String profile) throws IOException { + URLClassLoader classLoader = MavenUtil.getCompileClassLoader(mavenProject); + PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver(classLoader); + String propertiesFilePattern; + + //PROPERTIES + if (profile == null) { + propertiesFilePattern = "**/" + configFileName + ".properties"; + } else { + propertiesFilePattern = "**/" + configFileName + "-" + profile + ".properties"; + } + + //PROPERTIES + Resource[] propertiesResources = scanner.getResources(propertiesFilePattern); + + if (propertiesResources != null) { + includesResources.addAll(Arrays.asList(propertiesResources)); + } + + //YML + if (profile == null) { + propertiesFilePattern = "**/" + configFileName + ".yml"; + } else { + propertiesFilePattern = "**/" + configFileName + "-" + profile + ".yml"; + } + + Resource[] ymlResources = scanner.getResources(propertiesFilePattern); + if (ymlResources != null) { + includesResources.addAll(Arrays.asList(ymlResources)); + } + + //YAML + if (profile == null) { + propertiesFilePattern = "**/" + configFileName + ".yaml"; + } else { + propertiesFilePattern = "**/" + configFileName + "-" + profile + ".yaml"; + } + + Resource[] yamlResources = + scanner.getResources(propertiesFilePattern); + includesResources.addAll(Arrays.asList(yamlResources)); + + if (yamlResources != null) { + includesResources.addAll(Arrays.asList(ymlResources)); + } + + //JSON if (profile == null) { - ymlResource = compileClassLoader.findResource("application.yml"); - propertiesResource = compileClassLoader.findResource("application.properties"); - mergedProperties = getPropertiesFromYamlResource(ymlResource, activeProfiles); - mergedProperties.putAll(getPropertiesResource(propertiesResource)); + propertiesFilePattern = "**/" + configFileName + ".json"; } else { - ymlResource = compileClassLoader.findResource("application-" + profile + ".yml"); - profileProperties = getPropertiesFromYamlResource(ymlResource, activeProfiles); - propertiesResource = getResourceFromClasspath(compileClassLoader, - "application-" + profile + ".properties"); - profileProperties.putAll(getPropertiesResource(propertiesResource)); - mergedProperties.putAll(profileProperties); + propertiesFilePattern = "**/" + configFileName + "-" + profile + ".json"; + } + + Resource[] jsonResources = + scanner.getResources(propertiesFilePattern); + includesResources.addAll(Arrays.asList(yamlResources)); + + if (jsonResources != null) { + includesResources.addAll(Arrays.asList(jsonResources)); } } diff --git a/core/src/test/java/io/fabric8/maven/core/util/SpringBootUtilTest.java b/core/src/test/java/io/fabric8/maven/core/util/SpringBootUtilTest.java index 18b390be44..10412a57d6 100644 --- a/core/src/test/java/io/fabric8/maven/core/util/SpringBootUtilTest.java +++ b/core/src/test/java/io/fabric8/maven/core/util/SpringBootUtilTest.java @@ -15,27 +15,50 @@ */ package io.fabric8.maven.core.util; -import java.util.*; - import io.fabric8.utils.PropertiesHelper; - +import org.apache.maven.model.Build; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.FileUtils; import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.util.Collections; +import java.util.Properties; +import java.util.UUID; + +import static org.junit.Assert.*; /** * Checking the behaviour of utility methods. */ public class SpringBootUtilTest { - @Test - public void testYamlToPropertiesParsing() { + public void testYamlToPropertiesParsing() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application.yml"); + + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.yml")); + + Properties props = SpringBootUtil.getApplicationProperties(project, Collections.emptyList()); - Properties props = SpringBootUtil.getPropertiesFromYamlResource( - SpringBootUtilTest.class.getResource("/util/test-application.yml"), Collections.emptyList()); assertNotEquals(0, props.size()); assertEquals(new Integer(8081), PropertiesHelper.getInteger(props, "management.port")); @@ -48,55 +71,154 @@ public void testYamlToPropertiesParsing() { } @Test - public void testYamlToPropertiesParsingWithActiveProfiles() { + public void testYamlToPropertiesMerge() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application-merge-multi.yml"); - List activeProfiles = new ArrayList() {{ - add("dev"); - add("qa"); - }}; + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.yml"), "UTF-8", null, true); + + Properties props = SpringBootUtil.getApplicationProperties(project, Collections.emptyList()); - Properties props = SpringBootUtil.getPropertiesFromYamlResource( - SpringBootUtilTest.class.getResource("/util/test-application-multi.yml"), activeProfiles); assertNotEquals(0, props.size()); assertEquals(new Integer(9090), PropertiesHelper.getInteger(props, "server.port")); assertEquals("Hello", props.getProperty("my.name")); - assertEquals("Hola!", props.getProperty("their.name")); + assertEquals("Foo", props.getProperty("their.name")); } @Test - public void testYamlToPropertiesParsingWithActiveProfiles2() { + public void testWithDifferentConfigName() throws Exception { + + System.setProperty("spring.config.name", "foo"); + + MavenProject project = new MavenProject(); + Build build = new Build(); - List activeProfiles = new ArrayList() {{ - add("qa"); - add("dev"); - }}; + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application-named.yml"); + + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "foo.yml"), "UTF-8", null, true); + + Properties props = SpringBootUtil.getApplicationProperties(project, Collections.emptyList()); - Properties props = SpringBootUtil.getPropertiesFromYamlResource( - SpringBootUtilTest.class.getResource("/util/test-application-multi.yml"), activeProfiles); assertNotEquals(0, props.size()); + assertEquals(new Integer(9090), PropertiesHelper.getInteger(props, "server.port")); + assertEquals("Foo", props.getProperty("their.name")); + + System.getProperties().remove("spring.config.name"); + } + + @Test + public void testPropertiesInclude() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application-include.yml"); + + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.yml"), "UTF-8", null, true); + + Properties props = SpringBootUtil.getApplicationProperties(project,Collections.emptyList()); + + assertNotEquals(0, props.size()); + + assertEquals(new Integer(2020), PropertiesHelper.getInteger(props, "my.port")); + assertEquals("bar", props.getProperty("my.name")); + assertEquals("foo", props.getProperty("name")); + } + + + @Test + public void testProfilePropertiesForDev() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application-multi.yml"); + + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.yml"), "UTF-8", null, true); + + Properties props = SpringBootUtil.getApplicationProperties(project,"dev"); + assertEquals(new Integer(8080), PropertiesHelper.getInteger(props, "server.port")); assertEquals("Hello", props.getProperty("my.name")); - assertEquals("Hola!", props.getProperty("their.name")); } @Test - public void testNonExistentYamlToPropertiesParsing() { + public void testProfilePropertiesForQa() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application-multi.yml"); - Properties props = SpringBootUtil.getPropertiesFromYamlResource( - SpringBootUtilTest.class.getResource("/this-file-does-not-exist") - , Collections.emptyList()); - assertNotNull(props); - assertEquals(0, props.size()); + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.yml"), "UTF-8", null, true); + Properties props = SpringBootUtil.getApplicationProperties(project,"qa"); + + assertNotEquals(0, props.size()); + + assertEquals(new Integer(9090), PropertiesHelper.getInteger(props, "server.port")); + assertEquals("Hola!", props.getProperty("their.name")); } +// // @Test TODO SK Remove this after Roland Review - this will not happen at all +// public void testNonExistentYamlToPropertiesParsing() throws Exception { +// +// Properties props = SpringBootUtil.getPropertiesFromYamlResource( +// SpringBootUtilTest.class.getResource("/this-file-does-not-exist") +// , null); +// +// MavenProject project = new MavenProject(); +// Build build = new Build(); +// +// setMavenProject(project, build); +// +// URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/this-file-does-not-exist"); +// +// FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", +// "application.yml"), "UTF-8", null, true); +// +// Properties props = SpringBootUtil.getApplicationProperties(project,"qa"); +// assertNotNull(props); +// assertEquals(0, props.size()); +// +// } + @Test - public void testPropertiesParsing() { + public void testPropertiesParsing() throws Exception { + + MavenProject project = new MavenProject(); + Build build = new Build(); + + setMavenProject(project, build); + + URL testAppPropertyResource = SpringBootUtilTest.class.getResource("/util/test-application.properties"); + + FileUtils.copyFile(ResourceUtils.getFile(testAppPropertyResource), new File("target/test-classes", + "application.properties"), "UTF-8", null, true); + + Properties props = SpringBootUtil.getApplicationProperties(project,Collections.emptyList()); + - Properties props = SpringBootUtil.getPropertiesResource( - SpringBootUtilTest.class.getResource("/util/test-application.properties")); assertNotEquals(0, props.size()); assertEquals(new Integer(8081), PropertiesHelper.getInteger(props, "management.port")); @@ -106,13 +228,21 @@ public void testPropertiesParsing() { } - @Test - public void testNonExistentPropertiesParsing() { - - Properties props = SpringBootUtil.getPropertiesResource(SpringBootUtilTest.class.getResource("/this-file-does-not-exist")); - assertNotNull(props); - assertEquals(0, props.size()); - +// @Test TODO SK Remove this after Roland Review +// public void testNonExistentPropertiesParsing() throws IOException { +// +// Properties props = SpringBootUtil.getPropertiesResource(SpringBootUtilTest.class.getResource( +// "/this-file-does-not-exist"), null); +// assertNotNull(props); +// assertEquals(0, props.size()); +// } + + public void setMavenProject(final MavenProject project, final Build build) throws IOException { + //Set Build Dir + final String outputTempDir = Files.createTempDirectory(UUID.randomUUID().toString()).toFile().getAbsolutePath(); + new File(outputTempDir).mkdirs(); + build.setOutputDirectory(outputTempDir); + project.setBuild(build); } } diff --git a/core/src/test/resources/util/test-application-include.yml b/core/src/test/resources/util/test-application-include.yml new file mode 100644 index 0000000000..456275f76e --- /dev/null +++ b/core/src/test/resources/util/test-application-include.yml @@ -0,0 +1,14 @@ +--- +spring: + active: + profiles: foo + profiles: + include: bar +name: foo + +--- +my: + name: bar + port: 2020 +spring: + profiles: bar \ No newline at end of file diff --git a/core/src/test/resources/util/test-application-merge-multi.yml b/core/src/test/resources/util/test-application-merge-multi.yml new file mode 100644 index 0000000000..4f0328a7f9 --- /dev/null +++ b/core/src/test/resources/util/test-application-merge-multi.yml @@ -0,0 +1,9 @@ +--- +my: + name: "Hello" + +--- +server: + port: 9090 +their: + name: Foo diff --git a/core/src/test/resources/util/test-application-multi.yml b/core/src/test/resources/util/test-application-multi.yml index 6efadbc32f..6bca6cd1df 100644 --- a/core/src/test/resources/util/test-application-multi.yml +++ b/core/src/test/resources/util/test-application-multi.yml @@ -1,7 +1,3 @@ -spring: - profiles: - active: dev,qa - --- spring: diff --git a/core/src/test/resources/util/test-application-named.yml b/core/src/test/resources/util/test-application-named.yml new file mode 100644 index 0000000000..f54c389134 --- /dev/null +++ b/core/src/test/resources/util/test-application-named.yml @@ -0,0 +1,4 @@ +server: + port: 9090 +their: + name: Foo \ No newline at end of file diff --git a/generator/spring-boot/src/main/java/io/fabric8/maven/generator/springboot/SpringBootGenerator.java b/generator/spring-boot/src/main/java/io/fabric8/maven/generator/springboot/SpringBootGenerator.java index 367f16d3ac..8afdf7ab0e 100644 --- a/generator/spring-boot/src/main/java/io/fabric8/maven/generator/springboot/SpringBootGenerator.java +++ b/generator/spring-boot/src/main/java/io/fabric8/maven/generator/springboot/SpringBootGenerator.java @@ -52,7 +52,9 @@ public class SpringBootGenerator extends JavaExecGenerator { private static final String DEFAULT_SERVER_PORT = "8080"; public enum Config implements Configs.Key { - color {{ d = "false"; }}, + color {{ + d = "false"; + }}, // comma separated list of spring boot profile(s) that would be passed set as -Dspring.profiles.active activeProfiles; @@ -89,8 +91,7 @@ public List customize(List configs, bool protected Map getEnv(boolean prePackagePhase) throws MojoExecutionException { Map res = super.getEnv(prePackagePhase); if (getContext().isWatchMode()) { - String strActiveProfiles = getContext().getConfig().getConfig("spring-boot", "activeProfiles"); - Properties properties = SpringBootUtil.getApplicationProperties(getProject(), strActiveProfiles); + Properties properties = getSpringBootProperties(); // adding dev tools token to env variables to prevent override during recompile String secret = properties.getProperty(SpringBootProperties.DEV_TOOLS_REMOTE_SECRET); if (secret != null) { @@ -127,12 +128,8 @@ protected boolean isFatJar() throws MojoExecutionException { protected List extractPorts() { List answer = new ArrayList<>(); - String strActiveProfiles = getConfig(activeProfiles); - - Properties properties = SpringBootUtil.getApplicationProperties(getContext().getProject(), - SpringBootUtil.getActiveProfiles(strActiveProfiles)); - - //TODO SK - do we need to handle the parsin of port properties like ${PORT:1234} + Properties properties = getSpringBootProperties(); + //TODO SK - do we need to handle the parsing of port properties like ${PORT:1234} String port = properties.getProperty(SpringBootProperties.SERVER_PORT, DEFAULT_SERVER_PORT); addPortIfValid(answer, getConfig(JavaExecGenerator.Config.webPort, port)); @@ -144,10 +141,7 @@ protected List extractPorts() { // ============================================================================= private void ensureSpringDevToolSecretToken() throws MojoExecutionException { - String strActiveProfiles = getConfig(activeProfiles); - - Properties properties = SpringBootUtil.getApplicationProperties(getContext().getProject(), - SpringBootUtil.getActiveProfiles(strActiveProfiles)); + Properties properties = getSpringBootProperties(); String remoteSecret = properties.getProperty(DEV_TOOLS_REMOTE_SECRET); if (Strings.isNullOrEmpty(remoteSecret)) { addSecretTokenToApplicationProperties(); @@ -295,6 +289,15 @@ private boolean isSpringBootRepackage() { return false; } + private Properties getSpringBootProperties() { + try { + String strActiveProfiles = getContext().getConfig().getConfig("spring-boot", "activeProfiles"); + return SpringBootUtil.getApplicationProperties(getProject(), strActiveProfiles); + } catch (IOException e) { + throw new IllegalStateException("Failed to load Spring Boot properties", e); + } + } + private File getSpringBootDevToolsJar() throws IOException { String version = SpringBootUtil.getSpringBootDevToolsVersion(getProject()); if (version == null) { diff --git a/parent/pom.xml b/parent/pom.xml index c3f5288d7a..e0d8d27dce 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -66,6 +66,7 @@ 0.7.8 2.2.215 2.3.1 + 1.5.3.RELEASE 0.0.13 0.21.0 diff --git a/watcher/standard/src/main/java/io/fabric8/maven/watcher/standard/SpringBootWatcher.java b/watcher/standard/src/main/java/io/fabric8/maven/watcher/standard/SpringBootWatcher.java index 1a71b2aa63..11e1f74938 100644 --- a/watcher/standard/src/main/java/io/fabric8/maven/watcher/standard/SpringBootWatcher.java +++ b/watcher/standard/src/main/java/io/fabric8/maven/watcher/standard/SpringBootWatcher.java @@ -159,7 +159,12 @@ private void runRemoteSpringApplication(String url) { log.info("Running RemoteSpringApplication against endpoint: " + url); String strActiveProfiles = getContext().getConfig().getConfig("spring-boot", "activeProfiles"); - Properties properties = SpringBootUtil.getApplicationProperties(getContext().getProject(), strActiveProfiles); + Properties properties = null; + try { + properties = SpringBootUtil.getApplicationProperties(getContext().getProject(), strActiveProfiles); + } catch (IOException e) { + throw new IllegalStateException("Failed to load Spring Boot properties",e); + } String remoteSecret = properties.getProperty(DEV_TOOLS_REMOTE_SECRET, System.getProperty(DEV_TOOLS_REMOTE_SECRET)); if (Strings.isNullOrBlank(remoteSecret)) {