An approach to configurable parameters

It is annoying how much work you need to do just to get all the properties from the file mapped to a class catching all the exceptions and repeating many times the same keys thorough the configuration files. For example, normally I had before a class that has static String variables each one mapping a key in the property file and then I use those variables when loading the properties and validating, etc.

When you need to load some properties from a file to your application in order to have some configurable parameters normally you use an external file in case of having a Java SE application or a resource bundled in your Java package such as yourwar/META-INF/applicationProperties.xml.

I have write some dirty (ugly) code just to give you an idea of how that can be easier.

Supose the next scenario.
you have a applicationProperties.xml file
---

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<properties>
<comment>
The good thing of using the xml version of properties file is that
it is "easy" to see the whitespaces that normally endup at the end of
the strings and most of the times we forget to use value.trim() ...
and then some time is spent for that stupid bug
</comment>

<entry key="connectionString">jdbc:h2:file:c:\h2db\dbName</entry>
<entry key="user">sa</entry>
<entry key="password">saadmin</entry>
<entry key="poolSize">7</entry>
<entry key="timeoutMillis">7000</entry>
<entry key="retryInterval">3</entry>

</properties>

---

and the next class mapping your file properties
---

public class ConfigurableParameters {


   public String _connectionString;
   public String _user;
   public String _password;
   public Integer _poolSize;
   public Long _timeoutMillis;
   public Integer _retryInterval;
   
   private static ConfigurableParameters instance;
   public static ConfigurableParameters getInstance() {
      if (instance == null) {
         instance = new ConfigurableParameters();
      }
      return instance;
   }
}

---

You see, the only time where you repeated the keys are in the name of the variables of the class. Now, wouldn't it be nice to load all the properties like this ?

---

public static void main(String[] args) {
      boolean confSuccess = ConfigurationHelper.mapConfigurableProperties(
                           ConfigurationSource.FILE,
                           "applicationProperties.xml",
                           ConfigurableParameters.getInstance());
      if (!confSuccess) {
         System.out.println("Error loading configuration");
         return;
      }
      
      System.out.println(ConfigurableParameters.getInstance()._connectionString);
      System.out.println(ConfigurableParameters.getInstance()._user);
      System.out.println(ConfigurableParameters.getInstance()._password);
      System.out.println(ConfigurableParameters.getInstance()._poolSize);
      System.out.println(ConfigurableParameters.getInstance()._timeoutMillis);
      System.out.println(ConfigurableParameters.getInstance()._retryInterval);
   }

---

The reason I make that the function recognizes all the fields starting with an underscore is just to make it clear that it will expect that those fields have a key in the properties file.

Actually You can make the fields of ConfigurableParameters class to be private and just provide public getters, it will still set the parameters. Also you can load the properties from a bundle file resource of the packaged jar, just call the method with ConfigurationSource.RESOURCE, and your sourceAddress would be something like "/META-INF/applicationProperties.xml", depending where did you put the file.


The implementation for the ConfigurationHelper is here

---

public class ConfigurationHelper {


   public enum ConfigurationSource {
      RESOURCE, FILE
   }


   public static boolean mapConfigurableProperties(ConfigurationSource configurationSource, String sourceAddress, Object target) {


      if (configurationSource == null || sourceAddress == null || target == null )
         return false;
      
      try {
         Properties sourceProperties = 
            getSourceProperties(configurationSource, sourceAddress, target);


         if (sourceProperties.isEmpty())
            return false;


         for (Field f : target.getClass().getDeclaredFields()) {
            String fieldName = f.getName();
      
            if (!fieldName.startsWith("_"))
               continue;


            fieldName = fieldName.substring(1);


            if (!sourceProperties.containsKey(fieldName))
               continue;


            boolean originalAccesibleValue = f.isAccessible();


            f.setAccessible(true);
            f.set(target, getConvertedValueForType((String) sourceProperties.get(fieldName), f.getType()));
            f.setAccessible(originalAccesibleValue);
         }


      } catch (Exception e) {
         e.printStackTrace();
         return false;
      }
      return true;
   }


