This repository was archived by the owner on Jun 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 199
Handle Spring Boot Profiles #955
Open
kameshsampath
wants to merge
4
commits into
fabric8io:master
Choose a base branch
from
kameshsampath:spring-boot/issue-880
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
c587d49
Added extra config to spring boot generator to handle spring boot pro…
kameshsampath e27270b
Refactor:
kameshsampath 5d1ba17
Added dummy spring boot application
kameshsampath 942d031
Revert Commit which introducer spring-boot dependency
rhuss File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
core/src/main/java/io/fabric8/maven/core/util/DummySpringBootApplication.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (c) 2016 Red Hat, Inc. | ||
| * | ||
| * Red Hat licenses this file to you 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 io.fabric8.maven.core.util; | ||
|
|
||
| /** | ||
| * @author kameshs | ||
| */ | ||
| public class DummySpringBootApplication { | ||
| public static void main(String[] args) { | ||
| //nothing here... | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,21 +16,18 @@ | |
|
|
||
| package io.fabric8.maven.core.util; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.net.URL; | ||
| import java.net.URLClassLoader; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
| import java.util.Properties; | ||
| import java.util.SortedMap; | ||
|
|
||
| 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 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. | ||
|
|
@@ -39,17 +36,33 @@ public class SpringBootUtil { | |
|
|
||
| private static final transient Logger LOG = LoggerFactory.getLogger(SpringBootUtil.class); | ||
|
|
||
| /** | ||
| * This method computes the active profiles and delegate the call to the getApplicationProperties method | ||
| * | ||
| * @param project - the {@link MavenProject} | ||
| * @param activeProfiles - the comma separated String of profiles | ||
| * @return properties - the merged properties of all profiles | ||
| */ | ||
| public static Properties getApplicationProperties(MavenProject project, String activeProfiles) { | ||
| return getApplicationProperties(project, getActiveProfiles(activeProfiles)); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the spring boot configuration (supports `application.properties` and `application.yml`) | ||
| * or an empty properties object if not found | ||
| */ | ||
| public static Properties getSpringBootApplicationProperties(MavenProject project) { | ||
| public static Properties getApplicationProperties(MavenProject project, List<String> activeProfiles) { | ||
| URLClassLoader compileClassLoader = MavenUtil.getCompileClassLoader(project); | ||
| URL ymlResource = compileClassLoader.findResource("application.yml"); | ||
| URL propertiesResource = compileClassLoader.findResource("application.properties"); | ||
|
|
||
| Properties props = getPropertiesFromYamlResource(ymlResource); | ||
| props.putAll(getPropertiesResource(propertiesResource)); | ||
| Properties props = new Properties(); | ||
| addApplicationProperties(activeProfiles, compileClassLoader, props, null); | ||
|
|
||
| //If the profiles are available load the profile resources as well | ||
| if (activeProfiles != null) { | ||
| for (String profile : activeProfiles) { | ||
| addApplicationProperties(activeProfiles, compileClassLoader, props, profile); | ||
| } | ||
| } | ||
| return props; | ||
| } | ||
|
|
||
|
|
@@ -68,7 +81,7 @@ public static Properties getPropertiesFile(MavenProject project, String properti | |
| protected static Properties getPropertiesResource(URL resource) { | ||
| Properties answer = new Properties(); | ||
| if (resource != null) { | ||
| try(InputStream stream = resource.openStream()) { | ||
| try (InputStream stream = resource.openStream()) { | ||
| answer.load(stream); | ||
| } catch (IOException e) { | ||
| throw new IllegalStateException("Error while reading resource from URL " + resource, e); | ||
|
|
@@ -80,25 +93,79 @@ protected static Properties getPropertiesResource(URL resource) { | |
| /** | ||
| * 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) { | ||
| public static Properties getPropertiesFromYamlFile(MavenProject project, String yamlFileName, | ||
| List<String> activeProfiles) { | ||
| URLClassLoader compileClassLoader = MavenUtil.getCompileClassLoader(project); | ||
| URL resource = compileClassLoader.findResource(yamlFileName); | ||
| return getPropertiesFromYamlResource(resource); | ||
| return getPropertiesFromYamlResource(resource, activeProfiles); | ||
| } | ||
|
|
||
| /** | ||
| * 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) { | ||
| protected static Properties getPropertiesFromYamlResource(URL resource, List<String> activeProfiles) { | ||
| if (resource != null) { | ||
| try (InputStream yamlStream = resource.openStream()) { | ||
| Yaml yaml = new Yaml(); | ||
| @SuppressWarnings("unchecked") | ||
| SortedMap<String, Object> source = yaml.loadAs(yamlStream, SortedMap.class); | ||
| Yaml yaml = new Yaml(new SafeConstructor()); | ||
|
|
||
| Map<String, Map> profileDocs = new HashMap<>(); | ||
|
|
||
| Properties properties = new Properties(); | ||
| if (source != null) { | ||
| properties.putAll(getFlattenedMap(source)); | ||
|
|
||
| Iterable<Object> 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); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't you have to add an entry for every profile ? (not only a single entry for the comma separated list, which is not even normalized)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no thats taken care by previous block, this in case where the yaml has only one doc so ideally we will have only one profile.. i hope my understanding is right |
||
| } | ||
| } else if (docCount == 0) { | ||
| //the root doc | ||
| profileDocs.put("default", docRoot); | ||
| } | ||
|
|
||
| docCount++; | ||
| } | ||
|
|
||
| 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); | ||
|
|
@@ -117,9 +184,8 @@ public static String getSpringBootDevToolsVersion(MavenProject mavenProject) { | |
| /** | ||
| * Determine the spring-boot major version for the current project | ||
| */ | ||
| public static String getSpringBootVersion(MavenProject mavenProject) { | ||
| return MavenUtil.getDependencyVersion(mavenProject, SpringBootConfigurationHelper.SPRING_BOOT_GROUP_ID, SpringBootConfigurationHelper.SPRING_BOOT_ARTIFACT_ID); | ||
| } | ||
| public static String getSpringBootVersion(MavenProject mavenProject) {return MavenUtil.getDependencyVersion(mavenProject, SpringBootConfigurationHelper.SPRING_BOOT_GROUP_ID, | ||
| SpringBootConfigurationHelper.SPRING_BOOT_ARTIFACT_ID);} | ||
|
|
||
| /** | ||
| * Build a flattened representation of the Yaml tree. The conversion is compliant with the spring-boot rules. | ||
|
|
@@ -134,35 +200,81 @@ private static Map<String, Object> getFlattenedMap(Map<String, Object> source) { | |
| private static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) { | ||
| for (Map.Entry<String, Object> entry : source.entrySet()) { | ||
| String key = entry.getKey(); | ||
| if (path !=null && path.trim().length()>0) { | ||
| if (path != null && path.trim().length() > 0) { | ||
| if (key.startsWith("[")) { | ||
| key = path + key; | ||
| } | ||
| else { | ||
| } else { | ||
| key = path + "." + key; | ||
| } | ||
| } | ||
| Object value = entry.getValue(); | ||
| if (value instanceof String) { | ||
| result.put(key, value); | ||
| } | ||
| else if (value instanceof Map) { | ||
| } else if (value instanceof Map) { | ||
|
|
||
| Map<String, Object> map = (Map<String, Object>) value; | ||
| buildFlattenedMap(result, map, key); | ||
| } | ||
| else if (value instanceof Collection) { | ||
| } else if (value instanceof Collection) { | ||
| Collection<Object> collection = (Collection<Object>) value; | ||
| int count = 0; | ||
| for (Object object : collection) { | ||
| buildFlattenedMap(result, | ||
| Collections.singletonMap("[" + (count++) + "]", object), key); | ||
| } | ||
| } | ||
| else { | ||
| } else { | ||
| result.put(key, (value != null ? value : "")); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static List<String> getActiveProfiles(String strActiveProfiles) { | ||
| List<String> activeProfiles = new ArrayList<>(); | ||
| if (strActiveProfiles != null) { | ||
| activeProfiles = Arrays.asList(strActiveProfiles.split("\\s*,\\s*")); | ||
| } | ||
| return activeProfiles; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Utility method to find classpath resource | ||
| * | ||
| * @param compileClassLoader - the classloader to search resource for | ||
| * @param resourceName - the name of the resource | ||
| * @return URL of the resource | ||
| */ | ||
| private static URL getResourceFromClasspath(URLClassLoader compileClassLoader, String resourceName) { | ||
| URL urlResource = compileClassLoader.findResource(resourceName); | ||
| return urlResource; | ||
| } | ||
|
|
||
| /** | ||
| * 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 | ||
| */ | ||
| private static void addApplicationProperties(List<String> activeProfiles, URLClassLoader compileClassLoader, | ||
| Properties mergedProperties, String profile) { | ||
| URL ymlResource; | ||
| URL propertiesResource; | ||
| Properties profileProperties; | ||
|
|
||
| if (profile == null) { | ||
| ymlResource = compileClassLoader.findResource("application.yml"); | ||
| propertiesResource = compileClassLoader.findResource("application.properties"); | ||
| mergedProperties = getPropertiesFromYamlResource(ymlResource, activeProfiles); | ||
| mergedProperties.putAll(getPropertiesResource(propertiesResource)); | ||
| } else { | ||
| ymlResource = compileClassLoader.findResource("application-" + profile + ".yml"); | ||
| profileProperties = getPropertiesFromYamlResource(ymlResource, activeProfiles); | ||
| propertiesResource = getResourceFromClasspath(compileClassLoader, | ||
| "application-" + profile + ".properties"); | ||
| profileProperties.putAll(getPropertiesResource(propertiesResource)); | ||
| mergedProperties.putAll(profileProperties); | ||
| } | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If profiles can take multiple values, why do you split it here then ? And couldn't it be that
profilescould be also a list ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaiu
activeProfilesis a cascading mechanism where the profiles later in the list override the former.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's about
spring.profiles.include?