alsutton/enterprisepasswordsafe

View on GitHub
src/main/java/com/enterprisepasswordsafe/database/ConfigurationDAO.java

Summary

Maintainability
A
30 mins
Test Coverage
F
51%
/*
 * Copyright (c) 2017 Carbon Security Ltd. <opensource@carbonsecurity.co.uk>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package com.enterprisepasswordsafe.database;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class ConfigurationDAO
        extends JDBCBase {

    private static final String GET_SQL =
            "SELECT property_value FROM configuration WHERE property_name = ?";

    private static final String UPDATE_SQL =
            "UPDATE configuration SET property_value = ? WHERE property_name = ?";

    private static final String INSERT_SQL =
            "INSERT INTO configuration(property_value, property_name) VALUES (?, ?)";

    private static final String DELETE_SQL =
            "DELETE FROM configuration WHERE property_name = ?";

    private static final Map<String,CachedValue> cache = new HashMap<>();

    private ConfigurationDAO() {
        super();
    }

    public String get(final ConfigurationOption configurationOption)
        throws SQLException {
        if (configurationOption == null) {
            return null;
        }

        return get(configurationOption.getPropertyName(), configurationOption.getDefaultValue());
    }

    public String get(final String name, final String defaultValue)
            throws SQLException {
        if (name == null) {
            return null;
        }

        String cachedValue = getValueFromCache(name);
        if(cachedValue != null) {
            return cachedValue;
        }

        try(PreparedStatement ps = BOMFactory.getCurrentConntection().prepareStatement(GET_SQL)) {
            ps.setString(1, name);
            ps.setMaxRows(1);

            try(ResultSet rs = ps.executeQuery()) {
                if (!rs.next()) {
                    return defaultValue;
                }

                String value = rs.getString(1);
                if(rs.wasNull()) {
                    return defaultValue;
                }

                synchronized(cache) {
                    cache.put(name, new CachedValue(value));
                }

                return value;
            }
        }
    }

    private boolean exists(final String name)
            throws SQLException {
        if (name == null) {
            return false;
        }
        return exists(GET_SQL, name);
    }

    public void delete(final ConfigurationOption configurationOption)
        throws SQLException {
        if (configurationOption == null) {
            return;
        }

        delete(configurationOption.getPropertyName());
    }

    public void delete(final String name)
            throws SQLException {
        if (name == null) {
            return;
        }

        try(PreparedStatement ps = BOMFactory.getCurrentConntection().prepareStatement(DELETE_SQL)) {
            ps.setString(1, name);
            ps.executeUpdate();
        }

        synchronized (cache) {
            cache.remove(name);
        }
    }

    public void set(final ConfigurationOption configurationOption, final String value)
            throws SQLException {
        set(configurationOption.getPropertyName(), value);
    }

    public void set(final String name, final String value)
        throws SQLException {
        String sqlStatement = exists(name) ? UPDATE_SQL : INSERT_SQL;

        try(PreparedStatement ps = BOMFactory.getCurrentConntection().prepareStatement(sqlStatement)) {
            ps.setString(1, value);
            ps.setString(2, name);
            ps.executeUpdate();
        }

        putValueInCache(name, value);

        final List<ConfigurationListenersDAO.ConfigurationListener> listeners =
            ConfigurationListenersDAO.getListenersForProperty(name);
        if( listeners != null )
        {
            for(ConfigurationListenersDAO.ConfigurationListener thisListener: listeners) {
                thisListener.configurationChange(name, value);
            }
        }
    }

    private void putValueInCache(final String name, final String value) {
        synchronized(cache) {
            if (value == null) {
                cache.remove(name);
                return;
            }
            cache.put(name, new CachedValue(value));
        }
    }

    private String getValueFromCache(final String name) {
        synchronized(cache) {
            CachedValue cachedValue = cache.get(name);
            if( cachedValue != null ) {
                if( cachedValue.hasExpired() ) {
                    cache.remove(name);
                } else {
                    return cachedValue.getValue();
                }
            }
        }

        return null;
    }



    /**
     * Class holding a cached configuration value.
     */

    private static class CachedValue {
        /**
         * The maximum life of a cached entry.
         */

        private static final long CACHE_LIFETIME = 30 * 1000;    // 30s

        /**
         * The time the record was inserted into the cache.
         */

        private final long insertTime;

        /**
         * The value.
         */

        private final String value;

        /**
         * Constructor. Stores data.
         *
         * @param newValue The value to be cached.
         */
        private CachedValue( String newValue ) {
            insertTime = System.currentTimeMillis();
            value = newValue;
        }

        /**
         * Check to see if this entry has expired.
         */

        boolean hasExpired() {
            return System.currentTimeMillis() > (insertTime + CACHE_LIFETIME);
        }

        /**
         * Gets the value.
         */

        String getValue() {
            return value;
        }
    }

    public static String getValue(final ConfigurationOption configurationOption)
            throws SQLException {
        return getInstance().get(configurationOption);
    }

    public static String getValue(final String propertyName, final String defaultValue)
            throws SQLException {
        return getInstance().get(propertyName, defaultValue);
    }

    public static Long getLongValue(final ConfigurationOption configurationOption) {
        try {
            String value = getValue(configurationOption);
            return parseLongValue(value);
        } catch(SQLException | NumberFormatException e) {
            try {
                return parseLongValue(configurationOption.getDefaultValue());
            } catch (NumberFormatException nfe) {
                return null;
            }
        }
    }

    private static Long parseLongValue(String value)
        throws NumberFormatException {
        if(value == null) {
            return null;
        }

        return Long.parseLong(value);
    }

    //------------------------

    private static final class InstanceHolder {
        static final ConfigurationDAO INSTANCE = new ConfigurationDAO();
    }

    public static ConfigurationDAO getInstance() {
        return InstanceHolder.INSTANCE;
   }
}