com.voxelplugineering.voxelsniper.service.persistence.JsonDataSourceReader.java Source code

Java tutorial

Introduction

Here is the source code for com.voxelplugineering.voxelsniper.service.persistence.JsonDataSourceReader.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 The Voxel Plugineering Team
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.voxelplugineering.voxelsniper.service.persistence;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Optional;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.voxelplugineering.voxelsniper.GunsmithLogger;

/**
 * A data source which serializes data to a file as Json.
 */
public class JsonDataSourceReader implements DataSourceReader {

    /**
     * A {@link DataSourceBuilder} for json data sources.
     */
    public static final DataSourceBuilder<JsonDataSourceReader> getBuilder(final DataSourceFactory factory) {
        return new DataSourceBuilder<JsonDataSourceReader>() {

            @Override
            public Optional<JsonDataSourceReader> build(DataContainer args) {
                if (!args.containsKey("source") || !args.containsKey("sourceArgs")) {
                    GunsmithLogger.getLogger().warn("Failed to build JsonDataSourceReader, invalid args");
                    return Optional.absent();
                }
                String sourceName = args.getString("source").get();
                Optional<DataSource> source = factory.build(sourceName, args.getContainer("sourceArgs").get());
                if (!source.isPresent()) {
                    GunsmithLogger.getLogger().warn("Failed to build data source for JsonDataSourceReader");
                    return Optional.absent();
                }
                if (!StreamDataSource.class.isAssignableFrom(source.get().getClass())) {
                    GunsmithLogger.getLogger()
                            .warn("Failed to build JsonDataSourceReader: Source was not a StreamDataSource");
                    return Optional.absent();
                }
                StreamDataSource stream = (StreamDataSource) source.get();
                return Optional.of(new JsonDataSourceReader(stream));
            }

        };
    }

    private final StreamDataSource source;
    private boolean pretty;

    /**
     * Creates a new {@link JsonDataSourceReader} based on the given stream source.
     * 
     * @param source The source
     */
    public JsonDataSourceReader(StreamDataSource source) {
        this.source = source;
    }

    /**
     * Sets whether this data source reader should output pretty json.
     * 
     * @param pretty Pretty json
     */
    public void setPrettyOutput(boolean pretty) {
        this.pretty = pretty;
    }

    @Override
    public void write(DataContainer container) throws IOException {
        Gson gson;
        if (this.pretty) {
            gson = new GsonBuilder().setPrettyPrinting().create();
        } else {
            gson = new GsonBuilder().create();
        }
        JsonObject json = fromContainer(container);

        String data = gson.toJson(json);
        this.source.write(data.getBytes("UTF-8"));
    }

    /**
     * Recursively converts the given {@link DataContainer} to a {@link JsonObject}.
     * 
     * @param container The container to convert
     * @return The json object representing the container
     */
    public JsonObject fromContainer(DataContainer container) {
        JsonObject json = new JsonObject();

        for (Map.Entry<String, Object> entry : container.entrySet()) {
            Class<?> type = entry.getValue().getClass();
            if (type == Byte.class || type == byte.class || type == Short.class || type == short.class
                    || type == Integer.class || type == int.class || type == Long.class || type == long.class
                    || type == Float.class || type == float.class || type == Double.class || type == double.class) {
                json.addProperty(entry.getKey(), (Number) entry.getValue());
            } else if (type == Boolean.class || type == boolean.class) {
                json.addProperty(entry.getKey(), (Boolean) entry.getValue());
            } else if (type == Character.class || type == char.class) {
                json.addProperty(entry.getKey(), (Character) entry.getValue());
            } else if (type == String.class) {
                json.addProperty(entry.getKey(), (String) entry.getValue());
            } else if (DataContainer.class.isAssignableFrom(type)) {
                json.add(entry.getKey(), fromContainer((DataContainer) entry.getValue()));
            } else if (DataSerializable.class.isAssignableFrom(type)) {
                json.add(entry.getKey(), fromContainer(((DataSerializable) entry.getValue()).toContainer()));
            }
        }
        return json;
    }

    @Override
    public DataContainer read() throws IOException {
        DataContainer container = null;
        String data = new String(this.source.read(), "UTF-8");
        JsonParser parser = new JsonParser();
        JsonElement rootelement = parser.parse(data);
        container = toContainer(rootelement);
        return container;
    }

    /**
     * Recursively converts the given {@link JsonElement} to a {@link DataContainer}.
     * 
     * @param rootelement The element to convert
     * @return The new {@link DataContainer}
     */
    public DataContainer toContainer(JsonElement rootelement) {
        DataContainer container = new MemoryContainer("");

        if (rootelement.isJsonObject()) {
            JsonObject root = rootelement.getAsJsonObject();
            for (Entry<String, JsonElement> entry : root.entrySet()) {
                String key = entry.getKey();
                JsonElement element = entry.getValue();
                if (element.isJsonPrimitive()) {
                    JsonPrimitive primitive = element.getAsJsonPrimitive();
                    if (primitive.isBoolean()) {
                        container.setBoolean(key, primitive.getAsBoolean());
                    } else if (primitive.isString()) {
                        container.setString(key, primitive.getAsString());
                    } else if (primitive.isNumber()) {
                        container.setNumber(key, primitive.getAsNumber());
                    }
                } else if (element.isJsonObject()) {
                    container.setContainer(key, toContainer(element));
                }
            }
        }

        return container;

    }

    @Override
    public void write(DataSerializable serial) throws IOException {
        write(serial.toContainer());
    }

    @Override
    public <T extends DataSerializable> T read(T object) throws IOException {
        object.fromContainer(read());
        return object;
    }

    @Override
    public Optional<String> getName() {
        return this.source.getName();
    }

    @Override
    public boolean exists() {
        return this.source.exists();
    }

}