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

com.goeuro.sync4j.sync.LockFile Maven / Gradle / Ivy

package com.goeuro.sync4j.sync;

import com.goeuro.sync4j.fs.LoosePath;
import com.goeuro.sync4j.fs.Path;
import com.goeuro.sync4j.fs.Paths;
import com.goeuro.sync4j.utils.Applications;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.io.*;
import java.time.OffsetDateTime;
import java.util.Optional;
import java.util.Properties;
import java.util.UUID;

import static com.goeuro.sync4j.fs.Paths.normalize;
import static com.goeuro.sync4j.fs.Paths.open;
import static com.goeuro.sync4j.sync.LockFileContent.lockFileContent;
import static com.goeuro.sync4j.utils.IOStreams.closeQuietly;
import static java.util.Optional.*;

@Immutable
public class LockFile {

    @Nonnull
    public static  Builder lockFile(@Nonnull Path file) {
        return new Builder<>(file);
    }

    @Nonnull
    private final Path file;

    protected LockFile(
        @Nonnull Path file
    ) {
        this.file = file;
    }

    public void delete() {
        Paths.delete(file());
    }

    public void write(@Nonnull LockFileContent content) {
        try (final InputStream is = createPropertiesAsInputStream(content)) {
            Paths.write(file(), is);
        } catch (final IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Nonnull
    protected Properties createPropertiesFor(@Nonnull LockFileContent content) {
        final Properties properties = new Properties();
        properties.setProperty("id", content.id().toString());
        properties.setProperty("lastPing", content.lastPing().toString());
        content.owner().ifPresent(owner -> properties.setProperty("owner", owner));

        properties.setProperty("agent.name", Applications.name());
        properties.setProperty("agent.version", Applications.version());
        properties.setProperty("agent.buildTimestamp", Applications.buildTimestamp().toString());
        return properties;
    }

    @Nonnull
    protected byte[] createPropertiesAsBytesFor(@Nonnull LockFileContent content) throws IOException {
        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            createPropertiesFor(content).store(baos, null);
            return baos.toByteArray();
        }
    }

    @Nonnull
    protected InputStream createPropertiesAsInputStream(@Nonnull LockFileContent content) throws IOException {
        final byte[] bytes = createPropertiesAsBytesFor(content);
        return new ByteArrayInputStream(bytes);
    }

    @Nonnull
    public Optional read() {
        try {
            final Optional stream = tryOpenInputStream();
            try {
                return stream
                    .flatMap(this::parse);
            } finally {
                closeQuietly(stream);
            }
        } catch (final IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Nonnull
    protected Optional tryOpenInputStream() throws IOException {
        return open(file());
    }

    @Nonnull
    protected Optional parse(@Nonnull InputStream is) {
        try {
            final Properties properties = new Properties();
            properties.load(is);
            return parse(properties);
        } catch (final IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Nonnull
    protected Optional parse(@Nonnull Properties properties) throws IOException {
        final Optional id = ofNullable(properties.getProperty("id")).map(UUID::fromString);
        final Optional lastPing = ofNullable(properties.getProperty("lastPing")).map(OffsetDateTime::parse);
        final Optional owner = ofNullable(properties.getProperty("owner"));

        if (!id.isPresent() || !lastPing.isPresent()) {
            return empty();
        }
        return of(lockFileContent()
            .withId(id)
            .lastPingedAt(lastPing)
            .withOwner(owner)
            .build());
    }

    @Nonnull
    protected Path file() {
        return file;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + ":" + file();
    }

    public static class Builder {

        @Nonnull
        private final Path file;

        protected Builder(
            @Nonnull Path file
        ) {
            this.file = normalize(file)
                .orElseThrow(() -> new IllegalArgumentException("Illegal path provided: " + file));
        }

        @Nonnull
        public LockFile build() {
            return new LockFile<>(
                file
            );
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy