com.tulskiy.musique.system.configuration.Configuration.java Source code

Java tutorial

Introduction

Here is the source code for com.tulskiy.musique.system.configuration.Configuration.java

Source

/*
 * Copyright (c) 2008, 2009, 2010, 2011 Denis Tulskiy
 *
 * This program 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 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with this work.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.tulskiy.musique.system.configuration;

import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Logger;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.tulskiy.musique.plugins.hotkeys.HotkeyConfiguration;
import com.tulskiy.musique.system.Application;

/**
 * Author: Denis Tulskiy
 * Date: Jun 15, 2010
 */
public class Configuration extends XMLConfiguration {

    public static final int VERSION = 1;

    public static final String PROPERTY_INFO_VERSION = "info.version";

    private Logger logger = Logger.getLogger(getClass().getName());
    // TODO move to ConfigurationListener given by Configuration Commons
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);

    @Deprecated
    private Map<String, Object> map = new TreeMap<String, Object>();

    {
        // Disable delimiter mechanism completely for this instance
        //
        // https://issues.apache.org/jira/browse/CONFIGURATION-268
        // We might add a note in the javadoc suggesting that setDelimiterParsingDisabled(true)
        // is not recommended if list properties are used in attributes,
        // and that changing the list delimiter to an untypical character is preferred.
        //
        // http://commons.apache.org/configuration/userguide/howto_xml.html
        // Using the static setDefaultDelimiter() method of AbstractConfiguration
        // you can globally define a different delimiter character
        // or - by setting the delimiter to 0 - disabling this mechanism completely.
        setListDelimiter((char) 0);
    }

    @Override
    public void load(Reader reader) {
        logger.fine("Loading configuration");

        try {
            super.load(reader);
        } catch (ConfigurationException e) {
            // error log disabled as we're gonna try to load deprecated configuration file of v0.2
            //            logger.severe("Failed to load configuration: " + e.getMessage());
            convertOldConfiguration(reader);
        }

        int version = getInt(PROPERTY_INFO_VERSION, -1);
        if (version > VERSION) {
            logger.warning(String.format("Configuration of newer v%d found, but v%d is latest supported."
                    + " Backward compatibility is not guaranteed.", version, VERSION));
        } else if (version == -1) {
            logger.warning(
                    "Configuration of unknown version is loaded." + " Backward compatibility is not guaranteed.");
        } else {
            logger.config(String.format("Configuration of v%d is loaded.", version));
        }
    }

    @SuppressWarnings("unchecked")
    @Deprecated
    private void convertOldConfiguration(Reader reader) {
        // reader has been used, so try to reposition read point to start
        try {
            reader.reset();
        } catch (IOException e) {
            // just ignore, will try to read from where it is
        }

        loadFromCustomFormat(reader);

        setFile(new File(Application.getInstance().CONFIG_HOME, "config"));
        addProperty(PROPERTY_INFO_VERSION, VERSION);

        Iterator<Entry<String, Object>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Entry<String, Object> entry = entries.next();
            String key = /*"musique." +*/ entry.getKey();
            if (entry.getValue() instanceof List) {
                List values = (List) entry.getValue();
                if (key.equals("albumart.stubs")) {
                    AlbumArtConfiguration.setStubs(values);
                } else if (key.equals("fileOperations.patterns")) {
                    FileOperationsConfiguration.setPatterns(values);
                } else if (key.equals("hotkeys.list")) {
                    HotkeyConfiguration.setHotkeysRaw(values);
                } else if (key.equals("library.folders")) {
                    LibraryConfiguration.setFolders(values);
                } else if (key.equals("playlist.columns")) {
                    PlaylistConfiguration.setColumnsRaw(values);
                } else if (key.equals("playlist.tabs.bounds")) {
                    PlaylistConfiguration.setTabBoundsRaw(values);
                } else if (key.equals("playlists")) {
                    PlaylistConfiguration.setPlaylistsRaw(values);
                } else {
                    for (Object value : values) {
                        addProperty(key, value);
                    }
                }
            } else {
                if (key.equals("wavpack.encoder.hybrid.wvc")) {
                    addProperty("encoder.wavpack.hybrid.wvc.enabled", entry.getValue());
                } else if (key.equals("playlist.activePlaylist")) {
                    addProperty("playlists.activePlaylist", entry.getValue());
                } else if (key.equals("playlist.cursorFollowsPlayback")) {
                    addProperty("playlists.cursorFollowsPlayback", entry.getValue());
                } else if (key.equals("playlist.groupBy")) {
                    addProperty("playlists.groupBy", entry.getValue());
                } else if (key.equals("playlist.lastDir")) {
                    addProperty("playlists.lastDir", entry.getValue());
                } else if (key.equals("playlist.playbackFollowsCursor")) {
                    addProperty("playlists.playbackFollowsCursor", entry.getValue());
                } else if (key.equals("playlist.tabs.hideSingle")) {
                    addProperty("playlists.tabs.hideSingle", entry.getValue());
                } else if (key.startsWith("ape.encoder")) {
                    addProperty(key.replace("ape.encoder", "encoder.ape"), entry.getValue());
                } else if (key.startsWith("vorbis.encoder")) {
                    addProperty(key.replace("vorbis.encoder", "encoder.vorbis"), entry.getValue());
                } else if (key.startsWith("wavpack.encoder")) {
                    addProperty(key.replace("wavpack.encoder", "encoder.wavpack"), entry.getValue());
                } else {
                    addProperty(key, entry.getValue());
                }
            }
        }

        map.clear();

        try {
            save();
        } catch (ConfigurationException e) {
            logger.severe("Failed to save converted configuration: " + e.getMessage());
        }
    }

    @Override
    public void save(Writer writer) {
        logger.fine("Saving configuration");

        try {
            OutputFormat format = new OutputFormat(createDocument());
            format.setLineWidth(65);
            format.setIndenting(true);
            format.setIndent(2);
            XMLSerializer serializer = new XMLSerializer(writer, format);
            serializer.serialize(getDocument());
            writer.close();
        } catch (ConfigurationException ce) {
            logger.severe("Failed to save configuration: " + ce.getMessage());
        } catch (IOException ioe) {
            logger.severe("Failed to save configuration: " + ioe.getMessage());
        }
    }

    // TODO remove when 0.3 released
    @Deprecated
    public void loadFromCustomFormat(Reader reader) {
        try {
            BufferedReader r = new BufferedReader(reader);

            ArrayList<String> array = null;
            String key = null;
            while (r.ready()) {
                String line = r.readLine();

                if (line == null)
                    break;

                if (line.startsWith("  ") && array != null) {
                    array.add(line.trim());
                } else {
                    if (array != null) {
                        if (array.size() > 0)
                            map.put(key, array);
                        array = null;
                    }

                    int index = line.indexOf(':');
                    if (index == -1)
                        continue;

                    key = line.substring(0, index);
                    String value = line.substring(index + 1).trim();
                    if (value.isEmpty()) {
                        array = new ArrayList<String>();
                    } else {
                        map.put(key, value);
                    }
                }
            }

            if (array != null)
                map.put(key, array);
        } catch (IOException e) {
            logger.severe("Failed to load configuration: " + e.getMessage());
        }
    }

    @Deprecated
    /**
     * use addProperty instead
     */
    public void add(String key, Object value) {
        Object old = get(key);
        addProperty(key, value == null ? null : value.toString());
        changeSupport.firePropertyChange(key, old, value);
    }

    @Deprecated
    /**
     * use setProperty instead
     */
    public void put(String key, Object value) {
        Object old = get(key);
        if (value == null) {
            remove(key);
        } else {
            setProperty(key, value.toString());
        }
        changeSupport.firePropertyChange(key, old, value);
    }

    public void remove(String key) {
        clearTree(key);
    }

    @Deprecated
    /**
     * use getProperty instead
     */
    public Object get(String key) {
        return getProperty(key);
    }

    public void setInt(String key, int value) {
        put(key, value);
    }

    public void setFloat(String key, float value) {
        put(key, value);
    }

    public void setString(String key, String value) {
        put(key, value);
    }

    public Color getColor(String key, Color def) {
        try {
            String s = getString(key).substring(1);
            return new Color(Integer.parseInt(s, 16));
        } catch (Exception e) {
            setColor(key, def);
            return def;
        }
    }

    public void setColor(String key, Color value) {
        if (value == null)
            remove(key);
        else {
            String s = new Formatter().format("#%06X", value.getRGB() & 0xFFFFFF).toString();
            put(key, s);
        }
    }

    public Rectangle getRectangle(String key, Rectangle def) {
        try {
            String value = getString(key);
            String[] tokens = value.split(" ");
            if (tokens.length != 4)
                throw new NumberFormatException();

            int[] values = new int[4];
            for (int i = 0; i < tokens.length; i++) {
                String s = tokens[i];
                values[i] = Integer.parseInt(s);
            }
            return new Rectangle(values[0], values[1], values[2], values[3]);
        } catch (Exception e) {
            setRectangle(key, def);
            return def;
        }
    }

    public void setRectangle(String key, Rectangle value) {
        if (value == null)
            remove(key);
        else {
            String s = new Formatter().format("%d %d %d %d", (int) value.getX(), (int) value.getY(),
                    (int) value.getWidth(), (int) value.getHeight()).toString();
            put(key, s);
        }
    }

    public Font getFont(String key, Font def) {
        try {
            String value = getString(key);
            String[] tokens = value.split(", ");

            return new Font(tokens[0], Integer.parseInt(tokens[1]), Integer.parseInt(tokens[2]));
        } catch (Exception e) {
            setFont(key, def);
            return def;
        }
    }

    public void setFont(String key, Font value) {
        if (value == null)
            remove(key);
        else {
            String s = new Formatter().format("%s, %d, %d", value.getName(), value.getStyle(), value.getSize())
                    .toString();
            put(key, s);
        }
    }

    public void setBoolean(String key, boolean value) {
        put(key, value);
    }

    public void setList(String key, List<?> values) {
        remove(key);
        if (values == null) {
            // TODO refactor when dev cycle finished (right now check implemented for debug in emergency case)
            logger.severe("Illegal argument (empty list). Please check calling code.");
        }
        for (Object value : values) {
            add(key, value);
        }
    }

    @SuppressWarnings({ "unchecked" })
    public <E extends Enum<E>> E getEnum(String key, E def) {
        String val = getString(key, def.name());
        Class<E> clazz = (Class<E>) def.getClass();
        return E.valueOf(clazz, val);
    }

    public <E extends Enum<E>> void setEnum(String key, E value) {
        setString(key, value.name());
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    }

    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(propertyName, listener);
    }

    public void addPropertyChangeListener(String propertyName, boolean initialize,
            PropertyChangeListener listener) {
        addPropertyChangeListener(propertyName, listener);
        if (initialize)
            listener.propertyChange(new PropertyChangeEvent(this, propertyName, null, get(propertyName)));
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }
}