All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.yudichev.jiotty.common.varstore.VarStoreImpl Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
package net.yudichev.jiotty.common.varstore;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.inject.BindingAnnotation;
import net.yudichev.jiotty.common.lang.MoreThrowables;

import javax.inject.Inject;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.nio.file.Files.*;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static net.yudichev.jiotty.common.lang.Locks.inLock;

final class VarStoreImpl implements VarStore {
    private static final ObjectMapper mapper = new ObjectMapper()
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule())
            .registerModule(new GuavaModule())
            .enable(SerializationFeature.INDENT_OUTPUT);

    private final Path storeFile;
    private final Lock lock = new ReentrantLock();
    private final Path storeFileTmp;

    @Inject
    VarStoreImpl(@AppName String applicationName) {
        storeFile = Paths.get(System.getProperty("user.home"), "." + applicationName, "data.json");
        storeFileTmp = storeFile.resolveSibling("data.json.tmp");
    }

    @Override
    public void saveValue(String key, Object value) {
        inLock(lock, () -> MoreThrowables.asUnchecked(() -> {
            ObjectNode configNode = readConfig();

            configNode.set(key, mapper.valueToTree(value));
            mapper.writeValue(storeFileTmp.toFile(), configNode);
            move(storeFileTmp, storeFile, REPLACE_EXISTING);
        }));
    }

    @Override
    public  Optional readValue(Class type, String key) {
        return inLock(lock, () -> MoreThrowables.getAsUnchecked(() -> {
            ObjectNode configNode = readConfig();

            return Optional.ofNullable(configNode.get(key))
                    .map(valueNode -> MoreThrowables.getAsUnchecked(() -> mapper.readerFor(type).readValue(valueNode)));
        }));
    }

    private ObjectNode readConfig() throws IOException {
        if (!isRegularFile(storeFile)) {
            createDirectories(storeFile.getParent());
            createFile(storeFile);
        }

        ObjectNode configNode;
        byte[] contents = readAllBytes(storeFile);
        if (contents.length > 0) {
            configNode = mapper.readValue(contents, ObjectNode.class);
        } else {
            configNode = mapper.createObjectNode();
        }

        return configNode;
    }

    @BindingAnnotation
    @Target({FIELD, PARAMETER, METHOD})
    @Retention(RUNTIME)
    @interface AppName {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy