expandable properties

In one of my projects, I want to have such properties defined
url.qa=…
url.prod=…
url=${url.${target}}

Above Ant style properties are expandable. This is very useful in configuration properties. Last Ant has support of expandable properties through the Contrib library, however I could not figure out how to utilize it in a Java application. So I wrote a simple customized Properties class


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

/**
 * Properties which can handle expanded ant style value.
 * For example
 * a=1
 * b=${a}
 * c1=aaa
 * d=${c${b}}
 * the d will have resolved value aaa
 * 
 * Note: you have to order the properties in the file so that the referenced
 * property is read before the nesting property. (like above example shows)
 * 
 * this properties can handle the environment value too.
 * For example, set below in property file
 * 
 * a=222
 * a.production=3333
 * b=4
 * b.ref=5
 * and set a System property "target=production"
 * then getProperty("a") will return 33333
 * getProperty("b") will return 4
 */
public class NestedProperties extends Properties {

	Logger log = LogManager.getLogger(this.getClass());

	private final String target_key="target";
	String target=null;
	
	@Override
	public String getProperty(String key, String defaultValue) {
		if(target!=null){
			//check whether there is key.target exist
			if(this.contains(key+"."+target)){
				return super.getProperty(key+"."+target, defaultValue);
			}
		}
		return super.getProperty(key, defaultValue);
	}


	private void load(BufferedReader br) throws IOException{
		if(System.getProperty(target_key)!=null){
			target = System.getProperty(target_key);
		}
		String line = null;
		try{
			while((line=br.readLine())!=null){
				String cleaned = StringUtils.chomp(line.trim());
				if(cleaned.isEmpty() || cleaned.startsWith("#")){
					continue;
				}else{
					int i = cleaned.indexOf("=");
					String key = cleaned.substring(0,i).trim();
					String value = cleaned.substring(i+1).trim();
					if(value.indexOf("${")<0){
						//not embeded
						//internalProps.setProperty(key, value);
						this.put(key, value);
					}else{
						//resolve
						String resolvedValue = this.resolve4(value);
						log.debug("nested property " + key + " to value:" + value);
						log.debug("resolved property " + key + " to value:" + resolvedValue);
						//internalProps.setProperty(key, resolvedValue);
						this.put(key, resolvedValue);
					}
				}
			}
		}finally{
			
		}
	}
	@Override
	public synchronized void load(Reader reader) throws IOException {
		this.load(new BufferedReader(reader));
	}

	@Override
	public synchronized void load(InputStream inStream) throws IOException {
		this.load(new BufferedReader(new InputStreamReader(inStream)));
	}

	@Override
	public synchronized void loadFromXML(InputStream in) throws IOException,
			InvalidPropertiesFormatException {
		throw new UnsupportedOperationException("sorry xml not supported!");
	}
	

	public String resolve4(String sourcestring){
		char[] chars = sourcestring.toCharArray();
		StringBuilder res = new StringBuilder();
		int start=0;
		int end=chars.length;
		String s = sourcestring;
//		System.out.println(s);
		while(start<end){
			char c = chars[start];
//			System.out.println(c);
			if(c=='}'){
				//back check ${
				boolean replaced=false;
				for(int i=start-1;i>=0;i--){
					char d1 = chars[i];
					char d2 = chars[i+1];
					if(d1=='$' && d2=='{'){
						replaced=true;
//						System.out.println("d1=" +d1+" d2=" +d2);
						String variable = String.copyValueOf(chars, i+2, start-i-2);
//						System.out.println("bingo, find the stuff " + variable);
						String value = (String) this.get(variable);
						//replace the ${..} with value in the array
						StringBuilder newS = new StringBuilder();
						newS.append(s.substring(0, i));
						newS.append(value);
						int nextStart = newS.length();
						if(start<s.length()-1){
							newS.append(s.substring(start+1));
						}
						//
						s=null;
						s = newS.toString();
						chars=null;
						chars=s.toCharArray();
						end=chars.length;
						System.out.println(s);
						start=nextStart;
						break;
					}
				}
				if(!replaced){
					start++;
				}
			}else{
				start++;
			}
			
		}
		return s;
	}

}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s