Skip to main content

skip to main content

developerWorks  >  XML | Java technology  >

Delve into Hierarchical Inherited Rule-Interpreted XML

Use this new XML technology to create dynamic Java properties

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss


Rate this page

Help us improve this content


Level: Intermediate

Chad L. Meadows (cmeadows@us.ibm.com), Lead Reuse Engineer, IBM

09 Jan 2007

With the new XML technology called Hierarchical Inherited Rule-Interpreted XML, you can replace standard Java properties with dynamic versions. It allows you to define properties that you can evaluate based on the state of the application using simple expressions or even Groovy expressions, and it lets you use only one properties file for multiple instances of the application. Learn how to apply this technology in a simple, practical example as a replacement for Java properties files.

Java properties (java.lang.Properties) are the most common method of application configuration in use in Java programming. You typically use Java properties to determine how an application is configured on initialization, as well as to determine some types of runtime behavior. Properties often specify things such as servers and ports that the application needs to communicate with when initialized. They also can specify application runtime properties that determine behavior such as the maximum number of news items to display on the home page or simply the text to display for the page title.

Regardless of their many uses, properties are always static. You define them within the properties file, which you then store within the file system. The application starts and reads the properties file by initializing all the property values to the values contained within. At this point, you have no option to change the values until you restart the application. You might add a trigger mechanism to wrap the properties so you can reload them without an application restart, but the property values are still confined to be exactly as they were recorded in the properties file until the trigger signals the reload or restart. An application might feature multiple installations, whether development, test, production, or geographical installations. Each instance typically requires a unique set of configuration parameters for the application to work properly. In order to accommodate each unique instance, you need to manage an additional properties file.

The problem with the traditional use of Java properties is that you have an inflexible configuration that will cost you more in maintenance. Instead, you can avoid these limitations using Hierarchical Inherited Rule-Interpreted XML. You can use Hierarchical Inherited Rule-Interpreted XML to replace the standard Java properties with a dynamic version. This allows you to define properties that you can evaluate based on the state of the application. Hierarchical Inherited Rule-Interpreted XML also enables you to use one properties file for multiple instances of the application.

Follow a basic property example

Begin with a simple properties file with two properties, as shown in Listing 1. With this properties file, I will demonstrate the difference between using normal Java properties and the enhanced properties.


Listing 1. Sample properties file
news_source = mynews.myserver.com
news_max_items = 5

Listing 2 shows the typical code for loading a properties file, obtaining property values, and displaying the values to the console.


Listing 2. Application code to load and display properties
public static void main(String[] args) {
   // Get the URL of the properties file
   URL propertiesURL = StandardExample.class.getClassLoader().
                       getResource("example1/properties.properties") ;

   try {
      // Show the system property values for demonstration and reference
      System.out.println("Current system properties:") ;
      System.out.println(System.getProperties().toString()) ;
      System.out.println("Executing example \n\n") ;

      // Create the instance of the properties object
      Properties properties = new Properties() ;

      // Load the properties as you normally would
      properties.load( propertiesURL.openStream() ) ;

      // Get property values and write out to the console for this example
      System.out.println( properties.get("news_source")) ;
      System.out.println( properties.get("news_max_items")) ;

   } catch (IOException e) {
      e.printStackTrace() ;
   }

}

Listing 3 demonstrates the XML representation of the same properties file. All properties are listed using the <property> element. The id attribute is the key, and the value attribute contains the value for the key. In this particular example, the property 'news_max_items' has a value set to ${5} instead of simply 5. This demonstrates that with the enhanced properties, a value can contain values other than just of type java.lang.String. In this case, the value is expressed as a java.lang.Integer.


Listing 3. XML properties file with same values as Listing 1
<properties>
        <property id='news_source'    value='mynews.myserver.com' />
        <property id='news_max_items' value="${5}" />
<properties>

Next, Listing 4 shows the change required to use the enhanced properties to perform the same function. This requires you to change only one line of code from the original code in Listing 2. You replace the original java.lang.Properties with com.ibm.dolphin.hirix.properties.HirixProperties, which is the enhanced properties class.


Listing 4. Change to the original application to use enhanced properties
// Create the instance of the properties object
Properties properties = new HirixProperties() ;

This is all you need to do to begin using the enhanced properties. You can conveniently use them as a replacement for the standard java.lang.Properties. By design, the enhanced properties are an easy replacement for existing properties' implementations. Existing applications can readily begin using more sophisticated features of the enhanced properties as the need arises.



Back to top


Define dynamic properties

You can use Hierarchical Inherited Rule-Interpreted XML to define these same enhanced properties in order to interpret them dynamically at runtime. The values of dynamic properties are expressions that utilize Java Expression Language (JEXL) as the expression interpreter (see Resources for more information about JEXL expressions). Listing 5 shows how to construct a properties file that uses these expressions to resolve the values at runtime.


Listing 5. Properties file containing dynamic values
<!-- This properties file demonstrates how to make the values change based on
     state of the application.
     The 'user' variable is placed into the context by the application -->
<!-- system['key'] is equivalent to System.getProperties.get("key") -->

<properties>
     <!-- Adding an 'if' attribute allows you to control when the value is used
          Properties are tested in order.
          The first property which evaluates true will return its value -->

     <property id='news_source'     value='developer_news.myserver.com'
                                    if="${user.job == 'developer'}"/>

     <property id='news_source'     value='architect_news.myserver.com'
                                    if="${user.job == 'architect'}"/>

     <property id='news_max_items'  value="${5}"
                                    if="${user.job == 'developer'}"/>

     <property id='news_max_items'  value="${10}"
                                    if="${user.job == 'architect'}"/>

     <Demonstrating the use of combining values into a single value -->
     <property id="greeting"
               value="Hello ${user.name}
                      we are retrieving ${news_max_items} items for ${user.job}"/>

     <This property makes use of combining values
          and the system properties as well -->

     <property id="resource_directory" value="${system['user.dir']}/${user.name}" />

<properties>

Listing 5 defines the following dynamic properties and values.

news_source

The news_source property appears to be defined twice. When the property is read, the first value discovered is tested to see if any conditions have been applied. A condition is applied using an if attribute on the <property> element. If a condition exists, the condition must evaluate to true in order for the value to be returned as the result. Otherwise, the next news_source property is then tested. This process continues until a condition passes or until no more news_source properties exist, in which case a null result is returned.

The condition applied here in Listing 5 tests if the job property of the user object is equal to developer. If this is true, then developer_news.myserver.com is returned as the result. Otherwise, if the job property is equal to architect, then the value of architect_news.myserver.com is returned as the result.

news_max_items

The news_max_items property has the same conditions applied as news_source. In this instance, if the job property value of the user object is equal to developer, then the value of 5 is returned as a java.lang.Integer. Otherwise, if architect is the value of the job property, then 10 is returned as a java.lang.Integer.

greeting

The greeting property has no conditions; however, this property demonstrates the capability of substituting values within a string. The following three values are inserted into the string for this property:

  • ${user.name}: This places the user name in the string.
  • ${news_max_items}: This is the value of the news_max_items property. Properties may refer to other properties as well.
  • ${user.job}: This places the user job in the string.

resource_directory

The value of the resource_directory property uses a defined system property of user.dir, along with the user's name included in the string value.

Notice that the properties file makes use of a variable named user. This is set by the application into something called the context. In order to share information from the application within the properties XML file, you must store all references within a shared context, as shown in Listing 6. The method getUserInfo1() returns a Map object, which you then store into the context with the key user.


Listing 6. Setting values into the context from the application
// update the current context with the current user
properties.getContext().put("user", getUserInfo1()) ;

After Map is stored into the context, you can access it anywhere within the properties file using the syntax ${user}. All public methods of the object are available for you to call using ${user.methodName()}. You can also access values within a Map object using the short form ${user.propertyName}, which would be equivalent to the method call ${user.get('propertyName')}. In Listing 7, the user variable is set in the context to the Map created by the method getUserInfo1(). All of the property values are fetched and logged to the console. All of the property values will be generated using the current state of user set just before the properties are obtained. After the values are logged to the console, the context value of user is then updated to the Map value returned by getUserInfo2(). The same properties are requested as before, but now you will actually get different results from the property values, since they are now evaluated with a different user.


Listing 7. Application code to demonstrate dynamic property values
/**
 * @author cmeadows
 *
 * This example demonstrates the use of HirixProperties where you make the
 * values dynamic based on the state of the application.
 * In this example the current user is changed during execution.
 * After the current user is changed, the same property values are
 * retrieved, but different results will be obtained.
 */
public class HirixExample {

