
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.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 - 2025 Weber Informatics LLC | Privacy Policy