io.github.lucaseasedup.logit.profile.ProfileManager.java Source code

Java tutorial

Introduction

Here is the source code for io.github.lucaseasedup.logit.profile.ProfileManager.java

Source

/*
 * ProfileManager.java
 *
 * Copyright (C) 2012-2014 LucasEasedUp
 *
 * 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 <http://www.gnu.org/licenses/>.
 */
package io.github.lucaseasedup.logit.profile;

import com.google.common.collect.ImmutableList;
import io.github.lucaseasedup.logit.LogItCoreObject;
import io.github.lucaseasedup.logit.profile.field.Field;
import io.github.lucaseasedup.logit.profile.field.FloatField;
import io.github.lucaseasedup.logit.profile.field.IntegerField;
import io.github.lucaseasedup.logit.profile.field.SetField;
import io.github.lucaseasedup.logit.profile.field.StringField;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.bukkit.configuration.file.YamlConfiguration;

public final class ProfileManager extends LogItCoreObject {
    public ProfileManager(File path, Map<String, Object> fields) {
        if (path == null || fields == null)
            throw new IllegalArgumentException();

        this.path = path;

        for (Map.Entry<String, Object> e : fields.entrySet()) {
            String fieldName = e.getKey();
            String fieldDefinition = e.getValue().toString();

            try {
                definedFields.add(newField(fieldName, fieldDefinition));
            } catch (RuntimeException ex) {
                String exMsg = ex.getMessage();

                if (exMsg == null) {
                    exMsg = ex.getClass().getSimpleName();

                    log(Level.WARNING, ex);
                }

                log(Level.WARNING,
                        "Invalid field definition." + " Field name: " + fieldName + "." + " Cause: " + exMsg);
            }
        }
    }

    @Override
    public void dispose() {
        path = null;

        if (definedFields != null) {
            definedFields.clear();
            definedFields = null;
        }

        if (fileCache != null) {
            fileCache.clear();
            fileCache = null;
        }

        if (configurationCache != null) {
            configurationCache.clear();
            configurationCache = null;
        }
    }

    public boolean containsProfile(String playerName) {
        if (StringUtils.isBlank(playerName))
            throw new IllegalArgumentException();

        return new File(path, playerName.toLowerCase() + ".yml").exists();
    }

    /**
     * Returns a field with the specified name.
     * 
     * @param fieldName the field name.
     * 
     * @return the field object or {@code null} if no field with this name was found.
     */
    public Field getField(String fieldName) {
        if (fieldName == null)
            throw new IllegalArgumentException();

        for (Field field : definedFields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }

        return null;
    }

    public List<Field> getDefinedFields() {
        return ImmutableList.copyOf(definedFields);
    }

    public boolean isFieldDefined(String fieldName) {
        if (fieldName == null)
            throw new IllegalArgumentException();

        for (Field field : definedFields) {
            if (field.getName().equals(fieldName)) {
                return true;
            }
        }

        return false;
    }

    public Object getProfileObject(String playerName, String fieldName) {
        return getProfileConfiguration(playerName).get(fieldName);
    }

    public String getProfileString(String playerName, String fieldName) {
        return getProfileConfiguration(playerName).getString(fieldName);
    }

    public int getProfileInteger(String playerName, String fieldName) {
        return getProfileConfiguration(playerName).getInt(fieldName);
    }

    public double getProfileFloat(String playerName, String fieldName) {
        return getProfileConfiguration(playerName).getDouble(fieldName);
    }

    public void setProfileString(String playerName, String fieldName, String value) {
        if (StringUtils.isBlank(playerName) || StringUtils.isBlank(fieldName) || value == null) {
            throw new IllegalArgumentException();
        }

        Field field = getField(fieldName);

        if (field instanceof StringField) {
            StringField stringField = (StringField) field;

            if (value.length() < stringField.getMinLength() || value.length() > stringField.getMaxLength()) {
                throw new IllegalArgumentException();
            }
        } else if (field instanceof SetField) {
            SetField setField = (SetField) field;

            if (!setField.isAccepted(value)) {
                throw new IllegalArgumentException();
            }
        } else {
            throw new RuntimeException("Incompatible field type: " + field.getClass().getSimpleName());
        }

        getProfileConfiguration(playerName).set(fieldName, value);
        saveProfileConfiguration(playerName);
    }

    public void setProfileInteger(String playerName, String fieldName, int value) {
        if (StringUtils.isBlank(playerName) || StringUtils.isBlank(fieldName)) {
            throw new IllegalArgumentException();
        }

        Field field = getField(fieldName);

        if (!(field instanceof IntegerField)) {
            throw new RuntimeException("Incompatible field type: " + field.getClass().getSimpleName());
        }

        IntegerField integerField = (IntegerField) field;

        if (value < integerField.getMinValue() || value > integerField.getMaxValue()) {
            throw new IllegalArgumentException();
        }

        getProfileConfiguration(playerName).set(fieldName, value);
        saveProfileConfiguration(playerName);
    }

