Table of Contents

Configurator

Configurator is a tool to assemble configuration of Java objects in a GUI editor and then instantiate the configuration at runtime and parameterize it with substitution tokens and deployment profiles.

One of definitions of software development is Software development is a process of binding decisions to make them executable 1). With Configurator decisions binding is organized as follows:

While Configurator can be used by its own, the primary purpose of the product is

For example, Euphrates model extends Configurator model. Also, Euphrates flow definitions get transformed to Configurator models for execution.

License

LGPL

Version

1.3.0

Value proposition

Separation of non-functional concerns (configuration, qualities of service, deployment variations) core functional concerns (business logic).

Requirements

Resources and downloads

Product components

Problem statement

In modern applications significant part of code deals with configuration. For example, to make a connection with a database the application shall know:

If an application wants to send a JMS message, then number of configuration parameters increases dramatically because of vendor-specific configuration parameters and quality of service parameters (e.g. persistent/non persistent, time to live).

So a real life application shall deal sometimes with hundreds if not thousands configuration parameters. Then, some applications shall be deployed to multiple environments (e.g. Development, Test, Production) with. Some parameters will be the same in all environments, some will differ by environment, some will be server-specific. Maintenance of dozens of slightly different configuration files becomes a nightmare.

With Configurator you can have a single configuration file parameterizable at deployment time with profile name and substitution tokens.

Tutorial

This tutorial shows how to create configuration for a simple class and then instantiate and configure the class from the configuration file.

Set up

Create business class

The code below shows out business class. Note that it is “pure business” - there is no code dealing with reading configuration.

Receipt.java
package com.hammurapi.test;
 
import java.util.Map;
 
public class Receipt {
 
	private String companyName;
	private double tax;
	private String promotion;
 
	public void setCompanyName(String companyName) {
		this.companyName = companyName;
	}	
 
	public void setTax(Double tax) {
		this.tax = tax;
	}
 
	public void setPromotion(String promotion) {
		this.promotion = promotion;
	}
 
	public void print(Map<String, Double> items) {
		System.out.println("\t\t"+companyName);
		double total = 0;
		for (Map.Entry<String, Double> entry: items.entrySet()) {
			System.out.println(entry.getKey()+":\t"+entry.getValue());
			total+=entry.getValue();
		}
		System.out.println("---------");
		System.out.println("Tax:\t"+tax+" %");
		System.out.println("Total:\t"+total*(1+tax/100));
		if (promotion!=null) {
			System.out.println();
			System.out.println("*** "+promotion+" ***");
		}		
	}
 
}

Create configuration file

Create a configuration for our business as shown here.

Edit configuration

This presentation shows how to populate configuration model in the editor.

This is the resulting configuration file:

My.hgconfig
<?xml version="1.0" encoding="UTF-8"?>
<com.hammurapi.config:ObjectDefinition 
    xmi:version="2.0" 
    xmlns:xmi="http://www.omg.org/XMI" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:com.hammurapi.config="http://www.hammurapi.com/config"
    description="Receipt printer"
    type="com.hammurapi.test.Receipt">
 
  <property 
      xsi:type="com.hammurapi.config:NamedObjectDefinition" 
      description="Company name" 
      name="companyName" value="HG Store"/>
 
  <property xsi:type="com.hammurapi.config:NamedObjectDefinition" name="promotion" value="$[promotion]"/>
 
  <profile name="st_johns" description="Saint Johns County">
    <property 
         xsi:type="com.hammurapi.config:NamedObjectDefinition"
         name="tax" 
         value="6.0"
         type=""/>
  </profile>
 
  <profile name="duval">
    <property xsi:type="com.hammurapi.config:NamedObjectDefinition" name="tax" value="7.0"/>
  </profile>
</com.hammurapi.config:ObjectDefinition>

Client code (application)

The code below shows how to instantiate our business object from configuration and instantiation time parameters.

MyApp.java
package com.hammurapi.test;
 
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
 
import org.eclipse.emf.ecore.resource.Resource;
 
import com.hammurapi.config.Factory;
import com.hammurapi.config.runtime.ConfigurationException;
import com.hammurapi.config.runtime.FactoryConfig;
import com.hammurapi.config.runtime.FactoryResult;
import com.hammurapi.config.runtime.MapTokenSource;
import com.hammurapi.config.runtime.ResourceLoader;
 
public class MyApp {
 
	/**
	 * @param args
	 * @throws ConfigurationException 
	 */
	public static void main(String[] args) throws Exception {
		Resource resource = ResourceLoader.load("My.hgconfig");
		Factory root = (Factory) resource.getContents().get(0);
		FactoryConfig fConfig = new FactoryConfig();
		fConfig.setProfilePath("st_johns");
 
		Map<String, String> tokens = new HashMap<String, String>();
		tokens.put("promotion", "Organic milk - buy one, get one free!");
		fConfig.setTokenSource(new MapTokenSource(tokens));
 
		FactoryResult<Object> fr = root.create(fConfig);
		try {
			Receipt receipt = (Receipt) fr.call();
 
			Map<String, Double> items = new TreeMap<String, Double>();
			items.put("Milk", 3.53);
			items.put("Bread", 1.82);
			receipt.print(items);
		} finally {
			fr.destroy();
		}
	}
 
}

Note that the configuration file is parameterized at instantiation time with

This program produces the following output:

		HG Store
Bread:	1.82
Milk:	3.53
---------
Tax:	6.0 %
Total:	5.671

*** Organic milk - buy one, get one free! ***

If we change profile to duval, tax rate will change to 7.0%. This example is very simple and is intended primarily to demonstrate how to use the tool.

Application-specific configurations

Imagine you have a middleware JMS application called MyBroker. It listens for requests on JMS queues. When it receives a request, it communicates with a number of back-end systems also over JMS and sends a reply to requesting application. The application uses a thread pool for parallel processing of multiple requests. The application processes requests differently depending on request parameters and there are hundreds of different combinations. The application is deployed to multiple environments with different connection parameters, quality of service settings, and thread pool configurations. In order to improve manageability of the application you decided to use Configurator to configure the application.

While you can use Configurator AS-IS, it is better to create an application-specific ECore model based on the Configurator model. The model would have MyBroker root class with references to JmsConnection class for the front-end and back-end connections. It will also have a reference to a thread pool definition.

To do so you need to:

Creating configuration models programmatically

Configurator models can be created programmatically. It can be needed in the following cases:

The tutorial contains a class which shows how to create configurator models programmatically. The code of this class is below:

BuildModel.java
package com.hammurapi.test;
 
import java.io.File;
 
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
 
import com.hammurapi.config.ConfigFactory;
import com.hammurapi.config.ObjectDefinition;
 
 
/**
 * This class builds configurator model programmatically and saves it to Generated.hgconfig
 * @author Pavel Vlasov
 *
 */
public class BuildModel {
 
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		ObjectDefinition objDef = ConfigFactory.eINSTANCE.createObjectDefinition();
		objDef.setDescription("Generated object definition");
		objDef.setType("java.lang.Integer");
		objDef.setValue("1234");
 
		ResourceSet resourceSet = new ResourceSetImpl();
		// Register the appropriate resource factory to handle all file extensions.
		//
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
				Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl());
 
		URI uri = URI.createFileURI(new File("Generated.hgconfig").getAbsolutePath());
		Resource configResource = resourceSet.createResource(uri);
		EList<EObject> contents = configResource.getContents();
		contents.add(objDef);
		configResource.save(null);
	}
 
}

This code produces configuration file shown below:

<?xml version="1.0" encoding="ASCII"?>
<com.hammurapi.config:ObjectDefinition 
    xmi:version="2.0" 
    xmlns:xmi="http://www.omg.org/XMI" 
    xmlns:com.hammurapi.config="http://www.hammurapi.com/config" 
    description="Generated object definition" 
    value="1234" 
    type="java.lang.Integer"/>
2) Shipping and Handling