   private static Properties getSourceProperties(ConfigurationSource configurationSource, String sourceAddress, Object target) {
      Properties prop = new Properties();
      try {
         InputStream is = 
            configurationSource == ConfigurationSource.FILE ? 
               new FileInputStream(sourceAddress) : 
                  target.getClass().getResourceAsStream(sourceAddress);
               
         prop.loadFromXML(is);
         is.close();
      } catch (Exception e) {
         e.printStackTrace();
      }


      return prop;
   }


   private static Object getConvertedValueForType(String sourceValue, Class c) {
      Object convertedValue = null;
      if (c == String.class) {
         convertedValue = sourceValue;
      } 
      else if (c == Long.class) {
         convertedValue = new Long((String) sourceValue);
      }
      else if (c == Integer.class) {
         convertedValue = new Integer((String) sourceValue);
      } 
      else if (c == BigDecimal.class) {
         convertedValue = new BigDecimal((String) sourceValue);
      }


      return convertedValue;
   }


}

---

This all may seem out of the standard conventions and I just didn't think of another way of doing this. It is just an idea of how can you make the work of loading configurable properties easier.

Have fun trying it and please give me feedback about how you are doing it.

Easiest way to publish Java Web Services --how to

In a previous post I wrote about publishing a Web Service through an embeddable ejb3 implementation, which is good since @Stateless beans can have injected managed entityManagers, in some cases that is the way to go if you don't want to deploy your app in a full J2EE server or you need a more flexible environment.

Just days ago I found that the J2SE itself has an lightweight http server embedded into, and the API itself has an Endpoint class that allows you to publish a Web Service in a J2SE environment.

There is more than one way for doing this, but this is the more automatic I could found, the next is a working example. The JRE version I am using is 6 update 7, I am not sure since when it supports it

-----

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.Endpoint;


@WebService
@SOAPBinding(style=Style.RPC) // without this it does not work automatically.

public class ASimpleTest {
public static class WebServiceTest {
public String callMe(String name) {
return "Hello "+name+" !";  
}
}
public static void main(String[] args) {
Endpoint.publish("http://localhost:8080/sayHello", 
new WebServiceTest());
// http://localhost:8080/sayHello?wsdl will be the 
// place for the wsdl generated on the fly

// remember to use the DNS address of your IP or 
// your IP itself if you want to expose so as to 
// be accessible not only from localhost or
// 127.0.0.1
}
}

----- 


Now you wonder how does this work ? Well, as you publish(...) it starts its embedded http server and binds the webservice automatically generated from the WebServiceTest class to the ip:port you've specified. The threading configuration should be quite ok for most cases.

Have fun trying it !

Run Java application as Windows Services

Sometimes you need to execute a java program as the machine starts without the needing to log-in. To achieve that you need to make a Windows Service.

For the purpose of this short how to, I will assume you have a folder with aRunnableJarFile.jar with maybe a lib folder and a configuration file for the java application, which is the usual way for packaging Java applications

One option, and the one I like the most is to use the open source project at Java Service Launcher, it gives you two important files. jsl.exe and jsl.ini. you normally put those files in the same folder as yourRunnableJarFile.jar.
You edit the jsl.ini file so as to tell jsl.exe how to launch your runnable jar ( e. g. cmdline= -jar aRunnableJarFile.jar ), you can also configure where the jvm is, where will be the working directory for your application as the service starts, where you'll redirect all the output or erroutput of the sevice to a file and things like that.
As you have the jsl.ini configured you can run your application with 'jsl.exe -debug' which will launch your java app rigth in the console so you can see if everything went ok with the jsl.ini, you can also run 'jsl.exe -install' and it will create a windows service pointing to that jsl.exe file.
As you start the windows service ( or normally configure it to automatically start ) it will launch the jsl.exe file wihch will run your java application. When you stop the windows service jsl will call System.exit() in you app, so any shutdown hooks that you configured will be called by default. It is really easy.

Another option is to create a exe wrapping your jar file. JSmooth is an open source project that does exactly that.
It has a graphic user interface that walks you though wizard-like steps to create an exe wrapper for your Java application and as you create the wrapper, you tell jsmooth that you want the wrapper to be a windows service.
It produces aRunnableFileWrappingYourJarFile.exe which you can run with an 'install' or 'remove' argument to install or remove the application as a windows service.

Although I didn't see something similar to jsl.exe, there are lots of programs like jsmoth but mostly commercial.

Hope you can find useful this post and any problems you have I'll do my best to help you

P.D.: please forgive my bad English