From ca1b6b1c41046157029ed757415367adc0589361 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 6 May 2018 15:30:49 -0600 Subject: [PATCH 01/35] add templates --- CODE_OF_CONDUCT.md | 46 +++++++++ ISSUE_TEMPLATE.md | 10 ++ LICENSE | 201 +++++++++++++++++++++++++++++++++++++++ PULL_REQUEST_TEMPLATE.md | 10 ++ pom.xml | 5 + 5 files changed, 272 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 ISSUE_TEMPLATE.md create mode 100644 LICENSE create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ea1931e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at piszmogcode@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..937c25f --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,10 @@ +### Issue Description + + +### Steps to Reproduce + + +### Expected Behavior + + +### Acceptance Criteria diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..45cb439 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Kuglblitz + + 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. diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..a21cec2 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,10 @@ +### Changes Description + + +### Associated Issues + + +### Affected Files + + +### Unit Tests Changed or Added diff --git a/pom.xml b/pom.xml index 808f3e3..cf32ca0 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,11 @@ spring-cloud-services-starter-config-client provided + + + org.springframework.boot + spring-boot-test-autoconfigure + From 979ec0946d79d3dfe25d71e3cf668c4018d201ab Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 6 May 2018 15:33:03 -0600 Subject: [PATCH 02/35] update pom --- pom.xml | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/pom.xml b/pom.xml index cf32ca0..950dba4 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ cloud-config-client-autoconfig Auto Configuration for creating Config Clients + https://github.com/Piszmog/cloud-config-client-autoconfig @@ -30,6 +31,9 @@ 1.8 3.7.0 + + 1.5 + 1.6.7 1.5.0.RELEASE 1.5.12.RELEASE @@ -98,8 +102,72 @@ ${java.version} + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven-gpg-plugin.version} + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + true + + ossrh + https://oss.sonatype.org/ + true + + + + + + + @@ -134,7 +202,17 @@ Piszmog piszmogcode@gmail.com + https://github.com/Piszmog/cloud-config-client-autoconfig + + + + + + scm:git:git://github.com/Piszmog/cloud-config-client-autoconfig.git + scm:git:ssh://github.com/Piszmog/cloud-config-client-autoconfig.git + https://github.com/Piszmog/cloud-config-client-autoconfig/tree/master + From 129a8e6faceb6d1b08bf108fc0fc0973ab8cb303 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Tue, 8 May 2018 19:52:35 -0600 Subject: [PATCH 03/35] fix autoconfigurations --- pom.xml | 8 +------- .../client/ConfigClientAutoConfiguration.java | 10 +++++----- .../template/LocalConfigTemplateAutoConfiguration.java | 2 -- .../OAuth2ConfigTemplateAutoConfiguration.java | 2 +- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/pom.xml b/pom.xml index 950dba4..2cc276f 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 1.5.0.RELEASE 1.5.12.RELEASE - 1.0-SNAPSHOT + 1.0 @@ -50,18 +50,12 @@ io.github.piszmog cloud-config-client ${cloud-config-client.version} - true io.pivotal.spring.cloud spring-cloud-services-starter-config-client provided - - - org.springframework.boot - spring-boot-test-autoconfigure - diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java index 68e3d79..5b7d52f 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java @@ -1,13 +1,11 @@ package io.github.piszmog.cloudconfigclient.autoconfig.client; -import io.github.piszmog.cloudconfig.client.ConfigClient; import io.github.piszmog.cloudconfig.client.impl.DecryptConfigClient; import io.github.piszmog.cloudconfig.client.impl.EncryptConfigClient; import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfig.client.impl.PublicKeyClient; import io.github.piszmog.cloudconfig.template.ConfigTemplate; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,8 +15,6 @@ * Created by Piszmog on 5/5/2018 */ @Configuration -@ConditionalOnClass( ConfigClient.class ) -@ConditionalOnBean( ConfigTemplate.class ) public class ConfigClientAutoConfiguration { // ============================================================ @@ -32,6 +28,7 @@ public class ConfigClientAutoConfiguration * @return The decryption client. */ @Bean + @ConditionalOnProperty( prefix = "cloud.config.client", name = "decrypt.enabled", matchIfMissing = true ) public DecryptConfigClient decryptConfigClient( final ConfigTemplate configTemplate ) { return new DecryptConfigClient( configTemplate ); @@ -44,6 +41,7 @@ public DecryptConfigClient decryptConfigClient( final ConfigTemplate configTempl * @return The encryption client. */ @Bean + @ConditionalOnProperty( prefix = "cloud.config.client", name = "encrypt.enabled", matchIfMissing = true ) public EncryptConfigClient encryptConfigClient( final ConfigTemplate configTemplate ) { return new EncryptConfigClient( configTemplate ); @@ -56,6 +54,7 @@ public EncryptConfigClient encryptConfigClient( final ConfigTemplate configTempl * @return The file client. */ @Bean + @ConditionalOnProperty( prefix = "cloud.config.client", name = "file.enabled", matchIfMissing = true ) public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) { return new FileConfigClient( configTemplate ); @@ -68,6 +67,7 @@ public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) * @return The public key client. */ @Bean + @ConditionalOnProperty( prefix = "cloud.config.client", name = "publickey.enabled", matchIfMissing = true ) public PublicKeyClient publicKeyClient( final ConfigTemplate configTemplate ) { return new PublicKeyClient( configTemplate ); diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 8608e5c..4dcb269 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -3,7 +3,6 @@ import io.github.piszmog.cloudconfig.template.ConfigTemplate; import io.github.piszmog.cloudconfig.template.impl.LocalConfigTemplate; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.cloud.config.client.ConfigClientProperties; @@ -16,7 +15,6 @@ * Created by Piszmog on 5/5/2018 */ @Configuration -@ConditionalOnClass( ConfigTemplate.class ) @ConditionalOnBean( ConfigClientProperties.class ) @ConditionalOnMissingClass( "org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails" ) public class LocalConfigTemplateAutoConfiguration diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index c28faea..5ed3cf4 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -16,7 +16,7 @@ * Created by Piszmog on 5/5/2018 */ @Configuration -@ConditionalOnClass( { ConfigTemplate.class, OAuth2ProtectedResourceDetails.class } ) +@ConditionalOnClass( { OAuth2ProtectedResourceDetails.class } ) @ConditionalOnBean( ConfigClientProperties.class ) public class OAuth2ConfigTemplateAutoConfiguration { From d399a0767a1eb478f8f4a16f0299e58e6304d532 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Tue, 8 May 2018 20:40:55 -0600 Subject: [PATCH 04/35] add readme and add conditionals --- README.md | 45 +++++++++++++++++++ .../LocalConfigTemplateAutoConfiguration.java | 1 + ...OAuth2ConfigTemplateAutoConfiguration.java | 4 +- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..66feb2b --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Config Server Commons + +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.piszmog/cloud-config-client-autoconfig/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.github.piszmog/cloud-config-client-autoconfig) + +## Description +Spring Auto-configuration library for [Cloud Config Client](https://github.com/Piszmog/cloud-config-client). + +Creates Spring Beans for `DecryptConfigClient`, `EncryptConfigClient`, `FileConfigClient`, and `PublicKeyClient`. Simply +inject the beans where needed. + +## Usage +To use, add the following as a dependency, + +```xml + + io.github.piszmog + cloud-config-client-autoconfig + #{cloud-config-client-autoconfig.version} + +``` + +### Local Config Server +Local Config Server is considered a locally running application setup as a Config Server. +(see [Spring Config Server](https://github.com/spring-cloud/spring-cloud-config/tree/master/spring-cloud-config-server)). + +### Spring Cloud Config Server (PCF) +When deploying applications to PCF, a Config Server service can be created to. Once created, +applications deployed to the space can bind to the service. + +### Disabling Clients +To disable any of the clients, add the following to the application's configuration file. + +```yaml +cloud: + config: + client: + decrypt: + enabled: false + encrypt: + enabled: false + file: + enabled: false + publickey: + enabled: false +``` \ No newline at end of file diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 4dcb269..5c37872 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -16,6 +16,7 @@ */ @Configuration @ConditionalOnBean( ConfigClientProperties.class ) +@ConditionalOnMissingBean( type = "org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails" ) @ConditionalOnMissingClass( "org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails" ) public class LocalConfigTemplateAutoConfiguration { diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index 5ed3cf4..c513b65 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -16,8 +16,8 @@ * Created by Piszmog on 5/5/2018 */ @Configuration -@ConditionalOnClass( { OAuth2ProtectedResourceDetails.class } ) -@ConditionalOnBean( ConfigClientProperties.class ) +@ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) +@ConditionalOnBean( { ConfigClientProperties.class, OAuth2ProtectedResourceDetails.class } ) public class OAuth2ConfigTemplateAutoConfiguration { // ============================================================ From 507f0a244bcf9e4f6404b75cd6a4b4e4b4398c5c Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 20 May 2018 13:22:42 -0600 Subject: [PATCH 05/35] release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2cc276f..607a26f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.0-SNAPSHOT + 1.0 jar From 3e3b55308c5bbdb5fb57a0cdf4fd1e44bb287aba Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 20 May 2018 13:25:29 -0600 Subject: [PATCH 06/35] up to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 607a26f..6b5aaa9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.0 + 1.1-SNAPSHOT jar From f410c46afd3e1e2df9e9e23daaee080a435a6649 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sat, 21 Jul 2018 20:47:50 -0600 Subject: [PATCH 07/35] initial commit for pulling down json files --- pom.xml | 12 +++- .../client/ConfigClientAutoConfiguration.java | 3 + .../autoconfig/env/ApplicationJsonConfig.java | 20 ++++++ .../env/ApplicationJsonException.java | 60 +++++++++++++++++ .../env/ApplicationJsonLocator.java | 65 +++++++++++++++++++ .../env/ApplicationResourceInitializer.java | 63 ++++++++++++++++++ .../autoconfig/env/model/ApplicationFile.java | 16 +++++ ...itional-spring-configuration-metadata.json | 39 +++++++++++ src/main/resources/META-INF/spring.factories | 8 ++- 9 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java create mode 100644 src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/pom.xml b/pom.xml index 6b5aaa9..a4c97ac 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 1.5.0.RELEASE 1.5.12.RELEASE - 1.0 + 1.1-SNAPSHOT @@ -51,6 +51,16 @@ cloud-config-client ${cloud-config-client.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-properties + 2.9.6 + + + org.springframework.boot + spring-boot-configuration-processor + true + io.pivotal.spring.cloud spring-cloud-services-starter-config-client diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java index 5b7d52f..144cae8 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java @@ -8,6 +8,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; /** * Auto-configurations for creating config clients. diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java new file mode 100644 index 0000000..51db0f4 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java @@ -0,0 +1,20 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Created by Piszmog on 7/21/2018 + */ +@Configuration +public class ApplicationJsonConfig +{ + @Bean + public ApplicationJsonLocator locator( final FileConfigClient fileConfigClient ) + { + return new ApplicationJsonLocator( fileConfigClient ); + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java new file mode 100644 index 0000000..f18ebe3 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java @@ -0,0 +1,60 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +/** + * Exception thrown when an error occurs when operating on the config server. + *

