Java tutorial
/* * 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); } } }