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

org.javers.repository.inmemory.InMemoryRepository Maven / Gradle / Ivy

There is a newer version: 7.6.1
Show newest version
package org.javers.repository.inmemory;

import org.javers.common.collections.Lists;

import java.util.Optional;
import org.javers.common.validation.Validate;
import org.javers.core.CommitIdGenerator;
import org.javers.core.commit.Commit;
import org.javers.core.commit.CommitId;
import org.javers.core.json.JsonConverter;
import org.javers.core.metamodel.object.CdoSnapshot;
import org.javers.core.metamodel.object.GlobalId;
import org.javers.core.metamodel.object.InstanceId;
import org.javers.core.metamodel.object.ValueObjectId;
import org.javers.core.metamodel.type.EntityType;
import org.javers.core.metamodel.type.ManagedType;
import org.javers.repository.api.JaversRepository;
import org.javers.repository.api.QueryParams;
import org.javers.repository.api.SnapshotIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * Fake impl of JaversRepository
 *
 * @author bartosz walacik
 */
public class InMemoryRepository implements JaversRepository {
    private static final Logger logger = LoggerFactory.getLogger(InMemoryRepository.class);

    private Map> snapshots = new ConcurrentHashMap<>();

    private Map commits = new ConcurrentHashMap<>();
    private AtomicInteger counter = new AtomicInteger();

    private CommitId head;
    private JsonConverter jsonConverter;

    public InMemoryRepository() {
    }

    @Override
    public List getValueObjectStateHistory(final EntityType ownerEntity, final String path, QueryParams queryParams) {
        Validate.argumentsAreNotNull(ownerEntity, path, queryParams);

        List result =  Lists.positiveFilter(getAll(), input -> {
            if (!(input.getGlobalId() instanceof ValueObjectId)) {
                return false;
            }
            ValueObjectId id = (ValueObjectId) input.getGlobalId();

            return id.hasOwnerOfType(ownerEntity)
                    && id.getFragment().equals(path);
        });

        return applyQueryParams(result, queryParams);
    }

    @Override
    public List getStateHistory(GlobalId globalId, QueryParams queryParams) {
        Validate.argumentsAreNotNull(globalId, queryParams);

        List filtered = new ArrayList<>();

        for (CdoSnapshot snapshot : getAll()) {
            if (snapshot.getGlobalId().equals(globalId)) {
                filtered.add(snapshot);
            }
            if (queryParams.isAggregate() && isParent(globalId, snapshot.getGlobalId())){
                filtered.add(snapshot);
            }
        }

        return applyQueryParams(filtered, queryParams);
    }

    private boolean isParent(GlobalId parentCandidate, GlobalId childCandidate) {
        if (! (parentCandidate instanceof InstanceId && childCandidate instanceof ValueObjectId)){
            return false;
        }

        InstanceId parent = (InstanceId)parentCandidate;
        ValueObjectId child = (ValueObjectId)childCandidate;

        return child.getOwnerId().equals(parent);
    }

    @Override
    public List getStateHistory(Set givenClasses, QueryParams queryParams) {
        Validate.argumentsAreNotNull(givenClasses, queryParams);
        List filtered = new ArrayList<>();

        for (CdoSnapshot snapshot : getAll()) {
            for (ManagedType givenClass : givenClasses) {
                if (snapshot.getGlobalId().isTypeOf(givenClass)) {
                    filtered.add(snapshot);
                }
                if (queryParams.isAggregate() && isParent(givenClass, snapshot.getGlobalId())){
                    filtered.add(snapshot);
                }
            }
        }

        return applyQueryParams(filtered, queryParams);
    }

    private boolean isParent(ManagedType parentCandidate, GlobalId childCandidate) {
        if (! (parentCandidate instanceof EntityType && childCandidate instanceof ValueObjectId)){
            return false;
        }

        EntityType parent = (EntityType)parentCandidate;
        ValueObjectId child = (ValueObjectId)childCandidate;

        return child.getOwnerId().getTypeName().equals(parent.getName());
    }

    private List applyQueryParams(List snapshots, final QueryParams queryParams){
        if (queryParams.commitIds().size() > 0) {
            snapshots = filterSnapshotsByCommitIds(snapshots, queryParams.commitIds());
        }
        if (queryParams.toCommitId().isPresent()) {
            snapshots = filterSnapshotsByToCommitId(snapshots, queryParams.toCommitId().get());
        }
        if (queryParams.version().isPresent()) {
            snapshots = Lists.positiveFilter(snapshots, snapshot -> snapshot.getVersion() == queryParams.version().get());
        }
        if (queryParams.author().isPresent()) {
            snapshots = filterSnapshotsByAuthor(snapshots, queryParams.author().get());
        }
        if (queryParams.hasDates()) {
            snapshots = filterSnapshotsByCommitDate(snapshots, queryParams);
        }
        if (queryParams.changedProperty().isPresent()){
            snapshots = filterByPropertyName(snapshots, queryParams.changedProperty().get());
        }
        if (queryParams.snapshotType().isPresent()){
            snapshots = Lists.positiveFilter(snapshots, snapshot -> snapshot.getType() == queryParams.snapshotType().get());
        }
        snapshots = filterSnapshotsByCommitProperties(snapshots, queryParams.commitProperties());
        return trimResultsToRequestedSlice(snapshots, queryParams.skip(), queryParams.limit());
    }