   public static void main(String[] args) {
	   // Get the URL of the properties file
      URL propertiesURL = HirixExample.class.getClassLoader().
                          getResource("example2/properties.xml");
      try {

         // Create the instance of the properties object
         HirixProperties properties = new HirixProperties() ;

         // Load the properties as you normally would
         properties.load( propertiesURL.openStream() ) ;

         // update the current context with the current user
         properties.getContext().put("user", getUserInfo1()) ;

         // Get property values and write out to the console for this example
         System.out.println( properties.get("news_source")) ;
         System.out.println( properties.get("news_max_items")) ;
         System.out.println( properties.getProperty("greeting")) ;
         System.out.println( "we will save your news in: " +
                              properties.getProperty("resource_directory")) ;

         // update the current context with the current user
         properties.getContext().put("user", getUserInfo2()) ;

         // Get property values and write out to the console for this example
         System.out.println( properties.get("news_source")) ;
         System.out.println( properties.get("news_max_items")) ;
         System.out.println( properties.getProperty("greeting")) ;
         System.out.println( "we will save your news in: " +
                              properties.getProperty("resource_directory")) ;

      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   /**
    * Create a sample user who is a developer
    * @return
    */
   public static Map getUserInfo1 () {
      Map user = new HashMap() ;
      user.put("name", "Chad") ;
      user.put("job", "developer") ;
      return user;
   }
   /**
    * Create a sample user who is an architect
    * @return
    */
   public static Map getUserInfo2 () {
      Map user = new HashMap() ;
      user.put("name", "John") ;
      user.put("job", "architect") ;
      return user;
   }
}

Listing 8 shows the actual output of executing the application code of Listing 7. The values are obtained from the properties file of Listing 5 for two different instances of user. You can see how the different instances of user result in different values obtained from the properties. Lines 1-4 are the output using the Map object returned from getUserInfo1(), and lines 5-8 are the output of using the Map object returned from getUserInfo2().


Listing 8. The console output of running the application code of Listing 5
//1//   developer_news.myserver.com
//2//   5
//3//   Hello Chad we are retrieving 5 items for developer
//4//   we will save your news in:
        W:\workspace-callisto\dolphin\dolphin-hirix-example-properties/Chad
//5//   architect_news.myserver.com
//6//   10
//7//   Hello John we are retrieving 10 items for architect
//8//   we will save your news in:
        W:\workspace-callisto\dolphin\dolphin-hirix-example-properties/John



Back to top


Use properties with Groovy scripting

Hierarchical Inherited Rule-Interpreted XML also lets you include dynamic script within the XML properties file, allowing you to create values of any type. Groovy is a powerful scripting language that allows you to use virtually the full power of Java and more as expressions (see Resources for more information). The example in Listing 9 uses Groovy scripting to create a Map object for the property user1 and to create an actual class in the property user2.


Listing 9. Properties file with Groovy script
<!-- system['key'] is equivalent to System.getProperties.get("key") -->

<!-- This is an equivalent properties file with properties grouped by conditions -->

<properties>

     <!-- Define the Map object for the user info.
          Using Groovy you can use a simple
          expression here to define the map and values.

          HirixProperties allows you to return objects as well as strings. -->

   <property id="user1">
      <value>${groovy: [name:'Chad', job:'developer']}<value>
   </property>



   <!-- Define a class using Groovy script.
        You create the class with methods that will be compatible
        with the Map using the property style access. -->

   <property id="user2">
      <value>${groovy:
         class UserInfo {
            public getName() {
               return ("John") ;
            }
            public getJob() {
               return ("architect") ;
            }
         }
         return new UserInfo() ;}
      <value>
   </property>

</properties>

Listing 10 shows how you access the defined properties from your Java code and print the results.


Listing 10. Application code for processing the properties
   ...
         // Get property values and write out to the console for this example
         System.out.println( properties.get("user1")) ;
         System.out.println( properties.get("user2")) ;
   ...

Listing 11 shows the console output of running the application code of Listing 10. The first line is the output of the Map object, and the second line is the UserInfo object reference.


Listing 11. The console output of running the application code of Listing 10
{name=Chad, job=developer}
UserInfo@63026302



Back to top


Conclusion

Share this...

digg Digg this story
del.icio.us Post to del.icio.us
Slashdot Slashdot it!

Hierarchical Inherited Rule-Interpreted XML gives you a new and powerful way to configure applications. When you use the Java properties implementation included with this technology, you can easily use a powerful and enhanced properties design and still remain compatible with the standard java.lang.Properties object. This new technology allows you to build dynamic, flexible applications capable of rapidly adapting to changing requirements and business needs.

This article only begins to scratch the surface of the potential applications of Hierarchical Inherited Rule-Interpreted XML and the capabilities it provides. Future articles will demonstrate the use of other scripting languages, sharing the servlet context in Web applications, building modular components, and using the full power of dynamic XML configuration.



Resources

Learn

Get products and technologies

Discuss


About the author

Photo of Chad Meadows

Chad Meadows is the IBM Global Account's Lead Reuse Engineer. He is deeply involved with systematic reuse strategies and reusable assets throughout the company. He has been working at IBM in IT since 1993. Mr. Meadows is also an IBM Innovation Catalyst who assists in the development and adoption of innovative ideas and technologies for the company.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top