Reputation: 137
I have a class called ConfigManagement which uses only static methods/fields. One of the static methods, called initializeConfig() takes a Property object (points at application.properties) as input and populates the fields and calls some other methods with the values from the application.properties file.
public class ConfigManagement {
private static String signatureAlgorithm;
private static String myName;
private static RSAPublicKey myPublicKey;
private static RSAPrivateKey myPrivateKey;
private static HashMap<String, RSAPublicKey> peerPubKeys = new HashMap<String, RSAPublicKey>();
private static boolean isInitialized = false;
/**
* @return the signatureAlgorithm
*/
public static void initializeConfig(Properties props) {
signatureAlgorithm = props.getProperty("cybertrust.crypto.signatureAlgorithm");
myName = props.getProperty("cybertrust.crypto.myName");
try {
try {
myPublicKey = Loader.getPublicKeyFromCertificateFile(props.getProperty("cybertrust.crypto.myCertificate"));
}
catch (Exception e) {
throw new IllegalStateException("cybertrust.crypto.myCertificate is empty, the file is not found or it contains invalid data");
}
try {
myPrivateKey = Loader.getPrivateKeyFromFile(props.getProperty("cybertrust.crypto.myPrivateKey"));
}
catch (Exception e) {
throw new IllegalStateException("cybertrust.crypto.myPrivateKey is empty, the file is not found or it contains invalid data");
}
peerPubKeys.put(myName, myPublicKey);
int peerCounter = 0;
do {
String peerNameProp = String.format("cybertrust.crypto.peerModules.%d.name", peerCounter);
String peerName = props.getProperty(peerNameProp);
if (peerName == null)
break;
String peerNameCertFileProp = String.format("cybertrust.crypto.peerModules.%d.certificate", peerCounter);
String peerNameCertFile = props.getProperty(peerNameCertFileProp);
if (peerNameCertFile == null) // Do not halt the program, produce though an error
Logger.getLogger("ConfigManagement").log(Level.SEVERE,
String.format("Property %s not found while property %s is defined", peerNameCertFile, peerNameProp));
// instantiate public key from file
try {
RSAPublicKey peerRsaPubKey = Loader.getPublicKeyFromCertificateFile(peerNameCertFile);
peerPubKeys.put(peerName, peerRsaPubKey);
}
catch (Exception e) {
Logger.getLogger("ConfigManagement").log(Level.SEVERE,
String.format("File %s specified in property %s not found or does not contains a valid RSA key", peerNameCertFile, peerNameCertFileProp)); }
peerCounter++;
} while (true);
}
catch (Exception e) {
throw(e);
}
if ((myPublicKey == null) || (signatureAlgorithm == null) || (myName == null))
throw new IllegalStateException("one of the properties cybertrust.crypto.signatureAlgorithm, cybertrust.crypto.myName, cybertrust.crypto.myPublicKey, cybertrust.crypto.myPrivateKey is not defined");
isInitialized = true;
}
private static void testInitialized() {
if (!isInitialized)
throw new IllegalStateException("The configuration has not been initialized");
}
public static String getSignatureAlgorithm() {
testInitialized();
return signatureAlgorithm;
}
/**
* @return the myName
*/
public static String getMyName() {
testInitialized();
return myName;
}
/**
* @return the myPublicKey
*/
public static RSAPublicKey getMyPublicKey() {
testInitialized();
return myPublicKey;
}
/**
* @return the myPrivateKey
*/
public static RSAPrivateKey getMyPrivateKey() {
testInitialized();
return myPrivateKey;
}
public static RSAPublicKey getPublicKey(String peerName) throws NoSuchElementException {
testInitialized();
RSAPublicKey result = peerPubKeys.get(peerName);
if (result == null)
throw new NoSuchElementException("No known key for module " + peerName);
else
return result;
}
}
The application.properties file looks something like this:
cybertrust.crypto.myName=tms1235.cybertrust.eu
cybertrust.crypto.myCertificate=tms1235.cert.pem
cybertrust.crypto.myPrivateKey=tms1235.key.pem
cybertrust.crypto.signatureAlgorithm=SHA256withRSA
cybertrust.crypto.peerModules.0.name=sga1234.cybertrust.eu
cybertrust.crypto.peerModules.0.certificate=sga1234.cert.pem
cybertrust.crypto.peerModules.1.name=tms1234.cybertrust.eu
cybertrust.crypto.peerModules.1.certificate=tms1234.cert.pem
In a simple Java project I run ConfigManagement.initializeConfig(props);
in main() and the fields are initialized and I can use the rest of the methods. In Spring it's not that simple.
I am trying to integrate this code in a SpringBoot application and I don't know how/where to initialize this class.
I am posting the Spring configuration for reference:
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.cybertrust.tms")
//@PropertySource({ "classpath:persistence-mysql.properties" })
@PropertySource({ "classpath:model.properties" })
public class DemoAppConfig implements WebMvcConfigurer {
@Autowired
private Environment env;
private Logger logger = Logger.getLogger(getClass().getName());
// define a bean for ViewResolver
@Bean
public DataSource myDataSource() {
// create connection pool
ComboPooledDataSource myDataSource = new ComboPooledDataSource();
// set the jdbc driver
try {
myDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
}
catch (PropertyVetoException exc) {
throw new RuntimeException(exc);
}
// for sanity's sake, let's log url and user ... just to make sure we are reading the data
logger.info("jdbc.url=" + env.getProperty("spring.datasource.url"));
logger.info("jdbc.user=" + env.getProperty("spring.datasource.username"));
// set database connection props
myDataSource.setJdbcUrl(env.getProperty("spring.datasource.url"));
myDataSource.setUser(env.getProperty("spring.datasource.username"));
myDataSource.setPassword(env.getProperty("spring.datasource.password"));
// set connection pool props
myDataSource.setInitialPoolSize(getIntProperty("connection.pool.initialPoolSize"));
myDataSource.setMinPoolSize(getIntProperty("connection.pool.minPoolSize"));
myDataSource.setMaxPoolSize(getIntProperty("connection.pool.maxPoolSize"));
myDataSource.setMaxIdleTime(getIntProperty("connection.pool.maxIdleTime"));
return myDataSource;
}
private Properties getHibernateProperties() {
// set hibernate properties
Properties props = new Properties();
props.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
props.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
props.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
return props;
}
// need a helper method
// read environment property and convert to int
private int getIntProperty(String propName) {
String propVal = env.getProperty(propName);
// now convert to int
int intPropVal = Integer.parseInt(propVal);
return intPropVal;
}
@Bean
public LocalSessionFactoryBean sessionFactory(){
// create session factorys
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
// set the properties
sessionFactory.setDataSource(myDataSource());
sessionFactory.setPackagesToScan(env.getProperty("hibernate.packagesToScan"));
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
// setup transaction manager based on session factory
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
@Bean
public ConfigManagement configManagement() {
return new ConfigManagement();
}
}
And the Spring Boot main():
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.cybertrust.tms")
//@PropertySource({ "classpath:persistence-mysql.properties" })
@PropertySource({ "classpath:model.properties" })
//@EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
@SpringBootApplication(exclude = {HibernateJpaAutoConfiguration.class})
public class TMS extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(TMS.class, args);
}
}
Upvotes: 1
Views: 2251
Reputation: 137
In order to integrate this code to a Spring project, I had to:
Make the class a bean, managed by Spring, by adding it in my configuration file that I posted in my question, I added this:
@Bean
public ConfigManagement configManagement() {
return new ConfigManagement();
}
Remove the static
declaration from the class properties and use the @Value
annotation to initialize them from the application.properties file, as suggested by @user7294900.
However, some of the class properties were not primitive types and couldn't be initialized directly from the application.properties. They needed some "business-logic" to be run at initialization time. In order to achieve that, I had to remove the static
declaration and add the @PostConstruct
annotation in the initializeConfig()
method, which is the one that handled the initialization of the rest of the properties.
public class ConfigManagement {
@Value("${cybertrust.crypto.signatureAlgorithm}")
private String signatureAlgorithm;
@Value("${cybertrust.crypto.myName}")
private String myName;
@Value("${cybertrust.crypto.myCertificate}")
private String myCertificate;
@Value("${cybertrust.crypto.myPrivateKey}")
private String myPrivateKey;
private RSAPublicKey myRSAPublicKey;
private RSAPrivateKey myRSAPrivateKey;
private HashMap<String, RSAPublicKey> peerPubKeys = new HashMap<String, RSAPublicKey>();
private boolean isInitialized = false;
int peerCounter;
/**
* @return the signatureAlgorithm
*/
public ConfigManagement() {
}
@PostConstruct
public void initializeConfig() throws Exception {
try {
try {
myRSAPublicKey = Loader.getPublicKeyFromCertificateFile("C:\\Users\\Findorgri\\git\\trust-management\\TMS-rest\\" + myCertificate);
}
catch (Exception e) {
throw new IllegalStateException("cybertrust.crypto.myCertificate is empty, the file is not found or it contains invalid data");
}
try {
myRSAPrivateKey = Loader.getPrivateKeyFromFile("C:\\Users\\Findorgri\\git\\trust-management\\TMS-rest\\" + myPrivateKey);
}
catch (Exception e) {
throw new IllegalStateException("cybertrust.crypto.myPrivateKey is empty, the file is not found or it contains invalid data");
}
peerPubKeys.put(myName, myRSAPublicKey);
Properties props = loadProperties("C:\\Users\\Findorgri\\git\\trust-management\\TMS-rest\\src\\main\\resources\\application.properties");
if (props == null) {
throw new Exception("Properties file not found");
}
peerCounter = 0;
do {
String peerNameProp = String.format("cybertrust.crypto.peerModules.%d.name", peerCounter);
String peerName = props.getProperty(peerNameProp);
System.out.println("####TEST####\n" + peerNameProp + "\n" + peerName +"\n####TEST####");
if (peerName == null)
break;
String peerNameCertFileProp = String.format("cybertrust.crypto.peerModules.%d.certificate", peerCounter);
String peerNameCertFile = props.getProperty(peerNameCertFileProp);
System.out.println("####TEST####\n" + peerNameCertFileProp + "\n" + peerNameCertFile +"\n####TEST####");
if (peerNameCertFile == null) // Do not halt the program, produce though an error
Logger.getLogger("ConfigManagement").log(Level.SEVERE,
String.format("Property %s not found while property %s is defined", peerNameCertFile, peerNameProp));
// instantiate public key from file
try {
RSAPublicKey peerRsaPubKey = Loader.getPublicKeyFromCertificateFile("C:\\Users\\Findorgri\\git\\trust-management\\TMS-rest\\" + peerNameCertFile);
peerPubKeys.put(peerName, peerRsaPubKey);
}
catch (Exception e) {
Logger.getLogger("ConfigManagement").log(Level.SEVERE,
String.format("File %s specified in property %s not found or does not contains a valid RSA key", peerNameCertFile, peerNameCertFileProp)); }
peerCounter++;
} while (true);
}
catch (Exception e) {
throw(e);
}
if ((myRSAPublicKey == null) || (signatureAlgorithm == null) || (myName == null))
throw new IllegalStateException("one of the properties cybertrust.crypto.signatureAlgorithm, cybertrust.crypto.myName, cybertrust.crypto.myPublicKey, cybertrust.crypto.myPrivateKey is not defined");
isInitialized = true;
peerPubKeys.forEach((key, value) -> System.out.println(key + ":" + value));
}
....
Finally, for completeness' sake, for the initializeConfig()
method to have access at the application.properties I had to use this method:
private static Properties loadProperties(String fileName) throws IOException {
FileInputStream fis = null;
Properties prop = null;
try {
fis = new FileInputStream(fileName);
prop = new Properties();
prop.load(fis);
} catch(FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
} finally {
fis.close();
}
return prop;
}
Upvotes: 1
Reputation: 58782
Your static solution won't work in a Spring environment as is, because static can be executed before Spring is up and loaded all beans and properties
You should rewrite your code in a Spring way by getting propertyies using @Value
Injecting a property with the @Value annotation is straightforward:
@Value( "${jdbc.url}" ) private String jdbcUrl;
Upvotes: 1