Fork me on GitHub

Dynamic Attributes

Distributed, scoped dynamic attributes provide a mechanism to configure/alter your cluster at runtime. Attributes can be changed for all instances of all services in the cluster, only for a particular service, only for a particular instance, etc.

Usage

Dynamic Attribute support is enabled via configuration. See the Dynamic Attributes Configuration section for details. SoaBase comes with implementations for MyBatis and JDBI.

Mybatis

A nice side-effect of using the standard JDBC integration is that you can directly access the Mybatis SqlSession instance for any other database usage you might have. You can even create multiple SqlSession instances for different databases. Each Sql instance defined in your Configuration is set in SoaFeatures with the configured name.

Even if you don't directly need to access the Mybatis session, you'll need to create a minimal Mybatis configuration file. For most uses, this file will suffice:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="Class Name of your JDBC Driver"/>
                <property name="url" value="Connection URL for the Driver"/>
                <property name="username" value="XXXX"/>
                <property name="password" value="XXXX"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

Whatever database you use, you need to set up the schema for Dynamic Attributes. You can do this manually or via a Soabase utility. The SQL to create the table is:

CREATE TABLE SoaAttributes
(
    fKEY VARCHAR(255) NOT NULL,
    fSCOPE VARCHAR(255) NOT NULL,
    fVALUE VARCHAR(65535),
    fTIMESTAMP VARCHAR(255) NOT NULL,
    PRIMARY KEY (fKEY, fSCOPE))
)

To do it programmatically, use the Mybatis session:

SoaFeatures features = SoaBundle.getFeatures(environment);
SqlSession session = features.getNamedRequired(SqlSession.class, name);
AttributeEntityMapper mapper = session.getMapper(AttributeEntityMapper.class);
mapper.createTable();

Once the database is set up, you can add attributes manually or via the Administration Console. To add manually, use this SQL (fTIMESTAMP is a GUID):

INSERT INTO SoaAttributes (fKEY, fSCOPE, fVALUE, fTIMESTAMP) VALUES (?, ?, ?, ?)

You can also create/update/delete attributes using the Mybatis session:

SoaFeatures features = SoaBundle.getFeatures(environment);
SqlSession session = features.getNamedRequired(SqlSession.class, name);
AttributeEntityMapper mapper = session.getMapper(AttributeEntityMapper.class);
mapper.insert(...);
mapper.update(...);
mapper.delete(...);

JDBI

You can use a JDBI connection for Dynamic Attributes as well. Create the DBI instance in the normal manner and then register it by calling:

SoaBundle.getFeatures(environment).putNamed(instance, DBI.class, SoaFeatures.DEFAULT_NAME);

Whatever database you use, you need to set up the schema for Dynamic Attributes. You can do this manually or via a Soabase utility. See the MyBatis section above for the database schema. To create the table programmatically:

AttributeEntityDao dao = dbiInstance.onDemand(AttributeEntityDao.class);
dao.createTable();

API

Dynamic Attributes are accessed via the DynamicAttributes instance from SoaFeatures. It has methods to get attributes coerced to various types, override attributes and listen for changes.

Adding a Custom Implementation

To use something other than the JDOBC implementation, follow these steps:

  • Create implementations for DynamicAttributesFactory and WritableDynamicAttributes
  • Add a directory named META-INF/services that contains two files: io.dropwizard.jackson.Discoverable and io.soabase.core.features.attributes.DynamicAttributesFactory.

DynamicAttributesFactory

Your DynamicAttributesFactory implementation is like other Dropwizard factories. It should be both configuration and a factory. Use SqlDynamicAttributesFactory.java as an example. This class must be annotated with JsonTypeName and given a unique name. You then use this name as the value for the discovery type in your configuration file. E.g.

package com.me.my;

@JsonTypeName("my-discovery")
public class MyAttributesFactory implements SqlDynamicAttributesFactory {
    public String aConfigValue;

    public int anotherConfigValue;

        ...

    @Override
    public DynamicAttributes build(Environment environment, List<String> scopes)
    {
            ...
        return new MyAttributes(...);
    }
}

WritableDynamicAttributes

Your DynamicAttributes implementation does the actual work. The details will depend on your implementation's needs. Note: your custom class should implement WritableDynamicAttributes not DynamicAttributes. This allows your implementation to interact with the Administration Console.

ServiceLoader files

Like other Dropwizard plugins, your Dynamic Attributes implementation needs Service Loader files. In the io.dropwizard.jackson.Discoverable file add a line containing: io.soabase.core.features.attributes.DynamicAttributesFactory. In the io.soabase.core.features.attributes.DynamicAttributesFactory file add a line the with fully-qualified path name of your class. E.g. com.me.my.MyAttributesFactory

StandardAttributesContainer

Take advantage of the StandardAttributesContainer which has basic implementations for most of the features of Dynamic Attributes. Look at SqlDynamicAttributes for an example of how to use it.