Google Guice Properties Management - java

I would like to create a proper properties management strategy in a java webapp that relays on google guice as a DI framework.
I would like to have a mechanism answering the following 3 requirements:
I would like to be able to inject properties using guice (#Named)
I would like to be able to access properties in a static way
The mechanism should support prioritization of properties, meaning that a property can be wrapped in the deployed war with a certain value but it can also be redundant in the target system level or local file system (of the target machine I deploy on), in such a case the value in the war will be overridden by the value that exists in the target machine.
I believe this is a standard requirement. Now, using guice standard binder I can easily get the first requirement but not the other two. To get the other two I created my own class that does the following:
Wraps and exposes the binding methods of guice (those that binds properties) For example:
public static void bindString(AnnotatedBindingBuilder<String> binder, String property, String defaultValue) {
binder.annotatedWith(Names.named(property)).toInstance(getProperty(property, defaultValue));
}
Where the getProperty method knows how to handle my properties (get the value from the war or system level) and exposes the properties statically as well.
So basically as long as I'm using this utility that I created for properties bindings I'm good, it covers all my requirements but once I use the standard guice bindings I'm losing the second and third requirement.
Is there a way to override guice bindings and get all those 3 requirements?
Once I had the same challange in a spring based app and was pretty easy. I implemented ApplicationContextInitializer with the following method:
#Override
public void initialize(ConfigurableWebApplicationContext ctx) {
PropertySource<Map<String, Object>> localProps = null;
try {
localProps = new ResourcePropertySource(new ClassPathResource(LOCAL_PROPERTIES_FILE_NAME));
} catch (IOException e) {
LOG.fatal("Could not load local properties from classpath " + LOCAL_PROPERTIES_FILE_NAME);
return;
}
LOG.info("Loaded configuration from classpath local file " + LOCAL_PROPERTIES_FILE_NAME);
ctx.getEnvironment().getPropertySources().addFirst(localProps);
}
so this gave me a way to add local properties with highest priority to my Environment. In case of overlap with war properties the local ones had higher priority. In addition I exposed my Environment statically so I has static access to my properties (for services that are not managed by the container, legacy mostly).
How can I achieve this with guice?

Unfortunately, I don't think that you are going to find anything that gives you a truly clean and satisfying implementation. Especially, I don't think that you will find anything that gives you exactly what you want without implementing at least portions of it yourself.
If I had those needs, I would make sure that my injector is created in a central InjectorFactory. If you require a large number of parameters from outside to create your injector, I would simply create it once at the very beginning of my application and then cache the injector into a static final field. This would make it available to a static method. I would bind my "fall-back" property loading to an explicit provider. That way, instead of using the standard Names.bindProperties(...) method, I would bind it directly to a Provider. This provider then implements the logic that is necessary to perform the fallback or to merge multiple property files. Having the injector cached to a static field means that I can call a static method to access properties from a global-context outside of my injected classes.
Using your own provider seems initially unpleasant, but can provide some additional benefits. For starters, you can implement your fallback strategy exactly how you want. Additionally, you can add additional behaviors such as auto-reloading your property files, etc (not shown in my code sample).
public class InjectorFactory {
private static Injector injector = null;
public static synchronized Injector getOrCreateInjector() {
if(injector == null) {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
Properties properties1 = createProperties("file1.properties");
Properties properties2 = createProperties("file2.properties");
Set<Object> propertyNames = new HashSet<Object>();
propertyNames.addAll(properties1.keySet());
propertyNames.addAll(properties2.keySet());
for (Object object : propertyNames) {
String propertyName = (String) object;
bind(String.class).annotatedWith(Names.named(propertyName)).toProvider(new StringProvider(properties1, properties2, propertyName));
}
}
private Properties createProperties(String propertyFileName) {
try {
InputStream stream = InjectorFactory.class.getResourceAsStream(propertyFileName);
try {
Properties properties = new Properties();
properties.load(stream);
return properties;
} finally {
stream.close();
}
} catch (IOException exception) {
throw new RuntimeException("Could not load properties file");
}
}
});
}
return injector;
}
public static String getProperty(String propertyName) {
return getOrCreateInjector().getInstance(Key.get(String.class, Names.named(propertyName)));
}
}
Given the above code and file1.properties:
property1=Property1Value
property2=Property2Value
And file.properties:
property2=IncorrectProperty2Value
property3=Property3Value
with the provider
public class StringProvider implements Provider<String> {
private Properties properties1;
private Properties properties2;
private String propertyName;
public StringProvider(Properties properties1, Properties properties2,
String propertyName) {
this.properties1 = properties1;
this.properties2 = properties2;
this.propertyName = propertyName;
}
public String get() {
if(properties1.containsKey(propertyName)) {
return properties1.getProperty(propertyName);
}
return properties2.getProperty(propertyName);
}
}
The following usage:
public class InjectorFactoryTest {
public static void main(String ... parameters) {
System.out.println(InjectorFactory.getProperty("property1"));
System.out.println(InjectorFactory.getProperty("property2"));
System.out.println(InjectorFactory.getProperty("property3"));
}
}
Outputs:
Property1Value
Property2Value
Property3Value

