/**
* Copyright (C) 2009 Future Invent Informationsmanagement GmbH. All rights
* reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option) any
* later version.
*
* This library 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*/
package org.fuin.utils4j;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import org.das2.util.LoggerManager;
/**
* A directory and PropertiesFile
based Preferences
* API implementation.
*/
public final class PropertiesFilePreferences extends AbstractPreferences {
private static final Logger logger= LoggerManager.getLogger("autoplot.dom.options");
/** Filename the properties of this node are stored under. */
public static final String FILENAME = "preferences.properties";
private final File dir;
private final PropertiesFile file;
private boolean removed;
/**
* Constructor with directory. This is constructing the "root" node.
*
* @param dir
* Directory where the preferences are stored.
*/
public PropertiesFilePreferences(final File dir) {
this(null, dir, "");
}
/**
* Constructor with directory. This is constructing the "root" node.
*
* @param dir
* Directory where the preferences are stored.
* @param propFileName the properties file name where the properties will be stored.
*/
public PropertiesFilePreferences(final File dir, String propFileName ) {
this(null, dir, "", propFileName );
}
/**
* Constructor with parent node and directory.
*
* @param parent
* Parent node.
* @param dir
* Directory where the preferences are stored.
*/
public PropertiesFilePreferences(final PropertiesFilePreferences parent, final File dir) {
this(parent, dir, dir.getName(),FILENAME);
}
private PropertiesFilePreferences(final PropertiesFilePreferences parent, final File dir,
final String name ) {
this(parent, dir, name, FILENAME);
}
/**
* Constructor with parent node and directory.
*
* @param parent
* Parent node.
* @param dir
* Directory where the preferences are stored.
* @param name
* Name of the node.
*/
private PropertiesFilePreferences(final PropertiesFilePreferences parent, final File dir,
final String name, final String propertiesFileName) {
super(parent, name);
this.dir = dir;
File propertiesFile= new File(dir, propertiesFileName);
if ( !propertiesFile.exists() ) {
if ( !propertiesFile.getParentFile().canWrite() ) {
logger.log(Level.FINE, "unable to write prefs file at {0}", propertiesFile);
} else {
logger.log(Level.FINE, "creating prefs file at {0}", propertiesFile);
}
}
this.file = new PropertiesFile(propertiesFile);
this.removed = false;
}
/**
* {@inheritDoc}
*/
protected final AbstractPreferences childSpi(final String name) {
final File childDir = new File(dir, name);
return new PropertiesFilePreferences(this, childDir, name);
}
/**
* {@inheritDoc}
*/
protected final String[] childrenNamesSpi() throws BackingStoreException {
try {
final List childs = new ArrayList();
final File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
childs.add(files[i].getName());
}
}
}
return (String[]) childs.toArray(new String[0]);
} catch (final RuntimeException ex) {
throw new BackingStoreException(ex);
}
}
/**
* {@inheritDoc}
*/
protected void flushSpi() throws BackingStoreException {
try {
if (removed) {
file.delete();
dir.delete();
} else {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final String[] comments = new String[] { "Do not edit, as this is a copy of properties during migration.",
"See https://sourceforge.net/p/autoplot/bugs/2175/",
"Created by " + this.getClass().getName(), sdf.format(new Date()) };
mkdirIfNecessary();
file.save(comments, true);
}
} catch (final Exception ex) {
throw new BackingStoreException(ex);
}
}
private void mkdirIfNecessary() throws BackingStoreException {
if (!dir.exists() && !dir.mkdirs()) {
throw new BackingStoreException("Failed to create directory '" + dir + "'!");
}
}
/**
* {@inheritDoc}
*/
protected final String getSpi(final String key) {
loadIfNecessary();
return file.get(key);
}
/**
* {@inheritDoc}
*/
protected final String[] keysSpi() throws BackingStoreException {
loadIfNecessary();
return file.getKeyArray();
}
/**
* {@inheritDoc}
*/
protected final void putSpi(final String key, final String value) {
loadIfNecessary();
file.put(key, value);
}
/**
* {@inheritDoc}
*/
protected final void removeNodeSpi() throws BackingStoreException {
file.clear();
removed = true;
}
/**
* {@inheritDoc}
*/
protected final void removeSpi(final String key) {
loadIfNecessary();
file.remove(key);
}
private void loadIfNecessary() {
if (!file.isLoaded()) {
try {
syncSpi();
} catch (final BackingStoreException ex) {
throw new RuntimeException(ex);
}
}
}
/**
* {@inheritDoc}
*/
protected final void syncSpi() throws BackingStoreException {
if (dir.exists() && file.exists()) {
try {
file.load();
} catch (final Exception ex) {
throw new BackingStoreException(ex);
}
}
}
/**
* Returns a copy of all properties.
*
* @return All key/values without deleted ones.
*/
public final Properties toProperties() {
return file.toProperties();
}
}