samedi 5 avril 2014

Faire référence à des variables système dans un fichier de propriétés

Lorsqu'un fichier de propriété (xxx.properties) est lu, il peut être intéressant de faire référence à une variable d'environnement.
Par exemple, un répertoire de base contenant des fichiers :
logDir=${sys:HOME}/home
Par défaut, évidement, ce n'est pas possible.
La mise en oeuvre est très simple, comme le montre l'exemple suivant en dérivant de la classe java.util.Properties :
package org.emeric.property;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.InvalidPropertiesFormatException;
import java.util.Map.Entry;
import java.util.Properties;

/**
 * Extends properties to add support ${sys:xxx} notation.
 * 
 * @author emeric_martineau
 */
public class ExtendProperties extends Properties {

    /**
     * Serial number.
     */
    private static final long serialVersionUID = -123874838055277825L;

    /**
     * Open tag to replace.
     */
    private static final String OPEN_TAG = "${sys:";
    
    /**
     * Open tag length.
     */
    private static final int OPEN_TAG_LEN = OPEN_TAG.length();
    
    /**
     * Close tag to replace.
     */
    private static final String END_TAG = "}";
    
    /**
     * Create empry properties.
     */
    public ExtendProperties() {
        super();
    }
    
    /**
     * Create properties.
     * 
     * @param defaults defautl value/
     */
    public ExtendProperties(final Properties defaults) {
        super();

        // Copy properties
        for(Entry entry : defaults.entrySet()) {
            setProperty((String) entry.getKey(), (String) entry.getValue());
        }
        
        loadExternalProperties();
    }    
    
    @Override
    public synchronized void load(InputStream inStream) throws IOException {
        super.load(inStream);
        
        loadExternalProperties();
    }
    
    @Override
    public synchronized void loadFromXML(InputStream in) throws IOException,
            InvalidPropertiesFormatException {
        super.loadFromXML(in);
        
        loadExternalProperties();
    }
    
    @Override
    public synchronized void load(Reader reader) throws IOException {
        super.load(reader);
        
        loadExternalProperties();
    }
    
    /**
     * Replace external properties reference (${sys:}). 
     */
    private void loadExternalProperties() {
        StringBuilder sb = new StringBuilder();
        
        for(Entry entry : entrySet()) {
            // Clear StringBuilder
            sb.delete(0, sb.length());
            
            replaceValue(entry, sb);
        }
    }
    
    /**
     * Replace value if necessary.
     * 
     * @param entry entry.
     * @param sb string builder
     */
    private void replaceValue(final Entry entry,
            final StringBuilder sb) {
        // Value to search and replace
        String value = (String) entry.getValue();
        // Start tag index
        int startTag = value.indexOf(OPEN_TAG);
        // End tag
        int endTag;
        // Star variable name
        int startVar;
        // Offset
        int offsetTag = 0;
        
        // System var name
        String varName;
        // If value modified
        boolean modified = startTag != -1;        
        
        while (startTag != -1) {
            startVar = startTag + OPEN_TAG_LEN;
            endTag = value.indexOf(END_TAG, startVar);
            
            // Get var name
            varName = value.substring(startVar, endTag);
            
            // Copy value before startTag
            sb.append(value.substring(offsetTag, startTag));
            // Add tag replacement
            sb.append(System.getProperty(varName));
            
            // New start of search
            offsetTag = endTag + 1;
            // Search new tag
            startTag = value.indexOf(OPEN_TAG, offsetTag);
        }
        
        // Add end of string
        sb.append(value.substring(offsetTag)) ;
        
        if (modified) {
            // Update value
            setProperty((String) entry.getKey(), sb.toString());
        }
    }
}

Il serait intéressant maintenant de pouvoir référence une propriété définit dans le fichier de properties.
Ce sera le sujet d'un prochain article.

Aucun commentaire:

Enregistrer un commentaire