com.sk89q.craftbook.mech.area.CopyManager.java Source code

Java tutorial

Introduction

Here is the source code for com.sk89q.craftbook.mech.area.CopyManager.java

Source

package com.sk89q.craftbook.mech.area;

// $Id$
/*
 * CraftBook Copyright (C) 2010 sk89q <http://www.sk89q.com>
 * 
 * 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/>.
 */

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.bukkit.World;

import com.sk89q.craftbook.bukkit.CraftBookPlugin;
import com.sk89q.craftbook.util.HistoryHashMap;
import com.sk89q.worldedit.data.DataException;

/**
 * Used to load, save, and cache cuboid copies.
 *
 * @author sk89q, Silthus
 */
public class CopyManager {

    private static CraftBookPlugin plugin = CraftBookPlugin.inst();
    private static final CopyManager INSTANCE = new CopyManager();
    private static final Pattern NAME_PATTERN = Pattern.compile("^[a-z0-9_]+$", Pattern.CASE_INSENSITIVE);

    /**
     * Cache.
     */
    private final HashMap<String, HistoryHashMap<String, CuboidCopy>> cache = new HashMap<String, HistoryHashMap<String, CuboidCopy>>();

    /**
     * Remembers missing copies so as to not look for them on disk.
     */
    private final HashMap<String, HistoryHashMap<String, Long>> missing = new HashMap<String, HistoryHashMap<String, Long>>();

    /**
     * Gets the copy manager instance
     *
     * @return The Copy Manager Instance
     */
    public static CopyManager getInstance() {

        return INSTANCE;
    }

    /**
     * Checks to see whether a name is a valid copy name.
     *
     * @param name
     *
     * @return
     */
    public static boolean isValidName(String name) {

        // name needs to be between 1 and 13 letters long so we can fit the
        return !name.isEmpty() && name.length() <= 13 && NAME_PATTERN.matcher(name).matches();
    }

    /**
     * Checks to see whether a name is a valid namespace.
     *
     * @param name
     *
     * @return
     */
    public static boolean isValidNamespace(String name) {

        return !name.isEmpty() && name.length() <= 14 && NAME_PATTERN.matcher(name).matches();
    }

    /**
     * Renames a namespace.
     * 
     * @param originalName The old name.
     * @param newName The new name. (Post rename)
     */
    public static void renameNamespace(File dataFolder, String originalName, String newName) {

        File oldDir = new File(dataFolder, "areas/" + originalName);
        File newDir = new File(dataFolder, "areas/" + newName);
        if (oldDir.isDirectory()) {
            oldDir.renameTo(newDir);
        } else {
            oldDir.mkdir();
            oldDir.renameTo(newDir);
        }
    }

    /**
     * Checks if the area and namespace exists.
     *
     * @param namespace to check
     * @param area      to check
     */
    public static boolean isExistingArea(File dataFolder, String namespace, String area) {

        area = StringUtils.replace(area, "-", "") + getFileSuffix();
        File file = new File(dataFolder, "areas/" + namespace);
        return new File(file, area).exists();
    }

    /**
     * Load a copy from disk. This may return a cached copy. If the copy is not cached,
     * the file will be loaded from disk if possible. If the copy
     * does not exist, an exception will be raised. An exception may be raised if the file exists but cannot be read
     * for whatever reason.
     *
     * @param namespace
     * @param id
     *
     * @return
     *
     * @throws IOException
     * @throws MissingCuboidCopyException
     * @throws CuboidCopyException
     */
    public CuboidCopy load(World world, String namespace, String id) throws IOException, CuboidCopyException {

        id = id.toLowerCase(Locale.ENGLISH);
        String cacheKey = namespace + "/" + id;

        HistoryHashMap<String, Long> missing = getMissing(world.getUID().toString());

        if (missing.containsKey(cacheKey)) {
            long lastCheck = missing.get(cacheKey);
            if (lastCheck > System.currentTimeMillis())
                throw new MissingCuboidCopyException(id);
        }

        HistoryHashMap<String, CuboidCopy> cache = getCache(world.getUID().toString());

        CuboidCopy copy = cache.get(cacheKey);

        if (copy == null) {
            File folder = new File(new File(plugin.getDataFolder(), "areas"), namespace);
            copy = CuboidCopy.load(new File(folder, id + getFileSuffix()), world);
            missing.remove(cacheKey);
            cache.put(cacheKey, copy);
            return copy;
        }

        return copy;
    }

    /**
     * Save a copy to disk. The copy will be cached.
     *
     * @param id
     * @param copyFlat
     *
     * @throws IOException
     */
    public void save(World world, String namespace, String id, CuboidCopy copyFlat)
            throws IOException, DataException {

        HistoryHashMap<String, CuboidCopy> cache = getCache(world.getUID().toString());

        File folder = new File(new File(plugin.getDataFolder(), "areas"), namespace);

        if (!folder.exists()) {
            folder.mkdirs();
        }

        id = id.toLowerCase(Locale.ENGLISH);

        String cacheKey = namespace + "/" + id;

        copyFlat.save(new File(folder, id + getFileSuffix()));
        missing.remove(cacheKey);
        cache.put(cacheKey, copyFlat);
    }

    /**
     * Gets whether a copy can be made.
     *
     * @param namespace
     * @param ignore
     *
     * @return -1 if the copy can be made, some other number for the count
     */
    public int meetsQuota(World world, String namespace, String ignore, int quota) {

        String ignoreFilename = ignore + getFileSuffix();

        String[] files = new File(new File(plugin.getDataFolder(), "areas"), namespace).list();

        if (files == null)
            return quota > 0 ? -1 : 0;
        else if (ignore == null)
            return files.length < quota ? -1 : files.length;
        else {
            int count = 0;

            for (String f : files) {
                if (f.equals(ignoreFilename))
                    return -1;

                count++;
            }

            return count < quota ? -1 : count;
        }
    }

    private HistoryHashMap<String, CuboidCopy> getCache(String world) {

        HistoryHashMap<String, CuboidCopy> worldCache = cache.get(world);
        if (worldCache != null) {
            return worldCache;
        } else {
            worldCache = new HistoryHashMap<String, CuboidCopy>(10);
            cache.put(world, worldCache);
            return worldCache;
        }
    }

    private HistoryHashMap<String, Long> getMissing(String world) {

        HistoryHashMap<String, Long> worldCache = missing.get(world);
        if (worldCache != null) {
            return worldCache;
        } else {
            worldCache = new HistoryHashMap<String, Long>(10);
            missing.put(world, worldCache);
            return worldCache;
        }
    }

    private static String getFileSuffix() {

        return plugin.getConfiguration().areaUseSchematics ? ".schematic" : ".cbcopy";
    }
}