Package com.skcraft.launcher.persistence

Source Code of com.skcraft.launcher.persistence.Persistence

/*
* SK's Minecraft Launcher
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
* Please see LICENSE.txt for license information.
*/

package com.skcraft.launcher.persistence;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.ByteSink;
import com.google.common.io.ByteSource;
import com.google.common.io.Closer;
import com.google.common.io.Files;
import lombok.NonNull;
import lombok.extern.java.Log;

import java.io.*;
import java.util.WeakHashMap;
import java.util.logging.Level;

/**
* Simple persistence framework that can read an object from a file, bind
* that object to that file, and allow any code having a reference to the
* object make changes to the object and save those changes back to disk.
* </p>
* For example:
* <pre>config = Persistence.load(file, Configuration.class);
* config.changeSomething();
* Persistence.commit(config);</pre>
*/
@Log
public final class Persistence {

    private static final ObjectMapper mapper = new ObjectMapper();
    private static final WeakHashMap<Object, ByteSink> bound =
            new WeakHashMap<Object, ByteSink>();

    private Persistence() {
    }

    /**
     * Bind an object to a path where the object will be saved.
     *
     * @param object the object
     * @param sink the byte sink
     */
    public static void bind(@NonNull Object object, @NonNull ByteSink sink) {
        synchronized (bound) {
            bound.put(object, sink);
        }
    }

    /**
     * Save an object to file.
     *
     * @param object the object
     * @throws java.io.IOException on save error
     */
    public static void commit(@NonNull Object object) throws IOException {
        ByteSink sink;
        synchronized (bound) {
            sink = bound.get(object);
            if (sink == null) {
                throw new IOException("Cannot persist unbound object: " + object);
            }
        }

        Closer closer = Closer.create();
        try {
            OutputStream os = closer.register(sink.openBufferedStream());
            mapper.writeValue(os, object);
        } finally {
            closer.close();
        }
    }

    /**
     * Save an object to file, and send all errors to the log.
     *
     * @param object the object
     */
    public static void commitAndForget(@NonNull Object object)  {
        try {
            commit(object);
        } catch (IOException e) {
            log.log(Level.WARNING, "Failed to save " + object.getClass() + ": " + object.toString(), e);
        }
    }

    /**
     * Read an object from a byte source, without binding it.
     *
     * @param source byte source
     * @param cls the class
     * @param returnNull true to return null if the object could not be loaded
     * @param <V> the type of class
     * @return an object
     */
    public static <V> V read(ByteSource source, Class<V> cls, boolean returnNull) {
        V object;
        Closer closer = Closer.create();

        try {
            object = mapper.readValue(closer.register(source.openBufferedStream()), cls);
        } catch (IOException e) {
            if (!(e instanceof FileNotFoundException)) {
                log.log(Level.INFO, "Failed to load" + cls.getCanonicalName(), e);
            }

            if (returnNull) {
                return null;
            }

            try {
                object = cls.newInstance();
            } catch (InstantiationException e1) {
                throw new RuntimeException(
                        "Failed to construct object with no-arg constructor", e1);
            } catch (IllegalAccessException e1) {
                throw new RuntimeException(
                        "Failed to construct object with no-arg constructor", e1);
            }
        } finally {
            try {
                closer.close();
            } catch (IOException e) {
            }
        }

        return object;
    }

    /**
     * Read an object from file, without binding it.
     *
     * @param file the file
     * @param cls the class
     * @param returnNull true to return null if the object could not be loaded
     * @param <V> the type of class
     * @return an object
     */
    public static <V> V read(File file, Class<V> cls, boolean returnNull) {
        return read(Files.asByteSource(file), cls, returnNull);
    }


    /**
     * Read an object from file, without binding it.
     *
     * @param file the file
     * @param cls the class
     * @param <V> the type of class
     * @return an object
     */
    public static <V> V read(File file, Class<V> cls) {
        return read(file, cls, false);
    }

    /**
     * Read an object from file.
     *
     * @param file the file
     * @param cls the class
     * @param returnNull true to return null if the object could not be loaded
     * @param <V> the type of class
     * @return an object
     */
    public static <V> V load(File file, Class<V> cls, boolean returnNull) {
        ByteSource source = Files.asByteSource(file);
        ByteSink sink = new MkdirByteSink(Files.asByteSink(file), file.getParentFile());

        Scrambled scrambled = cls.getAnnotation(Scrambled.class);
        if (cls.getAnnotation(Scrambled.class) != null) {
            source = new ScramblingSourceFilter(source, scrambled.value());
            sink = new ScramblingSinkFilter(sink, scrambled.value());
        }

        V object = read(source, cls, returnNull);
        Persistence.bind(object, sink);
        return object;
    }

    /**
     * Read an object from file.
     *
     * <p>If the file does not exist or loading fails, construct a new instance of
     * the given class by using its no-arg constructor.</p>
     *
     * @param file the file
     * @param cls the class
     * @param <V> the type of class
     * @return an object
     */
    public static <V> V load(File file, Class<V> cls) {
        return load(file, cls, false);
    }

    /**
     * Write an object to file.
     *
     * @param file the file
     * @param object the object
     * @throws java.io.IOException on I/O error
     */
    public static void write(File file, Object object) throws IOException {
        file.getParentFile().mkdirs();
        mapper.writeValue(file, object);
    }

}
TOP

Related Classes of com.skcraft.launcher.persistence.Persistence

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.