001package fr.aumgn.bukkitutils.gson;
002
003import java.io.BufferedWriter;
004import java.io.File;
005import java.io.FileInputStream;
006import java.io.FileOutputStream;
007import java.io.IOException;
008import java.io.InputStreamReader;
009import java.io.OutputStreamWriter;
010import java.lang.reflect.Type;
011
012import org.bukkit.plugin.Plugin;
013
014import com.google.common.base.Charsets;
015import com.google.gson.Gson;
016import com.google.gson.reflect.TypeToken;
017import com.google.gson.stream.JsonReader;
018
019/**
020 * Class which handle loading of .json resources
021 * for a given plugin using {@link Gson}.
022 */
023public class GsonLoader {
024
025    private final Gson gson;
026    private final Plugin plugin;
027
028    public GsonLoader(Gson gson, Plugin plugin) {
029        this.gson = gson;
030        this.plugin = plugin;
031    }
032
033    private File getFile(String filename)
034            throws GsonLoadException {
035        File file = new File(plugin.getDataFolder(), filename);
036        File folder = file.getParentFile();
037        if (!file.exists() && !folder.exists() && !folder.mkdirs()) {
038            throw new GsonLoadException("Unable to create directory : "
039                    + plugin.getDataFolder().getPath());
040        }
041
042        return file;
043    }
044
045    /**
046     * Loads if exists or creates the given resource.
047     */
048    public <T> T loadOrCreate(String filename, Class<T> klass)
049            throws GsonLoadException {
050        return loadOrCreate(filename, klass, klass);
051    }
052
053    /**
054     * Loads if exists or creates the given resource.
055     */
056    @SuppressWarnings("unchecked")
057    public <T> T loadOrCreate(String filename, TypeToken<T> typeToken)
058            throws GsonLoadException {
059        return (T) loadOrCreate(filename, typeToken.getType(),
060                typeToken.getRawType());
061    }
062
063    private <T> T loadOrCreate(String filename, Type type, Class<T> klass)
064            throws GsonLoadException {
065        try {
066            File file = getFile(filename);
067            T instance;
068            if (file.createNewFile()) {
069                instance = klass.newInstance();
070            } else {
071                instance = unsafeLoad(file, type);
072            }
073
074            // This ensures user file is updated with newer fields.
075            write(file, instance);
076
077            return instance;
078        } catch (IOException exc) {
079            throw new GsonLoadException(exc);
080        } catch (InstantiationException exc) {
081            throw new GsonLoadException(exc);
082        } catch (IllegalAccessException exc) {
083            throw new GsonLoadException(exc);
084        }
085    }
086
087    /**
088     * Loads the given resource.
089     */
090    public <T> T load(File file, Type klass) throws GsonLoadException {
091        try {
092            return unsafeLoad(file, klass);
093        } catch (IOException exc) {
094            throw new GsonLoadException(exc);
095        }
096    }
097
098    /**
099     * Loads the given resource.
100     */
101    public <T> T load(File file, TypeToken<T> typeToken)
102            throws GsonLoadException {
103        try {
104            return unsafeLoad(file, typeToken.getRawType());
105        } catch (IOException exc) {
106            throw new GsonLoadException(exc);
107        }
108    }
109
110    private <T> T unsafeLoad(File file, Type klass) throws IOException {
111        InputStreamReader isr = new InputStreamReader(
112                new FileInputStream(file), Charsets.UTF_8);
113        JsonReader reader = new JsonReader(isr);
114
115        try {
116            return gson.fromJson(reader, klass);
117        } finally {
118            reader.close();
119        }
120    }
121
122    /**
123     * Writes the given resource.
124     */
125    public void write(String filename, Object instance)
126            throws GsonLoadException {
127        try {
128            write(getFile(filename), instance);
129        } catch (IOException exc) {
130            throw new GsonLoadException(exc);
131        }
132    }
133
134    private void write(File file, Object instance) throws IOException {
135        OutputStreamWriter osw = new OutputStreamWriter(
136                new FileOutputStream(file), Charsets.UTF_8);
137        BufferedWriter writer = new BufferedWriter(osw);
138
139        try {
140            writer.write(gson.toJson(instance));
141        } finally {
142            writer.close();
143        }
144    }
145}