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

com.jparams.store.index.ReferenceIndex Maven / Gradle / Ivy

package com.jparams.store.index;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.jparams.store.KeyProvider;
import com.jparams.store.comparison.ComparisonPolicy;
import com.jparams.store.reference.Reference;

/**
 * Maintains indexes against references to stored items
 *
 * @param  value type
 */
public class ReferenceIndex extends AbstractIndex
{
    private final Map>> keyToReferenceMap;
    private final Map, Set> referenceToKeysMap;

    public ReferenceIndex(final String indexName, final KeyProvider, V> keyProvider, final ComparisonPolicy comparisonPolicy)
    {
        super(indexName, keyProvider, comparisonPolicy);
        this.keyToReferenceMap = new HashMap<>();
        this.referenceToKeysMap = new HashMap<>();
    }

    private ReferenceIndex(final String indexName, final KeyProvider, V> keyProvider, final ComparisonPolicy comparisonPolicy, final Map>> keyToReferenceMap, final Map, Set> referenceToKeysMap)
    {
        super(indexName, keyProvider, comparisonPolicy);
        this.keyToReferenceMap = keyToReferenceMap;
        this.referenceToKeysMap = referenceToKeysMap;
    }

    @Override
    public Optional findFirst(final Object key)
    {
        final Object comparableKey = getComparableKey(key);
        final Set> references = keyToReferenceMap.get(comparableKey);

        if (references == null)
        {
            return Optional.empty();
        }

        return references.stream().map(Reference::get).findFirst();
    }

    @Override
    public List get(final Object key)
    {
        final Object comparableKey = getComparableKey(key);
        final Set> references = keyToReferenceMap.get(comparableKey);

        if (references == null)
        {
            return Collections.emptyList();
        }

        return references.stream().map(Reference::get).collect(Collectors.toList());
    }

    @Override
    public void index(final Reference reference) throws IndexCreationException
    {
        final Set keys = generateKeys(reference);

        removeIndex(reference);

        if (!keys.isEmpty())
        {
            referenceToKeysMap.put(reference, Collections.unmodifiableSet(keys));
            keys.forEach(key -> keyToReferenceMap.computeIfAbsent(key, ignore -> new LinkedHashSet<>()).add(reference));
        }
    }

    @Override
    public void removeIndex(final Reference reference)
    {
        final Set keys = referenceToKeysMap.get(reference);

        if (keys == null)
        {
            return;
        }

        for (final Object key : keys)
        {
            final Set> references = keyToReferenceMap.get(key);

            if (reference != null)
            {
                references.remove(reference);

                if (references.isEmpty())
                {
                    keyToReferenceMap.remove(key);
                }
            }
        }

        referenceToKeysMap.remove(reference);
    }

    @Override
    protected AbstractIndex copy(final String name, final KeyProvider, V> keyProvider, final ComparisonPolicy comparisonPolicy)
    {
        final Map>> keyToReferenceMapCopy = keyToReferenceMap.entrySet()
                                                                                      .stream()
                                                                                      .collect(Collectors.toMap(Entry::getKey, references -> new LinkedHashSet<>(references.getValue())));

        final Map, Set> referenceToKeysMapCopy = new HashMap<>(referenceToKeysMap);

        return new ReferenceIndex<>(name, keyProvider, comparisonPolicy, keyToReferenceMapCopy, referenceToKeysMapCopy);
    }

    @Override
    public void clear()
    {
        keyToReferenceMap.clear();
        referenceToKeysMap.clear();
    }
}