Related

Specify hibernate.multi_tenant_connection_provider without using reflection

Currently I am specifying the hibernate multi tenant connection provider and resolver in a properties file using this.
hibernate.multi_tenant_connection_provider: com.app.MapMultiTenantConnectionProvider
hibernate.tenant_identifier_resolver: com.app.MultiTenantCurrentTenantIdentifierResolver
Hibernate is using reflection to load these classes. The problem is that I need these classes to have access to certain variables. E.g. The DropWizard config file and users organisation to know what the database URL is and the tenant id. Currently I'm having to make variables static so that the provider has access to it.
The tutorials like this have all the required info specified in the properties file while I need mine to be dynamic depending on the currently connected user.
Here is an example of the kind of thing I'm having to do with static variables. Overall it makes the code quite messy.
public class MapMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
private static Logger log = LoggerFactory.getLogger(MapMultiTenantConnectionProvider.class);
private Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
public MapMultiTenantConnectionProvider() throws IOException {
}
#Override
protected ConnectionProvider getAnyConnectionProvider() {
return getConnectionProviderForTenant("chorus");
}
#Override
protected ConnectionProvider selectConnectionProvider(final String tenantIdentifier) {
return getConnectionProviderForTenant(tenantIdentifier);
}
private ConnectionProvider getConnectionProviderForTenant(final String tenantId) {
final ConnectionProvider connectionProvider;
if (!connectionProviderMap.containsKey(tenantId)) {
// Access a static variable here that contains the database URL, username, etc
final MyConfig config = MyApp.CONFIGURATION;
final Properties properties = new Properties();
properties.setProperty("hibernate.connection.url", config.connectionUrl);
properties.setProperty("hibernate.connection.username", config.username);
properties.setProperty("hibernate.connection.password", config.password);
properties.setProperty("hibernate.dialect", config.databaseConfig.getHibernateDialect());
final DriverManagerConnectionProviderImpl newConnectionProvider = new DriverManagerConnectionProviderImpl();
newConnectionProvider.configure(properties);
this.connectionProviderMap.put(tenantId, newConnectionProvider);
connectionProvider = newConnectionProvider;
} else {
connectionProvider = connectionProviderMap.get(tenantId);
}
return connectionProvider;
}
}
I would like to create an instance and pass in the configuration (or anything else needed) like this.
new MapMultiTenantConnectionProvider(configuration)
Is it possible to specify the provider by creating an instance of it instead of defining it in a properties file?
You could implement the ServiceRegistryAwareService interface to get access to the Hibernate ServiceRegistry which provides you access to almost all Hibernate configurations. I don't know how you'd normally access this dropwizard configuration, but in case it is available through a managed bean, you could access the ManagedBeanRegistry and access the bean that provides this information. Other than that, there is not much you can do. Please note though, that you current implementation is not thread safe. You should be using a ConcurrentHashMap and use putIfAbsent, or even better, computeIfAbsent.

Using google guice with statically bound parameters

I would like to bind some parameters with guice in similar way that guice binds the unannotated Injector class to the calling injector instance for use with a provider.
In particular, on our project we have an object called the ResourceEnvironment, this object is effectively a wrapper on the method Class.getClassLoader().getResource(), enabling us to elegantly convert "com-paths" (class relative resource paths) into the resources they represent (FXML files, image files, etc). We use this to load resources that are deployed within our jar.
Right now, this code is repeated with a huge amount of frequency:
Class ClazzX{
private final ResourceEnvironment env;
#Inject
public ClazzX(ResourceEnvironment.Factory envFactory){
env = envFactory.create(this.getClass())
}
}
when what I would really like to do is much more simply:
Class ClazzX{
private #Inject ResourceEnvironment env;
}
but to do that, I would effectively need a provider:
binder.install(new Module(){
#Provides ResourceEnvironment getResourceEnv(Injector callingInjector){
Class targetClazz = callingInjector.getDependencyBeingResolved(); //not a real method
ResourceEnivonment.Factory factory = callingInjector.getInstance(RE.F.class)
return factory.create(targetClazz);
}
});
Is it possible to get some information about the type currently being resolved through the injector at runtime?
Using the custom injection of loggers as a template (https://github.com/google/guice/wiki/CustomInjections) it should be easy to implement a specific memberinjector that uses the declaring class as a source for the environment injection. From what I know, this requires a custom annotaion as well.
class ResourceEnvironmentMembersInjector<T> implements MembersInjector<T> {
private final Field field;
private final ResourceEnvironment env;
ResourceEnvironmentMembersInjector(Field field) {
this.field = field;
env = envFactory.create(field.getDeclaringClass());
field.setAccessible(true);
}
public void injectMembers(T t) {
try {
field.set(t, env);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

Is it possible to use the Multibinder within Guice to construct dynamic sets based on application configuration?

I have an application which relies on Properties configuration to determine whether to mix in various components or not.
For example, the configuration has boolean flags like "componentX.enabled" etc which determine whether these components should be active or not.
Currently I am using these flags in my provider methods like so:
#Provides
#Singleton
#Nullable
public ComponentX provideComponentX(Properties props) {
if (props.isComponentXEnabled()) {
return new ComponentX();
} else {
return null;
}
}
#Provides
#Singleton
public Set<Component> provideComponentSet(
#Nullable ComponentX compX,
ComponentY compY,
ComponentZ compZ
) {
Set<Component> comps = new HashSet<>();
if (compX != null) {
comps.add(compX);
}
comps.add(compY);
comps.add(compZ);
return comps;
}
This approach seems a little clunky (it relies on possible injecting null)- but is there a better way?
The only other way I can think of doing it is by using a parent injector to obtain the application Properties into my module, and then using the set Multibinder.
Then use the create child injector with the new module to complete the bootstrap process.
public class Module extends AbstractModule {
Properties props;
public Module(Properties props) {
this.props = props;
}
public void configure() {
Multibinder<Component> compBinder = Multibinder.newSetBinder(binder(), Component.class);
if (props.isComponentXEnabled()) {
compBinder.addBinding().to(ComponentX.class);
}
compBinder.addBinding().to(ComponentY.class);
compBinder.addBinding().to(ComponentZ.class);
}
}
This also seems a little clunky because it requires the use of a child injector etc.
Again, is there a better way?
Maybe I could use Netflix's Governator (https://github.com/Netflix/governator/wiki/Configuration-Mapping) to inject Configuration values into my module (not sure if that is possible or not)?
How do other people approach this problem?
The applications I've been working with recently have a properties file (or other configuration) that is used to decide which parts of the application are relevant. Our typical approach is parse those properties immediately (just to a Properties object) and construct the application module(s) from that, and they will then conditionally include other modules based on the values specified.
In a couple of places, this has grown into an "init parameters" set, with an enumeration of possible parameters:
enum InitParam {
PricesQueue("prices.queue")
}
Each enum instance is related to a property key and there is a method to get a basic string value for each parameter from Properties:
boolean presentIn(Properties props) { return props.containsKey(propertyKey); }
String valueIn(Properties props) { return props.getProperty(propertyKey); }
So this can be used like so:
public AppModule extends AbstractModule {
private final Properties config;
protected void configure() {
if (InitParam.PricesQueue.presentIn(config)) {
install(new PricesQueueConsumerModule(config));
}
}
}
Additionally, there is a module to bind all the values in the config properties to String, Optional<String> etc, allowing:
#Inject
public PricesQueueConsumer(#FromInitParam(InitParam.PricesQueue) String queueName) {
}
This will trap the queue consumer being referenced when the configuration isn't available (the module won't bind a string if the value isn't present in the config file) while still allowing the behaviour for when the value isn't present to be deferred to later (by injecting Optional<String> instead)
So this is somewhat similar to your second approach, except that I'd not considered the using-Guice-to-inject-Guice-modules approach, which seems a bit convoluted. Although probably it's essentially the same. Maybe rather than a parent/child injector you could simply create a "bootstrapping" injector to build your top-level application module, and then use that to build a completely separate injector?

Spring: How to replace the Environment bean created in Application Context

I am looking to replace the Environment bean used by Spring with my own implementation. Is this bad-practice, and if not, how can I do this cleanly? Currently I have created a bean that implements the Environment interface and uses the existing Environment bean, but this means all the configuration code needing the Environment bean must now use my custom Environment bean. I would think it would be cleaner to replace Springs Environment bean with my own, then no configuration needing it would need to change. Currently the only way I can think to do this would be to either create my own ApplicationContext thus setting the environment to my own, or to have something be ApplicationContextAware and set the environment there. Both of these seem to be a bit hokey to me.
Constraints:
I am using the latest version of Spring3.
I am using Java based configuration; not XML
Thank you.
Edit: Background
I suppose I should explain why I want to do this in case my thinking is flawed. I was avoid this in order to avoid the nonconstructive "why would you want to do that?" responses.
The Spring Environment bean, when looking for property values, uses a set of property sources. A typical stack looks like this (but is not limited to):
JNDI
System Properties (set via -Dmyprop=foo)
Environment Variables
...
For security reason, it is necessary to encrypt some of these properties (e.g. database passwords). The go to solution is to use Jasypt for property encryption. However, the Spring/Jasypt only provide a means of inserting a new property source into the environment. So:
Property file with potentially encrypted values
JNDI
System Properties (set via -Dmyprop=foo)
Environment Variables
...
However, this is not ideal as this means that properties can only be stored in a single file to be maintained by the operations group or that properties would be spread out amongst property files, environment variables, etc. In addition, I feel that properties have the potential of being encrypted regardless of their property source.
So this lead me to thinking that I either need to decrypt the properties in my code wherever I attempt to access them from the environment, or I need to create my own Environment bean that can do this for me.
I'm welcome to hear constructive comments and alternatives.
EDIT: Adding solution based on answer from M. Deinum
public class EnvironmentBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static final String CONFIGURATION_PROPERTY_PBE_ALGORITHM = "PBE_ALGORITHM";
private static final String CONFIGURATION_PROPERTY_PBE_PASSWORD = "PBE_PASSWORD";
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
StandardEnvironment environment = (StandardEnvironment) beanFactory.getBean("environment");
if (environment != null) {
StringEncryptor encryptor = this.getEncryptor(environment);
MutablePropertySources mutablePropertySources = environment.getPropertySources();
for (PropertySource<?> propertySource : mutablePropertySources) {
mutablePropertySources.replace(
propertySource.getName(),
new EncryptablePropertySourcePropertySource(propertySource.getName(), propertySource, encryptor));
}
}
}
private StringEncryptor getEncryptor(Environment environment) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
String algorithm = environment.getProperty(CONFIGURATION_PROPERTY_PBE_ALGORITHM);
if (algorithm != null) {
encryptor.setAlgorithm(algorithm);
}
String password = environment.getProperty(CONFIGURATION_PROPERTY_PBE_PASSWORD);
if (password != null) {
encryptor.setPassword(password);
}
return encryptor;
}
private class EncryptablePropertySourcePropertySource extends PropertySource<PropertySource<?>> {
private StringEncryptor stringEncryptor;
private TextEncryptor textEncryptor;
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final StringEncryptor encryptor) {
super(name, propertySource);
this.stringEncryptor = encryptor;
}
public EncryptablePropertySourcePropertySource(final String name, final PropertySource<?> propertySource, final TextEncryptor encryptor) {
super(name, propertySource);
this.textEncryptor = encryptor;
}
#Override
public Object getProperty(String name) {
Object value = this.source.getProperty(name);
if (value != null && value instanceof String) {
value = this.decode((String) value);
}
return value;
}
private String decode(String encodedValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(encodedValue)) {
return encodedValue;
}
if (this.stringEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.stringEncryptor);
}
if (this.textEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(encodedValue, this.textEncryptor);
}
throw new EncryptionOperationNotPossibleException(
"Neither a string encryptor nor a text encryptor exist "
+ "for this instance of EncryptableProperties. This is usually "
+ "caused by the instance having been serialized and then "
+ "de-serialized in a different classloader or virtual machine, "
+ "which is an unsupported behaviour (as encryptors cannot be "
+ "serialized themselves)");
}
}
}
However, the Spring/Jasypt only provide a means of inserting a new property source into the environment.
Actually that is where you are wrong, you can replace PropertySources as well. See the javadoc of MutablePropertySources. This is also used internally by Spring to first add some dummy PropertySources and replace them later.
What you could do is create a PropertySource which delegates to another PropertySource and decrypts the value on the fly. That way you could replace all PropertySources with a one which wraps around the original.
MutablePropertySources mps = env.getgetPropertySources();
for (PropertySource ps : env.getgetPropertySources()) {
EncryptablePropertySource eps = new EncryptablePropertySource(ps.getName(), ps, encryptor);
mps.replace(ps.getName(), eps);
}
You could use the EncryptablePropertiesPropertySource as a sample, what you basically need to do is replace the Properties with PropertySource.
It would be easier if SPR-8928 would be fixed as that would allow simply for the EncryptedPropertySourcesPlaceholderConfigurer to be registered and all properties would converted and you wouldn't need these hacks.

Make Java Properties available across classes?

I chose to take properties file for customization of some settings.
I use the following code to make a Properties Object available in a class
Properties defaultProps = new Properties();
try {
FileInputStream in = new FileInputStream("custom.properties");
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
Do I have to add this to every class? Probably not because then every class would open a stream to this file.
But I'm not sure how to handle this properly.
Should I make a class MyProperties and instantiate it in whatever class needs properties?
Thanks in advance!
Once you initialized defaultProps, you can make its contents available to other objects in your app e.g. via a public static accessor method, e.g.:
public class Config {
private static Properties defaultProps = new Properties();
static {
try {
FileInputStream in = new FileInputStream("custom.properties");
defaultProps.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getProperty(String key) {
return defaultProps.getProperty(key);
}
}
This is the simplest approach, however it creates an extra dependency which makes unit testing harder (unless you provide a method in Config to set a mock property object for unit testing).
An alternative is to inject defaultProps (or individual configuration values from it) into each object which needs it. However, this may mean you need to add extra parameter(s) to lots of methods if your call hierarchies are deep.
If you only need one instance of your properties class you can use the singleton (anti?)-pattern.
It would look like a class like this:
public class MyProperties extends Properties {
private static MyProperties instance = null;
private MyProperties() {
}
public static MyProperties getInstance() {
if (instance == null) {
try {
instance = new MyProperties();
FileInputStream in = new FileInputStream("custom.properties");
instance.load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return instance;
}
}
Why not use a static ResourceBundle ?
static final ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", currentLocale);
There's too little information to determine what the best way to handle this would be. You may want to expose it using an accessor, or pass it into each class that requires it. Alternatively, you may pull out the properties that each class needs and pass their values into the class's constructor.
Load the properties once using and store the Properties somewheres that others classes can pull from. If that is a MyProperties class that references a static variable somewhere that is fine.
This is a special case of making anything available globally. Using static methods is quite bad. A better but bad solution is using the sigleton pattern. Testing is the greatest problem here. IMHO, the best way is using Dependency injection, although it may be an overkill for small applications.
Since this information is static across all instances, I recommend implementing the Properties class as a singleton. By using the static initialization block method, you can have it load the file automatically when the program starts up.
public class Properties {
static {
try {
FileInputStream in = new FileInputStream("custom.properties");
load(in);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected static void load(FileInputStream in) {
// existing load functionality here
}
}
You are still going to need an internal storage mechanism and accessor mechanism. These should also be marked static.
Rather than loading properties in every class. Load it somewhere around main() and pass it to other classes via their constructors.
Don't share them globally.
- Difficult to test
- Against the abstraction (Global access, DAO can access user settings. it should be prevented by passing only what it needs.. not everything)
- Classes lie what they need

Categories

Resources