01 Getting Started

Getting started with ConfigureMe

To get started with ConfigureMe you need three things. First you need something to configure which we call configurable. Than you need something to configure your configurable with, that'll be the configuration. And finally you need to ask the ConfigurationManager to configure your configurable with your configuration somewhere in your code.

Selling hamburgers

Lets get concrete. Imagine you are opening a fast food restaurant. To make it real fast you offer just one product, the BigPack. Since you are a great developer you are writing the software for your cash box yourself, and you want the price to come from a configuration file to be able to react to the financial crises fast.

Creating a configurable

First of all we need an object to store the prices, our configurable object:

Pricing.java
package pricing;

import org.configureme.annotations.Configure;
import org.configureme.annotations.ConfigureMe;

@ConfigureMe 
public class Pricing {
	/**
	 * The local currency.
	 */
	@Configure
        private String currency;
	/**
	 * The price of the BigPack in local currency.
	 */
	@Configure 
        private float price;
	
	public void setCurrency(String aCurrency){
		currency = aCurrency;
	}
	
	public void setPrice(float aPrice){
		price = aPrice;
	}
	
	/**
	 * Returns the price for the customer.
	 */
	public String getProductPrice(){
		return price+" "+currency;
	}
}

Our configurable is nothing more than a JavaBean which an additional method: getProductPrice_ which return the price we have to show the customer. Since we are planing to get international pretty soon, we introduced a special field for the currency, to be able to operate in different countries.

Creating a configuration file.

Now that we have a configurable we need a configuration.

pricing.json
{
	price: 3.57,
	currency: "$",
}

Note that the default name resolution is deduced from the class name, but you can change it by parameterizing the annotation.

Showing the price

Now that we have prepared everything, the first customer can come in. All we need is to add 3 more lines of code:

ShowPrice.java
package pricing;

import org.configureme.ConfigurationManager;

public class ShowPrice {
	public static void main(String a[]){
		Pricing pricing = new Pricing();
		ConfigurationManager.INSTANCE.configure(pricing);
		System.out.println("Please pay "+pricing.getProductPrice());
	}
}

Once run the output of the program is:

Please pay 3.57 $

Changing environment

Now since your business is running well, it's time to become a global player and run international branches. To start with you launch 3 international branches, one in germany, one in austria and one in united kingdom. The only thing you need to change is the config file, you just have to specify the different environments:

pricing.json
{
	price: 3.57,
	currency: "$",
	
	europe: {
		//many european countries have euro as currency
		currency: "€",
		uk:{
			price: 2.29,
			currency: "£",
		},
		
		de: {
			price: 3.00,
		},
		
		at: {
			price: 3.50,
		},
		 
	},
}

Done? Almost. Now you simply have to tell the program in which environment its executed so it can select the proper configuration. In your branch in united kingdom you will have to run the program with following parameter:
java -Dconfigureme.defaultEnvironment=europe_uk pricing.ShowPrice

The output will be as expected:

Please pay 2.29 £

Explicitly specifying the environment

Now that your BigPack business is flourishing you don't need to work anymore and spent time with things that matter. You even gave away the pricing policy to a high ranked manager in your conglomerate. However, for the sake of good old times you want to check the sales and prices from time to time. But doing it with the method from last paragraph is rather uncomfortable, since you have to travel to the target country to check the price in it. Fortunately for you ConfigureMe offers a possibility to specify execution environment explicitly:

ShowPrice.java
public class ShowPrice {
	public static void main(String a[]){
		showPriceIn("USA", GlobalEnvironment.INSTANCE);
		showPriceIn("United Kingdom", new DynamicEnvironment("europe", "uk"));
		showPriceIn("Germany", new DynamicEnvironment("europe", "de"));
		showPriceIn("Austria", new DynamicEnvironment("europe", "at"));
	}
	
	private static void showPriceIn(String description, Environment environment){
		Pricing pricing = new Pricing();
		ConfigurationManager.INSTANCE.configure(pricing, environment);
		System.out.println("Price in "+description+" is "+pricing.getProductPrice());
	}
}

When you are starting the program now it prints the prices in all branches, leaving you enough time for your other projects:

Price in USA is 3.57 $
Price in United Kingdom is 2.29 £
Price in Germany is 3.0 €
Price in Austria is 3.5 €

Configuring the whole class.

Finally you may ask (and actually people asked (smile)), if all fields in the class, as in the above example, are configureable, why they all must be annotated? They don't. In fact you can add a parameter to the ConfigureMe annotation telling it, that all fields are configureable:

