Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Spring Framework | Web Services | BioInformatics | Java Server Faces | Jboss 3.0 tutorial | Hibernate 3.0 | XML

Tutorial Categories: Ajax | Articles | JSP | Bioinformatics | Database | Free Books | Hibernate | J2EE | J2ME | Java | JavaScript | JDBC | JMS | Linux | MS Technology | PHP | RMI | Web-Services | Servlets | Struts | UML


 

Search Host

Monthly Fee($)
Disk Space (MB)
Register With us for Newsletter!
Visit Forum! Post Questions!
Jobs At RoseIndia.net!

Have tutorials?
Add your tutorial to our Java Resource and get tons of hits.

We offer free hosting for your tutorials. and exposure for thousands of readers. drop a mail
roseindia_net@yahoo.com
 
   

Tutorials

Java Server Pages

JAXB

Java Beans

JDBC

MySQL

Java Servlets

Struts

Bioinformatics

Java Code Examples

Interview Questions

 
Join For Newsletter

Powered by groups.yahoo.com
Visit Group! Post Questions!

Web Promotion

Web Submission

Submit Sites

Manual Submission?

Web Promotion Guide

Hosting Companies

Web Hosting Guide

Web Hosting

Linux

Beginner Guide to Linux Server

Frameworks

Persistence Framework

Web Frameworks

Free EAI Tools

Web Servers

Aspect Oriented Programming

Free Proxy Servers

Softwares

Adware & Spyware Remover

Open Source Softwares

Self-reloading XML Property Files

       

2004-09-30 The Java Specialists' Newsletter [Issue 095] - Self-reloading XML Property Files

Author: Dr. Heinz M. Kabutz

JDK version: Sun JDK 1.5.0-rc

If you are reading this, and have not subscribed, please consider doing it now by going to our subscribe page. You can subscribe either via email or RSS.


Welcome to the 95th edition of The Java(tm) Specialists' Newsletter. A special thank you goes to Ng Keng Yap from Malaysia for motivating me to publish this newsletter.

Self-reloading XML Property Files

I was chatting to a friend of mine tonight, who mentioned that after installing automatic Windows updates, the glorious operating system was now prompting him every five minutes whether he wanted to restart his computer. Irritating, is it not?

Whenever possible, I try to write software that you can configure "on the fly" without requiring a restart. This can get difficult when the only way of configuration is a bunch of XML files. Usually, the only way for these changes to apply to our system is to restart the program once the XML files have been edited.

To start, I use an interface that I call Configuration. It allows me to get one or all properties, and allows me to add listeners for property changes. I try to use generics whenever I can, since they make the code clearer, in my opinion (not shared by many ;-) If you look at getAllProperties(), we can clearly see what it returns - a set of Map.Entry implementations, each of which consists of a String/Object pair.

import java.beans.PropertyChangeListener;
import java.util.*;

public interface Configuration {
  Object getProperty(String propertyName);
  Set<Map.Entry<String,Object>> getAllProperties();
  void addPropertyChangeListener(PropertyChangeListener listener);
  boolean removePropertyChangeListener(PropertyChangeListener listener);
}
  

I have implemented a basic AbstractConfiguration that could be extended with many different types of config loaders. Whenever a property is set, it checks whether it is the same value as before. If it is not, it sends a PropertyChangeEvent to all the listeners.

There are two types of lists that I use: ArrayList and my CircularArrayList. I have not found a single use for LinkedList yet, have you? A new list that I will use here is the CopyOnWriteArrayList from the new java.util.concurrent package. This list is handy when the contents of your list change seldomly. Whenever the list is changed, it makes a copy of the old list and changes the copy. You can therefore have active Iterators on the old list and you will not get a ConcurrentModificationException anymore.

import java.beans.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author Heinz Kabutz
 */
public abstract class AbstractConfiguration implements Configuration {
  /** * A map of all the properties for the configuration */
  private final Map<String, Object> properties =
      new HashMap<String, Object>();

  private final Collection<PropertyChangeListener> listeners =
      new CopyOnWriteArrayList<PropertyChangeListener>();

  /** Make a daemon timer to check for changes. */
  private final Timer timer = new Timer(true);

  /**
   * This class has a timer to check periodically if the
   * configuration has changed.  If it has, it reloads the
   * properties.  This may cause the property change events to
   * fire.
   *
   * @param period number of milliseconds between checking for
   *               property changes.
   */
  protected AbstractConfiguration(int period) {
    timer.schedule(new TimerTask() {
      public void run() {
        checkForPropertyChanges();
      }
    }, period, period);
  }

  /**
   * This method should be overridden to check whether the
   * properties could maybe have changed, and if yes, to reload
   * them.
   */
  protected abstract void checkForPropertyChanges();

  public final Object getProperty(String propertyName) {
    synchronized (properties) {
      return properties.get(propertyName);
    }
  }

  public Set<Map.Entry<String, Object>> getAllProperties() {
    synchronized (properties) {
      return properties.entrySet();
    }
  }