+ * Created by Piszmog on 5/5/2018 + */ +public class ApplicationJsonException extends RuntimeException +{ + /** + * Creates a new config exception. + */ + public ApplicationJsonException() + { + } + + /** + * Creates a new config exception. + * + * @param message the message associated with the exception + */ + public ApplicationJsonException( final String message ) + { + super( message ); + } + + /** + * Creates a new config exception. + * + * @param message the message associated with the exception + * @param cause the cause of th exception + */ + public ApplicationJsonException( final String message, final Throwable cause ) + { + super( message, cause ); + } + + /** + * Creates a new config exception. + * + * @param cause the cause of th exception + */ + public ApplicationJsonException( final Throwable cause ) + { + super( cause ); + } + + /** + * Creates a new config exception. + * + * @param message the message associated with the exception + * @param cause the cause of th exception + * @param enableSuppression determines if suppression is enabled + * @param writableStackTrace determines if the stack is writeable + */ + public ApplicationJsonException( final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace ) + { + super( message, cause, enableSuppression, writableStackTrace ); + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java new file mode 100644 index 0000000..2838ddf --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java @@ -0,0 +1,65 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper; +import io.github.piszmog.cloudconfig.ConfigException; +import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; +import io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * Created by Piszmog on 7/21/2018 + */ +public class ApplicationJsonLocator +{ + private final JavaPropsMapper mapper = new JavaPropsMapper(); + private final FileConfigClient fileConfigClient; + + public ApplicationJsonLocator( final FileConfigClient fileConfigClient ) + { + this.fileConfigClient = fileConfigClient; + } + + public PropertySource locate( final List applicationFiles ) + { + CompositePropertySource composite = new CompositePropertySource( "applicationJson" ); + for ( ApplicationFile applicationFile : applicationFiles ) + { + final String directoryPath = applicationFile.getDirectoryPath(); + final String fileName = applicationFile.getFileName(); + getJsonConfiguration( composite, directoryPath, fileName ); + } + return composite; + } + + private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final String fileName ) + { + final Map map = new HashMap<>(); + try + { + final Map file = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); + final Properties properties = mapper.writeValueAsProperties( file ); + for ( Map.Entry entry : properties.entrySet() ) + { + final String key = (String) entry.getKey(); + final Object value = entry.getValue(); + map.put( key, value ); + } + } + catch ( ConfigException | IOException e ) + { + throw new ApplicationJsonException( "Failed to load the application JSON configuration.", e ); + } + if ( !map.isEmpty() ) + { + composite.addPropertySource( new MapPropertySource( directoryPath + "/" + fileName, map ) ); + } + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java new file mode 100644 index 0000000..64ec0a8 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java @@ -0,0 +1,63 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Piszmog on 7/21/2018 + */ +@Configuration +public class ApplicationResourceInitializer implements ApplicationContextInitializer, + Ordered +{ + private ApplicationJsonLocator applicationJsonLocator; + + @Autowired + public void setApplicationJsonLocator( final ApplicationJsonLocator applicationJsonLocator ) + { + this.applicationJsonLocator = applicationJsonLocator; + } + + @Override + public void initialize( final ConfigurableApplicationContext applicationContext ) + { + final ConfigurableEnvironment environment = applicationContext.getEnvironment(); + final Boolean isEnabled = environment.getProperty( "cloud.config.resource.enabled", Boolean.class ); + if ( BooleanUtils.toBoolean( isEnabled ) ) + { + final List applicationFiles = new ArrayList<>(); + for ( int i = 0; i < 1000; i++ ) + { + final String directory = environment.getProperty( "cloud.config.resource.files[" + i + "].directoryPath" ); + final String fileName = environment.getProperty( "cloud.config.resource.files[" + i + "].fileName" ); + if ( StringUtils.isBlank( directory ) || StringUtils.isBlank( fileName ) ) + { + break; + } + final ApplicationFile applicationFile = new ApplicationFile(); + applicationFile.setDirectoryPath( directory ); + applicationFile.setFileName( fileName ); + applicationFiles.add( applicationFile ); + } + final PropertySource propertySource = applicationJsonLocator.locate( applicationFiles ); + environment.getPropertySources().addFirst( propertySource ); + } + } + + @Override + public int getOrder() + { + return LOWEST_PRECEDENCE; + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java new file mode 100644 index 0000000..3829ac2 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java @@ -0,0 +1,16 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env.model; + +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * Created by Piszmog on 7/21/2018 + */ +@Data +public class ApplicationFile +{ + @NotBlank( message = "Directory Path must not be null or blank." ) + private String directoryPath; + @NotBlank( message = "File name must not be null or blank." ) + private String fileName; +} diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..76685ef --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,39 @@ +{ + "groups": [], + "properties": [ + { + "name": "cloud.config.resource.files", + "description": "The list of resources to load in addition to the application configurations.", + "type": "io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile" + }, + { + "name": "cloud.config.resource.enabled", + "description": "Determines if the application should lod the specified files.", + "type": "java.lang.Boolean" + }, + { + "name": "cloud.config.client.decrypt.enabled", + "defaultValue": true, + "description": "Determines if the decrypt client bean should be created.", + "type": "java.lang.Boolean" + }, + { + "name": "cloud.config.client.encrypt.enabled", + "defaultValue": true, + "description": "Determines if the encrypt client bean should be created.", + "type": "java.lang.Boolean" + }, + { + "name": "cloud.config.client.file.enabled", + "defaultValue": true, + "description": "Determines if the file client bean should be created.", + "type": "java.lang.Boolean" + }, + { + "name": "cloud.config.client.publickey.enabled", + "defaultValue": true, + "description": "Determines if the publickey client bean should be created..", + "type": "java.lang.Boolean" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index 4235807..c9af97c 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,4 +1,6 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ApplicationJsonConfig,\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ApplicationResourceInitializer,\ + io.github.piszmog.cloudconfigclient.autoconfig.client.ConfigClientAutoConfiguration,\ io.github.piszmog.cloudconfigclient.autoconfig.template.OAuth2ConfigTemplateAutoConfiguration,\ - io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateAutoConfiguration,\ - io.github.piszmog.cloudconfigclient.autoconfig.client.ConfigClientAutoConfiguration \ No newline at end of file + io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateAutoConfiguration From 458e8fd26048f099f588de3aede1006f3a876bc2 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 22 Jul 2018 11:11:47 -0600 Subject: [PATCH 08/35] refactor initializer and update readme and add unit tests --- README.md | 47 ++- pom.xml | 39 +- .../client/ConfigClientAutoConfiguration.java | 23 +- .../autoconfig/env/ApplicationJsonConfig.java | 20 -- .../env/ApplicationJsonLocator.java | 65 ---- .../env/ApplicationResourceInitializer.java | 63 ---- .../env/ConfigPropertySourceLocator.java | 117 ++++++ ...tion.java => ConfigResourceException.java} | 24 +- .../env/ConfigResourceInitializer.java | 118 +++++++ .../autoconfig/env/ResourceConfig.java | 48 +++ .../autoconfig/env/model/ApplicationFile.java | 16 - .../autoconfig/env/model/Resource.java | 21 ++ ...itional-spring-configuration-metadata.json | 11 +- src/main/resources/META-INF/spring.factories | 7 +- .../ConfigPropertySourceLocatorSpec.groovy | 123 +++++++ .../env/ConfigResourceInitializerSpec.groovy | 334 ++++++++++++++++++ 16 files changed, 868 insertions(+), 208 deletions(-) delete mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java delete mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java delete mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java rename src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/{ApplicationJsonException.java => ConfigResourceException.java} (53%) create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java delete mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java create mode 100644 src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocatorSpec.groovy create mode 100644 src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy diff --git a/README.md b/README.md index 66feb2b..bb66923 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To use, add the following as a dependency, io.github.piszmog cloud-config-client-autoconfig - #{cloud-config-client-autoconfig.version} + ${cloud-config-client-autoconfig.version} ``` @@ -42,4 +42,47 @@ cloud: enabled: false publickey: enabled: false -``` \ No newline at end of file +``` + +### Loading Files +`FileConfigClient` bean allows for the ability to pull down files either from a specified branch or from the default branch. + +If pulling from the default branch, files __must__ be located in a subdirectory. + +## Adding JSON Files are Property Sources +The Config Server Client will only pull down `.properties` and `.yml`/`.yaml` files for an application's configuration (property sources). As +more microservices move to _code by configuration_, these files can get very large and hard to maintain. Splitting configurations +out into JSON files that do not need to follow the Config Server's [naming convention](https://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.1.RELEASE/#_quick_start) +can help to better organize an application configuration. + +Leveraging the `FileConfigClient` bean, JSON files can be loaded as property sources. This allows for `ConfigurationProperties` +to have JSON values be injected into their fields. + +To add a JSON file as a property source, update the application configuration to have the following, +```yaml +cloud: + config: + client: + file: + resources: + - directory: + files: + - + - + ... + - directory: + files: + - + - + ... + ... +``` + +Where, +- `` is the directory path to the following files -- example `nonprod/example` or `configs` + - Sub-directory __must__ not be `null` or blank. +- `` is the JSON file to load that is located in the specified sub-directory + +### Specifying Configuration +Adding JSON files to be property sources can either be done in the `bootstrap.yml` (embedded with the application), in an embedded +application configuration, or in the Config Server. \ No newline at end of file diff --git a/pom.xml b/pom.xml index a4c97ac..f9f50ab 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,12 @@ 1.5.0.RELEASE 1.5.12.RELEASE - 1.1-SNAPSHOT + 1.1 + 2.9.6 + + 3.2.6 + 2.5.1 + 1.6.5 @@ -54,7 +59,7 @@ com.fasterxml.jackson.dataformat jackson-dataformat-properties - 2.9.6 + ${jackson-dataformat-properties.version} org.springframework.boot @@ -66,6 +71,36 @@ spring-cloud-services-starter-config-client provided + + + org.spockframework + spock-core + test + + + org.codehaus.groovy + groovy-all + test + + + + net.bytebuddy + byte-buddy + ${byte-buddy.version} + test + + + org.objenesis + objenesis + ${objenesis.version} + test + + + cglib + cglib + ${cglib.version} + test + diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java index 144cae8..a08ef20 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/client/ConfigClientAutoConfiguration.java @@ -2,22 +2,24 @@ import io.github.piszmog.cloudconfig.client.impl.DecryptConfigClient; import io.github.piszmog.cloudconfig.client.impl.EncryptConfigClient; -import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfig.client.impl.PublicKeyClient; import io.github.piszmog.cloudconfig.template.ConfigTemplate; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; /** * Auto-configurations for creating config clients. *

+ * {@link io.github.piszmog.cloudconfig.client.impl.FileConfigClient} is required for loading JSON files from the Config + * Server. To add the JSON files as property sources, the client must be created before Spring has refreshed the + * context. + *

* Created by Piszmog on 5/5/2018 */ @Configuration +@ConditionalOnBean( ConfigTemplate.class ) public class ConfigClientAutoConfiguration { // ============================================================ @@ -50,19 +52,6 @@ public EncryptConfigClient encryptConfigClient( final ConfigTemplate configTempl return new EncryptConfigClient( configTemplate ); } - /** - * Create a file client. - * - * @param configTemplate the config template - * @return The file client. - */ - @Bean - @ConditionalOnProperty( prefix = "cloud.config.client", name = "file.enabled", matchIfMissing = true ) - public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) - { - return new FileConfigClient( configTemplate ); - } - /** * Create a public key client. * diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java deleted file mode 100644 index 51db0f4..0000000 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.piszmog.cloudconfigclient.autoconfig.env; - -import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by Piszmog on 7/21/2018 - */ -@Configuration -public class ApplicationJsonConfig -{ - @Bean - public ApplicationJsonLocator locator( final FileConfigClient fileConfigClient ) - { - return new ApplicationJsonLocator( fileConfigClient ); - } -} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java deleted file mode 100644 index 2838ddf..0000000 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonLocator.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.piszmog.cloudconfigclient.autoconfig.env; - -import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper; -import io.github.piszmog.cloudconfig.ConfigException; -import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; -import io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile; -import org.springframework.core.env.CompositePropertySource; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -/** - * Created by Piszmog on 7/21/2018 - */ -public class ApplicationJsonLocator -{ - private final JavaPropsMapper mapper = new JavaPropsMapper(); - private final FileConfigClient fileConfigClient; - - public ApplicationJsonLocator( final FileConfigClient fileConfigClient ) - { - this.fileConfigClient = fileConfigClient; - } - - public PropertySource locate( final List applicationFiles ) - { - CompositePropertySource composite = new CompositePropertySource( "applicationJson" ); - for ( ApplicationFile applicationFile : applicationFiles ) - { - final String directoryPath = applicationFile.getDirectoryPath(); - final String fileName = applicationFile.getFileName(); - getJsonConfiguration( composite, directoryPath, fileName ); - } - return composite; - } - - private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final String fileName ) - { - final Map map = new HashMap<>(); - try - { - final Map file = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); - final Properties properties = mapper.writeValueAsProperties( file ); - for ( Map.Entry entry : properties.entrySet() ) - { - final String key = (String) entry.getKey(); - final Object value = entry.getValue(); - map.put( key, value ); - } - } - catch ( ConfigException | IOException e ) - { - throw new ApplicationJsonException( "Failed to load the application JSON configuration.", e ); - } - if ( !map.isEmpty() ) - { - composite.addPropertySource( new MapPropertySource( directoryPath + "/" + fileName, map ) ); - } - } -} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java deleted file mode 100644 index 64ec0a8..0000000 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationResourceInitializer.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.piszmog.cloudconfigclient.autoconfig.env; - -import io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.PropertySource; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Piszmog on 7/21/2018 - */ -@Configuration -public class ApplicationResourceInitializer implements ApplicationContextInitializer, - Ordered -{ - private ApplicationJsonLocator applicationJsonLocator; - - @Autowired - public void setApplicationJsonLocator( final ApplicationJsonLocator applicationJsonLocator ) - { - this.applicationJsonLocator = applicationJsonLocator; - } - - @Override - public void initialize( final ConfigurableApplicationContext applicationContext ) - { - final ConfigurableEnvironment environment = applicationContext.getEnvironment(); - final Boolean isEnabled = environment.getProperty( "cloud.config.resource.enabled", Boolean.class ); - if ( BooleanUtils.toBoolean( isEnabled ) ) - { - final List applicationFiles = new ArrayList<>(); - for ( int i = 0; i < 1000; i++ ) - { - final String directory = environment.getProperty( "cloud.config.resource.files[" + i + "].directoryPath" ); - final String fileName = environment.getProperty( "cloud.config.resource.files[" + i + "].fileName" ); - if ( StringUtils.isBlank( directory ) || StringUtils.isBlank( fileName ) ) - { - break; - } - final ApplicationFile applicationFile = new ApplicationFile(); - applicationFile.setDirectoryPath( directory ); - applicationFile.setFileName( fileName ); - applicationFiles.add( applicationFile ); - } - final PropertySource propertySource = applicationJsonLocator.locate( applicationFiles ); - environment.getPropertySources().addFirst( propertySource ); - } - } - - @Override - public int getOrder() - { - return LOWEST_PRECEDENCE; - } -} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java new file mode 100644 index 0000000..c5e02a7 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -0,0 +1,117 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper; +import io.github.piszmog.cloudconfig.ConfigException; +import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; +import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * JSON property source locator. Locates the JSON files to be loaded as property sources. + *

+ * Created by Piszmog on 7/21/2018 + */ +public class ConfigPropertySourceLocator +{ + // ============================================================ + // Class Constants: + // ============================================================ + + private static final String PROPERTY_SOURCE_NAME = "jsonResource"; + + // ============================================================ + // Class Attributes: + // ============================================================ + + private final FileConfigClient fileConfigClient; + private final JavaPropsMapper mapper = new JavaPropsMapper(); + + // ============================================================ + // Constructors: + // ============================================================ + + /** + * Creates a new instance of the locator. + * + * @param fileConfigClient the file config client to load files from the config server. + */ + public ConfigPropertySourceLocator( final FileConfigClient fileConfigClient ) + { + this.fileConfigClient = fileConfigClient; + } + + // ============================================================ + // Public Methods: + // ============================================================ + + /** + * Locates the JSON resources to load as property sources. + * + * @param resources the resources to load + * @return The property source with the JSON resources loaded. + */ + public PropertySource locateConfigResources( final List resources ) + { + CompositePropertySource composite = new CompositePropertySource( PROPERTY_SOURCE_NAME ); + for ( Resource resource : resources ) + { + final String directoryPath = resource.getDirectory(); + final List files = resource.getFiles(); + getJsonConfiguration( composite, directoryPath, files ); + } + return composite; + } + + // ============================================================ + // Private Methods: + // ============================================================ + + private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final List files ) + { + final Map map = new HashMap<>(); + for ( String fileName : files ) + { + final String filePath = getFilePath( directoryPath, fileName ); + try + { + final Map file = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); + final Properties properties; + try + { + properties = mapper.writeValueAsProperties( file ); + } + catch ( IOException e ) + { + throw new ConfigResourceException( "Failed to convert " + filePath + " to properties format to be loaded in the property sources." ); + } + for ( Map.Entry entry : properties.entrySet() ) + { + final String key = (String) entry.getKey(); + final Object value = entry.getValue(); + map.put( key, value ); + } + } + catch ( ConfigException e ) + { + throw new ConfigResourceException( "Failed to load " + filePath, e ); + } + if ( !map.isEmpty() ) + { + composite.addPropertySource( new MapPropertySource( filePath, map ) ); + } + } + } + + private String getFilePath( final String directoryPath, final String fileName ) + { + return directoryPath + "/" + fileName; + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceException.java similarity index 53% rename from src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java rename to src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceException.java index f18ebe3..bcf6fed 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ApplicationJsonException.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceException.java @@ -1,59 +1,59 @@ package io.github.piszmog.cloudconfigclient.autoconfig.env; /** - * Exception thrown when an error occurs when operating on the config server. + * Exception thrown when an error occurs when loading configuration resource files. *

* Created by Piszmog on 5/5/2018 */ -public class ApplicationJsonException extends RuntimeException +public class ConfigResourceException extends RuntimeException { /** - * Creates a new config exception. + * Creates a new configuration resource exception. */ - public ApplicationJsonException() + public ConfigResourceException() { } /** - * Creates a new config exception. + * Creates a new configuration resource exception. * * @param message the message associated with the exception */ - public ApplicationJsonException( final String message ) + public ConfigResourceException( final String message ) { super( message ); } /** - * Creates a new config exception. + * Creates a new configuration resource exception. * * @param message the message associated with the exception * @param cause the cause of th exception */ - public ApplicationJsonException( final String message, final Throwable cause ) + public ConfigResourceException( final String message, final Throwable cause ) { super( message, cause ); } /** - * Creates a new config exception. + * Creates a new configuration resource exception. * * @param cause the cause of th exception */ - public ApplicationJsonException( final Throwable cause ) + public ConfigResourceException( final Throwable cause ) { super( cause ); } /** - * Creates a new config exception. + * Creates a new configuration resource exception. * * @param message the message associated with the exception * @param cause the cause of th exception * @param enableSuppression determines if suppression is enabled * @param writableStackTrace determines if the stack is writeable */ - public ApplicationJsonException( final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace ) + public ConfigResourceException( final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace ) { super( message, cause, enableSuppression, writableStackTrace ); } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java new file mode 100644 index 0000000..c99db83 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java @@ -0,0 +1,118 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; + +import java.util.ArrayList; +import java.util.List; + +/** + * If enabled and a list of resources to load exist, then the configuration resources are added as property sources. + *

+ * Only configuration file formats are accepted - .json + *

+ * Only loads the configuration files if {@code cloud.config.client.file.enabled} is true or missing and {@link + * ConfigPropertySourceLocator} bean was injected. + *

+ * Currently, the max size of files to load is set to {@code 1000}. It cannot be determined ahead of time what the + * actual size of the list is. + *

+ * Created by Piszmog on 7/21/2018 + */ +@Configuration +public class ConfigResourceInitializer implements ApplicationContextInitializer, Ordered +{ + // ============================================================ + // Class Constants: + // ============================================================ + + private static final String PROPERTY_FILE = "cloud.config.client.file"; + private static final String PROPERTY_ENABLED = PROPERTY_FILE + ".enabled"; + private static final int MAX_SIZE = 1000; + + // ============================================================ + // Class Attributes: + // ============================================================ + + private ConfigPropertySourceLocator configPropertySourceLocator; + + // ============================================================ + // Override Methods: + // ============================================================ + + @Override + public void initialize( final ConfigurableApplicationContext applicationContext ) + { + final ConfigurableEnvironment environment = applicationContext.getEnvironment(); + final String isEnabled = environment.getProperty( PROPERTY_ENABLED ); + if ( ( StringUtils.isBlank( isEnabled ) || BooleanUtils.toBoolean( isEnabled ) ) + && configPropertySourceLocator != null ) + { + final List resources = new ArrayList<>(); + for ( int i = 0; i < MAX_SIZE; i++ ) + { + final List files = new ArrayList<>(); + final String directory = environment.getProperty( PROPERTY_FILE + ".resources[" + i + "].directory" ); + for ( int j = 0; j < MAX_SIZE; j++ ) + { + final String fileName = environment.getProperty( PROPERTY_FILE + ".resources[" + i + "].files[" + j + "]" ); + if ( StringUtils.isBlank( fileName ) ) + { + break; + } + if ( StringUtils.isBlank( directory ) && StringUtils.isNotBlank( fileName ) ) + { + throw new ConfigResourceException( "Directory must not be null or blank when file is not blank or null." ); + } + if ( !StringUtils.endsWithIgnoreCase( fileName, ".json" ) ) + { + throw new ConfigResourceException( "File " + fileName + " is not a configuration file." + + " Only .json are accepted." ); + } + files.add( fileName ); + } + if ( StringUtils.isBlank( directory ) && files.isEmpty() ) + { + break; + } + final Resource resource = new Resource(); + resource.setDirectory( directory ); + resource.setFiles( files ); + resources.add( resource ); + } + if ( !resources.isEmpty() ) + { + final PropertySource propertySource = configPropertySourceLocator.locateConfigResources( resources ); + environment.getPropertySources().addFirst( propertySource ); + } + } + } + + @Override + public int getOrder() + { + // + // Want to let all other initializers go first. Potentially the config server needs to be loaded first + // before we can load the files. + // + return LOWEST_PRECEDENCE; + } + + // ============================================================ + // Public Methods: + // ============================================================ + + @Autowired( required = false ) + public void setConfigPropertySourceLocator( final ConfigPropertySourceLocator configPropertySourceLocator ) + { + this.configPropertySourceLocator = configPropertySourceLocator; + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java new file mode 100644 index 0000000..b64a53b --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java @@ -0,0 +1,48 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env; + +import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; +import io.github.piszmog.cloudconfig.template.ConfigTemplate; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Configuration for creating configuration resource beans. + *

+ * Created via {@link javax.validation.BootstrapConfiguration} so property sources can be loaded before Spring + * configuration properties are set up. + *

+ * Created by Piszmog on 7/21/2018 + */ +@Configuration +@ConditionalOnBean( ConfigServicePropertySourceLocator.class ) +public class ResourceConfig +{ + /** + * Create a file client. To disable, the property {@code cloud.config.client.file.enabled} must be set via bootstrap + * configuration. + * + * @param configTemplate the config template + * @return The file client. + */ + @Bean + @ConditionalOnProperty( prefix = "cloud.config.client", name = "file.enabled", matchIfMissing = true ) + public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) + { + return new FileConfigClient( configTemplate ); + } + + /** + * Creates a Configuration PropertySource Locator to finding config files to add to property sources. + * + * @param fileConfigClient the file config client to load files from the Config Server + * @return The locator. + */ + @Bean + public ConfigPropertySourceLocator configPropertySourceLocator( final FileConfigClient fileConfigClient ) + { + return new ConfigPropertySourceLocator( fileConfigClient ); + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java deleted file mode 100644 index 3829ac2..0000000 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/ApplicationFile.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.piszmog.cloudconfigclient.autoconfig.env.model; - -import lombok.Data; -import org.hibernate.validator.constraints.NotBlank; - -/** - * Created by Piszmog on 7/21/2018 - */ -@Data -public class ApplicationFile -{ - @NotBlank( message = "Directory Path must not be null or blank." ) - private String directoryPath; - @NotBlank( message = "File name must not be null or blank." ) - private String fileName; -} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java new file mode 100644 index 0000000..e04d358 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java @@ -0,0 +1,21 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env.model; + +import lombok.Data; + +import java.util.List; + +/** + * Object for containing information on the configuration resources to load. + *

+ * Created by Piszmog on 7/21/2018 + */ +@Data +public class Resource +{ + // ============================================================ + // Class Attributes: + // ============================================================ + + private String directory; + private List files; +} diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 76685ef..2681774 100644 --- a/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -2,14 +2,9 @@ "groups": [], "properties": [ { - "name": "cloud.config.resource.files", + "name": "cloud.config.client.file.resources", "description": "The list of resources to load in addition to the application configurations.", - "type": "io.github.piszmog.cloudconfigclient.autoconfig.env.model.ApplicationFile" - }, - { - "name": "cloud.config.resource.enabled", - "description": "Determines if the application should lod the specified files.", - "type": "java.lang.Boolean" + "type": "java.util.List" }, { "name": "cloud.config.client.decrypt.enabled", @@ -26,7 +21,7 @@ { "name": "cloud.config.client.file.enabled", "defaultValue": true, - "description": "Determines if the file client bean should be created.", + "description": "Determines if the file client bean should be created, and if JSON resources can be loaded.", "type": "java.lang.Boolean" }, { diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index c9af97c..59af3fb 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,6 +1,7 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + io.github.piszmog.cloudconfigclient.autoconfig.client.ConfigClientAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - io.github.piszmog.cloudconfigclient.autoconfig.env.ApplicationJsonConfig,\ - io.github.piszmog.cloudconfigclient.autoconfig.env.ApplicationResourceInitializer,\ - io.github.piszmog.cloudconfigclient.autoconfig.client.ConfigClientAutoConfiguration,\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ResourceConfig,\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ConfigResourceInitializer,\ io.github.piszmog.cloudconfigclient.autoconfig.template.OAuth2ConfigTemplateAutoConfiguration,\ io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateAutoConfiguration diff --git a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocatorSpec.groovy b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocatorSpec.groovy new file mode 100644 index 0000000..f8a55d8 --- /dev/null +++ b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocatorSpec.groovy @@ -0,0 +1,123 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env + +import io.github.piszmog.cloudconfig.client.impl.FileConfigClient +import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource +import spock.lang.Specification + +/** + * Created by Piszmog on 7/22/2018 + */ +class ConfigPropertySourceLocatorSpec extends Specification +{ + // ============================================================ + // Class Constants: + // ============================================================ + + private static final def JSON_FILE_CONTENTS = [ field: "value" ] + + // ============================================================ + // Class Attributes: + // ============================================================ + + private FileConfigClient fileConfigClient + + // ============================================================ + // Setup: + // ============================================================ + + def setup() + { + fileConfigClient = Stub( FileConfigClient ) + } + + // ============================================================ + // Tests: + // ============================================================ + + def "load a resource"() + { + given: "a configuration source locator" + def locator = new ConfigPropertySourceLocator( fileConfigClient ) + + and: "a resource to load with 1 file" + def resource = createResource( "directory", "file1.json" ) + + and: "files are found" + fileConfigClient.getFileFromDefaultBranch( _, _, _ ) >> JSON_FILE_CONTENTS + + when: "the locator looks for the resource" + def propertySource = locator.locateConfigResources( Collections.singletonList( resource ) ) + + then: "the file is converter to a properties object" + notThrown( ConfigResourceException ) + + and: "the property source contains the resource" + !propertySource.getProperties().isEmpty() + } + + def "load multiple resource files"() + { + given: "a configuration source locator" + def locator = new ConfigPropertySourceLocator( fileConfigClient ) + + and: "a resource to load with multiple files" + def resource = createResource( "directory", "file1.json", "file2.json", "file3.json" ) + + and: "a file is found" + fileConfigClient.getFileFromDefaultBranch( _, _, _ ) >> JSON_FILE_CONTENTS + + when: "the locator looks for the resource" + def propertySource = locator.locateConfigResources( Collections.singletonList( resource ) ) + + then: "the file is converter to a properties object" + notThrown( ConfigResourceException ) + + and: "the property source contains the resource" + !propertySource.getProperties().isEmpty() + } + + def "load multiple resources"() + { + given: "a configuration source locator" + def locator = new ConfigPropertySourceLocator( fileConfigClient ) + + and: "resources" + List resources = new ArrayList() + + and: "resource1 to load with 1 file" + def resource1 = createResource( "directory1", "file1.json" ) + resources.add( resource1 ) + + and: "resource2 to load with 1 file" + def resource2 = createResource( "directory2", "file2.json" ) + resources.add( resource2 ) + + and: "resource3 to load with 1 file" + def resource3 = createResource( "directory3", "file3.json" ) + resources.add( resource3 ) + + and: "files are found" + fileConfigClient.getFileFromDefaultBranch( _, _, _ ) >> JSON_FILE_CONTENTS + + when: "the locator looks for the resource" + def propertySource = locator.locateConfigResources( resources ) + + then: "the file is converter to a properties object" + notThrown( ConfigResourceException ) + + and: "the property source contains the resource" + !propertySource.getProperties().isEmpty() + } + + // ============================================================ + // Private Methods: + // ============================================================ + + private static Resource createResource( final String directory, final String... files ) + { + def resource = new Resource() + resource.setDirectory( directory ) + resource.setFiles( files as List ) + return resource + } +} diff --git a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy new file mode 100644 index 0000000..0484e4a --- /dev/null +++ b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy @@ -0,0 +1,334 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env + +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.core.env.CompositePropertySource +import org.springframework.core.env.ConfigurableEnvironment +import org.springframework.core.env.MutablePropertySources +import spock.lang.Specification + +/** + * Created by Piszmog on 7/22/2018 + */ +class ConfigResourceInitializerSpec extends Specification +{ + // ============================================================ + // Class Attributes: + // ============================================================ + + private ConfigPropertySourceLocator configPropertySourceLocator + private ConfigurableApplicationContext configurableApplicationContext + + // ============================================================ + // Setup: + // ============================================================ + + def setup() + { + configPropertySourceLocator = Stub( ConfigPropertySourceLocator ) + configurableApplicationContext = Stub( ConfigurableApplicationContext ) + } + + // ============================================================ + // TestS: + // ============================================================ + + def "configuration initializer adds json"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.json" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "the locator's property source is in the environment's property sources" + sources.contains( "example" ) + } + + def "configuration initializer adds yml"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.yml" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "yml files are not allowed to be added" + thrown( ConfigResourceException ) + } + + def "configuration initializer adds yaml"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.yaml" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "yaml files are not allowed to be added" + thrown( ConfigResourceException ) + } + + def "configuration initializer adds properties"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.properties" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "properties files are not allowed to be added" + thrown( ConfigResourceException ) + } + + def "configuration initializer is provided a text file to add"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.txt" + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "text files are not allowed to be added" + thrown( ConfigResourceException ) + } + + def "configuration initializer has a directory as blank"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.json" + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "the directory cannot be blank when a file is provided" + thrown( ConfigResourceException ) + } + + def "configuration initializer has a directory as null"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> null + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.json" + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "the directory cannot be null when a file is provided" + thrown( ConfigResourceException ) + } + + def "configuration initializer adds many json files"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.json" + environment.getProperty( "cloud.config.client.file.resources[0].files[1]" ) >> "file2.json" + environment.getProperty( "cloud.config.client.file.resources[0].files[2]" ) >> "file3.json" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "the locator's property source is in the environment's property sources" + sources.contains( "example" ) + } + + def "configuration initializer adds many json files in many directories"() + { + given: "A configuration initializer" + def initializer = new ConfigResourceInitializer() + + and: "the locator is set" + initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) + + and: "the context has an environment" + def environment = Stub( ConfigurableEnvironment ) + configurableApplicationContext.getEnvironment() >> environment + + and: "environment has property sources" + def sources = new MutablePropertySources() + environment.getPropertySources( ) >> sources + + and: "the environment does not find the enabled flag" + environment.getProperty( "cloud.config.client.file.enabled" ) >> null + + and: "directories and files are found" + environment.getProperty( "cloud.config.client.file.resources[0].directory" ) >> "directory1" + environment.getProperty( "cloud.config.client.file.resources[0].files[0]" ) >> "file1.json" + environment.getProperty( "cloud.config.client.file.resources[0].files[1]" ) >> "file2.json" + environment.getProperty( "cloud.config.client.file.resources[0].files[2]" ) >> "file3.json" + environment.getProperty( "cloud.config.client.file.resources[1].directory" ) >> "directory2" + environment.getProperty( "cloud.config.client.file.resources[1].files[0]" ) >> "file4.json" + environment.getProperty( "cloud.config.client.file.resources[1].files[1]" ) >> "file5.json" + environment.getProperty( "cloud.config.client.file.resources[1].files[2]" ) >> "file6.json" + environment.getProperty( "cloud.config.client.file.resources[2].directory" ) >> "directory3" + environment.getProperty( "cloud.config.client.file.resources[2].files[0]" ) >> "file7.json" + environment.getProperty( "cloud.config.client.file.resources[2].files[1]" ) >> "file8.json" + environment.getProperty( "cloud.config.client.file.resources[2].files[2]" ) >> "file9.json" + + and: "and property sources are found" + configPropertySourceLocator.locateConfigResources( _ ) >> new CompositePropertySource( "example" ) + + when: "the initializer is ran" + initializer.initialize( configurableApplicationContext ) + + then: "the locator's property source is in the environment's property sources" + sources.contains( "example" ) + } +} From 22982ab71bffe03055bc804f4d3eeee87a93bcde Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 22 Jul 2018 11:12:20 -0600 Subject: [PATCH 09/35] spelling mistake --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb66923..b259414 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ cloud: If pulling from the default branch, files __must__ be located in a subdirectory. -## Adding JSON Files are Property Sources +## Adding JSON Files as Property Sources The Config Server Client will only pull down `.properties` and `.yml`/`.yaml` files for an application's configuration (property sources). As more microservices move to _code by configuration_, these files can get very large and hard to maintain. Splitting configurations out into JSON files that do not need to follow the Config Server's [naming convention](https://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.1.RELEASE/#_quick_start) From 04d1c72b2cc31adef46a9bddfd3ef75e53be8f34 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 22 Jul 2018 11:53:46 -0600 Subject: [PATCH 10/35] update conditions - bootstrapping has race conditions --- .../cloudconfigclient/autoconfig/env/ResourceConfig.java | 7 ++----- .../template/LocalConfigTemplateAutoConfiguration.java | 4 ++-- .../template/OAuth2ConfigTemplateAutoConfiguration.java | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java index b64a53b..ed0bf97 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java @@ -2,22 +2,19 @@ import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfig.template.ConfigTemplate; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Configuration for creating configuration resource beans. *

- * Created via {@link javax.validation.BootstrapConfiguration} so property sources can be loaded before Spring - * configuration properties are set up. + * Created via {@link org.springframework.cloud.bootstrap.BootstrapConfiguration} so property sources can be loaded + * before Spring configuration properties are set up. *

* Created by Piszmog on 7/21/2018 */ @Configuration -@ConditionalOnBean( ConfigServicePropertySourceLocator.class ) public class ResourceConfig { /** diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 5c37872..3820123 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -16,8 +17,7 @@ */ @Configuration @ConditionalOnBean( ConfigClientProperties.class ) -@ConditionalOnMissingBean( type = "org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails" ) -@ConditionalOnMissingClass( "org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails" ) +@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId", matchIfMissing = true ) public class LocalConfigTemplateAutoConfiguration { // ============================================================ diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index c513b65..35d753a 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -2,9 +2,9 @@ import io.github.piszmog.cloudconfig.template.ConfigTemplate; import io.github.piszmog.cloudconfig.template.impl.OAuth2ConfigTemplate; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,7 +17,7 @@ */ @Configuration @ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) -@ConditionalOnBean( { ConfigClientProperties.class, OAuth2ProtectedResourceDetails.class } ) +@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId" ) public class OAuth2ConfigTemplateAutoConfiguration { // ============================================================ From bf78e0d96204404e92743fba0157ab240be75643 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 22 Jul 2018 11:54:19 -0600 Subject: [PATCH 11/35] prepare for release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f9f50ab..2742ac8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.1-SNAPSHOT + 1.1 jar From d11f311fbf3507a9c51610f340e6fbed2639fa98 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 22 Jul 2018 11:57:50 -0600 Subject: [PATCH 12/35] bring to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2742ac8..3affdb7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.1 + 1.2-SNAPSHOT jar From c8236c8e051ef23ab4b20497e2db6daaee2d8482 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:21:56 -0600 Subject: [PATCH 13/35] be able to load yml/yaml and properties and load files async --- pom.xml | 7 +- .../env/ConfigPropertySourceLocator.java | 141 ++++++++++++++---- .../env/ConfigResourceInitializer.java | 7 +- .../autoconfig/env/ResourceConfig.java | 2 + .../LocalConfigTemplateAutoConfiguration.java | 3 + ...OAuth2ConfigTemplateAutoConfiguration.java | 2 + .../env/ConfigResourceInitializerSpec.groovy | 12 +- 7 files changed, 135 insertions(+), 39 deletions(-) diff --git a/pom.xml b/pom.xml index 3affdb7..bd29f57 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 1.5.0.RELEASE 1.5.12.RELEASE - 1.1 + 1.2 2.9.6 3.2.6 @@ -61,6 +61,11 @@ jackson-dataformat-properties ${jackson-dataformat-properties.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.9.6 + org.springframework.boot spring-boot-configuration-processor diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index c5e02a7..f65edce 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -1,24 +1,30 @@ package io.github.piszmog.cloudconfigclient.autoconfig.env; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import io.github.piszmog.cloudconfig.ConfigException; import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; /** * JSON property source locator. Locates the JSON files to be loaded as property sources. *

* Created by Piszmog on 7/21/2018 */ +@Slf4j public class ConfigPropertySourceLocator { // ============================================================ @@ -26,13 +32,15 @@ public class ConfigPropertySourceLocator // ============================================================ private static final String PROPERTY_SOURCE_NAME = "jsonResource"; + private static final ObjectMapper YAML_MAPPER = new ObjectMapper( new YAMLFactory() ); + private static final JavaPropsMapper PROPERTIES_MAPPER = new JavaPropsMapper(); // ============================================================ // Class Attributes: // ============================================================ private final FileConfigClient fileConfigClient; - private final JavaPropsMapper mapper = new JavaPropsMapper(); + private final ExecutorService executorService = Executors.newFixedThreadPool( 10 ); // ============================================================ // Constructors: @@ -60,12 +68,28 @@ public ConfigPropertySourceLocator( final FileConfigClient fileConfigClient ) */ public PropertySource locateConfigResources( final List resources ) { + List> futures = new ArrayList<>(); CompositePropertySource composite = new CompositePropertySource( PROPERTY_SOURCE_NAME ); for ( Resource resource : resources ) { final String directoryPath = resource.getDirectory(); final List files = resource.getFiles(); - getJsonConfiguration( composite, directoryPath, files ); + getJsonConfiguration( composite, directoryPath, files, futures ); + } + try + { + for ( Future future : futures ) + { + future.get(); + } + } + catch ( InterruptedException | ExecutionException e ) + { + throw new ConfigResourceException( "Failed to retrieve file.", e ); + } + finally + { + executorService.shutdownNow(); } return composite; } @@ -74,39 +98,43 @@ public PropertySource locateConfigResources( final List resources ) // Private Methods: // ============================================================ - private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final List files ) + private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final List files, final List> futures ) { - final Map map = new HashMap<>(); for ( String fileName : files ) { - final String filePath = getFilePath( directoryPath, fileName ); - try + futures.add( executorService.submit( () -> loadConfigurationFile( composite, directoryPath, fileName ) ) ); + } + } + + private void loadConfigurationFile( final CompositePropertySource composite, final String directoryPath, final String fileName ) + { + final Map map = new HashMap<>(); + final String filePath = getFilePath( directoryPath, fileName ); + try + { + log.info( "Loading configuration {}...", filePath ); + Map file; + if ( StringUtils.endsWithIgnoreCase( fileName, ".yml" ) || StringUtils.endsWithIgnoreCase( fileName, ".yaml" ) ) { - final Map file = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); - final Properties properties; - try - { - properties = mapper.writeValueAsProperties( file ); - } - catch ( IOException e ) - { - throw new ConfigResourceException( "Failed to convert " + filePath + " to properties format to be loaded in the property sources." ); - } - for ( Map.Entry entry : properties.entrySet() ) - { - final String key = (String) entry.getKey(); - final Object value = entry.getValue(); - map.put( key, value ); - } + file = getYAMLFile( directoryPath, fileName, filePath ); } - catch ( ConfigException e ) + else if ( StringUtils.endsWithIgnoreCase( fileName, ".properties" ) ) { - throw new ConfigResourceException( "Failed to load " + filePath, e ); + file = getPropertiesFile( directoryPath, fileName, filePath ); } - if ( !map.isEmpty() ) + else { - composite.addPropertySource( new MapPropertySource( filePath, map ) ); + file = getJSONFile( directoryPath, fileName ); } + loaadPropertyValues( map, filePath, file ); + } + catch ( ConfigException e ) + { + throw new ConfigResourceException( "Failed to load " + filePath, e ); + } + if ( !map.isEmpty() ) + { + composite.addPropertySource( new MapPropertySource( filePath, map ) ); } } @@ -114,4 +142,57 @@ private String getFilePath( final String directoryPath, final String fileName ) { return directoryPath + "/" + fileName; } + + private Map getYAMLFile( final String directoryPath, final String fileName, final String filePath ) throws ConfigException + { + final Map file; + final String yamlFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, String.class ); + try + { + file = YAML_MAPPER.readValue( yamlFile, Map.class ); + } + catch ( IOException e ) + { + throw new ConfigResourceException( "Failed to convert " + filePath + " from YAML format to be loaded in the property sources.", e ); + } + return file; + } + + private Map getPropertiesFile( final String directoryPath, final String fileName, final String filePath ) throws ConfigException + { + final Map file; + try + { + file = PROPERTIES_MAPPER.readValue( fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, String.class ), Map.class ); + } + catch ( IOException e ) + { + throw new ConfigResourceException( "Failed to convert " + filePath + " from PROPERTIES format to be loaded in the property sources.", e ); + } + return file; + } + + private Map getJSONFile( final String directoryPath, final String fileName ) throws ConfigException + { + return fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); + } + + private void loaadPropertyValues( final Map map, final String filePath, final Map file ) + { + final Properties properties; + try + { + properties = PROPERTIES_MAPPER.writeValueAsProperties( file ); + } + catch ( IOException e ) + { + throw new ConfigResourceException( "Failed to convert " + filePath + " to properties format to be loaded in the property sources.", e ); + } + for ( Map.Entry entry : properties.entrySet() ) + { + final String key = (String) entry.getKey(); + final Object value = entry.getValue(); + map.put( key, value ); + } + } } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java index c99db83..27fea13 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java @@ -72,10 +72,13 @@ public void initialize( final ConfigurableApplicationContext applicationContext { throw new ConfigResourceException( "Directory must not be null or blank when file is not blank or null." ); } - if ( !StringUtils.endsWithIgnoreCase( fileName, ".json" ) ) + if ( !StringUtils.endsWithIgnoreCase( fileName, ".json" ) + && !StringUtils.endsWithIgnoreCase( fileName, ".yml" ) + && !StringUtils.endsWithIgnoreCase( fileName, ".yaml" ) + && !StringUtils.endsWithIgnoreCase( fileName, ".properties" ) ) { throw new ConfigResourceException( "File " + fileName + " is not a configuration file." + - " Only .json are accepted." ); + " Only .json, .yml, .yaml, and .properties are accepted." ); } files.add( fileName ); } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java index ed0bf97..da2bae8 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java @@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; /** * Configuration for creating configuration resource beans. @@ -14,6 +15,7 @@ *

* Created by Piszmog on 7/21/2018 */ +@Order @Configuration public class ResourceConfig { diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 3820123..530f8cb 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -9,12 +9,15 @@ import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; /** * Auto-configuration for creating a {@link LocalConfigTemplate}. *

* Created by Piszmog on 5/5/2018 */ +@Order @Configuration @ConditionalOnBean( ConfigClientProperties.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId", matchIfMissing = true ) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index 35d753a..f1eb063 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -8,6 +8,7 @@ import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; /** @@ -15,6 +16,7 @@ *

* Created by Piszmog on 5/5/2018 */ +@Order @Configuration @ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId" ) diff --git a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy index 0484e4a..0791e80 100644 --- a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy +++ b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy @@ -94,8 +94,8 @@ class ConfigResourceInitializerSpec extends Specification when: "the initializer is ran" initializer.initialize( configurableApplicationContext ) - then: "yml files are not allowed to be added" - thrown( ConfigResourceException ) + then: "yml files are allowed to be added" + notThrown( ConfigResourceException ) } def "configuration initializer adds yaml"() @@ -127,8 +127,8 @@ class ConfigResourceInitializerSpec extends Specification when: "the initializer is ran" initializer.initialize( configurableApplicationContext ) - then: "yaml files are not allowed to be added" - thrown( ConfigResourceException ) + then: "yaml files are allowed to be added" + notThrown( ConfigResourceException ) } def "configuration initializer adds properties"() @@ -160,8 +160,8 @@ class ConfigResourceInitializerSpec extends Specification when: "the initializer is ran" initializer.initialize( configurableApplicationContext ) - then: "properties files are not allowed to be added" - thrown( ConfigResourceException ) + then: "properties files are allowed to be added" + notThrown( ConfigResourceException ) } def "configuration initializer is provided a text file to add"() From 0e0238bad60431e9df9e8b3255a7e7b450ea6784 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:23:27 -0600 Subject: [PATCH 14/35] update docs --- README.md | 4 ++-- .../autoconfig/env/ConfigPropertySourceLocator.java | 2 +- .../autoconfig/env/ConfigResourceInitializer.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b259414..f985331 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ can help to better organize an application configuration. Leveraging the `FileConfigClient` bean, JSON files can be loaded as property sources. This allows for `ConfigurationProperties` to have JSON values be injected into their fields. -To add a JSON file as a property source, update the application configuration to have the following, +To add a file as a property source, update the application configuration to have the following, ```yaml cloud: config: @@ -81,7 +81,7 @@ cloud: Where, - `` is the directory path to the following files -- example `nonprod/example` or `configs` - Sub-directory __must__ not be `null` or blank. -- `` is the JSON file to load that is located in the specified sub-directory +- `` is the JSON, YAML, or Properties file to load that is located in the specified sub-directory ### Specifying Configuration Adding JSON files to be property sources can either be done in the `bootstrap.yml` (embedded with the application), in an embedded diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index f65edce..ce2094e 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -20,7 +20,7 @@ import java.util.concurrent.Future; /** - * JSON property source locator. Locates the JSON files to be loaded as property sources. + * Property source locator. Locates the JSON files to be loaded as property sources. *

* Created by Piszmog on 7/21/2018 */ diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java index 27fea13..12f50bb 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java @@ -17,7 +17,7 @@ /** * If enabled and a list of resources to load exist, then the configuration resources are added as property sources. *

- * Only configuration file formats are accepted - .json + * Only configuration file formats are accepted - .json, .yaml/.yml, and .properties *

* Only loads the configuration files if {@code cloud.config.client.file.enabled} is true or missing and {@link * ConfigPropertySourceLocator} bean was injected. From 75df99508cd1f0853732c89853511f9819f64d7c Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:39:10 -0600 Subject: [PATCH 15/35] remove @Order -- doing nothing --- .../cloudconfigclient/autoconfig/env/ResourceConfig.java | 2 -- .../template/LocalConfigTemplateAutoConfiguration.java | 4 ---- .../template/OAuth2ConfigTemplateAutoConfiguration.java | 2 -- 3 files changed, 8 deletions(-) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java index da2bae8..ed0bf97 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java @@ -5,7 +5,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; /** * Configuration for creating configuration resource beans. @@ -15,7 +14,6 @@ *

* Created by Piszmog on 7/21/2018 */ -@Order @Configuration public class ResourceConfig { diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 530f8cb..47fb837 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -4,20 +4,16 @@ import io.github.piszmog.cloudconfig.template.impl.LocalConfigTemplate; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; /** * Auto-configuration for creating a {@link LocalConfigTemplate}. *

* Created by Piszmog on 5/5/2018 */ -@Order @Configuration @ConditionalOnBean( ConfigClientProperties.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId", matchIfMissing = true ) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index f1eb063..35d753a 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -8,7 +8,6 @@ import org.springframework.cloud.config.client.ConfigClientProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; /** @@ -16,7 +15,6 @@ *

* Created by Piszmog on 5/5/2018 */ -@Order @Configuration @ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId" ) From 27ea068aca006351b4167aa09479770acb743b9c Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:40:13 -0600 Subject: [PATCH 16/35] replacement for jackson version --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index bd29f57..cbcce5b 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.5.12.RELEASE 1.2 - 2.9.6 + 2.9.6 3.2.6 2.5.1 @@ -59,12 +59,12 @@ com.fasterxml.jackson.dataformat jackson-dataformat-properties - ${jackson-dataformat-properties.version} + ${jackson-dataformat.version} com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.9.6 + ${jackson-dataformat.version} org.springframework.boot From c06bf9d5f895dab74d8bdf8e04cb63542632d9f1 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:40:30 -0600 Subject: [PATCH 17/35] preparing to release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cbcce5b..0af22da 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.2-SNAPSHOT + 1.2 jar From 4100d7be189d8362443fb8d37c7837c4817bb71f Mon Sep 17 00:00:00 2001 From: Piszmog Date: Mon, 23 Jul 2018 20:42:04 -0600 Subject: [PATCH 18/35] move to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0af22da..d8e954a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.2 + 1.3-SNAPSHOT jar From 29ae3a55f576ef742c0495bbd0788722708d4b17 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Tue, 24 Jul 2018 08:22:53 -0600 Subject: [PATCH 19/35] update for Spring Boot 2/Spring Framework 5 --- README.md | 16 +++++++++- pom.xml | 30 ++++++++++++++++--- .../env/ConfigPropertySourceLocator.java | 8 +++-- .../autoconfig/env/model/Resource.java | 27 +++++++++++++++-- .../LocalConfigTemplateAutoConfiguration.java | 3 ++ ...OAuth2ConfigTemplateAutoConfiguration.java | 4 +++ 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f985331..3785325 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,24 @@ -# Config Server Commons +# Cloud Config Client AutoConfig [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.piszmog/cloud-config-client-autoconfig/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.github.piszmog/cloud-config-client-autoconfig) ## Description Spring Auto-configuration library for [Cloud Config Client](https://github.com/Piszmog/cloud-config-client). +__Cloud Config Client AutoConfig 2.x__ is compatible with + +| Dependency | Version | +| :---: | :---: | +| Spring Boot | 2.x.x | +| Spring Cloud Services | 2.x.x.RELEASE | + +__Cloud Config Client AutoConfig 1.x__ is compatible with + +| Dependency | Version | +| :---: | :---: | +| Spring Boot | 1.5.x | +| Spring Cloud Services | 1.5.x.RELEASE | + Creates Spring Beans for `DecryptConfigClient`, `EncryptConfigClient`, `FileConfigClient`, and `PublicKeyClient`. Simply inject the beans where needed. diff --git a/pom.xml b/pom.xml index d8e954a..58eb2ec 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 1.3-SNAPSHOT + 2.0-SNAPSHOT jar @@ -35,13 +35,16 @@ 1.5 1.6.7 - 1.5.0.RELEASE - 1.5.12.RELEASE + 2.0.1.RELEASE + 2.0.3.RELEASE - 1.2 + 2.0 2.9.6 + 5.0.7.RELEASE + 2.3.3.RELEASE 3.2.6 + 1.0-groovy-2.4 2.5.1 1.6.5 @@ -76,11 +79,30 @@ spring-cloud-services-starter-config-client provided + + org.springframework + spring-context + ${spring-context.version} + + + org.springframework.security.oauth + spring-security-oauth2 + ${spring-security-oauth2.version} + true + provided + org.spockframework spock-core + ${spock-core.version} test + + + org.codehaus.groovy + groovy-all + + org.codehaus.groovy diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index ce2094e..fb5999e 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -6,8 +6,9 @@ import io.github.piszmog.cloudconfig.ConfigException; import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; @@ -24,9 +25,10 @@ *

* Created by Piszmog on 7/21/2018 */ -@Slf4j public class ConfigPropertySourceLocator { + private static final transient Log logger = LogFactory.getLog( ConfigPropertySourceLocator.class ); + // ============================================================ // Class Constants: // ============================================================ @@ -112,7 +114,7 @@ private void loadConfigurationFile( final CompositePropertySource composite, fin final String filePath = getFilePath( directoryPath, fileName ); try { - log.info( "Loading configuration {}...", filePath ); + logger.info( "Loading configuration " + filePath + "..." ); Map file; if ( StringUtils.endsWithIgnoreCase( fileName, ".yml" ) || StringUtils.endsWithIgnoreCase( fileName, ".yaml" ) ) { diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java index e04d358..417ff58 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/model/Resource.java @@ -1,7 +1,5 @@ package io.github.piszmog.cloudconfigclient.autoconfig.env.model; -import lombok.Data; - import java.util.List; /** @@ -9,7 +7,6 @@ *

* Created by Piszmog on 7/21/2018 */ -@Data public class Resource { // ============================================================ @@ -18,4 +15,28 @@ public class Resource private String directory; private List files; + + // ============================================================ + // Public Methods: + // ============================================================ + + public String getDirectory() + { + return directory; + } + + public void setDirectory( final String directory ) + { + this.directory = directory; + } + + public List getFiles() + { + return files; + } + + public void setFiles( final List files ) + { + this.files = files; + } } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java index 47fb837..1c8038b 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java @@ -6,8 +6,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; +import org.springframework.cloud.config.client.ConfigServiceBootstrapConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; /** * Auto-configuration for creating a {@link LocalConfigTemplate}. @@ -17,6 +19,7 @@ @Configuration @ConditionalOnBean( ConfigClientProperties.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId", matchIfMissing = true ) +@Import( ConfigServiceBootstrapConfiguration.class ) public class LocalConfigTemplateAutoConfiguration { // ============================================================ diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java index 35d753a..7654886 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java @@ -2,12 +2,15 @@ import io.github.piszmog.cloudconfig.template.ConfigTemplate; import io.github.piszmog.cloudconfig.template.impl.OAuth2ConfigTemplate; +import io.pivotal.spring.cloud.service.config.ConfigClientOAuth2BootstrapConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; +import org.springframework.cloud.config.client.ConfigServiceBootstrapConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; /** @@ -18,6 +21,7 @@ @Configuration @ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) @ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId" ) +@Import( { ConfigServiceBootstrapConfiguration.class, ConfigClientOAuth2BootstrapConfiguration.class } ) public class OAuth2ConfigTemplateAutoConfiguration { // ============================================================ From 5a5c1aac135b2ebc0d3e9d91abea90dfa5cf17e5 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Tue, 24 Jul 2018 08:23:15 -0600 Subject: [PATCH 20/35] prepare for 2.0 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58eb2ec..e1d0985 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.0-SNAPSHOT + 2.0 jar From bf0887d9b3f0e39662b1e954a6d280390663cf31 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Tue, 24 Jul 2018 08:24:02 -0600 Subject: [PATCH 21/35] up to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e1d0985..3737e85 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.0 + 2.1-SNAPSHOT jar From cbafb7a19bb1ff3edf80f973f3d27dc8c1f9e604 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Wed, 25 Jul 2018 21:21:55 -0600 Subject: [PATCH 22/35] refactor bootstraps class names and loading order and flatten maps if read from json or yml --- pom.xml | 2 +- .../env/ConfigPropertySourceLocator.java | 34 +++----- ...> ConfigResourceBootstrapInitializer.java} | 2 +- ...nfig.java => ResourceBootstrapConfig.java} | 12 ++- .../autoconfig/env/support/MapFlattener.java | 81 +++++++++++++++++++ ...ConfigTemplateBootstrapConfiguration.java} | 9 ++- ...ConfigTemplateBootStrapConfiguration.java} | 7 +- src/main/resources/META-INF/spring.factories | 8 +- ...igResourceBootstrapInitializerSpec.groovy} | 20 ++--- 9 files changed, 126 insertions(+), 49 deletions(-) rename src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/{ConfigResourceInitializer.java => ConfigResourceBootstrapInitializer.java} (97%) rename src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/{ResourceConfig.java => ResourceBootstrapConfig.java} (72%) create mode 100644 src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java rename src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/{LocalConfigTemplateAutoConfiguration.java => LocalConfigTemplateBootstrapConfiguration.java} (87%) rename src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/{OAuth2ConfigTemplateAutoConfiguration.java => OAuth2ConfigTemplateBootStrapConfiguration.java} (93%) rename src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/{ConfigResourceInitializerSpec.groovy => ConfigResourceBootstrapInitializerSpec.groovy} (95%) diff --git a/pom.xml b/pom.xml index 3737e85..da09452 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 2.0.1.RELEASE 2.0.3.RELEASE - 2.0 + 2.2 2.9.6 5.0.7.RELEASE 2.3.3.RELEASE diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index fb5999e..06fee1d 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -6,6 +6,7 @@ import io.github.piszmog.cloudconfig.ConfigException; import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; +import io.github.piszmog.cloudconfigclient.autoconfig.env.support.MapFlattener; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -14,7 +15,9 @@ import org.springframework.core.env.PropertySource; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -108,14 +111,14 @@ private void getJsonConfiguration( final CompositePropertySource composite, fina } } + @SuppressWarnings( "unchecked" ) private void loadConfigurationFile( final CompositePropertySource composite, final String directoryPath, final String fileName ) { - final Map map = new HashMap<>(); final String filePath = getFilePath( directoryPath, fileName ); + Map file; try { logger.info( "Loading configuration " + filePath + "..." ); - Map file; if ( StringUtils.endsWithIgnoreCase( fileName, ".yml" ) || StringUtils.endsWithIgnoreCase( fileName, ".yaml" ) ) { file = getYAMLFile( directoryPath, fileName, filePath ); @@ -128,15 +131,15 @@ else if ( StringUtils.endsWithIgnoreCase( fileName, ".properties" ) ) { file = getJSONFile( directoryPath, fileName ); } - loaadPropertyValues( map, filePath, file ); } catch ( ConfigException e ) { throw new ConfigResourceException( "Failed to load " + filePath, e ); } - if ( !map.isEmpty() ) + if ( !file.isEmpty() ) { - composite.addPropertySource( new MapPropertySource( filePath, map ) ); + final Map flattenMap = MapFlattener.flatten( file ); + composite.addPropertySource( new MapPropertySource( filePath, flattenMap ) ); } } @@ -178,23 +181,4 @@ private Map getJSONFile( final String directoryPath, final String fileName ) thr { return fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); } - - private void loaadPropertyValues( final Map map, final String filePath, final Map file ) - { - final Properties properties; - try - { - properties = PROPERTIES_MAPPER.writeValueAsProperties( file ); - } - catch ( IOException e ) - { - throw new ConfigResourceException( "Failed to convert " + filePath + " to properties format to be loaded in the property sources.", e ); - } - for ( Map.Entry entry : properties.entrySet() ) - { - final String key = (String) entry.getKey(); - final Object value = entry.getValue(); - map.put( key, value ); - } - } } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java similarity index 97% rename from src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java rename to src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java index 12f50bb..747d85c 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializer.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java @@ -28,7 +28,7 @@ * Created by Piszmog on 7/21/2018 */ @Configuration -public class ConfigResourceInitializer implements ApplicationContextInitializer, Ordered +public class ConfigResourceBootstrapInitializer implements ApplicationContextInitializer, Ordered { // ============================================================ // Class Constants: diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceBootstrapConfig.java similarity index 72% rename from src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java rename to src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceBootstrapConfig.java index ed0bf97..6a40ab1 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceConfig.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ResourceBootstrapConfig.java @@ -2,9 +2,13 @@ import io.github.piszmog.cloudconfig.client.impl.FileConfigClient; import io.github.piszmog.cloudconfig.template.ConfigTemplate; +import io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateBootstrapConfiguration; +import io.github.piszmog.cloudconfigclient.autoconfig.template.OAuth2ConfigTemplateBootStrapConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; /** * Configuration for creating configuration resource beans. @@ -14,8 +18,11 @@ *

* Created by Piszmog on 7/21/2018 */ +@Order @Configuration -public class ResourceConfig +@ConditionalOnProperty( prefix = "cloud.config.client", name = "file.enabled", matchIfMissing = true ) +@Import( { LocalConfigTemplateBootstrapConfiguration.class, OAuth2ConfigTemplateBootStrapConfiguration.class } ) +public class ResourceBootstrapConfig { /** * Create a file client. To disable, the property {@code cloud.config.client.file.enabled} must be set via bootstrap @@ -24,8 +31,8 @@ public class ResourceConfig * @param configTemplate the config template * @return The file client. */ + @Order @Bean - @ConditionalOnProperty( prefix = "cloud.config.client", name = "file.enabled", matchIfMissing = true ) public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) { return new FileConfigClient( configTemplate ); @@ -37,6 +44,7 @@ public FileConfigClient fileConfigClient( final ConfigTemplate configTemplate ) * @param fileConfigClient the file config client to load files from the Config Server * @return The locator. */ + @Order @Bean public ConfigPropertySourceLocator configPropertySourceLocator( final FileConfigClient fileConfigClient ) { diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java new file mode 100644 index 0000000..b5968f8 --- /dev/null +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java @@ -0,0 +1,81 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env.support; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Flattens maps into a Spring readable properties map. See https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding + * for more information on Spring key names. + *

+ * Copied from {@link org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor}. + *

+ * Created by Piszmog on 7/25/2018 + */ +public class MapFlattener +{ + // ============================================================ + // Static Methods: + // ============================================================ + + /** + * Flattens the provided map. + * + * @param map the map to flatten + * @return The flatten map with the keys in the Spring properties format. + */ + public static Map flatten( Map map ) + { + Map result = new LinkedHashMap<>(); + flatten( null, result, map ); + return result; + } + + // ============================================================ + // Private Methods: + // ============================================================ + + private static void flatten( String prefix, + Map result, + Map map ) + { + String namePrefix = ( prefix != null ? prefix + "." : "" ); + map.forEach( ( key, value ) -> { + String finalKey = key; + // + // If key has certain character in it, we want to wrap key in '[' and ']'. + // + if ( StringUtils.contains( key, ":" ) + || StringUtils.contains( key, "." ) + || StringUtils.contains( key, "*" ) ) + { + finalKey = "[" + key + "]"; + } + extract( namePrefix + finalKey, result, value ); + } ); + } + + @SuppressWarnings( "unchecked" ) + private static void extract( String name, Map result, Object value ) + { + if ( value instanceof Map ) + { + flatten( name, result, (Map) value ); + } + else if ( value instanceof Collection ) + { + int index = 0; + for ( Object object : (Collection) value ) + { + extract( name + "[" + index + "]", result, object ); + index++; + } + } + else + { + result.put( name, value ); + } + } +} diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateBootstrapConfiguration.java similarity index 87% rename from src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java rename to src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateBootstrapConfiguration.java index 1c8038b..255bb48 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/LocalConfigTemplateBootstrapConfiguration.java @@ -2,7 +2,6 @@ import io.github.piszmog.cloudconfig.template.ConfigTemplate; import io.github.piszmog.cloudconfig.template.impl.LocalConfigTemplate; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.config.client.ConfigClientProperties; @@ -10,17 +9,18 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; /** * Auto-configuration for creating a {@link LocalConfigTemplate}. *

* Created by Piszmog on 5/5/2018 */ +@Order @Configuration -@ConditionalOnBean( ConfigClientProperties.class ) -@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId", matchIfMissing = true ) +@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.client-id", matchIfMissing = true ) @Import( ConfigServiceBootstrapConfiguration.class ) -public class LocalConfigTemplateAutoConfiguration +public class LocalConfigTemplateBootstrapConfiguration { // ============================================================ // Beans: @@ -32,6 +32,7 @@ public class LocalConfigTemplateAutoConfiguration * @param configClientProperties the config client properties. * @return The config template. */ + @Order @Bean @ConditionalOnMissingBean public ConfigTemplate localConfigTemplate( final ConfigClientProperties configClientProperties ) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateBootStrapConfiguration.java similarity index 93% rename from src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java rename to src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateBootStrapConfiguration.java index 7654886..4360404 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateAutoConfiguration.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/template/OAuth2ConfigTemplateBootStrapConfiguration.java @@ -11,6 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; /** @@ -18,11 +19,12 @@ *

* Created by Piszmog on 5/5/2018 */ +@Order @Configuration @ConditionalOnClass( OAuth2ProtectedResourceDetails.class ) -@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.clientId" ) +@ConditionalOnProperty( value = "spring.cloud.config.client.oauth2.client-id" ) @Import( { ConfigServiceBootstrapConfiguration.class, ConfigClientOAuth2BootstrapConfiguration.class } ) -public class OAuth2ConfigTemplateAutoConfiguration +public class OAuth2ConfigTemplateBootStrapConfiguration { // ============================================================ // Beans: @@ -35,6 +37,7 @@ public class OAuth2ConfigTemplateAutoConfiguration * @param oAuth2ProtectedResourceDetails the OAuth2 details * @return The config template. */ + @Order @Bean @ConditionalOnMissingBean public ConfigTemplate oauth2ConfigTemplate( final ConfigClientProperties configClientProperties, diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index 59af3fb..92895ec 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,7 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ io.github.piszmog.cloudconfigclient.autoconfig.client.ConfigClientAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - io.github.piszmog.cloudconfigclient.autoconfig.env.ResourceConfig,\ - io.github.piszmog.cloudconfigclient.autoconfig.env.ConfigResourceInitializer,\ - io.github.piszmog.cloudconfigclient.autoconfig.template.OAuth2ConfigTemplateAutoConfiguration,\ - io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateAutoConfiguration + io.github.piszmog.cloudconfigclient.autoconfig.template.OAuth2ConfigTemplateBootStrapConfiguration,\ + io.github.piszmog.cloudconfigclient.autoconfig.template.LocalConfigTemplateBootstrapConfiguration,\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ResourceBootstrapConfig,\ + io.github.piszmog.cloudconfigclient.autoconfig.env.ConfigResourceBootstrapInitializer diff --git a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializerSpec.groovy similarity index 95% rename from src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy rename to src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializerSpec.groovy index 0791e80..55a2da5 100644 --- a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceInitializerSpec.groovy +++ b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializerSpec.groovy @@ -9,7 +9,7 @@ import spock.lang.Specification /** * Created by Piszmog on 7/22/2018 */ -class ConfigResourceInitializerSpec extends Specification +class ConfigResourceBootstrapInitializerSpec extends Specification { // ============================================================ // Class Attributes: @@ -35,7 +35,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds json"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -68,7 +68,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds yml"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -101,7 +101,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds yaml"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -134,7 +134,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds properties"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -167,7 +167,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer is provided a text file to add"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -197,7 +197,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer has a directory as blank"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -227,7 +227,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer has a directory as null"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -257,7 +257,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds many json files"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) @@ -292,7 +292,7 @@ class ConfigResourceInitializerSpec extends Specification def "configuration initializer adds many json files in many directories"() { given: "A configuration initializer" - def initializer = new ConfigResourceInitializer() + def initializer = new ConfigResourceBootstrapInitializer() and: "the locator is set" initializer.setConfigPropertySourceLocator( configPropertySourceLocator ) From 921e00717b1971c5de18b5928bc027a5399015b3 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Wed, 25 Jul 2018 21:22:24 -0600 Subject: [PATCH 23/35] release 2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da09452..9834e09 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.1-SNAPSHOT + 2.1 jar From 34a1a3afca867f66b18a71867979a829b04d832e Mon Sep 17 00:00:00 2001 From: Piszmog Date: Wed, 25 Jul 2018 21:23:42 -0600 Subject: [PATCH 24/35] up to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9834e09..b5c974d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.1 + 2.2-SNAPSHOT jar From e94ea0a0af3bdc11a79a3553502f9596bc45447b Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 29 Jul 2018 14:10:26 -0600 Subject: [PATCH 25/35] add additional special characters to add '[' ']' around --- .../autoconfig/env/support/MapFlattener.java | 6 +- .../env/support/MapFlattenerSpec.groovy | 102 ++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattenerSpec.groovy diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java index b5968f8..791a622 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattener.java @@ -45,11 +45,13 @@ private static void flatten( String prefix, map.forEach( ( key, value ) -> { String finalKey = key; // - // If key has certain character in it, we want to wrap key in '[' and ']'. + // If key has certain characters in it, we want to wrap key in '[' and ']'. // if ( StringUtils.contains( key, ":" ) || StringUtils.contains( key, "." ) - || StringUtils.contains( key, "*" ) ) + || StringUtils.contains( key, "*" ) + || StringUtils.startsWith( key, "$" ) + || StringUtils.startsWith( key, "#" ) ) { finalKey = "[" + key + "]"; } diff --git a/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattenerSpec.groovy b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattenerSpec.groovy new file mode 100644 index 0000000..956e52c --- /dev/null +++ b/src/test/groovy/io/github/piszmog/cloudconfigclient/autoconfig/env/support/MapFlattenerSpec.groovy @@ -0,0 +1,102 @@ +package io.github.piszmog.cloudconfigclient.autoconfig.env.support + + +import spock.lang.Specification + +/** + * Created by Piszmog on 7/29/2018 + */ +class MapFlattenerSpec extends Specification +{ + // ============================================================ + // Tests: + // ============================================================ + + def "flatten a simple map"() + { + given: "a map" + Map topLevelMap = new HashMap() + topLevelMap.put( "key1", "value1" ) + topLevelMap.put( "key2", "value2" ) + + when: "the map is flattened" + def flattenedMap = MapFlattener.flatten( topLevelMap ) + + then: "the map is flattened" + flattenedMap.get( "key1" ) == "value1" + flattenedMap.get( "key2" ) == "value2" + } + + def "flatten a nested map"() + { + given: "a map" + Map level2Map = new HashMap() + level2Map.put( "level2Key1", "value1" ) + level2Map.put( "level2Key2", "value2" ) + Map level1Map = new HashMap() + level1Map.put( "level2", level2Map ) + Map topLevelMap = new HashMap() + topLevelMap.put( "level1", level1Map ) + + when: "the map is flattened" + def flattenMap = MapFlattener.flatten( topLevelMap ) + + then: "the map is flattened" + flattenMap.get( "level1.level2.level2Key1" ) == "value1" + flattenMap.get( "level1.level2.level2Key2" ) == "value2" + } + + def "flatten a nested map with a list"() + { + given: "a map" + List list = new LinkedList() + list.add( "value1" ) + list.add( "value2" ) + Map level1Map = new HashMap() + level1Map.put( "list", list ) + Map topLevelMap = new HashMap() + topLevelMap.put( "level1", level1Map ) + + when: "the map is flattened" + def flattenMap = MapFlattener.flatten( topLevelMap ) + + then: "the map is flattened" + flattenMap.get( "level1.list[0]" ) == "value1" + flattenMap.get( "level1.list[1]" ) == "value2" + } + + def "flatten a nested map with special characters"() + { + given: "a map" + Map level2Map = new HashMap() + level2Map.put( "level2.Key1", "value1" ) + level2Map.put( "level2:Key2", "value2" ) + level2Map.put( "level2*Key3", "value3" ) + level2Map.put( "\$level2Key4", "value4" ) + level2Map.put( "#level2Key5", "value5" ) + level2Map.put( "%level2Key6", "value6" ) + level2Map.put( "!level2Key7", "value7" ) + level2Map.put( "^level2Key8", "value8" ) + level2Map.put( "@level2Key9", "value9" ) + level2Map.put( "&level2Key10", "value10" ) + Map level1Map = new HashMap() + level1Map.put( "level2", level2Map ) + Map topLevelMap = new HashMap() + topLevelMap.put( "level1", level1Map ) + + when: "the map is flattened" + def flattenMap = MapFlattener.flatten( topLevelMap ) + + then: "the map is flattened" + flattenMap.get( "level1.level2.[level2.Key1]" ) == "value1" + flattenMap.get( "level1.level2.[level2:Key2]" ) == "value2" + flattenMap.get( "level1.level2.[level2*Key3]" ) == "value3" + flattenMap.get( "level1.level2.[\$level2Key4]" ) == "value4" + flattenMap.get( "level1.level2.[#level2Key5]" ) == "value5" + flattenMap.get( "level1.level2.%level2Key6" ) == "value6" + flattenMap.get( "level1.level2.!level2Key7" ) == "value7" + flattenMap.get( "level1.level2.^level2Key8" ) == "value8" + flattenMap.get( "level1.level2.@level2Key9" ) == "value9" + flattenMap.get( "level1.level2.&level2Key10" ) == "value10" + } +} From a957b5c45695e3f24a4c4f25d0679e8110a0d2e2 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 29 Jul 2018 14:11:08 -0600 Subject: [PATCH 26/35] use Java 8 completable futures to load files -- attempt to increase performance --- pom.xml | 2 +- .../env/ConfigPropertySourceLocator.java | 74 +++++++++++-------- .../ConfigResourceBootstrapInitializer.java | 4 + 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/pom.xml b/pom.xml index b5c974d..5e6f09e 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 2.0.1.RELEASE 2.0.3.RELEASE - 2.2 + 2.3 2.9.6 5.0.7.RELEASE 2.3.3.RELEASE diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index 06fee1d..242dce6 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -8,6 +8,7 @@ import io.github.piszmog.cloudconfigclient.autoconfig.env.model.Resource; import io.github.piszmog.cloudconfigclient.autoconfig.env.support.MapFlattener; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.env.CompositePropertySource; @@ -18,10 +19,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.stream.Collectors; /** * Property source locator. Locates the JSON files to be loaded as property sources. @@ -37,6 +40,7 @@ public class ConfigPropertySourceLocator // ============================================================ private static final String PROPERTY_SOURCE_NAME = "jsonResource"; + private static final String THREAD_NAME = "ConfigLocator"; private static final ObjectMapper YAML_MAPPER = new ObjectMapper( new YAMLFactory() ); private static final JavaPropsMapper PROPERTIES_MAPPER = new JavaPropsMapper(); @@ -45,7 +49,11 @@ public class ConfigPropertySourceLocator // ============================================================ private final FileConfigClient fileConfigClient; - private final ExecutorService executorService = Executors.newFixedThreadPool( 10 ); + private final ExecutorService executorService = Executors.newFixedThreadPool( 10, + new BasicThreadFactory.Builder().namingPattern( THREAD_NAME + "-%d" ) + .daemon( true ) + .priority( Thread.MAX_PRIORITY ) + .build() ); // ============================================================ // Constructors: @@ -73,24 +81,26 @@ public ConfigPropertySourceLocator( final FileConfigClient fileConfigClient ) */ public PropertySource locateConfigResources( final List resources ) { - List> futures = new ArrayList<>(); CompositePropertySource composite = new CompositePropertySource( PROPERTY_SOURCE_NAME ); - for ( Resource resource : resources ) - { - final String directoryPath = resource.getDirectory(); - final List files = resource.getFiles(); - getJsonConfiguration( composite, directoryPath, files, futures ); - } + // + // Load files asynchronously + // + List> futures = new ArrayList<>(); + resources.stream().filter( Objects::nonNull ).map( resource -> + getJsonConfiguration( composite, resource.getDirectory(), resource.getFiles() ) ).forEach( futures::addAll ); + final CompletableFuture> listCompletableFuture = CompletableFuture.allOf( futures.toArray( new CompletableFuture[ 0 ] ) ) + .thenApply( future -> futures.stream().map( CompletableFuture::join ).collect( Collectors.toList() ) ); try { - for ( Future future : futures ) - { - future.get(); - } + // + // Wait for files to complete -- don't want Spring to start setting up Beans without all property sources + // + listCompletableFuture.get(); + logger.info( "Successfully loaded all external configuration files." ); } catch ( InterruptedException | ExecutionException e ) { - throw new ConfigResourceException( "Failed to retrieve file.", e ); + throw new ConfigResourceException( "Failed to retrieve files.", e ); } finally { @@ -103,16 +113,21 @@ public PropertySource locateConfigResources( final List resources ) // Private Methods: // ============================================================ - private void getJsonConfiguration( final CompositePropertySource composite, final String directoryPath, final List files, final List> futures ) + private List> getJsonConfiguration( final CompositePropertySource composite, + final String directoryPath, + final List files ) { - for ( String fileName : files ) - { - futures.add( executorService.submit( () -> loadConfigurationFile( composite, directoryPath, fileName ) ) ); - } + return files.stream().filter( Objects::nonNull ).map( file -> CompletableFuture.supplyAsync( () -> + loadConfigurationFile( directoryPath, file ), executorService ).thenAccept( mapPropertySource -> { + if ( mapPropertySource != null ) + { + composite.addPropertySource( mapPropertySource ); + } + } ) ).collect( Collectors.toList() ); } @SuppressWarnings( "unchecked" ) - private void loadConfigurationFile( final CompositePropertySource composite, final String directoryPath, final String fileName ) + private MapPropertySource loadConfigurationFile( final String directoryPath, final String fileName ) { final String filePath = getFilePath( directoryPath, fileName ); Map file; @@ -121,11 +136,11 @@ private void loadConfigurationFile( final CompositePropertySource composite, fin logger.info( "Loading configuration " + filePath + "..." ); if ( StringUtils.endsWithIgnoreCase( fileName, ".yml" ) || StringUtils.endsWithIgnoreCase( fileName, ".yaml" ) ) { - file = getYAMLFile( directoryPath, fileName, filePath ); + file = getYAMLFile( directoryPath, fileName ); } else if ( StringUtils.endsWithIgnoreCase( fileName, ".properties" ) ) { - file = getPropertiesFile( directoryPath, fileName, filePath ); + file = getPropertiesFile( directoryPath, fileName ); } else { @@ -139,8 +154,9 @@ else if ( StringUtils.endsWithIgnoreCase( fileName, ".properties" ) ) if ( !file.isEmpty() ) { final Map flattenMap = MapFlattener.flatten( file ); - composite.addPropertySource( new MapPropertySource( filePath, flattenMap ) ); + return new MapPropertySource( filePath, flattenMap ); } + return null; } private String getFilePath( final String directoryPath, final String fileName ) @@ -148,31 +164,31 @@ private String getFilePath( final String directoryPath, final String fileName ) return directoryPath + "/" + fileName; } - private Map getYAMLFile( final String directoryPath, final String fileName, final String filePath ) throws ConfigException + private Map getYAMLFile( final String directoryPath, final String fileName ) throws ConfigException { final Map file; - final String yamlFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, String.class ); + final byte[] yamlFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, byte[].class ); try { file = YAML_MAPPER.readValue( yamlFile, Map.class ); } catch ( IOException e ) { - throw new ConfigResourceException( "Failed to convert " + filePath + " from YAML format to be loaded in the property sources.", e ); + throw new ConfigResourceException( "Failed to convert " + fileName + " from YAML format to be loaded in the property sources.", e ); } return file; } - private Map getPropertiesFile( final String directoryPath, final String fileName, final String filePath ) throws ConfigException + private Map getPropertiesFile( final String directoryPath, final String fileName ) throws ConfigException { final Map file; try { - file = PROPERTIES_MAPPER.readValue( fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, String.class ), Map.class ); + file = PROPERTIES_MAPPER.readValue( fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, byte[].class ), Map.class ); } catch ( IOException e ) { - throw new ConfigResourceException( "Failed to convert " + filePath + " from PROPERTIES format to be loaded in the property sources.", e ); + throw new ConfigResourceException( "Failed to convert " + fileName + " from PROPERTIES format to be loaded in the property sources.", e ); } return file; } diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java index 747d85c..d63aa72 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigResourceBootstrapInitializer.java @@ -9,10 +9,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.StreamSupport; /** * If enabled and a list of resources to load exist, then the configuration resources are added as property sources. From e671964c34edade310d14472e026d32bf2ee9920 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 29 Jul 2018 14:11:34 -0600 Subject: [PATCH 27/35] release the next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e6f09e..6cb6eb0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.2-SNAPSHOT + 2.2 jar From 2621a353ab0be0b946ec457c8c0038c74cc91fd2 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 29 Jul 2018 14:12:25 -0600 Subject: [PATCH 28/35] up to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6cb6eb0..aba2a19 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.2 + 2.3-SNAPSHOT jar From 8689edd2474e819e669201bbca5d351b34d1fc9c Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 09:21:03 -0600 Subject: [PATCH 29/35] handle error when no file is returned --- .../env/ConfigPropertySourceLocator.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java index 242dce6..82f0065 100644 --- a/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java +++ b/src/main/java/io/github/piszmog/cloudconfigclient/autoconfig/env/ConfigPropertySourceLocator.java @@ -168,6 +168,10 @@ private Map getYAMLFile( final String directoryPath, final String fileName ) thr { final Map file; final byte[] yamlFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, byte[].class ); + if ( yamlFile == null ) + { + throw new ConfigResourceException( "Failed to find file " + fileName + " from the Config Server. Ensure the file exists." ); + } try { file = YAML_MAPPER.readValue( yamlFile, Map.class ); @@ -182,9 +186,14 @@ private Map getYAMLFile( final String directoryPath, final String fileName ) thr private Map getPropertiesFile( final String directoryPath, final String fileName ) throws ConfigException { final Map file; + final byte[] propertiesFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, byte[].class ); + if ( propertiesFile == null ) + { + throw new ConfigResourceException( "Failed to find file " + fileName + " from the Config Server. Ensure the file exists." ); + } try { - file = PROPERTIES_MAPPER.readValue( fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, byte[].class ), Map.class ); + file = PROPERTIES_MAPPER.readValue( propertiesFile, Map.class ); } catch ( IOException e ) { @@ -195,6 +204,11 @@ private Map getPropertiesFile( final String directoryPath, final String fileName private Map getJSONFile( final String directoryPath, final String fileName ) throws ConfigException { - return fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); + final Map jsonFile = fileConfigClient.getFileFromDefaultBranch( fileName, directoryPath, Map.class ); + if ( jsonFile == null ) + { + throw new ConfigResourceException( "Failed to find file " + fileName + " from the Config Server. Ensure the file exists." ); + } + return jsonFile; } } From e28a71b12e6c8bd3930bbfd6048af8efcf0d4d12 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 09:21:39 -0600 Subject: [PATCH 30/35] release next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aba2a19..0568650 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.3-SNAPSHOT + 2.3 jar From eec19310121e37d7b6e70393aba1feb07a7d96f0 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 09:22:39 -0600 Subject: [PATCH 31/35] up to next version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0568650..f4ffe7a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.3 + 2.4-SNAPSHOT jar From 437807ab0e48e2937bdf7a28236bee269cd5ba93 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 20:26:53 -0600 Subject: [PATCH 32/35] Delete LICENSE --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 45cb439..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 Kuglblitz - - 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. From 0d7e02b7153c4f9c1b9343d7625232da747e9080 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 20:27:09 -0600 Subject: [PATCH 33/35] Create LICENSE --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d1a79fe --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Piszmog + + 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. From 6fb2ac1f57fcec697e6e99e3841969719778df83 Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 20:27:24 -0600 Subject: [PATCH 34/35] Delete LICENSE --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 45cb439..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 Kuglblitz - - 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. From 88fdd8bae4979a8b1b3b5bad6e0bc0e2c4e60cab Mon Sep 17 00:00:00 2001 From: Piszmog Date: Sun, 5 Aug 2018 21:32:08 -0600 Subject: [PATCH 35/35] redo version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4ffe7a..0568650 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.github.piszmog cloud-config-client-autoconfig - 2.4-SNAPSHOT + 2.3 jar