    private List filterSnapshotsByToCommitId(List snapshots, CommitId commitId) {
        return Lists.positiveFilter(snapshots, snapshot -> snapshot.getCommitMetadata().getId().isBeforeOrEqual(commitId));
    }

    private List filterSnapshotsByCommitIds(List snapshots, final Set commitIds) {
        return Lists.positiveFilter(snapshots, snapshot -> commitIds.contains(snapshot.getCommitId()));
    }

    private List filterSnapshotsByAuthor(List snapshots, final String author) {
        return Lists.positiveFilter(snapshots, snapshot -> author.equals(snapshot.getCommitMetadata().getAuthor()));
    }

    private List filterSnapshotsByCommitDate(List snapshots, final QueryParams queryParams) {
        return Lists.positiveFilter(snapshots, snapshot -> queryParams.isDateInRange(snapshot.getCommitMetadata().getCommitDate()));
    }

    private List filterSnapshotsByCommitProperties(List snapshots, final Map commitProperties) {
        return Lists.positiveFilter(snapshots, snapshot ->
            commitProperties.entrySet().stream().allMatch(commitProperty -> {
                Map actualCommitProperties = snapshot.getCommitMetadata().getProperties();
                return actualCommitProperties.containsKey(commitProperty.getKey()) &&
                        actualCommitProperties.get(commitProperty.getKey()).equals(commitProperty.getValue());
            })
        );
    }

    private List trimResultsToRequestedSlice(List snapshots, int from, int size) {
        int fromIndex = Math.min(from, snapshots.size());
        int toIndex = Math.min(from + size, snapshots.size());
        return new ArrayList<>(snapshots.subList(fromIndex, toIndex));
    }

    @Override
    public Optional getLatest(GlobalId globalId) {
        Validate.argumentsAreNotNull(globalId);

        if (contains(globalId)) {
            return Optional.of(readSnapshots(globalId).peek());
        }

        return Optional.empty();
    }

    @Override
    public List getSnapshots(QueryParams queryParams) {
        Validate.argumentIsNotNull(queryParams);

        return applyQueryParams(getAll(), queryParams);
    }

    @Override
    public List getSnapshots(Collection snapshotIdentifiers) {
        return Lists.transform(getPersistedIdentifiers(snapshotIdentifiers), snapshotIdentifier -> {
            List objectSnapshots = readSnapshots(snapshotIdentifier.getGlobalId());
            return objectSnapshots.get(objectSnapshots.size() - ((int)snapshotIdentifier.getVersion()));
        });
    }

    private List getPersistedIdentifiers(Collection snapshotIdentifiers) {
        return Lists.positiveFilter(new ArrayList<>(snapshotIdentifiers), snapshotIdentifier -> contains(snapshotIdentifier.getGlobalId()) &&
            snapshotIdentifier.getVersion() <= readSnapshots(snapshotIdentifier.getGlobalId()).size());
    }

    @Override
    public void persist(Commit commit) {
        Validate.argumentsAreNotNull(commit);

        List snapshots = commit.getSnapshots();
        for (CdoSnapshot s : snapshots){
            persist(s);
        }
        logger.debug("{} snapshot(s) persisted", snapshots.size());
        head = commit.getId();
        commits.put(getHeadId(), counter.incrementAndGet());
    }

    @Override
    public CommitId getHeadId() {
        return head;
    }

    @Override
    public void setJsonConverter(JsonConverter jsonConverter) {
        this.jsonConverter = jsonConverter;
    }

    private List filterByPropertyName(List snapshots, final String propertyName){
        return Lists.positiveFilter(snapshots, input -> input.hasChangeAt(propertyName));
    }

    private List getAll(){
        List all = new ArrayList<>();

        snapshots.keySet().forEach(it -> all.addAll(readSnapshots(it)));
        Collections.sort(all, Comparator.comparingInt(o1 -> Integer.MAX_VALUE - getSeq(o1.getCommitMetadata().getId())));

        return all;
    }

    private int getSeq(CommitId commitId) {
        return commits.get(commitId);
    }

    private synchronized void persist(CdoSnapshot snapshot) {
        Validate.conditionFulfilled(jsonConverter != null, "jsonConverter is null");
        String globalIdValue = snapshot.getGlobalId().value();

        LinkedList snapshotsList = snapshots.get(globalIdValue);
        if (snapshotsList == null){
            snapshotsList = new LinkedList<>();
            snapshots.put(globalIdValue, snapshotsList);
        }

        snapshotsList.push(jsonConverter.toJson(snapshot));
    }

    @Override
    public void ensureSchema() {
    }

    private boolean contains(GlobalId globalId) {
        return contains(globalId.value());
    }

    private boolean contains(String globalIdValue) {
        return snapshots.containsKey(globalIdValue);
    }

    private LinkedList readSnapshots(String globalIdValue) {
        LinkedList result = new LinkedList<>();

        if (!contains(globalIdValue)) {
            return result;
        }

        snapshots.get(globalIdValue).forEach(it -> result.add(jsonConverter.fromJson(it, CdoSnapshot.class)));
        return result;
    }

    private LinkedList readSnapshots(GlobalId globalId) {
        return readSnapshots(globalId.value());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy