eforceconfig



What is?



This is a framework that has been developed during the last 4 years, adapting it to a lot of critical IT projects. It is studied to be easy to use, but heavly extensible and complex if needed, with a great care of performances.

The most interesting features are: runtime changes support, config caching and garbage collection, hierarchies, inheritance, config validation, and sql statement bind variables enforcement.

Thing to be implemented: Xstream (http://xstream.codehaus.org/) parameter-type support, eventually Database and LDAP config sources samples, user feedback will be very important.



From the XML point of view it is a hierarchy of "entities" and "components".

An entity can have child entities and child components. A component is always the child of an entity and cannot have childs. There is no limit on the level.

In the file-based implementation an entity is a "<entity name>.xml" file, or an "<entity name>" folder that contains an "entity.xml" file and eventually n "<childs>.xml" files.

Any .xml file represents an entity and contains entity's "parameters", "sql statements", and "components". Each component contains, component's "parameters" and "sql statements".

Actually there are 4 config implementation: file, web, classpath, but any inputstream capable source can be a repository for configs (LDAP/Database can be rapidly implemented on the data model basis).

An entity A can be child of entity B, and extend entity C, so it is located under entity B but inherits parameters, components and sql statements from entity C.



From the Java API point of view, there are n ConfigSet at top and eventually one Singleton ConfigSet.

Each ConfigSet contains n EntityConfig, and each EntityConfig contains n parameters, ComponentConfig, SQLStatement.



Components are simply sub-sections of an entity.

Parameters are generally java.lang.String, but the API, has a lot of cast methods, that makes really

effective the use of any other type, like:

my.beautifull.java.interface mbji= (my.beautifull.java.interface)config.getClassInstanceParameter("my-pluggable-interface");

where the parameter is:

<parameter name="my-pluggable-interface" value="my.beautifull.java.interface"/>.





SQLStatements are special java.lang.String that support a BindVariable position iterator,

so that a jdbc wrapper or an orm can know where to bind the value of fariable "foo" and "somethingelse":



select * from mytable where thiscolumn= ${foo} and eventhiscolumn= ${foo} and butthiscolumn= ${somethingelse}



the position iterator will say 1,2 for "foo" and 3 for "somethingelse":



The framework comes with an .xsd file to validate xml files, so that

when you initialize an entity it will throw exceptions if you define the

same parameter two-times or someting like this.



If you modify a "runtime change capable" source like a FileConfigSource,

the framework will change the value of the parameter in the cached instance of

the entity. Considering that each entity will exists only once in a JVM, every

referece to a parameter will be updated. The change controller can be started or

not.



A garbage collector can be activated to maintain a maximum of n entities cached in

the java heap space ona LRU basis. And even if the cache is active it is still possible

to set as non cacheable a specific entity, in its xml file.



Features



User feedback will drive development, submit your requests:

http://sourceforge.net/tracker/?group_id=198310



Download

Source/Doc or Binary package (initial release):

http://sourceforge.net/project/showfiles.php?group_id=198310

or CVS (updated frequently):

http://sourceforge.net/cvs/?group_id=198310

Use it

Hint: Download samples in the source package

Write down your sample.xml:
<?xml version="1.0" encoding="UTF-8"?>
<entity xmlns="http://eforceconfig.sourceforge.net/XML/entity-config" name="sample">
  <parameters>
      <parameter name="mypar" value="10" />
      <parameter name="myclass" value="eforce.util.config.samples.HelloWorld" />
      <parameter name="mytable" type="table">
         <value name="a" value="av"/>
         <value name="b" value="bv"/>
         <value name="c" value="cv"/>
         <value name="d" value="dv"/>
      </parameter>
      <parameter name="mylongpar">
      <![CDATA[
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla %{constant:eforce.util.config.samples.HelloWorld.MYCONSTANT} bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
         bla bla bla bla bla
      ]]>
      </parameter>
  </parameters>
  <sql>
    <!-- simple statement -->
    <statement name="mysql">
    <![CDATA[
          select *
            from dual
           where 1= ?
    ]]>
    </statement>
    <!-- statement with bind variable -->
    <statement name="mysql2" binding-type="named">
    <![CDATA[
          select *
            from dual
           where 1= ${MYBINDVAR}
    ]]>
    </statement>
    <!-- statement with expression literal that points to 
         local paramter named "adir" see above -->
    <statement name="sqlwithexpr" binding-type="named">
    <![CDATA[
          select DECODE('%{local:parameter/mytable/c}','cv','itworks','fu..')
            from dual
    ]]>
    </statement>
  </sql>
  <components>
    <component name="mycomp">
       <parameters>
         <parameter name="mylist" type="list">
            <value value="a"/>
            <value value="b"/>
            <value value="c"/>
            <value value="d"/>
         </parameter>
       </parameters>
       <sql>
         <statement name="acmpstmt">
         <![CDATA[
            select *
            from dual
         ]]>
         </statement>
       </sql>
    </component>
  </components>
</entity>

Use it in your class HelloWorld.java:

package eforce.util.config.samples;

import java.util.Iterator;
import java.util.Map;

import eforce.util.config.ComponentConfig;
import eforce.util.config.Config;
import eforce.util.config.ConfigException;
import eforce.util.config.EntityConfig;
import eforce.util.config.initializers.ClassPathConfigInitializer;

public class HelloWorld
{
    public static final String MYCONSTANT= "*************YEA*************";
    
    public static void main(String[] args)
    {
        Config config= new Config("samples");
        
        try
        {
            config.init(new ClassPathConfigInitializer("eforce.util.config.samples"));
        }
        catch (ConfigException e)
        {
            e.printStackTrace();
        }
        
        EntityConfig entity=  config.getEntity("sample");
        
        // get "mypar" parameter
        System.err.println("parameter mypar: '"+entity.getParameter("mypar")+"'");
        
        // get "mypar" parameter as int
        if (entity.getIntParameter("mypar")>20)
            System.err.println("mypar is greater than 20");
        else
            System.err.println("mypar is not greater than 20");
        
        // get "mylongpar" parameter with java constant in it
        System.err.println("mylongpar:");
        System.err.println(entity.getParameter("mylongpar"));
        
        // get "myclass" instance
        HelloWorld ew= (HelloWorld)entity.getClassInstanceParameter("myclass");
        System.err.println("new HelloWorld instance: "+ew);
        
        // cycle through "mytable" values
        Iterator i= entity.getTableParameter("mytable").entrySet().iterator();
        
        while (i.hasNext())
        {
           Map.Entry e= (Map.Entry)i.next();
           System.err.println("mytable key: "+e.getKey()+" value: "+e.getValue());
        }
        
        // get component "mycomp"
        ComponentConfig cc= entity.getComponent("mycomp");
        
        // cycle through "mylist" ordered values
        i= cc.getListParameter("mylist").iterator();
        int cnt=0;
        
        while (i.hasNext())
           System.err.println("mylist["+(cnt++)+"]: "+i.next());

        // get "sqlwithexpr" with "mytable" value in it
        System.err.println("sqlwithexpr: "+entity.getSQLstmt("sqlwithexpr"));
        
        config.stop();
    }

}

Use it in a webapp .war:


Copy binary package content into WEB-INF/lib:


<war-root>/WEB-INF/lib/eforceconfig.jar
                       eforceconfig-webapp.jar
                       commons-lang-2.0.jar
                       jakarta-oro-2.0.7.jar
                       jakarta-regexp-1.3.jar
                       log4j-1.2.8.jar


Or at container level (see your web container documentation).


Copy previous sample.xml into WEB-INF/entity-config:


<war-root>/WEB-INF/entity-config/sample.xml

Configure web.xml:


<?xml version = '1.0' encoding = 'UTF-8'?>

<web-app id="salonepro" version="2.4"

xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>sample webapp</display-name>

<description>show how to plug eforceconfig into a webapp</description>

<listener>

<display-name>ConfigInitializer</display-name>

<listener-class>eforce.util.config.plugin.webapp.ConfigContextListener</listener-class>

</listener>

<context-param>

<param-name>eforce.util.config.CONFIGSET_NAME</param-name>

<param-value>samplewebapp</param-value>

</context-param>

<context-param>

<param-name>eforce.util.config.CACHE_SIZE</param-name>

<param-value>20</param-value>

</context-param>

<context-param>

<param-name>eforce.util.config.CHANGE_CONTROL_INTERVAL</param-name>

<param-value>10000</param-value>

</context-param>

<context-param>

<param-name>eforce.util.config.GARBAGE_COLLECTOR_INTERVAL</param-name>

<param-value>10000</param-value>

</context-param>

<context-param>

<param-name>eforce.util.config.START_CHANGE_CONTROL</param-name>

<param-value>true</param-value>

</context-param>

<context-param>

<param-name>eforce.util.config.START_GARBAGE_COLLECTOR</param-name>

<param-value>true</param-value>

</context-param>

<servlet>

<servlet-name>HelloWorldServlet</servlet-name>

<servlet-class>eforce.util.config.samples.HelloWorldServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>HelloWorldServlet</servlet-name>

<url-pattern>/hello</url-pattern>

</servlet-mapping>

</web-app>

Sample servlet HelloWorldServlet.java:

package eforce.util.config.samples.webapp;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import eforce.util.config.ComponentConfig;
import eforce.util.config.Config;
import eforce.util.config.EntityConfig;
import eforce.util.config.samples.HelloWorld;

public class HelloWorldServlet extends HttpServlet
{
    private EntityConfig entity= Config.getConfigSet("samplewebapp").getEntity("sample"); 
        
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
    {
        PrintWriter out= response.getWriter();
        
        // get "mypar" parameter
        out.println("parameter mypar: '"+entity.getParameter("mypar")+"'<br>");
        
        // get "mypar" parameter as int
        if (entity.getIntParameter("mypar")>20)
            out.println("mypar is greater than 20<br>");
        else
            out.println("mypar is not greater than 20<br>");
        
        // get "mylongpar" parameter with java constant in it
        out.println("mylongpar:<br>");
        out.println(entity.getParameter("mylongpar")+"<br>");
        
        // get "myclass" instance
        HelloWorld ew= (HelloWorld)entity.getClassInstanceParameter("myclass");
        out.println("new HelloWorld instance: "+ew+"<br>");
        
        // cycle through "mytable" values
        Iterator i= entity.getTableParameter("mytable").entrySet().iterator();
        
        while (i.hasNext())
        {
           Map.Entry e= (Map.Entry)i.next();
           out.println("mytable key: "+e.getKey()+" value: "+e.getValue()+"<br>");
        }
        
        // get component "mycomp"
        ComponentConfig cc= entity.getComponent("mycomp");
        
        // cycle through "mylist" ordered values
        i= cc.getListParameter("mylist").iterator();
        int cnt=0;
        
        while (i.hasNext())
           out.println("mylist["+(cnt++)+"]: "+i.next()+"<br>");

        // get "sqlwithexpr" with "mytable" value in it
        out.println("sqlwithexpr: "+entity.getSQLstmt("sqlwithexpr")+"<br>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
    {
       doGet(request, response);
    }

}

Troubleshooting



If you get:

org.xml.sax.SAXNotRecognizedException: Property: http://java.sun.com/xml/jaxp/properties/schemaLanguage

probably you are not using a JAXP 1.2 compliant SAX parser, try using xerces.



If you get any other problem please subimt a support request:

http://sourceforge.net/tracker/?group_id=198310

About

eforceconfig is developed by Andrea A.A. Gariboldi