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

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

There is a newer version: 3.1.4
Show newest version
package com.jparams.store.index;

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

import com.jparams.store.index.comparison.ComparisonPolicy;
import com.jparams.store.index.reducer.Reducer;
import com.jparams.store.reference.Reference;

/**
 * Maintains indexes against references to stored items
 *
 * @param  value type
 */
public class ReferenceIndex implements Index
{
    private final String name;
    private final KeyMapper, V> keyMapper;
    private final Reducer reducer;
    private final ComparisonPolicy comparisonPolicy;
    private final Map> keyToReferencesMap;
    private final Map, Set> referenceToKeysMap;

    private ReferenceIndex(final String name, final KeyMapper, V> keyMapper, final Reducer reducer, final ComparisonPolicy comparisonPolicy, final Map> keyToReferencesMap, final Map, Set> referenceToKeysMap)
    {
        this.name = name;
        this.keyMapper = keyMapper;
        this.reducer = reducer;
        this.comparisonPolicy = comparisonPolicy;
        this.keyToReferencesMap = keyToReferencesMap;
        this.referenceToKeysMap = referenceToKeysMap;
    }

    public ReferenceIndex(final String indexName, final KeyMapper, V> keyMapper, final Reducer reducer, final ComparisonPolicy comparisonPolicy)
    {
        this(indexName, keyMapper, reducer, comparisonPolicy, new HashMap<>(), new HashMap<>());
    }

    @Override
    public String getName()
    {
        return name;
    }

    @Override
    public Optional findFirst(final Object key)
    {
        final K comparableKey = getComparableKey(key);
        final References references = keyToReferencesMap.get(comparableKey);

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

        return references.findFirst();
    }

    public Set> getReferences(final Object key)
    {
        final K comparableKey = getComparableKey(key);
        final References references = keyToReferencesMap.get(comparableKey);

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

        return references.getAllReferences();
    }

    @Override
    public List get(final Object key)
    {
        final K comparableKey = getComparableKey(key);
        final References references = keyToReferencesMap.get(comparableKey);

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

        return references.getAll();
    }

    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 -> keyToReferencesMap.computeIfAbsent(key, ignore -> new References<>(key, reference, reducer)).add(reference));
        }
    }

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

        if (keys == null)
        {
            return;
        }

        for (final K key : keys)
        {
            final References references = keyToReferencesMap.get(key);

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

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

        referenceToKeysMap.remove(reference);
    }

    public void clear()
    {
        keyToReferencesMap.clear();
        referenceToKeysMap.clear();
    }

    public ReferenceIndex copy()
    {
        final Map> keyToReferencesMapCopy = keyToReferencesMap.entrySet()
                                                                                  .stream()
                                                                                  .collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().copy()));

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

        return new ReferenceIndex<>(name, keyMapper, reducer, comparisonPolicy, keyToReferencesMapCopy, referenceToKeysMapCopy);
    }

    private Set generateKeys(final Reference reference) throws IndexCreationException
    {
        final V item;

        try
        {
            item = reference.get();
        }
        catch (final RuntimeException e)
        {
            throw new IndexCreationException("Index: " + name + ". Unable to retrieve item to index", e);
        }

        try
        {
            return keyMapper.map(item)
                            .stream()
                            .map(this::getComparableKey)
                            .filter(Objects::nonNull)
                            .collect(Collectors.toSet());
        }
        catch (final RuntimeException e)
        {
            throw new IndexCreationException("Index: " + name + ". Error generating indexes for item: " + item, e);
        }
    }

    private K getComparableKey(final Object key)
    {
        if (key == null || !comparisonPolicy.supports(key.getClass()))
        {
            return null;
        }

        @SuppressWarnings("unchecked") final K comparable = comparisonPolicy.createComparable((K) key);
        return comparable;
    }

    @Override
    public String toString()
    {
        return "Index[name='" + name + "\']";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy