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

global.namespace.fun.io.delta.model.DeltaModel Maven / Gradle / Ivy

There is a newer version: 2.4.1
Show newest version
/*
 * Copyright (C) 2013-2018 Schlichtherle IT Services.
 * All rights reserved. Use is subject to license terms.
 */
package global.namespace.fun.io.delta.model;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.empty;
import static java.util.Optional.of;

/**
 * A Value Object which represents the meta data in a delta-archive file.
 * It encapsulates unmodifiable collections of changed, unchanged, added and
 * removed entry names and message digests in canonical string notation,
 * attributed with the message digest algorithm name and byte length.
 *
 * @author Christian Schlichtherle
 */
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "ConstantConditions"})
public final class DeltaModel {

    private final String digestAlgorithmName;

    private final Optional digestByteLength;

    private final Map changed;

    private final Map unchanged, added, removed;

    private DeltaModel(final Builder b) {
        final MessageDigest digest = b.messageDigest.get();
        this.digestAlgorithmName = digest.getAlgorithm();
        this.digestByteLength = lengthBytes(digest);
        this.changed = changedMap(b.changed);
        this.unchanged = unchangedMap(b.unchanged);
        this.added = unchangedMap(b.added);
        this.removed = unchangedMap(b.removed);
    }

    /** Returns a new builder for a delta model. */
    public static Builder builder() { return new Builder(); }

    private static Optional lengthBytes(final MessageDigest digest) {
        final MessageDigest clone;
        try {
            clone = MessageDigest.getInstance(digest.getAlgorithm());
        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
        if (clone.getDigestLength() == digest.getDigestLength()) {
            return empty();
        } else {
            return of(digest.getDigestLength());
        }
    }

    private static Map changedMap(final Collection entries) {
        final Map map = new LinkedHashMap<>(initialCapacity(entries));
        for (EntryNameAndTwoDigestValues entryNameAndTwoDigestValues : entries) {
            map.put(entryNameAndTwoDigestValues.name(), entryNameAndTwoDigestValues);
        }
        return unmodifiableMap(map);
    }

    private static Map unchangedMap(final Collection entries) {
        final Map map = new LinkedHashMap<>(initialCapacity(entries));
        for (EntryNameAndDigestValue entryNameAndDigestValue : entries) {
            map.put(entryNameAndDigestValue.name(), entryNameAndDigestValue);
        }
        return unmodifiableMap(map);
    }

    private static int initialCapacity(Collection c) { return HashMaps.initialCapacity(c.size()); }

    /** Returns the message digest algorithm name. */
    public String digestAlgorithmName() { return digestAlgorithmName; }

    /**
     * Returns the message digest byte length.
     * This is empty if and only if the byte length of the message digest used to build this delta model is the default
     * value for the algorithm.
     */
    public Optional digestByteLength() { return digestByteLength; }

    /**
     * Returns a collection of the entry name and two message digests for the
     * changed entries.
     */
    public Collection changedEntries() { return changed.values(); }

    /** Looks up the given entry name in the changed entries. */
    public EntryNameAndTwoDigestValues changed(String name) { return changed.get(name); }

    /**
     * Returns a collection of the entry name and message digest for the
     * unchanged entries.
     */
    public Collection unchangedEntries() { return unchanged.values(); }

    /** Looks up the given entry name in the unchanged entries. */
    public EntryNameAndDigestValue unchanged(String name) { return unchanged.get(name); }

    /**
     * Returns a collection of the entry name and message digest for the
     * added entries.
     */
    public Collection addedEntries() { return added.values(); }

    /** Looks up the given entry name in the added entries. */
    public EntryNameAndDigestValue added(String name) { return added.get(name); }

    /**
     * Returns a collection of the entry name and message digest for the
     * removed entries.
     */
    public Collection removedEntries() { return removed.values(); }

    /** Looks up the given entry name in the removed entries. */
    public EntryNameAndDigestValue removed(String name) { return removed.get(name); }

    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof DeltaModel)) {
            return false;
        }
        final DeltaModel that = (DeltaModel) obj;
        return  this.digestAlgorithmName.equals(that.digestAlgorithmName) &&
                this.digestByteLength.equals(that.digestByteLength) &&
                this.changed.equals(that.changed) &&
                this.unchanged.equals(that.unchanged) &&
                this.added.equals(that.added) &&
                this.removed.equals(that.removed);
    }

    @Override
    public int hashCode() {
        int hash = 17;
        hash = 31 * hash + digestAlgorithmName.hashCode();
        hash = 31 * hash + digestByteLength.hashCode();
        hash = 31 * hash + changed.hashCode();
        hash = 31 * hash + unchanged.hashCode();
        hash = 31 * hash + added.hashCode();
        hash = 31 * hash + removed.hashCode();
        return hash;
    }

    /**
     * A builder for a delta model.
     * The default value for the collection of unchanged, changed,
     * added and removed entry names and message digests is an
     * empty collection.
     */
    public static final class Builder {

        private Optional messageDigest = empty();
        private Collection changed = emptyList();
        private Collection unchanged = emptyList(), added = emptyList(), removed = emptyList();

        private Builder() { }

        public Builder messageDigest(final MessageDigest messageDigest) {
            this.messageDigest = of(messageDigest);
            return this;
        }

        public Builder changedEntries(final Collection changed) {
            this.changed = requireNonNull(changed);
            return this;
        }

        public Builder unchangedEntries(final Collection unchanged) {
            this.unchanged = requireNonNull(unchanged);
            return this;
        }

        public Builder addedEntries(final Collection added) {
            this.added = requireNonNull(added);
            return this;
        }

        public Builder removedEntries(final Collection removed) {
            this.removed = requireNonNull(removed);
            return this;
        }

        public DeltaModel build() { return new DeltaModel(this); }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy