package org.vertexium.accumulo.iterator;
import org.apache.accumulo.core.client.IteratorSetting;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.iterators.Filter;
import org.apache.accumulo.core.iterators.IteratorEnvironment;
import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
import org.apache.hadoop.io.Text;
import org.vertexium.ElementFilter;
import org.vertexium.accumulo.iterator.util.SetOfStringsEncoder;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
public class HasAuthorizationFilter extends Filter {
private static final String SETTING_AUTHORIZATION_TO_MATCH = "authorizationToMatch";
private static final String SETTING_FILTERS = "filters";
private static final Pattern SPLIT_PATTERN = Pattern.compile("[^A-Za-z0-9_\\-\\.]");
private String authorizationToMatch;
private EnumSet<ElementFilter> filters;
private Map<Text, Boolean> matchCache;
public static void setAuthorizationToMatch(IteratorSetting settings, String authorizationToMatch) {
settings.addOption(SETTING_AUTHORIZATION_TO_MATCH, authorizationToMatch);
}
public static void setFilters(IteratorSetting settings, EnumSet<ElementFilter> filters) {
Set<String> filterStrings = new HashSet<>();
for (ElementFilter filter : filters) {
filterStrings.add(filter.name());
}
settings.addOption(SETTING_FILTERS, SetOfStringsEncoder.encodeToString(filterStrings));
}
@Override
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env) throws IOException {
super.init(source, options, env);
authorizationToMatch = options.get(SETTING_AUTHORIZATION_TO_MATCH);
Set<String> filterStrings = SetOfStringsEncoder.decodeFromString(options.get(SETTING_FILTERS));
List<ElementFilter> filtersCollection = new ArrayList<>();
for (String filterString : filterStrings) {
filtersCollection.add(ElementFilter.valueOf(filterString));
}
filters = EnumSet.copyOf(filtersCollection);
matchCache = new HashMap<>();
}
@Override
public SortedKeyValueIterator<Key, Value> deepCopy(IteratorEnvironment env) {
HasAuthorizationFilter filter = (HasAuthorizationFilter) super.deepCopy(env);
filter.authorizationToMatch = this.authorizationToMatch;
filter.filters = this.filters;
filter.matchCache = new HashMap<>();
return filter;
}
@Override
public boolean accept(Key k, Value v) {
if (filters.contains(ElementFilter.ELEMENT)
&& (k.getColumnFamily().equals(EdgeIterator.CF_SIGNAL) || k.getColumnFamily().equals(VertexIterator.CF_SIGNAL))
&& isMatch(k)) {
return true;
}
if (filters.contains(ElementFilter.PROPERTY) && k.getColumnFamily().equals(EdgeIterator.CF_PROPERTY) && isMatch(k)) {
return true;
}
if (filters.contains(ElementFilter.PROPERTY_METADATA) && k.getColumnFamily().equals(EdgeIterator.CF_PROPERTY_METADATA) && isMatch(k)) {
return true;
}
return false;
}
private boolean isMatch(Key k) {
Text columnVisibilityText = k.getColumnVisibility();
if (columnVisibilityText.getLength() == 0) {
return false;
}
Boolean match = matchCache.get(columnVisibilityText);
if (match != null) {
return match;
}
String[] parts = SPLIT_PATTERN.split(k.getColumnVisibilityParsed().toString());
for (String part : parts) {
if (part.equals(authorizationToMatch)) {
matchCache.put(columnVisibilityText, true);
return true;
}
}
matchCache.put(columnVisibilityText, false);
return false;
}
}