    public void setProfileFloat(String playerName, String fieldName, double value) {
        if (StringUtils.isBlank(playerName) || StringUtils.isBlank(fieldName)) {
            throw new IllegalArgumentException();
        }

        Field field = getField(fieldName);

        if (!(field instanceof FloatField)) {
            throw new RuntimeException("Incompatible field type: " + field.getClass().getSimpleName());
        }

        FloatField floatField = (FloatField) field;

        if (value < floatField.getMinValue() || value > floatField.getMaxValue()) {
            throw new IllegalArgumentException();
        }

        getProfileConfiguration(playerName).set(fieldName, value);
        saveProfileConfiguration(playerName);
    }

    public void removeProfileObject(String playerName, String fieldName) {
        if (StringUtils.isBlank(playerName) || StringUtils.isBlank(fieldName)) {
            throw new IllegalArgumentException();
        }

        getProfileConfiguration(playerName).set(fieldName, null);
        saveProfileConfiguration(playerName);
    }

    public File getPath() {
        return path;
    }

    private File[] listProfiles() {
        return path.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".yml");
            }
        });
    }

    private YamlConfiguration getProfileConfiguration(String playerName) {
        if (StringUtils.isBlank(playerName)) {
            throw new IllegalArgumentException();
        }

        File profileFile = fileCache.get(playerName);

        if (profileFile == null) {
            fileCache.put(playerName, profileFile = new File(path, playerName.toLowerCase() + ".yml"));
        }

        YamlConfiguration configuration = configurationCache.get(playerName);

        if (configuration == null) {
            configurationCache.put(playerName, configuration = YamlConfiguration.loadConfiguration(profileFile));
        }

        return configuration;
    }

    private void saveProfileConfiguration(String playerName) {
        if (StringUtils.isBlank(playerName)) {
            throw new IllegalArgumentException();
        }

        YamlConfiguration configuration = getProfileConfiguration(playerName);

        try {
            configuration.save(fileCache.get(playerName));
        } catch (IOException ex) {
            log(Level.WARNING, "Could not save profile configuration with player name: " + playerName, ex);
        }
    }

    private Field newField(String fieldName, String definitionString) {
        if (StringUtils.isBlank(fieldName) || StringUtils.isBlank(definitionString)) {
            throw new IllegalArgumentException();
        }

        Matcher definitionMatcher = FIELD_DEFINITION_PATTERN.matcher(definitionString);

        if (definitionMatcher.find()) {
            String type = definitionMatcher.group(1).toUpperCase();
            String arguments = definitionMatcher.group(2);

            switch (type) {
            case "STRING": {
                Matcher rangeMatcher = INTEGER_RANGE_PATTERN.matcher(arguments);

                if (rangeMatcher.find()) {
                    return new StringField(fieldName, Integer.parseInt(rangeMatcher.group(1)),
                            Integer.parseInt(rangeMatcher.group(2)));
                } else {
                    throw new RuntimeException("Malformed argument list.");
                }
            }
            case "INTEGER": {
                Matcher rangeMatcher = INTEGER_RANGE_PATTERN.matcher(arguments);

                if (rangeMatcher.find()) {
                    return new IntegerField(fieldName, Integer.parseInt(rangeMatcher.group(1)),
                            Integer.parseInt(rangeMatcher.group(2)));
                } else {
                    throw new RuntimeException("Malformed argument list.");
                }
            }
            case "FLOAT": {
                Matcher rangeMatcher = FLOAT_RANGE_PATTERN.matcher(arguments);

                if (rangeMatcher.find()) {
                    return new FloatField(fieldName, Double.valueOf(rangeMatcher.group(1)),
                            Double.valueOf(rangeMatcher.group(2)));
                } else {
                    throw new RuntimeException("Malformed argument list.");
                }
            }
            case "SET":
                return new SetField(fieldName, Arrays.asList(arguments.split("(?<!\\\\),")));

            default:
                throw new RuntimeException("Unknown field type.");
            }
        } else {
            throw new RuntimeException("Malformed field definition.");
        }
    }

    private final static Pattern FIELD_DEFINITION_PATTERN = Pattern.compile("^\\s*([A-Za-z_0-9]+)" // Type name
            + "\\s*\\[(.*)\\]\\s*$"); // Constraint arguments

    private final static Pattern INTEGER_RANGE_PATTERN = Pattern.compile("^\\s*(-?[0-9]+)" // Min
            + "\\s*\\.\\.\\." // Range operator
            + "\\s*(-?[0-9]+)\\s*$"); // Max

    private final static Pattern FLOAT_RANGE_PATTERN = Pattern.compile("^\\s*(-?[0-9]+\\.[0-9]+)" // Min
            + "\\s*\\.\\.\\." // Range operator
            + "\\s*(-?[0-9]+\\.[0-9]+)\\s*$"); // Max

    private File path;
    private List<Field> definedFields = new LinkedList<>();
    private Map<String, File> fileCache = new HashMap<>();
    private Map<String, YamlConfiguration> configurationCache = new HashMap<>();
}