|
|
@ -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. |
|
|
|
* <p> |
|
|
|
* Additionally, this class provides processing methods for Spring profile |
|
|
|
* properties configuration. |
|
|
|
* <p> |
|
|
|
* 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<Resource> getAdditionalResources() { |
|
|
|
List<Resource> resources = new ArrayList<Resource>(); |
|
|
|
List<Resource> classPathResources = new ArrayList<Resource>(); |
|
|
|
|
|
|
|
// 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<Resource> getAdditionalProfileResources(String[] profiles) { |
|
|
|
List<Resource> classPathResources = new ArrayList<Resource>(); |
|
|
|
|
|
|
|
/* |
|
|
|
* 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://<host_ip>:<TCP port>/<DB_DATABASE_NAME> ...", |
|
|
|
"spring.datasource.username = <DB_USERNAME>", |
|
|
|
"spring.datasource.password = <DB_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<String> missingProperties = new ArrayList<String>(); |
|
|
|
|
|
|
|
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<List<Resource>> additionalResources = new ArrayList<List<Resource>>(); |
|
|
|
|
|
|
|
additionalResources.add(getAdditionalResources()); |
|
|
|
additionalResources.add(getAdditionalProfileResources(environment.getActiveProfiles())); |
|
|
|
|
|
|
|
for (List<Resource> 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); |
|
|
|
} |
|
|
|
|
|
|
|