Pricing.java
...
@ConfigureMe (allfields=true) 
public class Pricing {
	private String currency;
	private float price;
...

If you run this program now, you will see that the results are exactly the same as in previous version.

Using ConfigureMe within a Spring Projekt

This is quite easy. ConfigureMe has Spring support allready included, just use the org.configureme.spring.ConfigureSpringBeans class and add all SpringBeans that should be configure as constructor argument.
For example when using the default environment:

applicationContext.xml
<bean id="pricing" class="Pricing" />

<bean class="org.configureme.spring.ConfigureSpringBeans">
    <constructor-arg ref="pricing" />
</bean>

you can also specify the a environment which should be used when adding a DynamicEnvironment as first constructor argument.

applicationContext.xml
<bean id="pricing" class="Pricing" />

<bean class="org.configureme.spring.ConfigureSpringBeans">
    <constructor-arg>
        <bean class="org.configureme.environments.DynamicEnvironment">
	    <constructor-arg value="europe" />
	    <constructor-arg value="de" />
	</bean>
    </constructor-arg>
    <constructor-arg ref="pricing" />
</bean>

Download and try ConfigureMe now: https://configureme.dev.java.net

  • No labels

2 Comments

  1. Hi Leon!

    I think I might have mentioned some of these to you earlier.  Also, I realize you're pretty far down the road with the current (documented) architecture for it, but you're going to hear it from your co-workers numerous times, I'd bet, so you should at least have good answers for them, and at best you should fix it.  (smile)
    - Are instance members *required* to have bean methods in order to be configurable via ConfigureMe?  If so, that seems unnecessary.  Why couldn't the config manager (or whatever) use reflection to find the member field and set it if there is no bean setter method?  Because you want to allow configuring private fields?  Well, if the field is private, and the setter method is public, then it's not very private anyway, right?  So that seems silly.  If you really have to have it that way, then this problem is specific to non-public fields with public setter methods, so just require public setter methods for non-public fields, and all the other public members don't need setter methods. Really, not every field should have bean methods, and developers and the JVM will eventually choke on them if they're always required.
    - Cascaded environment instance members do not show up at the same indentation level in the configuration file.  I realize why you have it that way, but
    - Is it *required* that cascaded environment values appear within the same configuration file?  They can't be separated into another file?  And, no entity include mechanism in JSON (I'm not sure if there is one)?
    - The annotation syntax:

      @Configure private String currency;

      Is very small/compact, and tells the configuration manager that the developer wants the currency value to be configured.  But, because it appears on the same line as "private String currency", it appears to not allow the developer to specify attributes in the annotation.  If you don't have any right now, fine, but it should still be on the line above, IMO.  It is valid Java code to have it on the same line, but it just doesn't look good to me that way.
    - Why should the developer need to annotate every member in the class just to say that it is possible to configure them via ConfigureMe? Why can't it just notice the @ConfigureMe class annotation, and allow every instance field to be configurable?  I think in a class where you have configurable fields, the majority case will be that all fields are configurable.. so it seems backwards to annotate the ones that are configurable instead of annotating the ones that are *not* configurable.  If you did it that way, and if there need to be special annotation attributes set on configurable fields, you can have a special annotation syntax for that.  But, set up like that, developers could just put the @ConfigureMe annotation at the top, and then any field in their class is already configurable.  Why not?

    Cheers.
    --
    Jason

    1. Hello Jason,

      thanx a lot for your feedback.

      1) The ConfigurationManager first checks the field accessibility. If the field is public the ConfigurationManager tries to set it directly, otherwise it looks for the appropriate setter method. Personally I don't like to use public fields but anyone is free to do it, the framework supports it.

      2) One of the goals of ConfigureMe was to provide one on one relationship between configurable and its configuration. We prefer to separate by making configurables "small" instead of separating environments. However, since we are preprocessing files anyway, we could implement any include mechanics wished. I just don't see the need right now (smile)

      3) Configuration syntax: personally I also prefer (or preferred) to write an annotation in the line above the annotated element. However, since I updated my knowledge with Bloch's Second Edition (highly recommended) I'm writing the annotations in the same line. But I see your point and updated the example accordingly.

      4) Now that is actually a really GREAT IDEA! Indeed most of configurables are just 'holder' classes, and need to configure all fields at once anyway. I added a boolean parameter allfields to the ConfigureMe annotation and updated the above example. I also added a DontConfigure annotation to explicitly prevent fields from being set. An open question is whether allfields is true or false by default. Personally I think that false is more intuitive, but I leave this decision to the users (smile)