com.adito.boot.PropertyPreferences.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.boot.PropertyPreferences.java

Source

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.adito.boot;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * A simple implementation for the preferences API. That stores preferences
 * in propery files. We do not have to worry about sharing the preferencese 
 * with other JVM instance so there is no need for any kind of synchronising
 * or locking.
 */
public class PropertyPreferences extends AbstractPreferences {

    /**
     * System root
     */
    public final static Preferences SYSTEM_ROOT = new PropertyPreferences(
            new File(new File(ContextHolder.getContext().getConfDirectory(), "prefs"), "system"));

    /**
     * User root
     */
    public final static Preferences USER_ROOT = new PropertyPreferences(
            new File(new File(ContextHolder.getContext().getConfDirectory(), "prefs"), "system"));

    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final int FLUSH_INTERVAL = 30; // seconds

    final static Log log = LogFactory.getLog(PropertyPreferences.class);

    private static Timer flushTimer = new Timer(true); // Daemon Thread

    static {
        // Add periodic timer task to periodically sync cached prefs
        flushTimer.schedule(new TimerTask() {
            public void run() {
                flushAll();
            }
        }, FLUSH_INTERVAL * 1000, FLUSH_INTERVAL * 1000);

        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                flushTimer.cancel();
                flushAll();
            }
        });
    }

    // Private instance variables

    private File dir;
    private File prefFile;
    private Properties prefs;

    /**
     * Constructor for root node.
     *
     * @param dir directory
     */
    public PropertyPreferences(File dir) {
        this(dir, null, "");
    }

    /**
     * Constructor.
     *
     * @param dir directory containing preferences and children
     * @param parent
     * @param name
     */
    public PropertyPreferences(File dir, AbstractPreferences parent, String name) {
        super(parent, name);
        this.dir = dir;
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#childSpi(java.lang.String)
     */
    protected AbstractPreferences childSpi(String name) {
        return new PropertyPreferences(new File(dir, encodeDirName(name)), this, name);
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#childrenNamesSpi()
     */
    protected String[] childrenNamesSpi() throws BackingStoreException {
        List result = new ArrayList();
        File[] dirContents = dir.listFiles();
        if (dirContents != null) {
            for (int i = 0; i < dirContents.length; i++)
                if (dirContents[i].isDirectory())
                    result.add(decodeDirName(dirContents[i].getName()));
        }
        return (String[]) result.toArray(EMPTY_STRING_ARRAY);
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#flushSpi()
     */
    protected void flushSpi() throws BackingStoreException {
        if (prefs == null) {
            return;
        }
        if (prefFile == null) {
            prefFile = new File(dir, "prefs.properties");
        }
        if (!dir.exists() && !dir.mkdirs()) {
            throw new BackingStoreException("Failed to create node directory " + dir.getPath() + ".");
        }
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(prefFile);
            prefs.store(fos, name());
        } catch (IOException ioe) {
            throw new BackingStoreException(ioe);
        } finally {
            Util.closeStream(fos);
        }
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#getSpi(java.lang.String)
     */
    protected String getSpi(String key) {
        checkLoaded();
        return prefs == null ? null : prefs.getProperty(key);
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#keysSpi()
     */
    protected String[] keysSpi() throws BackingStoreException {
        checkLoaded();
        return prefs == null ? EMPTY_STRING_ARRAY : (String[]) prefs.keySet().toArray(new String[prefs.size()]);
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#putSpi(java.lang.String, java.lang.String)
     */
    protected void putSpi(String key, String value) {
        checkLoaded();
        if (prefs == null) {
            prefs = new Properties();
        }
        prefs.setProperty(key, value);
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#removeNodeSpi()
     */
    protected void removeNodeSpi() throws BackingStoreException {
        if (!Util.delTree(dir)) {
            throw new BackingStoreException("Failed to remove preferencese node " + dir.getPath() + ".");
        }
    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#removeSpi(java.lang.String)
     */
    protected void removeSpi(String key) {
        checkLoaded();
        if (prefs != null) {
            prefs.remove(key);
        }

    }

    /* (non-Javadoc)
     * @see java.util.prefs.AbstractPreferences#syncSpi()
     */
    protected void syncSpi() throws BackingStoreException {
        flushSpi();

    }

    String encodeDirName(String dirName) {
        for (int i = 0, n = dirName.length(); i < n; i++) {
            if (!isValidChar(dirName.charAt(i))) {
                return "_" + Base64.encode(dirName.getBytes());
            }
        }
        return dirName;
    }

    String decodeDirName(String dirName) {
        if (dirName.startsWith("_")) {
            return new String(Base64.decode(dirName.substring(1)));
        }
        return dirName;
    }

    boolean isValidChar(char ch) {
        return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.' && ch != '_' && ch != '\\';
    }

    synchronized void checkLoaded() {
        if (prefFile == null) {
            prefFile = new File(dir, "prefs.properties");
        }
        if (prefFile.exists()) {
            if (prefs == null) {
                prefs = new Properties();
                FileInputStream fin = null;
                try {
                    fin = new FileInputStream(prefFile);
                    prefs.load(fin);
                } catch (IOException ioe) {
                    log.error("Failed to open preferences file " + prefFile.getPath() + ".", ioe);
                } finally {
                    Util.closeStream(fin);
                }

            }
        }
    }

    static void flushAll() {
        try {
            if (SYSTEM_ROOT != null)
                SYSTEM_ROOT.flush();
        } catch (BackingStoreException e) {
            log.warn("Couldn't flush system prefs.", e);
        }
        try {
            if (USER_ROOT != null)
                USER_ROOT.flush();
        } catch (BackingStoreException e) {
            log.warn("Couldn't flush user prefs.", e);
        }
    }

}