All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.naoghuman.lib.preferences.internal.FilePreferences Maven / Gradle / Ivy

Go to download

Lib-Preferences is a library for easy storing simple data in a Preferences.properties file in a JavaFx & Maven desktop application. See https://github.com/Naoghuman/lib-preferences for more details.

There is a newer version: 0.6.0
Show newest version
/*
 * Copyright (C) 2014 PRo
 *
 * 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 3 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, see .
 */
package com.github.naoghuman.lib.preferences.internal;

import com.github.naoghuman.lib.preferences.core.SimplePreferences;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

/**
 * Preferences implementation that stores to a user-defined file. See also
 * http://www.davidc.net/programming/java/java-preferences-using-file-backing-store
 *
 * @author David Croft (www.davidc.net)
 * @version $Id: FilePreferences.java 283 2009-06-18 17:06:58Z david $
 */
public final class FilePreferences extends AbstractPreferences {
    private static final Logger log = Logger.getLogger(FilePreferences.class.getName());
    private static FilePreferences instance = null;
    private static File preferencesFile = null;

    public static Preferences getUserRoot() {
        if (instance == null) {
            instance = new FilePreferences();
        }

        return instance;
    }

    public static Preferences userNodeForPackage(final Class clazz) {
        return FilePreferences.getUserRoot().node(FilePreferences.nodeName(clazz));
    }

    /**
     * Returns the absolute path name of the node corresponding to the package
     * of the specified object.
     *
     * @throws IllegalArgumentException if the package has node preferences node
     * associated with it.
     */
    private static String nodeName(final Class clazz) {
        if (clazz.isArray()) {
            throw new IllegalArgumentException(
                    "Arrays have no associated preferences node."); // NOI18N
        }

        String className = clazz.getName();
        int pkgEndIndex = className.lastIndexOf('.');
        if (pkgEndIndex < 0) {
            return "/"; // NOI18N
        }
        String packageName = className.substring(0, pkgEndIndex);

        return "/" + packageName.replace('.', '/'); // NOI18N
    }
    
    private boolean isRemoved = Boolean.FALSE;
    private Map root = null;
    private Map children = null;

    private FilePreferences() {
        this(null, "");
    }

    private FilePreferences(final AbstractPreferences parent, final String name) {
        super(parent, name);

        log.finest(String.format("Instantiating node %s", name)); // NOI18N

        root = new TreeMap<>();
        children = new TreeMap<>();

        try {
            this.sync();
        } catch (BackingStoreException e) {
            log.log(Level.SEVERE, "Unable to sync on creation of node " + name, e); // NOI18N
        }
    }

    @Override
    protected final void putSpi(final String key, final String value) {
        root.put(key, value);
        try {
            this.flush();
        } catch (BackingStoreException e) {
            log.log(Level.SEVERE, "Unable to flush after putting " + key, e); // NOI18N
        }
    }

    @Override
    protected final String getSpi(final String key) {
        return root.get(key);
    }

    @Override
    protected final void removeSpi(final String key) {
        root.remove(key);
        try {
            this.flush();
        } catch (BackingStoreException e) {
            log.log(Level.SEVERE, "Unable to flush after removing " + key, e); // NOI18N
        }
    }

    @Override
    protected final void removeNodeSpi() throws BackingStoreException {
        isRemoved = true;

        this.flush();
    }

    @Override
    protected final String[] keysSpi() throws BackingStoreException {
        return root.keySet().toArray(new String[root.keySet().size()]);
    }

    @Override
    protected final String[] childrenNamesSpi() throws BackingStoreException {
        return children.keySet().toArray(new String[children.keySet().size()]);
    }

    @Override
    protected final FilePreferences childSpi(final String name) {
        FilePreferences child = children.get(name);
        if (child == null || child.isRemoved()) {
            child = new FilePreferences(this, name);
            children.put(name, child);
        }

        return child;
    }

    @Override
    protected final void syncSpi() throws BackingStoreException {
        if (isRemoved()) {
            return;
        }

        final File file = FilePreferences.getPreferencesFile();
        if (!file.exists()) {
            return;
        }

        synchronized (file) {
            final Properties p = new Properties();
            try {
                p.load(new FileInputStream(file));

                final StringBuilder sb = new StringBuilder();
                this.getPath(sb);

                final String path = sb.toString();
                final Enumeration pnen = p.propertyNames();
                while (pnen.hasMoreElements()) {
                    final String propKey = (String) pnen.nextElement();
                    if (propKey.startsWith(path)) {
                        final String subKey = propKey.substring(path.length());
                        // Only load immediate descendants
                        if (subKey.indexOf('.') == -1) {
                            root.put(subKey, p.getProperty(propKey));
                        }
                    }
                }
            } catch (IOException e) {
                throw new BackingStoreException(e);
            }
        }
    }

    public static File getPreferencesFile() {
        if (preferencesFile == null) {
            String prefsFile = System.getProperty(SimplePreferences.SYSTEM_PREFERENCES__FILE);
            if (prefsFile == null || prefsFile.length() == 0) {
                prefsFile = System.getProperty("user.dir") + File.separator + ".fileprefs"; // NOI18N
            }
            
            preferencesFile = new File(prefsFile).getAbsoluteFile();

            log.finer(String.format("Preferences file is %s", preferencesFile)); // NOI18N
        }

        return preferencesFile;
    }

    private void getPath(final StringBuilder sb) {
        final FilePreferences parent = (FilePreferences) parent();
        if (parent == null) {
            return;
        }

        parent.getPath(sb);
        sb.append(name()).append('.');
    }

    @Override
    protected final void flushSpi() throws BackingStoreException {
        final File file = FilePreferences.getPreferencesFile();

        synchronized (file) {
            final Properties properties = new Properties();
            try {
                final StringBuilder sb = new StringBuilder();
                this.getPath(sb);
                final String path = sb.toString();

                if (file.exists()) {
                    properties.load(new FileInputStream(file));

                    final List toRemove = new ArrayList<>();

                    // Make a list of all direct children of this node to be removed
                    final Enumeration pnen = properties.propertyNames();
                    while (pnen.hasMoreElements()) {
                        final String propKey = (String) pnen.nextElement();
                        if (propKey.startsWith(path)) {
                            final String subKey = propKey.substring(path.length());
                            // Only do immediate descendants
                            if (subKey.indexOf('.') == -1) {
                                toRemove.add(propKey);
                            }
                        }
                    }

                    // Remove them now that the enumeration is done with
                    toRemove.stream()
                            .forEach((propKey) -> {
                                properties.remove(propKey);
                            });
                }

                // If this node hasn't been removed, add back in any values
                if (!isRemoved) {
                    root.keySet().stream()
                            .forEach((s) -> {
                                properties.setProperty(path + s, root.get(s));
                            });
                }

                properties.store(new FileOutputStream(file), "This file is automatically generated. Plz don't modified it manuelly."); // NOI18N
            } catch (IOException e) {
                throw new BackingStoreException(e);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy