Proven and opinionated programming, and configuration model for Java and Vertx based applications. Inspired from ATG Nucleus, provides powerful layer base configuration management using simple properties file.
What is Glue?
You will use Glue for same reason you will use Spring (dependency injection) in your application. But, in case of Glue, we have implemented few concepts to make your life much easier from development point of view.
-
HelloWorld class : We want to set
mHelloWorld
field to This is hello world example. Normally, this is done by creating new instance ofHelloWorld
class and then callingsetHelloWorld
method to setmHelloWorld
field. With Glue, this is done automatically. You just need to define a property file with values. -
Component Path:/in/erail/example/HelloWorldComponent (File Name:HelloWorldComponent.properties) : This file is used to create instance of
HelloWorld
class and set property values as defined in property file. -
To get instance of HelloWorld class, you just need to call
HelloWorld
inst = Glue.instance().<HelloWorld>resolve("/in/erail/example/HelloWorldComponent")
Configuration Layer
Configuration layer is root directory under which all configurations exists. For example, you
want to create instance of HelloWorld
class. Then, you will have to do below steps.
-
Create configuration layer on your file system. For example
/home/glue/layer1
. This folder will become root folder for all configurations. -
Then create
HelloWorldComponent.properties
file at/home/glue/layer1/in/erail/example/HelloWorldComponent.properties
. -
When you run your code, you will pass configuration layer to glue as java parameters.
java -Dglue.layers=/home/glue/layer1
. Now whenever you want to get instance ofHelloWorld
,HelloWorld inst = Glue.instance().<HelloWorld>resolve("/in/erail/example/HelloWorldComponent")
.HelloWorld
instance will be configured based on/home/glue/layer1/in/erail/example/HelloWorldComponent.properties
file.
Multiple Configuration Layers
You can define multiple configuration layers. Properties file defined at same location inside all layers are merged. And last overridden value is taken as value of property. for example:
#/in/erail/glue/test/component/MergedComponent
$class=in.erail.glue.component.PropertiesComponent
$scope=LOCAL
propString=TestString
#/in/erail/glue/test/component/MergedComponent
$scope=GLOBAL
propString=TestString2
#/in/erail/glue/test/component/MergedComponent
propString=TestString2
$scope=GLOBAL
As you can see above, second layer has overridden propString property.
Supported Property Type
Java Type | Example |
---|---|
String |
propString=TestString |
Array[String] |
propArray=a,b,c |
Array[Component] |
propArray=/abc/comp1,/abc/comp2 |
List<String> |
propList=a,b,c |
Map<String,String> |
propMap=a=b,c=d,e=f |
Boolean and boolean |
propBoolean=true |
Enum |
propEnum=TWO |
Set<String> |
propSet=a,b,b,c |
Integer and Int |
propInteger=2 |
Long and long |
propLong=2 |
File |
propFile=testconfig.json |
JsonObject (Vertx) |
propFile=testconfig.json |
ServiceMap |
Map of components |
Logging |
Logging component |
Component |
Reference to another component |
Null |
Null value |
Pattern |
String will be compiled into Pattern |
Timer (Dropwizard Metric) |
a timer will be created based on name given |
Counter (Dropwizard Metric) |
a counter will be created based on name given |
Meter (Dropwizard Metric) |
a meter will be created based on name given |
Histogram (Dropwizard Metric) |
a hitogram will be created based on name given |
Class |
propClass=java.lang.String |
Properties based configuration in detail
#/in/erail/glue/test/component/PropertiesComponent
$class=in.erail.glue.component.PropertiesComponent
$scope=LOCAL
propString=TestString
propArray=a,b,\
c
propList=a,b,\
c
propMap=a=b,c=d,\
e=f
propComponent=/in/erail/glue/test/component/GlobalObjectByDefault
propBoolean=true
propEnum=TWO
propSet=a,b,b,c
propBoolean2=true
propServiceMap=\
a=/in/erail/glue/test/component/GlobalObjectByDefault,\
b=/in/erail/glue/test/component/GlobalObjectByDefault,\
c=/in/erail/glue/test/component/GlobalObjectByDefault
propInt=2
propInteger=2
propFile=testconfig.json
propLong=2
propLong2=2
propLogger=true
propNullString=
propNullServiceMap=
propNullComponent=
Above is test property file PropertiesComponent.properties
to create component
PropertiesComponent. Physically, it is present in folder /in/erail/glue/test/component/
.
Folder structure itself is present in another folder called configuration layer folder.
We can provide multiple configuration layers to Glue. Physical location of
PropertiesComponent.properties file under configuration layer becomes actual mounting
point of component. In this case, PropertiesComponent is mounted at
/in/erail/glue/test/component/
. To get instance of PropertiesComponent, we use
/in/erail/glue/test/component/PropertiesComponent
path.
Basic Properties File Configuration
Property Name | Required | Default | Description |
---|---|---|---|
$class |
Yes |
N/A |
Instance of this class will be created whenever instance of this component is created. |
$scope |
No |
GLOBAL |
Default scope of component is "GLOBAL". Means, Whenever instance of this component is required, same instance of component is returned. This is same as Singleton Pattern. If new instance is required on each component creation call then "LOCAL" scope can be defined. This will ensure, Glue will return new instance each time. |
$basedOn |
No |
N/A |
One component can copy all property values of another component. And override only required properties |
#/in/erail/glue/test/component/BasedOnPropertiesComponent
$basedOn=/in/erail/glue/test/component/PropertiesComponent
propString=TestString2
In above example, all properties of this component will have value as set in
/in/erail/glue/test/component/PropertiesComponent
component. And in this component
propString
will be overridden with value TestString2
Configuration layer in detail
Layers are passed to Glue using JVM parameter
java -Dglue.layers=/testdata/layer1,/testdata/layer2
Override Property Value
If we have two properties files at same location under different layers. Glue will try to override or merge property file in same order as configuration layers are defined. For example:
#/in/erail/glue/test/component/MergedComponent
$class=in.erail.glue.component.PropertiesComponent
$scope=LOCAL
propString=TestString
propArray=a,b,\
c
propList=a,b,\
c
propMap=a=b,c=d,\
e=f
propComponent=/in/erail/glue/test/component/PropertiesComponent
propJson=testconfig.json
propSet=a,b,b,c
#/in/erail/glue/test/component/MergedComponent
propString=TestString2
propArray=a
propList-=a
propList+=b,c,d
propMap-=a=b
propMap+=z=b
propComponent=/in/erail/glue/test/component/PropertiesComponent2
propSet-=a,b
propSet+=e,f
Override Property Value
In above example, when instance of /in/erail/glue/test/component/MergedComponent
is created,PropertiesComponent.getPropString()
method will return TestString2
instead
of TestString
. As you can see in above example, Layer 2 is overriding propString value.
Merge Property Value
In case of List,Map,Set. Glue supports merge or deletion of property value. In above
example, PropertiesComponent.getPropList()
will return list with elements b,c,b,c,d.
Hyphen(-)
in propList-=a
will remove a from list. And Plus(+)
in propList+=b,c,d
will
add b,c,d elements to list. Same can be done in case of Map and Set.
Component Property
A component property can refer to another component property.As can be seen in
/in/erail/glue/test/component/PropertiesComponent
,
propComponent=/in/erail/glue/test/component/GlobalObjectByDefault
PropertiesComponent.getPropComponent()
will return instance of GlobalObjectByDefault
component.
Component property referring to another component property
#/in/erail/glue/test/component/RefPropertiesComponent
$class=in.erail.glue.component.PropertiesComponent
$scope=LOCAL
propString^=/in/erail/glue/test/component/PropertiesComponent.propString
propArray^=/in/erail/glue/test/component/PropertiesComponent.propArray
propList^=/in/erail/glue/test/component/PropertiesComponent.propList
propMap^=/in/erail/glue/test/component/PropertiesComponent.propMap
propComponent^=/in/erail/glue/test/component/PropertiesComponent.propComponent
propBoolean^=/in/erail/glue/test/component/PropertiesComponent.propBoolean
propEnum^=/in/erail/glue/test/component/PropertiesComponent.propEnum
propJson^=/in/erail/glue/test/component/MergedComponent.propJson
propServiceMap^=/in/erail/glue/test/component/PropertiesComponent.propServiceMap
As can be seen above. ^ is used for connecting component property to another component property.
Factory based creation of Component
Glue supports two factory classes which you can use to create instance of classes requiring factory for creation. For more example, refer to test cases.
MethodInstanceFactory
#/in/erail/glue/test/factory/TestComponentPC2
$class=in.erail.glue.factory.TestComponent
$instanceFactory=/in/erail/glue/test/factory/MethodInstanceFactory
$factory.class=in.erail.glue.factory.TestFactory
$factory.method.name=create
$factory.param.values=ninja,5
#factory.param.type=
#factory.instance=
$scope=GLOBAL
Field Name | Description |
---|---|
instanceFactory |
Reference to component: in.erail.glue.factory.MethodInstanceFactory |
factory.class |
Class responsible for creating instance |
factory.instance |
Path of component responsible for creation of instance |
factory.method.name |
Method name |
factory.param.values |
Method parameters (Support component path also) |
factory.param.type |
Optional method parameter type |
ParameterConstructorInstanceFactory
#/in/erail/glue/test/factory/TestComponentPC1
$class=in.erail.glue.factory.TestComponent2
$instanceFactory=/in/erail/glue/test/factory/ParameterConstructorInstanceFactory
$constructor.param.values=ninja,5,/in/erail/glue/test/component/PropertiesComponent,"a,b"
$scope=GLOBAL
Field Name | Description |
---|---|
instanceFactory |
Reference to component: in.erail.glue.factory.MethodInstanceFactory |
constructor.param.values |
Constructor parameters (Support component path also) |
constructor.param.type |
Optional constructor parameter type |
Advance
Configuration using glue.config file
Glue picks any configuration from three places in given order:
-
From Java command line (e.g. -Dglue.layer)
-
From Environment variable (e.g. GLUE_LAYER)
-
glue.config file
glue.layers=/common
To pass glue.config use -Dglue.config=/var/task/glue.config
Improve config loading performance
Normally, all properties files are loaded from layer location each time glue is started. To imporove performance, Glue can cache loaded configuration in file file. On any future restarted, Glue will first try to load full configuration from cache configuration file. This setup can be used in production to save some load time.
By default, configuration is always loaded from layers. To activate caching of configuration, you will have to use a different configuration loader as shown below.
-Dglue.serialization.factory=in.erail.glue.factory.LocalConfigSerializationFactory
Environment Variable | Default | Description |
---|---|---|
local.config.factory.file.location |
Current working directoy |
Directory from where file is loaded or saved |
local.config.factory.file.name |
glue.ser |
Default file name |
local.config.factory.identifier |
.default |
While generating file. Files can be generated with different identifier to generated different config files (for example for different env) |
local.config.factory.disable.save |
false |
If enable, then each time Glue starts, all layers are saved into file, which can be used in future to load configuration. |