  /**
   * Each time we set a property, we check whether it has changed
   * and if it has, we let the listeners know.
   */
  protected final void setProperty(String propertyName, Object value) {
    synchronized (properties) {
      Object old = properties.get(propertyName);
      if ((value != null && !value.equals(old))
          || value == null && old != null) {
        properties.put(propertyName, value);
        PropertyChangeEvent event = new PropertyChangeEvent(this,
            propertyName, old, value);
        for (PropertyChangeListener listener : listeners) {
          listener.propertyChange(event);
        }
      }
    }
  }

  public void addPropertyChangeListener(PropertyChangeListener l) {
    listeners.add(l);
  }

  public boolean removePropertyChangeListener(PropertyChangeListener l) {
    return listeners.remove(l);
  }
}
  

In my code, I usually have a central place to send Exceptions so that they can be logged, or the user alerted. I usually call this class Exceptions:

/**
 * In your code, you can make Exceptions more robust.  For
 * example, show a dialog to the user, send an email to the QA
 * team, etc.
 *
 * @author Heinz Kabutz
 */
public class Exceptions {
  public static void throwException(Throwable e) {
    e.printStackTrace();
  }
}

JDK 1.5 java.util.Properties has the ability to load and store property files in XML format directly, thanks to Ng Keng Yap for pointing this out to me. Our XMLFileConfiguration class reads the file date time and if it has changed, reads the values and sets them. Those properties that have changed will now cause events.

import java.io.*;
import java.util.*;

public class XMLFileConfiguration extends AbstractConfiguration {
  private final File file;
  private long lastModified = 0;

  public XMLFileConfiguration(Properties defaults, String filename, int period)
      throws IOException {
    super(period);
    setAllProperties(defaults);
    file = new File(filename);
    if (!file.exists()) {
      storeProperties();
    }
    loadProperties();
  }

  private void loadProperties() throws IOException {
    Properties properties = new Properties();
    properties.loadFromXML(new FileInputStream(file));
    setAllProperties(properties);
  }

  private void setAllProperties(Properties properties) {
    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
      setProperty((String) entry.getKey(), entry.getValue());
    }
  }

  public void storeProperties() {
    Properties properties = new Properties();
    for (Map.Entry<String, Object> entry : getAllProperties()) {
      properties.put(entry.getKey(), entry.getValue());
    }
    try {
      properties.storeToXML(new FileOutputStream(file),
          "Generated by XMLFileConfiguration");
    } catch (IOException e) {
      Exceptions.throwException(e);
    }
  }

  protected void checkForPropertyChanges() {
    if (lastModified != file.lastModified()) {
      try {
        lastModified = file.lastModified();
        loadProperties();
      } catch (IOException e) {
        Exceptions.throwException(e);
      }
    }
  }
}

This code is by no means robust. I wrote it very quickly, and there are many caveats that are not dealt with. For example, what if we need several properties in order to effectively change our system, such as a user name and password.

To show how it works, here is a short test class:

import java.beans.*;
import java.util.Properties;
import java.io.FileOutputStream;

public class Test {
  public static void main(String[] args) throws Exception {
    String filename = "test.xml";
    Properties defaults = new Properties();
    defaults.setProperty("name", "Heinz");
    defaults.setProperty("yahooid", "heinzkabutz");
    defaults.setProperty("age", "32");
    Configuration cfg = new XMLFileConfiguration(defaults, filename, 300);
    cfg.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        System.out.println("Property " + evt.getPropertyName() +
            " has now changed from <" + evt.getOldValue() +
            "> to <" + evt.getNewValue() + ">");
      }
    });
    Thread.sleep(1000);
    defaults.setProperty("age", "33");
    FileOutputStream fos = new FileOutputStream(filename);
    defaults.storeToXML(fos, "");
    fos.close();

    Thread.sleep(1000);
    defaults.setProperty("age", "32");
    fos = new FileOutputStream(filename);
    defaults.storeToXML(fos, "");
    fos.close();

    Thread.sleep(1000);
    defaults.setProperty("age", "2 ^ 4");
    fos = new FileOutputStream(filename);
    defaults.storeToXML(fos, "");
    fos.close();

    Thread.sleep(1000);
  }
}

Tomorrow (oh tomorrow is already today ;-) I am driving with a good friend all over the countryside upgrading a system that we built. We leave at 06:00, so now (00:35) I need to stop writing. Please let me know if you find obvious errors in the code :-)

Kind regards

Heinz

This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

       

Useful Links
  JDO Tutorials
  EAI Articles
  Struts Tutorials
  Java Tutorials
  Java Certification
Tell A Friend
Your Friend Name
Search Tutorials

 

 
Browse all Java Tutorials
Java JSP Struts Servlets Hibernate XML
Ajax JDBC EJB MySQL JavaScript JSF
Maven2 Tutorial JEE5 Tutorial Java Threading Tutorial Photoshop Tutorials Linux Technology
Technology Revolutions Eclipse Spring Tutorial Bioinformatics Tutorials Tools SQL
 

Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Search Engine | News Archive | Jboss 3.0 tutorial | Free Linux CD's | Forum | Blogs

About Us | Advertising On RoseIndia.net

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright 2007. All rights reserved.