diff --git a/bookstore/src/main/java/com/fjordtek/bookstore/config/AdditionalPropertiesConfig.java b/bookstore/src/main/java/com/fjordtek/bookstore/config/AdditionalPropertiesConfig.java
index c7ede3d..9e780e3 100644
--- a/bookstore/src/main/java/com/fjordtek/bookstore/config/AdditionalPropertiesConfig.java
+++ b/bookstore/src/main/java/com/fjordtek/bookstore/config/AdditionalPropertiesConfig.java
@@ -4,6 +4,7 @@ package com.fjordtek.bookstore.config;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import org.springframework.boot.SpringApplication;
@@ -24,6 +25,9 @@ import org.springframework.core.io.support.PropertiesLoaderUtils;
* Main purpose of this implementation is to load additional properties files into Spring
* environment as early as possible during Spring Boot initialization process.
*
+* Additionally, this class provides processing methods for Spring profile
+* properties configuration.
+*
* Loading of this class must be enabled in /resources/META-INF/spring.factories file.
*
* @author Pekka Helenius
@@ -33,15 +37,120 @@ import org.springframework.core.io.support.PropertiesLoaderUtils;
//@Order(Ordered.LOWEST_PRECEDENCE)
public class AdditionalPropertiesConfig implements EnvironmentPostProcessor {
+ // Add global properties
private List getAdditionalResources() {
- List resources = new ArrayList();
+ List classPathResources = new ArrayList();
- // Add your additional (classpath, filesystem, etc.) properties files here
- resources.add(new ClassPathResource("website.properties"));
- resources.add(new ClassPathResource("authentication.properties"));
- resources.add(new ClassPathResource("categories.properties"));
+ /*
+ * Add your additional global properties files here
+ */
+ classPathResources.add(new ClassPathResource("website.properties"));
+ classPathResources.add(new ClassPathResource("authentication.properties"));
+ classPathResources.add(new ClassPathResource("categories.properties"));
+
+ return classPathResources;
+ }
+
+ // Add predefined profile properties
+ private List getAdditionalProfileResources(String[] profiles) {
+ List classPathResources = new ArrayList();
+
+ /*
+ * Add your additional profile property file prefixes here
+ * For instance, if profile is 'dev':
+ * "database" ->> "database-dev.properties"
+ */
+ String[] resourceFilePrefixes = {
+ "database"
+ };
+
+ for (String profile : profiles) {
+
+ for (String prefix : resourceFilePrefixes) {
+ try {
+ ClassPathResource classPathResource = new ClassPathResource(prefix + "-" + profile + ".properties");
+ classPathResource.getFile().canRead();
+ classPathResources.add(classPathResource);
+ System.out.printf(
+ "Profile properties file found: %s\n",
+ classPathResource.getFilename()
+ );
+ } catch (IOException e) {
+
+ if ( prefix.equals("database") && profile.equals("prod") ) {
+
+ System.err.println(String.join("\n",
+ "Production mode was enabled. However the following issue occured.",
+ "",
+ "Missing file: database-prod.properties",
+ "",
+ "File is not found from application class path.",
+ "",
+ "Please provide the missing file with following entries:",
+ "",
+ "spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver",
+ "spring.datasource.url = jdbc:mysql://:/ ...",
+ "spring.datasource.username = ",
+ "spring.datasource.password = ",
+ "spring.datasource.initialization-mode = always",
+ "",
+ "spring.jpa.hibernate.use-new-id-generator-mappings = false",
+ "spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl",
+ "",
+ "Unable to run application. Exiting."
+ )
+ );
+ System.exit(1);
+
+ } else {
+ System.err.println(
+ "Resource " +
+ prefix + "-" + profile + ".properties" +
+ " not found!"
+ );
+ }
+ }
+ continue;
+ }
+ }
+ return classPathResources;
+ }
+
+ private void checkPropertiesExist(
+ ConfigurableEnvironment environment,
+ String[] propEntries
+ ) {
+
+ List missingProperties = new ArrayList();
+
+ for (String prop : propEntries) {
+ try {
+ environment.getRequiredProperty(prop);
+ } catch (IllegalStateException e) {
+ missingProperties.add(prop);
+ }
+ }
+
+ if (missingProperties.size() != 0) {
+ System.err.printf(
+ "\nFollowing, required application property entries are missing:\n\n"
+ );
+ int i = 0;
+ while (i < missingProperties.size()) {
+ System.err.printf(
+ "%s\n",
+ missingProperties.get(i)
+ );
+ i++;
+ }
+ System.err.printf(
+ "\nCannot continue. Exiting. (Active profiles: %s)\n",
+ Arrays.stream(environment.getActiveProfiles())
+ .toArray()
+ );
+ System.exit(1);
+ }
- return resources;
}
private void showSpringConfiguration(MutablePropertySources properties) {
@@ -60,19 +169,41 @@ public class AdditionalPropertiesConfig implements EnvironmentPostProcessor {
MutablePropertySources propertySources = environment.getPropertySources();
- for (Resource res : getAdditionalResources()) {
- try {
- propertySources.addLast(
- new PropertiesPropertySource(
- res.getFilename(),
- PropertiesLoaderUtils.loadProperties(res)
- )
- );
- } catch (IOException e) {
- e.printStackTrace();
+ List> additionalResources = new ArrayList>();
+
+ additionalResources.add(getAdditionalResources());
+ additionalResources.add(getAdditionalProfileResources(environment.getActiveProfiles()));
+
+ for (List resList : additionalResources) {
+ for (Resource res : resList) {
+ try {
+ propertySources.addLast(
+ new PropertiesPropertySource(
+ res.getFilename(),
+ PropertiesLoaderUtils.loadProperties(res)
+ )
+ );
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
}
+ if ( Arrays.stream(environment.getActiveProfiles()).anyMatch(p -> p.contains("prod")) ) {
+ checkPropertiesExist(
+ environment,
+ new String[] {
+ "spring.datasource.driver-class-name",
+ "spring.datasource.url",
+ "spring.datasource.username",
+ "spring.datasource.password",
+ "spring.datasource.initialization-mode",
+ "spring.jpa.hibernate.use-new-id-generator-mappings",
+ "spring.jpa.hibernate.naming.physical-strategy"
+ }
+ );
+ }
+
showSpringConfiguration(propertySources);
}