How it works
- The location of your property file is found by looking at a system property configured in the WildFly configuration file. This allows you to change the location of the property file, without having to recompile/redeploy the application.
- The property file is loaded and the values are stored in a HashMap inside a @Singleton session bean
- The properties are then injected into your CDI beans, making them accessible to your application code. This is achieved by creating a CDI Qualifier and producer method.
How its done
1. Create and populate a properties file inside the WildFly configuration folder$ echo 'docs.dir=/var/documents' >> .standalone/configuration/application.properties
2. Add a system property to the WildFly configuration file.
$ ./bin/jboss-cli.sh --connect [standalone@localhost:9990 /] /system-property=application.properties:add(value=${jboss.server.config.dir}/application.properties)
This will add the following to your server configuration file (standalone.xml or domain.xml):
<system-properties> <property name="application.properties" value="${jboss.server.config.dir}/application.properties"/> </system-properties>
3. Create the singleton session bean that loads and stores the application wide properties
package com.ritchie.chris.properties; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.annotation.PostConstruct; import javax.ejb.Singleton; @Singleton public class PropertyFileResolver { private Map<String, String> properties = new HashMap<>(); @PostConstruct private void init() throws IOException { //matches the property name as defined in the system-properties element in WildFly String propertyFile = System.getProperty("application.properties"); File file = new File(propertyFile); Properties properties = new Properties(); try { properties.load(new FileInputStream(file)); } catch (IOException e) { System.out.println("Unable to load properties file" + e); } HashMap hashMap = new HashMap<>(properties); this.properties.putAll(hashMap); } public String getProperty(String key) { return properties.get(key); } }
4. Create the CDI Qualifier. We will use this annotation on the Java variables we wish to inject into.
package com.ritchie.chris.properties; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.inject.Qualifier; @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR }) public @interface ApplicationProperty { // no default meaning a value is mandatory @Nonbinding String name(); }
5. Create the producer method; this generates the object to be injected
package com.ritchie.chris.properties; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.InjectionPoint; import javax.inject.Inject; public class ApplicaitonPropertyProducer { @Inject private PropertyFileResolver fileResolver; @Produces @ApplicationProperty(name = "") public String getPropertyAsString(InjectionPoint injectionPoint) { String propertyName = injectionPoint.getAnnotated().getAnnotation(ApplicationProperty.class).name(); String value = fileResolver.getProperty(propertyName); if (value == null || propertyName.trim().length() == 0) { throw new IllegalArgumentException("No property found with name " + value); } return value; } @Produces @ApplicationProperty(name="") public Integer getPropertyAsInteger(InjectionPoint injectionPoint) { String value = getPropertyAsString(injectionPoint); return value == null ? null : Integer.valueOf(value); } }
6. Lastly inject the property into one of your CDI beans
package com.ritchie.chris.properties; import javax.ejb.Stateless; import javax.inject.Inject; @Stateless public class MySimpleEJB { @Inject @ApplicationProperty(name = "docs.dir") private String myProperty; public String getProperty() { return myProperty; } }
Source code can be found on GitHub
Hi Chris, interesting post. I've also started a similar project that works independently of the application server where the configuration file is optional. Available on github goo.gl/sV1G8y
ReplyDeleteThis is just PERFECT!!! Just what I needed! I just plugged it in and it worked!!! Thanks a bunch!
ReplyDelete