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

com.jparams.store.AbstractStore Maven / Gradle / Ivy

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

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.jparams.store.comparison.ComparisonPolicy;
import com.jparams.store.index.AbstractIndex;
import com.jparams.store.index.Index;
import com.jparams.store.index.IndexCreationException;
import com.jparams.store.index.IndexException;
import com.jparams.store.reference.Reference;
import com.jparams.store.reference.ReferenceManager;

public abstract class AbstractStore extends AbstractCollection implements Store
{
    private final ReferenceManager referenceManager;
    private final Map> indexMap;

    protected AbstractStore(final ReferenceManager referenceManager)
    {
        this.referenceManager = referenceManager;
        this.indexMap = new HashMap<>();
    }

    protected AbstractStore(final ReferenceManager referenceManager, final Set> indexes)
    {
        this.referenceManager = referenceManager;
        this.indexMap = indexes.stream().collect(Collectors.toMap(AbstractIndex::getName, Function.identity()));
    }

    @Override
    public  Index multiIndex(final String indexName, final KeyProvider, V> keyProvider, final ComparisonPolicy comparisonPolicy) throws IndexException
    {
        if (indexMap.containsKey(indexName))
        {
            throw new IllegalArgumentException("An index already exists with this name");
        }

        final AbstractIndex newIndex = createIndex(indexName, keyProvider, comparisonPolicy);
        indexMap.put(indexName, newIndex);
        indexReferences(Collections.singleton(newIndex), referenceManager.getReferences());
        return newIndex;
    }

    @Override
    public Index getIndex(final String indexName)
    {
        return indexMap.get(indexName);
    }

    @Override
    public Collection> getIndexes()
    {
        return Collections.unmodifiableCollection(indexMap.values());
    }

    @Override
    public boolean removeIndex(final Index index)
    {
        if (index.equals(indexMap.get(index.getName())))
        {
            indexMap.remove(index.getName());
            return true;
        }

        return false;
    }

    @Override
    public boolean removeIndex(final String indexName)
    {
        return indexMap.remove(indexName) != null;
    }

    @Override
    public void reindex()
    {
        indexReferences(indexMap.values(), referenceManager.getReferences());
    }

    @Override
    public void reindex(final V item)
    {
        reindex(Collections.singleton(item));
    }

    @Override
    public void reindex(final Collection items)
    {
        indexReferences(indexMap.values(), items.stream()
                                                .map(referenceManager::findReference)
                                                .filter(Optional::isPresent)
                                                .map(Optional::get)
                                                .collect(Collectors.toList()));
    }

    @Override
    public int size()
    {
        return referenceManager.size();
    }

    @Override
    public boolean isEmpty()
    {
        return size() == 0;
    }

    @Override
    public boolean contains(final Object obj)
    {
        return referenceManager.findReference(obj).isPresent();
    }

    @Override
    public Iterator iterator()
    {
        return new StoreIterator(referenceManager.getReferences().iterator());
    }

    @Override
    public boolean addAll(final Collection collection)
    {
        final List> references = new ArrayList<>();
        boolean changed = false;

        for (final V item : collection)
        {
            final Optional> existingReference = referenceManager.findReference(item);

            if (existingReference.isPresent())
            {
                references.add(existingReference.get());
                continue;
            }

            references.add(referenceManager.add(item));
            changed = true;
        }

        indexReferences(indexMap.values(), references);
        return changed;
    }

    @Override
    public boolean add(final V item)
    {
        return addAll(Collections.singleton(item));
    }

    @Override
    public boolean remove(final Object obj)
    {
        final Reference reference = referenceManager.remove(obj);

        if (reference != null)
        {
            indexMap.values().forEach(index -> index.removeIndex(reference));
            return true;
        }

        return false;
    }

    @Override
    public void clear()
    {
        referenceManager.clear();
        indexMap.values().forEach(AbstractIndex::clear);
    }

    @Override
    public Store copy()
    {
        return createCopy(referenceManager, indexMap.values());
    }

    protected abstract Store createCopy(final ReferenceManager referenceManager, final Collection> indexes);

    protected abstract  AbstractIndex createIndex(String indexName, KeyProvider, V> keyProvider, ComparisonPolicy comparisonPolicy);

    protected ReferenceManager getReferenceManager()
    {
        return referenceManager;
    }

    private static  void indexReferences(final Collection> indexes, final Collection> references)
    {
        final List exceptions = new ArrayList<>();

        for (final Reference reference : references)
        {
            for (final AbstractIndex index : indexes)
            {
                try
                {
                    index.index(reference);
                }
                catch (final IndexCreationException e)
                {
                    exceptions.add(e);
                }
            }
        }

        if (!exceptions.isEmpty())
        {
            final String message = (exceptions.size() == 1 ? "1 exception" : exceptions.size() + " exceptions") + " occurred during indexing";
            throw new IndexException(message, exceptions);
        }
    }

    private class StoreIterator implements Iterator
    {
        private final Iterator> iterator;
        private Reference previous;

        StoreIterator(final Iterator> iterator)
        {
            this.iterator = iterator;
        }

        @Override
        public boolean hasNext()
        {
            return iterator.hasNext();
        }

        @Override
        public V next()
        {
            previous = iterator.next();
            return previous.get();
        }

        @Override
        public void remove()
        {
            iterator.remove();
            indexMap.values().forEach(index -> index.removeIndex(previous));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy